1 Star 0 Fork 2

who7708/etcd

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
.github
Documentation
alarm
auth
client
clientv3
cmd
compactor
contrib
discovery
e2e
error
etcdctl
etcdmain
etcdserver
hack
integration
lease
logos
mvcc
pkg
proxy
raft
rafthttp
scripts
snap
snappb
db.go
message.go
metrics.go
snapshotter.go
snapshotter_test.go
store
tools
version
wal
.dockerignore
.gitignore
.godir
.header
.travis.yml
CONTRIBUTING.md
DCO
Dockerfile
Dockerfile-release
LICENSE
MAINTAINERS
NOTICE
Procfile
README.md
ROADMAP.md
V2Procfile
build
build.bat
build.ps1
cover
etcd.conf.yml.sample
main.go
test
克隆/下载
snapshotter.go 5.10 KB
一键复制 编辑 原始数据 按行查看 历史
XiangLi 提交于 9年前 . snap: fix write snap
// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package snap stores raft nodes' states with snapshots.
package snap
import (
"errors"
"fmt"
"hash/crc32"
"io/ioutil"
"os"
"path"
"sort"
"strings"
"time"
pioutil "github.com/coreos/etcd/pkg/ioutil"
"github.com/coreos/etcd/pkg/pbutil"
"github.com/coreos/etcd/raft"
"github.com/coreos/etcd/raft/raftpb"
"github.com/coreos/etcd/snap/snappb"
"github.com/coreos/pkg/capnslog"
)
const (
snapSuffix = ".snap"
)
var (
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "snap")
ErrNoSnapshot = errors.New("snap: no available snapshot")
ErrEmptySnapshot = errors.New("snap: empty snapshot")
ErrCRCMismatch = errors.New("snap: crc mismatch")
crcTable = crc32.MakeTable(crc32.Castagnoli)
// A map of valid files that can be present in the snap folder.
validFiles = map[string]bool{
"db": true,
}
)
type Snapshotter struct {
dir string
}
func New(dir string) *Snapshotter {
return &Snapshotter{
dir: dir,
}
}
func (s *Snapshotter) SaveSnap(snapshot raftpb.Snapshot) error {
if raft.IsEmptySnap(snapshot) {
return nil
}
return s.save(&snapshot)
}
func (s *Snapshotter) save(snapshot *raftpb.Snapshot) error {
start := time.Now()
fname := fmt.Sprintf("%016x-%016x%s", snapshot.Metadata.Term, snapshot.Metadata.Index, snapSuffix)
b := pbutil.MustMarshal(snapshot)
crc := crc32.Update(0, crcTable, b)
snap := snappb.Snapshot{Crc: crc, Data: b}
d, err := snap.Marshal()
if err != nil {
return err
} else {
marshallingDurations.Observe(float64(time.Since(start)) / float64(time.Second))
}
err = pioutil.WriteAndSyncFile(path.Join(s.dir, fname), d, 0666)
if err == nil {
saveDurations.Observe(float64(time.Since(start)) / float64(time.Second))
} else {
err1 := os.Remove(path.Join(s.dir, fname))
if err1 != nil {
plog.Errorf("failed to remove broken snapshot file %s", path.Join(s.dir, fname))
}
}
return err
}
func (s *Snapshotter) Load() (*raftpb.Snapshot, error) {
names, err := s.snapNames()
if err != nil {
return nil, err
}
var snap *raftpb.Snapshot
for _, name := range names {
if snap, err = loadSnap(s.dir, name); err == nil {
break
}
}
if err != nil {
return nil, ErrNoSnapshot
}
return snap, nil
}
func loadSnap(dir, name string) (*raftpb.Snapshot, error) {
fpath := path.Join(dir, name)
snap, err := Read(fpath)
if err != nil {
renameBroken(fpath)
}
return snap, err
}
// Read reads the snapshot named by snapname and returns the snapshot.
func Read(snapname string) (*raftpb.Snapshot, error) {
b, err := ioutil.ReadFile(snapname)
if err != nil {
plog.Errorf("cannot read file %v: %v", snapname, err)
return nil, err
}
if len(b) == 0 {
plog.Errorf("unexpected empty snapshot")
return nil, ErrEmptySnapshot
}
var serializedSnap snappb.Snapshot
if err = serializedSnap.Unmarshal(b); err != nil {
plog.Errorf("corrupted snapshot file %v: %v", snapname, err)
return nil, err
}
if len(serializedSnap.Data) == 0 || serializedSnap.Crc == 0 {
plog.Errorf("unexpected empty snapshot")
return nil, ErrEmptySnapshot
}
crc := crc32.Update(0, crcTable, serializedSnap.Data)
if crc != serializedSnap.Crc {
plog.Errorf("corrupted snapshot file %v: crc mismatch", snapname)
return nil, ErrCRCMismatch
}
var snap raftpb.Snapshot
if err = snap.Unmarshal(serializedSnap.Data); err != nil {
plog.Errorf("corrupted snapshot file %v: %v", snapname, err)
return nil, err
}
return &snap, nil
}
// snapNames returns the filename of the snapshots in logical time order (from newest to oldest).
// If there is no available snapshots, an ErrNoSnapshot will be returned.
func (s *Snapshotter) snapNames() ([]string, error) {
dir, err := os.Open(s.dir)
if err != nil {
return nil, err
}
defer dir.Close()
names, err := dir.Readdirnames(-1)
if err != nil {
return nil, err
}
snaps := checkSuffix(names)
if len(snaps) == 0 {
return nil, ErrNoSnapshot
}
sort.Sort(sort.Reverse(sort.StringSlice(snaps)))
return snaps, nil
}
func checkSuffix(names []string) []string {
snaps := []string{}
for i := range names {
if strings.HasSuffix(names[i], snapSuffix) {
snaps = append(snaps, names[i])
} else {
// If we find a file which is not a snapshot then check if it's
// a vaild file. If not throw out a warning.
if _, ok := validFiles[names[i]]; !ok {
plog.Warningf("skipped unexpected non snapshot file %v", names[i])
}
}
}
return snaps
}
func renameBroken(path string) {
brokenPath := path + ".broken"
if err := os.Rename(path, brokenPath); err != nil {
plog.Warningf("cannot rename broken snapshot file %v to %v: %v", path, brokenPath, err)
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/who7708/etcd.git
git@gitee.com:who7708/etcd.git
who7708
etcd
etcd
v3.0.17

搜索帮助