2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.cluster.raft;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Stopwatch;
13 import java.util.concurrent.TimeUnit;
14 import javax.annotation.Nonnull;
15 import javax.annotation.Nullable;
16 import org.opendaylight.controller.cluster.raft.behaviors.LeaderInstallSnapshotState;
18 public class FollowerLogInformationImpl implements FollowerLogInformation {
19 private final Stopwatch stopwatch = Stopwatch.createUnstarted();
21 private final RaftActorContext context;
23 private long nextIndex;
25 private long matchIndex;
27 private long lastReplicatedIndex = -1L;
29 private final Stopwatch lastReplicatedStopwatch = Stopwatch.createUnstarted();
31 private short payloadVersion = -1;
33 // Assume the HELIUM_VERSION version initially for backwards compatibility until we obtain the follower's
34 // actual version via AppendEntriesReply. Although we no longer support the Helium version, a pre-Boron
35 // follower will not have the version field in AppendEntriesReply so it will be set to 0 which is
37 private short raftVersion = RaftVersions.HELIUM_VERSION;
39 private final PeerInfo peerInfo;
41 private LeaderInstallSnapshotState installSnapshotState;
43 public FollowerLogInformationImpl(PeerInfo peerInfo, long matchIndex, RaftActorContext context) {
44 this.nextIndex = context.getCommitIndex();
45 this.matchIndex = matchIndex;
46 this.context = context;
47 this.peerInfo = Preconditions.checkNotNull(peerInfo);
51 public long incrNextIndex() {
56 public long decrNextIndex() {
61 public boolean setNextIndex(long nextIndex) {
62 if(this.nextIndex != nextIndex) {
63 this.nextIndex = nextIndex;
71 public long incrMatchIndex(){
76 public boolean setMatchIndex(long matchIndex) {
77 if(this.matchIndex != matchIndex) {
78 this.matchIndex = matchIndex;
86 public String getId() {
87 return peerInfo.getId();
91 public long getNextIndex() {
96 public long getMatchIndex() {
101 public boolean isFollowerActive() {
102 if(peerInfo.getVotingState() == VotingState.VOTING_NOT_INITIALIZED) {
106 long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
107 return (stopwatch.isRunning()) &&
108 (elapsed <= context.getConfigParams().getElectionTimeOutInterval().toMillis());
112 public void markFollowerActive() {
113 if (stopwatch.isRunning()) {
120 public void markFollowerInActive() {
121 if (stopwatch.isRunning()) {
127 public long timeSinceLastActivity() {
128 return stopwatch.elapsed(TimeUnit.MILLISECONDS);
132 public boolean okToReplicate() {
133 if(peerInfo.getVotingState() == VotingState.VOTING_NOT_INITIALIZED) {
137 // Return false if we are trying to send duplicate data before the heartbeat interval
138 if(getNextIndex() == lastReplicatedIndex){
139 if(lastReplicatedStopwatch.elapsed(TimeUnit.MILLISECONDS) < context.getConfigParams()
140 .getHeartBeatInterval().toMillis()){
145 resetLastReplicated();
149 private void resetLastReplicated(){
150 lastReplicatedIndex = getNextIndex();
151 if(lastReplicatedStopwatch.isRunning()){
152 lastReplicatedStopwatch.reset();
154 lastReplicatedStopwatch.start();
158 public short getPayloadVersion() {
159 return payloadVersion;
163 public void setPayloadVersion(short payloadVersion) {
164 this.payloadVersion = payloadVersion;
168 public short getRaftVersion() {
173 public void setRaftVersion(short raftVersion) {
174 this.raftVersion = raftVersion;
179 public LeaderInstallSnapshotState getInstallSnapshotState() {
180 return installSnapshotState;
184 public void setLeaderInstallSnapshotState(@Nonnull LeaderInstallSnapshotState state) {
185 if(this.installSnapshotState == null) {
186 this.installSnapshotState = Preconditions.checkNotNull(state);
191 public void clearLeaderInstallSnapshotState() {
192 installSnapshotState = null;
196 public String toString() {
197 return "FollowerLogInformationImpl [id=" + getId() + ", nextIndex=" + nextIndex + ", matchIndex=" + matchIndex
198 + ", lastReplicatedIndex=" + lastReplicatedIndex + ", votingState=" + peerInfo.getVotingState()
199 + ", stopwatch=" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + ", followerTimeoutMillis="
200 + context.getConfigParams().getElectionTimeOutInterval().toMillis() + "]";