From f9bfd1462a1cb57a34a4e567c1931b629df901ea Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Fri, 1 Mar 2019 21:45:48 +0100 Subject: [PATCH] Introduce candidate election timeout divisor 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 --- .../controller/cluster/raft/ConfigParams.java | 8 ++++++++ .../cluster/raft/DefaultConfigParamsImpl.java | 11 ++++++++++- .../controller/cluster/raft/behaviors/Candidate.java | 6 ++++++ .../src/main/resources/initial/datastore.cfg | 5 +++++ .../cluster/datastore/DatastoreContext.java | 12 ++++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java index fb571f11f8..070218e92e 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java @@ -54,6 +54,14 @@ public interface ConfigParams { */ 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. diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java index 53728043fb..4185754da4 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java @@ -66,6 +66,7 @@ public class DefaultConfigParamsImpl implements ConfigParams { private int snapshotChunkSize = SNAPSHOT_CHUNK_SIZE; private long electionTimeoutFactor = 2; + private long candidateElectionTimeoutDivisor = 1; private String customRaftPolicyImplementationClass; private PeerAddressResolver peerAddressResolver = NoopPeerAddressResolver.INSTANCE; @@ -106,6 +107,10 @@ public class DefaultConfigParamsImpl implements ConfigParams { electionTimeOutInterval = null; } + public void setCandidateElectionTimeoutDivisor(final long candidateElectionTimeoutDivisor) { + this.candidateElectionTimeoutDivisor = candidateElectionTimeoutDivisor; + } + public void setTempFileDirectory(final String tempFileDirectory) { this.tempFileDirectory = tempFileDirectory; } @@ -133,7 +138,6 @@ public class DefaultConfigParamsImpl implements ConfigParams { return snapshotDataThresholdPercentage; } - @Override public FiniteDuration getHeartBeatInterval() { return heartBeatInterval; @@ -148,6 +152,11 @@ public class DefaultConfigParamsImpl implements ConfigParams { return electionTimeOutInterval; } + @Override + public long getCandidateElectionTimeoutDivisor() { + return candidateElectionTimeoutDivisor; + } + @Override public int getElectionTimeVariance() { return ELECTION_TIME_MAX_VARIANCE; diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.java index 7c111d28de..afa46892be 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.java @@ -21,6 +21,7 @@ import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply; 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. @@ -123,6 +124,11 @@ public class Candidate extends AbstractRaftActorBehavior { return this; } + @Override + protected FiniteDuration electionDuration() { + return super.electionDuration().$div(context.getConfigParams().getCandidateElectionTimeoutDivisor()); + } + @Override public RaftActorBehavior handleMessage(ActorRef sender, Object message) { if (message instanceof ElectionTimeout) { diff --git a/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/datastore.cfg b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/datastore.cfg index 20d28919f9..250a8149ff 100644 --- a/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/datastore.cfg +++ b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/datastore.cfg @@ -12,6 +12,11 @@ shard-election-timeout-factor=20 # 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 diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java index 98afd7f4e0..1a46e3d452 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java @@ -53,6 +53,7 @@ public class DatastoreContext implements ClientActorConfig { 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; @@ -106,6 +107,7 @@ public class DatastoreContext implements ClientActorConfig { 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); } @@ -142,6 +144,7 @@ public class DatastoreContext implements ClientActorConfig { 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()); @@ -268,6 +271,10 @@ public class DatastoreContext implements ClientActorConfig { raftConfig.setElectionTimeoutFactor(shardElectionTimeoutFactor); } + private void setCandidateElectionTimeoutDivisor(final long candidateElectionTimeoutDivisor) { + raftConfig.setCandidateElectionTimeoutDivisor(candidateElectionTimeoutDivisor); + } + private void setCustomRaftPolicyImplementation(final String customRaftPolicyImplementation) { raftConfig.setCustomRaftPolicyImplementationClass(customRaftPolicyImplementation); } @@ -473,6 +480,11 @@ public class DatastoreContext implements ClientActorConfig { return this; } + public Builder shardCandidateElectionTimeoutDivisor(final long candidateElectionTimeoutDivisor) { + datastoreContext.setCandidateElectionTimeoutDivisor(candidateElectionTimeoutDivisor); + return this; + } + public Builder transactionCreationInitialRateLimit(final long initialRateLimit) { datastoreContext.transactionCreationInitialRateLimit = initialRateLimit; return this; -- 2.36.6