// applyEntryNormal apples an EntryNormal type raftpb request to the EtcdServer func (s *EtcdServer) applyEntryNormal(e *raftpb.Entry) { shouldApplyV3 := false if e.Index > s.consistIndex.ConsistentIndex() { // set the consistent index of current executing entry s.consistIndex.setConsistentIndex(e.Index) shouldApplyV3 = true } // raft state machine may generate noop entry when leader confirmation. // skip it in advance to avoid some potential bug in the future if len(e.Data) == 0 { select { case s.forceVersionC <- struct{}{}: default: } return } var raftReq pb.InternalRaftRequest if !pbutil.MaybeUnmarshal(&raftReq, e.Data) { // backward compatible var r pb.Request pbutil.MustUnmarshal(&r, e.Data) s.w.Trigger(r.ID, s.applyV2Request(&r)) return } if raftReq.V2 != nil { req := raftReq.V2 s.w.Trigger(req.ID, s.applyV2Request(req)) return } // do not re-apply applied entries. if !shouldApplyV3 { return } id := raftReq.ID if id == 0 { id = raftReq.Header.ID } ar := s.applyV3.Apply(&raftReq) s.setAppliedIndex(e.Index) if ar.err != ErrNoSpace || len(s.alarmStore.Get(pb.AlarmType_NOSPACE)) > 0 { s.w.Trigger(id, ar) return } plog.Errorf("applying raft message exceeded backend quota") go func() { a := &pb.AlarmRequest{ MemberID: uint64(s.ID()), Action: pb.AlarmRequest_ACTIVATE, Alarm: pb.AlarmType_NOSPACE, } r := pb.InternalRaftRequest{Alarm: a} s.processInternalRaftRequest(context.TODO(), r) s.w.Trigger(id, ar) }() }
func rebuildStoreV2() store.Store { waldir := migrateWALdir if len(waldir) == 0 { waldir = path.Join(migrateDatadir, "member", "wal") } snapdir := path.Join(migrateDatadir, "member", "snap") ss := snap.New(snapdir) snapshot, err := ss.Load() if err != nil && err != snap.ErrNoSnapshot { ExitWithError(ExitError, err) } var walsnap walpb.Snapshot if snapshot != nil { walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term } w, err := wal.OpenForRead(waldir, walsnap) if err != nil { ExitWithError(ExitError, err) } defer w.Close() _, _, ents, err := w.ReadAll() if err != nil { ExitWithError(ExitError, err) } st := store.New() if snapshot != nil { err := st.Recovery(snapshot.Data) if err != nil { ExitWithError(ExitError, err) } } applier := etcdserver.NewApplierV2(st, nil) for _, ent := range ents { if ent.Type != raftpb.EntryNormal { continue } var raftReq pb.InternalRaftRequest if !pbutil.MaybeUnmarshal(&raftReq, ent.Data) { // backward compatible var r pb.Request pbutil.MustUnmarshal(&r, ent.Data) applyRequest(&r, applier) } else { if raftReq.V2 != nil { req := raftReq.V2 applyRequest(req, applier) } } } return st }
func retrieveMessage(e pb.Entry) serverpb.Request { var request serverpb.Request var raftReq serverpb.InternalRaftRequest if !pbutil.MaybeUnmarshal(&raftReq, e.Data) { // backward compatible pbutil.MustUnmarshal(&request, e.Data) } else { switch { case raftReq.V2 != nil: request = *raftReq.V2 } } return request }
// apply takes entries received from Raft (after it has been committed) and // applies them to the current state of the EtcdServer. // The given entries should not be empty. func (s *EtcdServer) apply(es []raftpb.Entry, confState *raftpb.ConfState) (uint64, bool) { var applied uint64 var shouldstop bool for i := range es { e := es[i] // set the consistent index of current executing entry s.consistIndex.setConsistentIndex(e.Index) switch e.Type { case raftpb.EntryNormal: // raft state machine may generate noop entry when leader confirmation. // skip it in advance to avoid some potential bug in the future if len(e.Data) == 0 { select { case s.forceVersionC <- struct{}{}: default: } break } var raftReq pb.InternalRaftRequest if !pbutil.MaybeUnmarshal(&raftReq, e.Data) { // backward compatible var r pb.Request pbutil.MustUnmarshal(&r, e.Data) s.w.Trigger(r.ID, s.applyRequest(r)) } else { switch { case raftReq.V2 != nil: req := raftReq.V2 s.w.Trigger(req.ID, s.applyRequest(*req)) default: s.w.Trigger(raftReq.ID, s.applyV3Request(&raftReq)) } } case raftpb.EntryConfChange: var cc raftpb.ConfChange pbutil.MustUnmarshal(&cc, e.Data) removedSelf, err := s.applyConfChange(cc, confState) shouldstop = shouldstop || removedSelf s.w.Trigger(cc.ID, err) default: plog.Panicf("entry type should be either EntryNormal or EntryConfChange") } atomic.StoreUint64(&s.r.index, e.Index) atomic.StoreUint64(&s.r.term, e.Term) applied = e.Index } return applied, shouldstop }
// applyEntryNormal apples an EntryNormal type raftpb request to the EtcdServer func (s *EtcdServer) applyEntryNormal(e *raftpb.Entry) { shouldApplyV3 := false if e.Index > s.consistIndex.ConsistentIndex() { // set the consistent index of current executing entry s.consistIndex.setConsistentIndex(e.Index) shouldApplyV3 = true } defer s.setAppliedIndex(e.Index) // raft state machine may generate noop entry when leader confirmation. // skip it in advance to avoid some potential bug in the future if len(e.Data) == 0 { select { case s.forceVersionC <- struct{}{}: default: } // promote lessor when the local member is leader and finished // applying all entries from the last term. if s.isLeader() { s.lessor.Promote(s.Cfg.electionTimeout()) } return } var raftReq pb.InternalRaftRequest if !pbutil.MaybeUnmarshal(&raftReq, e.Data) { // backward compatible var r pb.Request pbutil.MustUnmarshal(&r, e.Data) s.w.Trigger(r.ID, s.applyV2Request(&r)) return } if raftReq.V2 != nil { req := raftReq.V2 s.w.Trigger(req.ID, s.applyV2Request(req)) return } // do not re-apply applied entries. if !shouldApplyV3 { return } id := raftReq.ID if id == 0 { id = raftReq.Header.ID } var ar *applyResult needResult := s.w.IsRegistered(id) if needResult || !noSideEffect(&raftReq) { if !needResult && raftReq.Txn != nil { removeNeedlessRangeReqs(raftReq.Txn) } ar = s.applyV3.Apply(&raftReq) } if ar == nil { return } if ar.err != ErrNoSpace || len(s.alarmStore.Get(pb.AlarmType_NOSPACE)) > 0 { s.w.Trigger(id, ar) return } plog.Errorf("applying raft message exceeded backend quota") s.goAttach(func() { a := &pb.AlarmRequest{ MemberID: uint64(s.ID()), Action: pb.AlarmRequest_ACTIVATE, Alarm: pb.AlarmType_NOSPACE, } r := pb.InternalRaftRequest{Alarm: a} s.processInternalRaftRequest(context.TODO(), r) s.w.Trigger(id, ar) }) }
func rebuild(datadir string) ([]byte, *raftpb.HardState, store.Store, error) { waldir := path.Join(datadir, "member", "wal") snapdir := path.Join(datadir, "member", "snap") ss := snap.New(snapdir) snapshot, err := ss.Load() if err != nil && err != snap.ErrNoSnapshot { return nil, nil, nil, err } var walsnap walpb.Snapshot if snapshot != nil { walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term } w, err := wal.OpenForRead(waldir, walsnap) if err != nil { return nil, nil, nil, err } defer w.Close() meta, hardstate, ents, err := w.ReadAll() if err != nil { return nil, nil, nil, err } st := store.New(etcdserver.StoreClusterPrefix, etcdserver.StoreKeysPrefix) if snapshot != nil { err := st.Recovery(snapshot.Data) if err != nil { return nil, nil, nil, err } } cluster := membership.NewCluster("") cluster.SetStore(st) cluster.Recover(func(*semver.Version) {}) applier := etcdserver.NewApplierV2(st, cluster) for _, ent := range ents { if ent.Type == raftpb.EntryConfChange { var cc raftpb.ConfChange pbutil.MustUnmarshal(&cc, ent.Data) switch cc.Type { case raftpb.ConfChangeAddNode: m := new(membership.Member) if err := json.Unmarshal(cc.Context, m); err != nil { return nil, nil, nil, err } cluster.AddMember(m) case raftpb.ConfChangeRemoveNode: id := types.ID(cc.NodeID) cluster.RemoveMember(id) case raftpb.ConfChangeUpdateNode: m := new(membership.Member) if err := json.Unmarshal(cc.Context, m); err != nil { return nil, nil, nil, err } cluster.UpdateRaftAttributes(m.ID, m.RaftAttributes) } continue } var raftReq pb.InternalRaftRequest if !pbutil.MaybeUnmarshal(&raftReq, ent.Data) { // backward compatible var r pb.Request pbutil.MustUnmarshal(&r, ent.Data) applyRequest(&r, applier) } else { if raftReq.V2 != nil { req := raftReq.V2 applyRequest(req, applier) } } } return meta, &hardstate, st, nil }
func rebuildStoreV2() (store.Store, uint64) { var index uint64 cl := membership.NewCluster("") waldir := migrateWALdir if len(waldir) == 0 { waldir = path.Join(migrateDatadir, "member", "wal") } snapdir := path.Join(migrateDatadir, "member", "snap") ss := snap.New(snapdir) snapshot, err := ss.Load() if err != nil && err != snap.ErrNoSnapshot { ExitWithError(ExitError, err) } var walsnap walpb.Snapshot if snapshot != nil { walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term index = snapshot.Metadata.Index } w, err := wal.OpenForRead(waldir, walsnap) if err != nil { ExitWithError(ExitError, err) } defer w.Close() _, _, ents, err := w.ReadAll() if err != nil { ExitWithError(ExitError, err) } st := store.New() if snapshot != nil { err := st.Recovery(snapshot.Data) if err != nil { ExitWithError(ExitError, err) } } cl.SetStore(st) cl.Recover(api.UpdateCapability) applier := etcdserver.NewApplierV2(st, cl) for _, ent := range ents { if ent.Type == raftpb.EntryConfChange { var cc raftpb.ConfChange pbutil.MustUnmarshal(&cc, ent.Data) applyConf(cc, cl) continue } var raftReq pb.InternalRaftRequest if !pbutil.MaybeUnmarshal(&raftReq, ent.Data) { // backward compatible var r pb.Request pbutil.MustUnmarshal(&r, ent.Data) applyRequest(&r, applier) } else { if raftReq.V2 != nil { req := raftReq.V2 applyRequest(req, applier) } } if ent.Index > index { index = ent.Index } } return st, index }
// apply takes entries received from Raft (after it has been committed) and // applies them to the current state of the EtcdServer. // The given entries should not be empty. func (s *EtcdServer) apply(es []raftpb.Entry, confState *raftpb.ConfState) (uint64, bool) { var applied uint64 var shouldstop bool for i := range es { e := es[i] switch e.Type { case raftpb.EntryNormal: // raft state machine may generate noop entry when leader confirmation. // skip it in advance to avoid some potential bug in the future if len(e.Data) == 0 { select { case s.forceVersionC <- struct{}{}: default: } break } var raftReq pb.InternalRaftRequest if !pbutil.MaybeUnmarshal(&raftReq, e.Data) { // backward compatible var r pb.Request pbutil.MustUnmarshal(&r, e.Data) s.w.Trigger(r.ID, s.applyRequest(r)) } else if raftReq.V2 != nil { req := raftReq.V2 s.w.Trigger(req.ID, s.applyRequest(*req)) } else { // do not re-apply applied entries. if e.Index <= s.consistIndex.ConsistentIndex() { break } // set the consistent index of current executing entry s.consistIndex.setConsistentIndex(e.Index) ar := s.applyV3Request(&raftReq) if ar.err != ErrNoSpace || len(s.alarmStore.Get(pb.AlarmType_NOSPACE)) > 0 { s.w.Trigger(raftReq.ID, ar) break } plog.Errorf("applying raft message exceeded backend quota") go func() { a := &pb.AlarmRequest{ MemberID: uint64(s.ID()), Action: pb.AlarmRequest_ACTIVATE, Alarm: pb.AlarmType_NOSPACE, } r := pb.InternalRaftRequest{Alarm: a} s.processInternalRaftRequest(context.TODO(), r) s.w.Trigger(raftReq.ID, ar) }() } case raftpb.EntryConfChange: var cc raftpb.ConfChange pbutil.MustUnmarshal(&cc, e.Data) removedSelf, err := s.applyConfChange(cc, confState) shouldstop = shouldstop || removedSelf s.w.Trigger(cc.ID, err) default: plog.Panicf("entry type should be either EntryNormal or EntryConfChange") } atomic.StoreUint64(&s.r.index, e.Index) atomic.StoreUint64(&s.r.term, e.Term) applied = e.Index } return applied, shouldstop }