package raft import ( "context" "encoding/json" "fmt" "io" "time" "github.com/hashicorp/raft" ) type FSM Store /*type FSM struct { store *Store client *clientv3.Client } func NewFSM(endpoints []string, store *Store) (*FSM, error) { // Se connecter au cluster etcd client, err := clientv3.New(clientv3.Config{ Endpoints: endpoints, DialTimeout: 5 * time.Second, }) if err != nil { return nil, err } return &FSM{ store: store, client: client, }, nil }*/ // Apply applies a Raft log entry to the key-value store. func (f *FSM) Apply(l *raft.Log) interface{} { switch l.Type { case raft.LogCommand: var c command if err := json.Unmarshal(l.Data, &c); err != nil { panic(fmt.Sprintf("failed to unmarshal command: %s", err.Error())) } switch c.Op { case "set": f.applySet(c.Key, c.Value) case "delete": f.applyDelete(c.Key) default: panic(fmt.Sprintf("unrecognized command op: %s", c.Op)) } // On réplique sur etcd si ce n'est pas une reprise des logs et si le noeud est leader if l.Index > f.lastIndex && f.Raft.State() == raft.Leader { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) switch c.Op { case "set": f.etcd.Put(ctx, fmt.Sprintf("/deevirt/cluster/%s%s", f.conf.ClusterID, c.Key), string(c.Value)) case "delete": f.etcd.Delete(ctx, fmt.Sprintf("/deevirt/cluster/%s%s", f.conf.ClusterID, c.Key)) } defer cancel() } default: println(l.Type.String()) } return nil } // Snapshot returns a snapshot of the key-value store. func (f *FSM) Snapshot() (raft.FSMSnapshot, error) { f.mu.Lock() defer f.mu.Unlock() // Clone the map. o := make(map[string][]byte) for k, v := range f.m { o[k] = v } return &fsmSnapshot{store: o}, nil } // Restore stores the key-value store to a previous state. func (f *FSM) Restore(rc io.ReadCloser) error { o := make(map[string][]byte) if err := json.NewDecoder(rc).Decode(&o); err != nil { return err } // Set the state from the snapshot, no lock required according to // Hashicorp docs. f.m = o return nil } func (f *FSM) applySet(key string, value []byte) interface{} { f.mu.Lock() defer f.mu.Unlock() f.m[key] = value return nil } func (f *FSM) applyDelete(key string) interface{} { f.mu.Lock() defer f.mu.Unlock() delete(f.m, key) return nil } type fsmSnapshot struct { store map[string][]byte } func (f *fsmSnapshot) Persist(sink raft.SnapshotSink) error { err := func() error { // Encode data. b, err := json.Marshal(f.store) if err != nil { return err } // Write data to sink. if _, err := sink.Write(b); err != nil { return err } // Close the sink. return sink.Close() }() if err != nil { sink.Cancel() } return err } func (f *fsmSnapshot) Release() { }