| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- package migrate
- import (
- "encoding/json"
- "errors"
- "fmt"
- "hash/crc32"
- "io/ioutil"
- "log"
- "os"
- "path"
- "sort"
- "strconv"
- "strings"
- raftpb "github.com/coreos/etcd/raft/raftpb"
- )
- type Snapshot4 struct {
- State []byte `json:"state"`
- LastIndex uint64 `json:"lastIndex"`
- LastTerm uint64 `json:"lastTerm"`
- Peers []struct {
- Name string `json:"name"`
- ConnectionString string `json:"connectionString"`
- } `json:"peers"`
- //TODO(bcwaldon): is this needed?
- //Path string `json:"path"`
- }
- func (s *Snapshot4) Snapshot5() *raftpb.Snapshot {
- snap5 := raftpb.Snapshot{
- Data: s.State,
- Index: int64(s.LastIndex),
- Term: int64(s.LastTerm),
- Nodes: make([]int64, len(s.Peers)),
- }
- for i, p := range s.Peers {
- snap5.Nodes[i] = hashName(p.Name)
- }
- return &snap5
- }
- func DecodeLatestSnapshot4FromDir(snapdir string) (*Snapshot4, error) {
- fname, err := FindLatestFile(snapdir)
- if err != nil {
- return nil, err
- }
- if fname == "" {
- return nil, nil
- }
- snappath := path.Join(snapdir, fname)
- log.Printf("Decoding snapshot from %s", snappath)
- return DecodeSnapshot4FromFile(snappath)
- }
- // FindLatestFile identifies the "latest" filename in a given directory
- // by sorting all the files and choosing the highest value.
- func FindLatestFile(dirpath string) (string, error) {
- dir, err := os.OpenFile(dirpath, os.O_RDONLY, 0)
- if err != nil {
- if os.IsNotExist(err) {
- err = nil
- }
- return "", err
- }
- defer dir.Close()
- fnames, err := dir.Readdirnames(-1)
- if err != nil {
- return "", err
- }
- if len(fnames) == 0 {
- return "", nil
- }
- names, err := NewSnapshotFileNames(fnames)
- if err != nil {
- return "", err
- }
- return names[len(names)-1].FileName, nil
- }
- func DecodeSnapshot4FromFile(path string) (*Snapshot4, error) {
- // Read snapshot data.
- f, err := os.OpenFile(path, os.O_RDONLY, 0)
- if err != nil {
- return nil, err
- }
- defer f.Close()
- return DecodeSnapshot4(f)
- }
- func DecodeSnapshot4(f *os.File) (*Snapshot4, error) {
- // Verify checksum
- var checksum uint32
- n, err := fmt.Fscanf(f, "%08x\n", &checksum)
- if err != nil {
- return nil, err
- } else if n != 1 {
- return nil, errors.New("miss heading checksum")
- }
- // Load remaining snapshot contents.
- b, err := ioutil.ReadAll(f)
- if err != nil {
- return nil, err
- }
- // Generate checksum.
- byteChecksum := crc32.ChecksumIEEE(b)
- if uint32(checksum) != byteChecksum {
- return nil, errors.New("bad checksum")
- }
- // Decode snapshot.
- snapshot := new(Snapshot4)
- if err = json.Unmarshal(b, snapshot); err != nil {
- return nil, err
- }
- return snapshot, nil
- }
- func NewSnapshotFileNames(names []string) ([]SnapshotFileName, error) {
- s := make([]SnapshotFileName, 0)
- for _, n := range names {
- trimmed := strings.TrimSuffix(n, ".ss")
- if trimmed == n {
- return nil, fmt.Errorf("file %q does not have .ss extension", n)
- }
- parts := strings.SplitN(trimmed, "_", 2)
- if len(parts) != 2 {
- return nil, fmt.Errorf("unrecognized file name format %q", n)
- }
- fn := SnapshotFileName{FileName: n}
- var err error
- fn.Term, err = strconv.ParseUint(parts[0], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("unable to parse term from filename %q: %v", err)
- }
- fn.Index, err = strconv.ParseUint(parts[1], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("unable to parse index from filename %q: %v", err)
- }
- s = append(s, fn)
- }
- sortable := SnapshotFileNames(s)
- sort.Sort(&sortable)
- return s, nil
- }
- type SnapshotFileNames []SnapshotFileName
- type SnapshotFileName struct {
- FileName string
- Term uint64
- Index uint64
- }
- func (n *SnapshotFileNames) Less(i, j int) bool {
- iTerm, iIndex := (*n)[i].Term, (*n)[i].Index
- jTerm, jIndex := (*n)[j].Term, (*n)[j].Index
- return iTerm < jTerm || (iTerm == jTerm && iIndex < jIndex)
- }
- func (n *SnapshotFileNames) Swap(i, j int) {
- (*n)[i], (*n)[j] = (*n)[j], (*n)[i]
- }
- func (n *SnapshotFileNames) Len() int {
- return len([]SnapshotFileName(*n))
- }
|