public void onVote(MessageContext context, Vote vote) { synchronized (messageLock) { final PendingBallot ballot = pending.get(vote.getXid()); if (ballot != null) { zlg.t("Received %s", z -> z.arg(vote)); final boolean decided = ballot.castVote(zlg, vote); if (decided) { decideBallot(ballot); } } else { zlg.t("Missing pending ballot for vote %s", z -> z.arg(vote)); } } }
public void onProposal(MessageContext context, Proposal proposal) { synchronized (messageLock) { final PendingBallot newBallot = new PendingBallot(proposal); final PendingBallot existingBallot = pending.put(proposal.getXid(), newBallot); if (existingBallot != null) { zlg.t("Skipping redundant %s (ballot already pending)", z -> z.arg(proposal)); pending.put(proposal.getXid(), existingBallot); return; } else { newBallot.setConfirmation(context.begin(proposal)); } } zlg.t("Initiating ballot for %s", z -> z.arg(proposal)); }
boolean castVote(Zlg zlg, Vote vote) { final Response response = vote.getResponse(); final Response existing = responses.put(response.getCohort(), response); if (existing != null) { zlg.t("Skipping redundant %s (already cast in current ballot)", z -> z.arg(vote)); responses.put(existing.getCohort(), existing); return false; } final Intent intent = response.getIntent(); if (intent == Intent.REJECT) { resolution = Resolution.ABORT; abortReason = AbortReason.REJECT; return true; } else if (intent == Intent.TIMEOUT) { resolution = Resolution.ABORT; abortReason = AbortReason.EXPLICIT_TIMEOUT; return true; } else if (hasLapsed(vote)) { resolution = Resolution.ABORT; abortReason = AbortReason.IMPLICIT_TIMEOUT; return true; } return allResponsesPresent(); }
private void decideBallot(PendingBallot ballot) { zlg.t("Decided ballot for %s: resolution: %s", z -> z.arg(ballot::getProposal).arg(ballot::getResolution)); final Proposal proposal = ballot.getProposal(); final String xid = proposal.getXid(); final Object metadata = metadataEnabled ? new OutcomeMetadata(proposal.getTimestamp()) : null; final Outcome outcome = new Outcome(xid, ballot.getResolution(), ballot.getAbortReason(), ballot.getResponses(), metadata) .inResponseTo(proposal).withSource(groupId); pending.remove(xid); if (trackingEnabled) { additions.add(outcome); } action.appendOutcome(outcome, (id, x) -> { if (x == null) { ballot.getConfirmation().confirm(); } else { zlg.w("Error appending to ledger [message: %s]", z -> z.arg(outcome).threw(x)); } }); }