func (g *group) save(rdsv readySaved) error { glog.V(3).Infof("%v saving state", g) if rdsv.ready.SoftState != nil && rdsv.ready.SoftState.Lead != 0 { g.node.notifyElection(g.id) } // Apply snapshot to storage if it is more updated than current snapped. if !etcdraft.IsEmptySnap(rdsv.ready.Snapshot) { if err := g.diskStorage.SaveSnap(rdsv.ready.Snapshot); err != nil { glog.Fatalf("err in save snapshot: %v", err) } g.raftStorage.ApplySnapshot(rdsv.ready.Snapshot) glog.Infof("%v saved incoming snapshot at index %d", g, rdsv.ready.Snapshot.Metadata.Index) } err := g.diskStorage.Save(rdsv.ready.HardState, rdsv.ready.Entries) if err != nil { glog.Fatalf("err in raft storage save: %v", err) } glog.V(3).Infof("%v saved state on disk", g) g.raftStorage.Append(rdsv.ready.Entries) glog.V(3).Infof("%v appended entries in storage", g) // Apply config changes in the node as soon as possible // before applying other entries in the state machine. for _, e := range rdsv.ready.CommittedEntries { if e.Type != raftpb.EntryConfChange { continue } if e.Index <= g.saved { continue } g.saved = e.Index var cc raftpb.ConfChange pbutil.MustUnmarshal(&cc, e.Data) if glog.V(2) { glog.Infof("%v applies conf change %s: %s", g, formatConfChange(cc), formatEntry(e)) } if err := g.validConfChange(cc); err != nil { glog.Errorf("%v received an invalid conf change for node %v: %v", g, cc.NodeID, err) cc.NodeID = etcdraft.None g.node.node.ApplyConfChange(g.id, cc) continue } cch := make(chan struct{}) go func() { g.confState = *g.node.node.ApplyConfChange(g.id, cc) close(cch) }() select { case <-g.node.done: return ErrStopped case <-cch: } } glog.V(3).Infof("%v successfully saved ready", g) rdsv.saved <- struct{}{} select { case g.applyc <- rdsv.ready: case <-g.node.done: } return nil }