Example #1
0
// 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
}
Example #2
0
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()
}