+ @Override
+ String getLastValidLeaderId() {
+ return lastValidLeaderId;
+ }
+
+ @Override
+ short getLeaderPayloadVersion() {
+ return leaderPayloadVersion;
+ }
+ }
+
+ /**
+ * Class tracking behavior-related information, which we need to keep around and pass across behavior switches.
+ * An instance is created for each RaftActor. It has two functions:
+ * - it keeps track of the last leader ID we have encountered since we have been created
+ * - it creates state capture needed to transition from one behavior to the next
+ */
+ private static final class BehaviorStateTracker {
+ /**
+ * A {@link BehaviorState} corresponding to null {@link RaftActorBehavior} state. Since null behavior is only
+ * allowed before we receive the first message, we know the leader ID to be null.
+ */
+ private static final BehaviorState NULL_BEHAVIOR_STATE = new BehaviorState() {
+ @Override
+ RaftActorBehavior getBehavior() {
+ return null;
+ }
+
+ @Override
+ String getLastValidLeaderId() {
+ return null;
+ }
+
+ @Override
+ short getLeaderPayloadVersion() {
+ return -1;
+ }
+ };
+
+ private String lastValidLeaderId;
+
+ BehaviorState capture(final RaftActorBehavior behavior) {
+ if (behavior == null) {
+ Verify.verify(lastValidLeaderId == null, "Null behavior with non-null last leader");
+ return NULL_BEHAVIOR_STATE;
+ }
+
+ final String leaderId = behavior.getLeaderId();
+ if (leaderId != null) {
+ lastValidLeaderId = leaderId;
+ }
+
+ return new SimpleBehaviorState(lastValidLeaderId, behavior);