func (g *group) applyConfChange(e raftpb.Entry) error { var cc raftpb.ConfChange pbutil.MustUnmarshal(&cc, e.Data) glog.V(2).Infof("%v applies conf change %v: %#v", g, e.Index, cc) if len(cc.Context) == 0 { g.stateMachine.ApplyConfChange(cc, GroupNode{}) return nil } if id, req, err := g.node.decReq(cc.Context); err == nil { if gn, ok := req.Data.(GroupNode); ok { res := Response{ID: id} res.Err = g.stateMachine.ApplyConfChange(cc, gn) g.node.line.call(res) return nil } } var gn GroupNode if err := bhgob.Decode(&gn, cc.Context); err != nil { glog.Fatalf("%v cannot decode config change: %v", g, err) } if gn.Node != cc.NodeID { glog.Fatalf("invalid config change: %v != %v", gn.Node, cc.NodeID) } g.stateMachine.ApplyConfChange(cc, gn) return nil }
// ReadAll reads out records of the current WAL. // If opened in write mode, it must read out all records until EOF. Or an error // will be returned. // If opened in read mode, it will try to read all records if possible. // If it cannot read out the expected snap, it will return ErrSnapshotNotFound. // If loaded snap doesn't match with the expected one, it will return // all the records and error ErrSnapshotMismatch. // TODO: detect not-last-snap error. // TODO: maybe loose the checking of match. // After ReadAll, the WAL will be ready for appending new records. func (w *WAL) ReadAll() (metadata []byte, state raftpb.HardState, ents []raftpb.Entry, err error) { w.mu.Lock() defer w.mu.Unlock() rec := &walpb.Record{} decoder := w.decoder var match bool for err = decoder.decode(rec); err == nil; err = decoder.decode(rec) { switch rec.Type { case entryType: e := mustUnmarshalEntry(rec.Data) if e.Index > w.start.Index { ents = append(ents[:e.Index-w.start.Index-1], e) } w.enti = e.Index case stateType: state = mustUnmarshalState(rec.Data) case metadataType: if metadata != nil && !reflect.DeepEqual(metadata, rec.Data) { state.Reset() return nil, state, nil, ErrMetadataConflict } metadata = rec.Data case crcType: crc := decoder.crc.Sum32() // current crc of decoder must match the crc of the record. // do no need to match 0 crc, since the decoder is a new one at this case. if crc != 0 && rec.Validate(crc) != nil { state.Reset() return nil, state, nil, ErrCRCMismatch } decoder.updateCRC(rec.Crc) case snapshotType: var snap walpb.Snapshot pbutil.MustUnmarshal(&snap, rec.Data) if snap.Index == w.start.Index { if snap.Term != w.start.Term { state.Reset() return nil, state, nil, ErrSnapshotMismatch } match = true } default: state.Reset() return nil, state, nil, fmt.Errorf("unexpected block type %d", rec.Type) } } switch w.f { case nil: // We do not have to read out all entries in read mode. // The last record maybe a partial written one, so // ErrunexpectedEOF might be returned. if err != io.EOF && err != io.ErrUnexpectedEOF { state.Reset() return nil, state, nil, err } default: // We must read all of the entries if WAL is opened in write mode. if err != io.EOF { state.Reset() return nil, state, nil, err } } err = nil if !match { err = ErrSnapshotNotFound } // close decoder, disable reading w.decoder.close() w.start = walpb.Snapshot{} w.metadata = metadata if w.f != nil { // create encoder (chain crc with the decoder), enable appending w.encoder = newEncoder(w.f, w.decoder.lastCRC()) w.decoder = nil lastIndexSaved.Set(float64(w.enti)) } return metadata, state, ents, err }
func mustUnmarshalState(d []byte) raftpb.HardState { var s raftpb.HardState pbutil.MustUnmarshal(&s, d) return s }
func mustUnmarshalEntry(d []byte) raftpb.Entry { var e raftpb.Entry pbutil.MustUnmarshal(&e, d) return e }
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 }