示例#1
0
文件: node.go 项目: jyzhe/beehive
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
}
示例#2
0
文件: wal.go 项目: jyzhe/beehive
// 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
}
示例#3
0
文件: decoder.go 项目: jyzhe/beehive
func mustUnmarshalState(d []byte) raftpb.HardState {
	var s raftpb.HardState
	pbutil.MustUnmarshal(&s, d)
	return s
}
示例#4
0
文件: decoder.go 项目: jyzhe/beehive
func mustUnmarshalEntry(d []byte) raftpb.Entry {
	var e raftpb.Entry
	pbutil.MustUnmarshal(&e, d)
	return e
}
示例#5
0
文件: node.go 项目: jyzhe/beehive
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
}