func (r *Replica) handleForward(fwd *paxosproto.Forward) { if state.IsRead(&fwd.Command) { if r.maintainReadStats { r.readStats.AddRead(fwd.Command.K, fwd.ReplicaId) } //make sure that the channel is not going to be full, //because this may cause the consumer to block when trying to //put request back for len(r.fwdReadsChannel) >= READ_CHAN_SIZE-10000 { time.Sleep(1000) } r.fwdReadsChannel <- fwd } else { // the forward is a write r.handlePropose(&genericsmr.Propose{&genericsmrproto.Propose{0, fwd.Command, 0}, fwd.ReplicaId, fwd.PropId, nil, nil}) } }
func (r *Replica) handlePropose(propose *genericsmr.Propose) { batches := make(map[int64][]state.Command, 10) proposals := make(map[int64][]*genericsmr.Propose, 10) haveWrites := false totalLen := len(r.ProposeChan) + 1 if totalLen > MAX_BATCH { totalLen = MAX_BATCH } for i := 0; i < totalLen; i++ { if state.IsRead(&propose.Command) && (r.IsLeader || r.isKeyGranted(propose.Command.K)) { reads++ //make sure that the channel is not going to be full, //because this may cause the consumer to block when trying to //put request back for len(r.readsChannel) >= READ_CHAN_SIZE-10000 { time.Sleep(1000) } r.readsChannel <- propose } else if !r.IsLeader { if state.IsRead(&propose.Command) { reads++ } r.fwdId++ r.fwdPropMap[r.fwdId] = propose r.SendMsg(r.leaderId, r.forwardRPC, &paxosproto.Forward{r.Id, r.fwdId, propose.Command}) } else { q := quorumToInt64(r.getLeaseQuorumForKey(propose.Command.K, r.Id)) var cmds []state.Command var present bool var props []*genericsmr.Propose props = proposals[q] if cmds, present = batches[q]; !present { cmds = make([]state.Command, 0, totalLen/2+1) props = make([]*genericsmr.Propose, 0, totalLen/2+1) } cmds = append(cmds, propose.Command) batches[q] = cmds props = append(props, propose) proposals[q] = props haveWrites = true } if i < totalLen-1 { propose = <-r.ProposeChan } } if !haveWrites { return } /* if !r.IsLeader { preply := &genericsmrproto.ProposeReplyTS{FALSE, -1, state.NIL, 0} r.ReplyProposeTS(preply, propose) return }*/ for r.instanceSpace[r.crtInstance] != nil { r.crtInstance++ } //dlog.Printf("Batched %d\n", batchSize) status := PREPARING ballot := r.makeUniqueBallot(0) if r.defaultBallot > -1 { status = PREPARED ballot = r.defaultBallot } for q, cmds := range batches { if len(cmds) == 0 { continue } //log.Printf("Batching %d\n", len(cmds)) props := proposals[q] r.instanceSpace[r.crtInstance] = &Instance{ cmds, ballot, status, &LeaderBookkeeping{props, 0, 0, 0, 0, 0}, 0, false} if status == PREPARING { r.bcastPrepare(r.crtInstance, ballot, true) dlog.Printf("Classic round for instance %d\n", r.crtInstance) } else { r.recordInstanceMetadata(r.instanceSpace[r.crtInstance]) r.recordCommands(cmds) r.sync() if r.crtInstance > r.latestAcceptedInst { r.latestAcceptedInst = r.crtInstance } if props[0].FwdReplica >= 0 && props[0].FwdReplica != r.Id { r.addUpdatingKeys(cmds) } //TODO: make sure it supports Forwards r.instanceSpace[r.crtInstance].lb.acceptOKsToWait, _ = r.bcastAccept(r.crtInstance, ballot, cmds, props[0].FwdReplica, props[0].FwdId) dlog.Printf("Fast round for instance %d\n", r.crtInstance) if genericsmr.SendError { log.Println("BCAST ERROR") r.delayedInstances <- r.crtInstance } } r.crtInstance++ } }