func (n *node) process(e raftpb.Entry, pending chan struct{}) { if e.Type != raftpb.EntryNormal { return } pending <- struct{}{} // This will block until we can write to it. var proposal task.Proposal x.Check(proposal.Unmarshal(e.Data)) var err error if proposal.Mutations != nil { err = n.processMutation(e, proposal.Mutations) } else if proposal.Membership != nil { err = n.processMembership(e, proposal.Membership) } n.props.Done(proposal.Id, err) <-pending // Release one. }
func (n *node) ProposeAndWait(ctx context.Context, proposal *task.Proposal) error { if n.raft == nil { return x.Errorf("RAFT isn't initialized yet") } proposal.Id = rand.Uint32() slice := slicePool.Get().([]byte) if len(slice) < proposal.Size() { slice = make([]byte, proposal.Size()) } defer slicePool.Put(slice) upto, err := proposal.MarshalTo(slice) if err != nil { return err } proposalData := slice[:upto] che := make(chan error, 1) n.props.Store(proposal.Id, che) if err = n.raft.Propose(ctx, proposalData); err != nil { return x.Wrapf(err, "While proposing") } // Wait for the proposal to be committed. if proposal.Mutations != nil { x.Trace(ctx, "Waiting for the proposal: mutations.") } else { x.Trace(ctx, "Waiting for the proposal: membership update.") } select { case err = <-che: x.TraceError(ctx, err) return err case <-ctx.Done(): return ctx.Err() } }