github.com/clly/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  }