// Must be called from the processing goroutine, inside a transaction. // Returns false if it discarded the accepted message because of it being // too far in our future. Any other reason for discarding the message, // as well as the accept succeeding, will return true. func addAccepted(node uint16, accepted *coproto.Accepted) bool { slots := store.InstructionSlots() msgProposal, msgLeader := *accepted.Proposal, uint16(*accepted.Leader) newReq := accepted.Instruction.Request slot := *accepted.Instruction.Slot ourStart := store.InstructionStart() relativeSlot := int(slot - ourStart) // If our instruction slot slice is not this long, // we know we do not have any value in this slot yet, // and so need to add a new one. if len(slots) <= relativeSlot { chreq := makeExtChangeRequest(newReq) newInst := store.AddInstructionValue(slot, chreq) if newInst == nil { return false } newInst.Accept(node, msgProposal, msgLeader) return true } // If we have already chosen an instruction in this slot, // we can ignore subsequent Accepted messages for it. if len(slots[relativeSlot]) == 1 && slots[relativeSlot][0].IsChosen() { return true } // Returns if it successfully finds an existing matching value. for _, value := range slots[relativeSlot] { chreq := value.ChangeRequest() if chreq.RequestNode != uint16(*newReq.RequestNode) { continue } if chreq.RequestId != *newReq.RequestId { continue } value.Accept(node, msgProposal, msgLeader) return true } chreq := makeExtChangeRequest(newReq) newInst := store.AddInstructionValue(slot, chreq) if newInst == nil { return false } newInst.Accept(node, msgProposal, msgLeader) return true }
func handleInstructionData(f *followConn, content []byte) { store.StartTransaction() defer store.EndTransaction() f.lock.Lock() if f.closed { f.lock.Unlock() return } var msg fproto.InstructionData if err := proto.Unmarshal(content, &msg); err != nil { f.Close() f.lock.Unlock() return } if f.receivingBurst { f.waiting = append(f.waiting, &msg) f.lock.Unlock() return } // We need to unlock before we start mutating the store, // due to callbacks from the store package to elsewhere. f.lock.Unlock() // If we have a chosen instruction in this slot already, // or it is prior to our instruction start number, // discard this message. relativeSlot := int(*msg.Slot - store.InstructionStart()) if relativeSlot < 0 { return } instructions := store.InstructionSlots() if relativeSlot < len(instructions) && len(instructions[relativeSlot]) == 1 && instructions[relativeSlot][0].IsChosen() { return } // Construct a store.ChangeRequest from our // internal ChangeRequest. chrequest := new(store.ChangeRequest) chrequest.RequestEntity = *msg.Request.RequestEntity chrequest.RequestNode = uint16(*msg.Request.RequestNode) chrequest.RequestId = *msg.Request.RequestId chrequest.Changeset = make([]store.Change, len(msg.Request.Changeset)) for i, ch := range msg.Request.Changeset { chrequest.Changeset[i].TargetEntity = *ch.TargetEntity chrequest.Changeset[i].Key = *ch.Key chrequest.Changeset[i].Value = *ch.Value } // Add instruction value and immediately choose it. store.AddInstructionValue(*msg.Slot, chrequest).Choose() }