When a candidate is waiting for an election to occur, it is sometimes
preferable to shorten the timeout interval down, so that we do not
wait the full election timeout.
This patch introduces the knob which serves to divide the normal
timeout -- i.e. it can be halved.
Change-Id: Idbe81c39bf7aecf56b9f13a242bea89a1a4ac4f1
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
*/
FiniteDuration getElectionTimeOutInterval();
*/
FiniteDuration getElectionTimeOutInterval();
+ /**
+ * Returns the number by which a candidate should divide the election timeout it has calculated. This serves
+ * to speed up retries when elections result in a stalemate.
+ *
+ * @return the interval as a FiniteDuration.
+ */
+ long getCandidateElectionTimeoutDivisor();
+
/**
* Returns the maximum election time variance. The election is scheduled using both the election timeout
* and variance.
/**
* Returns the maximum election time variance. The election is scheduled using both the election timeout
* and variance.
private int snapshotChunkSize = SNAPSHOT_CHUNK_SIZE;
private long electionTimeoutFactor = 2;
private int snapshotChunkSize = SNAPSHOT_CHUNK_SIZE;
private long electionTimeoutFactor = 2;
+ private long candidateElectionTimeoutDivisor = 1;
private String customRaftPolicyImplementationClass;
private PeerAddressResolver peerAddressResolver = NoopPeerAddressResolver.INSTANCE;
private String customRaftPolicyImplementationClass;
private PeerAddressResolver peerAddressResolver = NoopPeerAddressResolver.INSTANCE;
electionTimeOutInterval = null;
}
electionTimeOutInterval = null;
}
+ public void setCandidateElectionTimeoutDivisor(final long candidateElectionTimeoutDivisor) {
+ this.candidateElectionTimeoutDivisor = candidateElectionTimeoutDivisor;
+ }
+
public void setTempFileDirectory(final String tempFileDirectory) {
this.tempFileDirectory = tempFileDirectory;
}
public void setTempFileDirectory(final String tempFileDirectory) {
this.tempFileDirectory = tempFileDirectory;
}
return snapshotDataThresholdPercentage;
}
return snapshotDataThresholdPercentage;
}
@Override
public FiniteDuration getHeartBeatInterval() {
return heartBeatInterval;
@Override
public FiniteDuration getHeartBeatInterval() {
return heartBeatInterval;
return electionTimeOutInterval;
}
return electionTimeOutInterval;
}
+ @Override
+ public long getCandidateElectionTimeoutDivisor() {
+ return candidateElectionTimeoutDivisor;
+ }
+
@Override
public int getElectionTimeVariance() {
return ELECTION_TIME_MAX_VARIANCE;
@Override
public int getElectionTimeVariance() {
return ELECTION_TIME_MAX_VARIANCE;
import org.opendaylight.controller.cluster.raft.messages.RaftRPC;
import org.opendaylight.controller.cluster.raft.messages.RequestVote;
import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
import org.opendaylight.controller.cluster.raft.messages.RaftRPC;
import org.opendaylight.controller.cluster.raft.messages.RequestVote;
import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
+import scala.concurrent.duration.FiniteDuration;
/**
* The behavior of a RaftActor when it is in the Candidate raft state.
/**
* The behavior of a RaftActor when it is in the Candidate raft state.
+ @Override
+ protected FiniteDuration electionDuration() {
+ return super.electionDuration().$div(context.getConfigParams().getCandidateElectionTimeoutDivisor());
+ }
+
@Override
public RaftActorBehavior handleMessage(ActorRef sender, Object message) {
if (message instanceof ElectionTimeout) {
@Override
public RaftActorBehavior handleMessage(ActorRef sender, Object message) {
if (message instanceof ElectionTimeout) {
# The interval at which a shard will send a heart beat message to its remote shard.
#shard-heartbeat-interval-in-millis=500
# The interval at which a shard will send a heart beat message to its remote shard.
#shard-heartbeat-interval-in-millis=500
+# The amount by which to divide election timeout in case of a candidate. This serves as a counter-balance
+# to shard-election-timeout-factor. The default value is 1, i.e. election timeout is the same in all
+# situations.
+#shard-candidate-election-timeout-divisor=1
+
# The maximum amount of time to wait for a shard to elect a leader before failing an operation (eg transaction create).
#shard-leader-election-timeout-in-seconds=30
# The maximum amount of time to wait for a shard to elect a leader before failing an operation (eg transaction create).
#shard-leader-election-timeout-in-seconds=30
public static final FileAkkaConfigurationReader DEFAULT_CONFIGURATION_READER = new FileAkkaConfigurationReader();
public static final int DEFAULT_SHARD_SNAPSHOT_DATA_THRESHOLD_PERCENTAGE = 12;
public static final int DEFAULT_SHARD_ELECTION_TIMEOUT_FACTOR = 2;
public static final FileAkkaConfigurationReader DEFAULT_CONFIGURATION_READER = new FileAkkaConfigurationReader();
public static final int DEFAULT_SHARD_SNAPSHOT_DATA_THRESHOLD_PERCENTAGE = 12;
public static final int DEFAULT_SHARD_ELECTION_TIMEOUT_FACTOR = 2;
+ public static final int DEFAULT_SHARD_CANDIDATE_ELECTION_TIMEOUT_DIVISOR = 1;
public static final int DEFAULT_TX_CREATION_INITIAL_RATE_LIMIT = 100;
public static final String UNKNOWN_DATA_STORE_TYPE = "unknown";
public static final int DEFAULT_SHARD_BATCHED_MODIFICATION_COUNT = 1000;
public static final int DEFAULT_TX_CREATION_INITIAL_RATE_LIMIT = 100;
public static final String UNKNOWN_DATA_STORE_TYPE = "unknown";
public static final int DEFAULT_SHARD_BATCHED_MODIFICATION_COUNT = 1000;
setIsolatedLeaderCheckInterval(DEFAULT_ISOLATED_LEADER_CHECK_INTERVAL_IN_MILLIS);
setSnapshotDataThresholdPercentage(DEFAULT_SHARD_SNAPSHOT_DATA_THRESHOLD_PERCENTAGE);
setElectionTimeoutFactor(DEFAULT_SHARD_ELECTION_TIMEOUT_FACTOR);
setIsolatedLeaderCheckInterval(DEFAULT_ISOLATED_LEADER_CHECK_INTERVAL_IN_MILLIS);
setSnapshotDataThresholdPercentage(DEFAULT_SHARD_SNAPSHOT_DATA_THRESHOLD_PERCENTAGE);
setElectionTimeoutFactor(DEFAULT_SHARD_ELECTION_TIMEOUT_FACTOR);
+ setCandidateElectionTimeoutDivisor(DEFAULT_SHARD_CANDIDATE_ELECTION_TIMEOUT_DIVISOR);
setSyncIndexThreshold(DEFAULT_SYNC_INDEX_THRESHOLD);
setMaximumMessageSliceSize(DEFAULT_MAX_MESSAGE_SLICE_SIZE);
}
setSyncIndexThreshold(DEFAULT_SYNC_INDEX_THRESHOLD);
setMaximumMessageSliceSize(DEFAULT_MAX_MESSAGE_SLICE_SIZE);
}
setIsolatedLeaderCheckInterval(other.raftConfig.getIsolatedCheckIntervalInMillis());
setSnapshotDataThresholdPercentage(other.raftConfig.getSnapshotDataThresholdPercentage());
setElectionTimeoutFactor(other.raftConfig.getElectionTimeoutFactor());
setIsolatedLeaderCheckInterval(other.raftConfig.getIsolatedCheckIntervalInMillis());
setSnapshotDataThresholdPercentage(other.raftConfig.getSnapshotDataThresholdPercentage());
setElectionTimeoutFactor(other.raftConfig.getElectionTimeoutFactor());
+ setCandidateElectionTimeoutDivisor(other.raftConfig.getCandidateElectionTimeoutDivisor());
setCustomRaftPolicyImplementation(other.raftConfig.getCustomRaftPolicyImplementationClass());
setMaximumMessageSliceSize(other.getMaximumMessageSliceSize());
setShardSnapshotChunkSize(other.raftConfig.getSnapshotChunkSize());
setCustomRaftPolicyImplementation(other.raftConfig.getCustomRaftPolicyImplementationClass());
setMaximumMessageSliceSize(other.getMaximumMessageSliceSize());
setShardSnapshotChunkSize(other.raftConfig.getSnapshotChunkSize());
raftConfig.setElectionTimeoutFactor(shardElectionTimeoutFactor);
}
raftConfig.setElectionTimeoutFactor(shardElectionTimeoutFactor);
}
+ private void setCandidateElectionTimeoutDivisor(final long candidateElectionTimeoutDivisor) {
+ raftConfig.setCandidateElectionTimeoutDivisor(candidateElectionTimeoutDivisor);
+ }
+
private void setCustomRaftPolicyImplementation(final String customRaftPolicyImplementation) {
raftConfig.setCustomRaftPolicyImplementationClass(customRaftPolicyImplementation);
}
private void setCustomRaftPolicyImplementation(final String customRaftPolicyImplementation) {
raftConfig.setCustomRaftPolicyImplementationClass(customRaftPolicyImplementation);
}
+ public Builder shardCandidateElectionTimeoutDivisor(final long candidateElectionTimeoutDivisor) {
+ datastoreContext.setCandidateElectionTimeoutDivisor(candidateElectionTimeoutDivisor);
+ return this;
+ }
+
public Builder transactionCreationInitialRateLimit(final long initialRateLimit) {
datastoreContext.transactionCreationInitialRateLimit = initialRateLimit;
return this;
public Builder transactionCreationInitialRateLimit(final long initialRateLimit) {
datastoreContext.transactionCreationInitialRateLimit = initialRateLimit;
return this;