Skip to content

Implement ring-based ElectionTransaction FSM and coordinator recovery - #97

Merged
Tech-Matt merged 11 commits into
mainfrom
feature/electionTransaction
Aug 28, 2026
Merged

Implement ring-based ElectionTransaction FSM and coordinator recovery#97
Tech-Matt merged 11 commits into
mainfrom
feature/electionTransaction

Conversation

@Tech-Matt

Copy link
Copy Markdown
Collaborator

Summary

Implements the ring-based coordinator election flow and integrates it with heartbeat failure detection and coordinator recovery.

This PR targets:

What changed

Election protocol

  • Added ElectionTransaction as the local FSM owned by each Replica.
  • Added immutable election messages: ElectionMsg, ElectionAckMsg, ElectionAckTimeoutMsg, ElectionStartMsg, ElectionRejectMsg, and SynchronizationMsg.
  • Preserved one transaction ID while an election token travels through the ring.
  • Added deterministic candidate ordering: observed update first, then newer EpochPair, then higher replica ID for equal pairs.
  • Added sorted ring navigation with wraparound and skipping of unavailable replicas.

ACKs, timeouts, and failures

  • A replica forwards the election token before acknowledging the previous sender.
  • Added per-hop ACK timeout handling.
  • Added timeout-attempt versioning so stale timeout messages cannot skip a healthy replica.
  • Failed or non-responsive ring members are marked unavailable and skipped.
  • Election transaction IDs use a negative sequence-number namespace so they cannot collide with heartbeat or ordinary transaction IDs.
  • Added arbitration for competing election tokens caused by multiple replicas detecting the same coordinator failure.
  • The preferred election is selected deterministically by initiator replica ID, and losing tokens are rejected.

Heartbeat handoff and recovery

  • Heartbeat watchdog expiry now starts the election flow for the failed coordinator.
  • Added delayed ring-priority election startup to reduce duplicate initiators.
  • Added synchronization from the elected coordinator to surviving replicas.
  • Synchronization validates the failed-coordinator term, announced coordinator, message sender, newer epoch, epoch metadata, and positions snapshot shape.
  • Invalid or stale election and synchronization messages are ignored before they can create invalid transactions or poison the recovery term.
  • The election FSM now transitions through SYNCHRONIZING and DONE, and old election/heartbeat state is removed before the new heartbeat term starts.
  • The new coordinator and followers invoke the required election callbacks.

Tests and documentation

  • Expanded TestElectionTransaction with coverage for candidate ordering, ring wraparound, skipped replicas, immutable payloads, invalid synchronization senders, invalid snapshots, malformed election identities, and term preservation after rejected input.
  • Updated the election state-machine and sequence diagrams to match the implemented message order and validation rules.

Verification

  • gradle regression passes on the committed branch head.
  • Election callback-contract checks pass: replicaReportsStartedElections and replicaReportsElectedCoordinators.
  • git diff --check passes.
  • gradle staticAnalysis completes under the repository configured ignoreFailures policy.

The callback-contract task still reports unrelated pre-existing failures for read and update callbacks. Those are outside this election-focused PR.

Scope note

This PR synchronizes the current authoritative positions snapshot and uses EpochPair election metadata. Full ordered update-history replay and incomplete-update recovery require the separate UpdateTransaction and history contract, and are intentionally not introduced here.

…action diagrams inside the `charts/transactions` folder
Introduce immutable election candidates ordered by EpochPair, with
replica ID as the deterministic tie-breaker. Add ring-navigation rules
for wraparound, skipped replicas, and the no-available-replica case.

These pure rules establish predictable election behavior before adding
Akka messages, timeouts, and FSM transitions.
Add deterministic candidate comparison and ring navigation with wraparound and failed-replica skipping.

Introduce immutable ElectionMsg, ElectionAckMsg, and local ElectionAckTimeoutMsg objects. Add regression coverage and update the election sequence diagram to match the simplified message contract.
Implement ElectionTransaction with immutable election messages, candidate
comparison, deterministic replica-ID tie-breaking, ring navigation, ACK
timeouts, failed-replica skipping, and coordinator selection.

Integrate election startup with heartbeat failure detection and Replica
message dispatch. Add coordinator callbacks, synchronization messages carrying
the authoritative positions snapshot, epoch advancement, and heartbeat restart
after election completion.

Extend regression coverage for candidate ordering, ring navigation, message
immutability, ACK metadata, timeout metadata, and synchronization snapshots.
Update the election sequence diagram to document the implemented protocol flow.
Reserve a separate transaction-ID namespace for elections so delayed ACKs and timeouts cannot be routed to heartbeat transactions. Schedule election startup according to ring distance, arbitrate concurrent election attempts by initiator ID, and reject losing election transactions. Increase ACK timeout coverage to include token forwarding and the return acknowledgement, preventing healthy replicas from being discarded prematurely. Update the election diagrams to document the arbitration and round-trip timeout behavior.
Reject malformed or stale election and synchronization messages before they can create invalid local transactions or poison a recovery term. Track the election transaction through synchronizing and completion, align the diagrams with forward-before-ACK ordering, and add regression coverage for forged, malformed, and invalid synchronization traffic.

@alanmasu alanmasu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one comment, please add the Javadoc on the new functions/classes.

Comment on lines +43 to +55
public ElectionTransaction(
TransactionId id,
DistributedActor owner,
EpochPair startEpochPair) {
super(id, owner, startEpochPair);
this.failedCoordinatorId = -1;
this.replicaRefs = Map.of();
this.ringNavigation = null;
this.localInitiator = false;
this.unavailableReplicaIds = new HashSet<>();
this.pendingTargetId = -1;
this.state = State.NEW;
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could diverge from the last constructor. BTW if this is provided only for compatibility with the super, please remove it.

Comment on lines +57 to +61
public ElectionTransaction(TransactionId id, DistributedActor owner, EpochPair startEpochPair,
int failedCoordinatorId, Map<Integer, ActorRef> replicaRefs)
{
this(id, owner, startEpochPair, failedCoordinatorId, replicaRefs, true);
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not needed please remove all misleading and not fully functional constructors

@Tech-Matt
Tech-Matt merged commit 4dbb54e into main Aug 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement the FSM [ElectionTransaction]

2 participants