github.imxd.top/hashicorp/consul@v1.4.5/agent/consul/fsm/snapshot.go (about) 1 package fsm 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/armon/go-metrics" 8 "github.com/hashicorp/consul/agent/consul/state" 9 "github.com/hashicorp/consul/agent/structs" 10 "github.com/hashicorp/go-msgpack/codec" 11 "github.com/hashicorp/raft" 12 ) 13 14 // snapshot is used to provide a snapshot of the current 15 // state in a way that can be accessed concurrently with operations 16 // that may modify the live state. 17 type snapshot struct { 18 state *state.Snapshot 19 } 20 21 // snapshotHeader is the first entry in our snapshot 22 type snapshotHeader struct { 23 // LastIndex is the last index that affects the data. 24 // This is used when we do the restore for watchers. 25 LastIndex uint64 26 } 27 28 // persister is a function used to help snapshot the FSM state. 29 type persister func(s *snapshot, sink raft.SnapshotSink, encoder *codec.Encoder) error 30 31 // persisters is a list of snapshot functions. 32 var persisters []persister 33 34 // registerPersister adds a new helper. This should be called at package 35 // init() time. 36 func registerPersister(fn persister) { 37 persisters = append(persisters, fn) 38 } 39 40 // restorer is a function used to load back a snapshot of the FSM state. 41 type restorer func(header *snapshotHeader, restore *state.Restore, decoder *codec.Decoder) error 42 43 // restorers is a map of restore functions by message type. 44 var restorers map[structs.MessageType]restorer 45 46 // registerRestorer adds a new helper. This should be called at package 47 // init() time. 48 func registerRestorer(msg structs.MessageType, fn restorer) { 49 if restorers == nil { 50 restorers = make(map[structs.MessageType]restorer) 51 } 52 if restorers[msg] != nil { 53 panic(fmt.Errorf("Message %d is already registered", msg)) 54 } 55 restorers[msg] = fn 56 } 57 58 // Persist saves the FSM snapshot out to the given sink. 59 func (s *snapshot) Persist(sink raft.SnapshotSink) error { 60 defer metrics.MeasureSince([]string{"fsm", "persist"}, time.Now()) 61 62 // Write the header 63 header := snapshotHeader{ 64 LastIndex: s.state.LastIndex(), 65 } 66 encoder := codec.NewEncoder(sink, msgpackHandle) 67 if err := encoder.Encode(&header); err != nil { 68 sink.Cancel() 69 return err 70 } 71 72 // Run all the persisters to write the FSM state. 73 for _, fn := range persisters { 74 if err := fn(s, sink, encoder); err != nil { 75 sink.Cancel() 76 return err 77 } 78 } 79 return nil 80 } 81 82 func (s *snapshot) Release() { 83 s.state.Close() 84 }