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;
19 * Implementation of the FollowerLogInformation interface.
22 * @author Thomas Pantelis
24 public class FollowerLogInformationImpl implements FollowerLogInformation {
25 private final Stopwatch stopwatch = Stopwatch.createUnstarted();
27 private final RaftActorContext context;
29 private long nextIndex;
31 private long matchIndex;
33 private long lastReplicatedIndex = -1L;
35 private final Stopwatch lastReplicatedStopwatch = Stopwatch.createUnstarted();
37 private short payloadVersion = -1;
39 // Assume the HELIUM_VERSION version initially for backwards compatibility until we obtain the follower's
40 // actual version via AppendEntriesReply. Although we no longer support the Helium version, a pre-Boron
41 // follower will not have the version field in AppendEntriesReply so it will be set to 0 which is
43 private short raftVersion = RaftVersions.HELIUM_VERSION;
45 private final PeerInfo peerInfo;
47 private LeaderInstallSnapshotState installSnapshotState;
50 * Constructs an instance.
52 * @param peerInfo the associated PeerInfo of the follower.
53 * @param matchIndex the initial match index.
54 * @param context the RaftActorContext.
56 public FollowerLogInformationImpl(PeerInfo peerInfo, long matchIndex, RaftActorContext context) {
57 this.nextIndex = context.getCommitIndex();
58 this.matchIndex = matchIndex;
59 this.context = context;
60 this.peerInfo = Preconditions.checkNotNull(peerInfo);
64 public long incrNextIndex() {
69 public long decrNextIndex() {
74 public boolean setNextIndex(long nextIndex) {
75 if (this.nextIndex != nextIndex) {
76 this.nextIndex = nextIndex;
84 public long incrMatchIndex() {
89 public boolean setMatchIndex(long matchIndex) {
90 if (this.matchIndex != matchIndex) {
91 this.matchIndex = matchIndex;
99 public String getId() {
100 return peerInfo.getId();
104 public long getNextIndex() {
109 public long getMatchIndex() {
114 public boolean isFollowerActive() {
115 if (peerInfo.getVotingState() == VotingState.VOTING_NOT_INITIALIZED) {
119 long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
120 return stopwatch.isRunning()
121 && elapsed <= context.getConfigParams().getElectionTimeOutInterval().toMillis();
125 public void markFollowerActive() {
126 if (stopwatch.isRunning()) {
133 public void markFollowerInActive() {
134 if (stopwatch.isRunning()) {
140 public long timeSinceLastActivity() {
141 return stopwatch.elapsed(TimeUnit.MILLISECONDS);
145 public boolean okToReplicate() {
146 if (peerInfo.getVotingState() == VotingState.VOTING_NOT_INITIALIZED) {
150 // Return false if we are trying to send duplicate data before the heartbeat interval
151 if (getNextIndex() == lastReplicatedIndex && lastReplicatedStopwatch.elapsed(TimeUnit.MILLISECONDS)
152 < context.getConfigParams().getHeartBeatInterval().toMillis()) {
156 resetLastReplicated();
160 private void resetLastReplicated(){
161 lastReplicatedIndex = getNextIndex();
162 if (lastReplicatedStopwatch.isRunning()) {
163 lastReplicatedStopwatch.reset();
165 lastReplicatedStopwatch.start();
169 public short getPayloadVersion() {
170 return payloadVersion;
174 public void setPayloadVersion(short payloadVersion) {
175 this.payloadVersion = payloadVersion;
179 public short getRaftVersion() {
184 public void setRaftVersion(short raftVersion) {
185 this.raftVersion = raftVersion;
190 public LeaderInstallSnapshotState getInstallSnapshotState() {
191 return installSnapshotState;
195 public void setLeaderInstallSnapshotState(@Nonnull LeaderInstallSnapshotState state) {
196 if (this.installSnapshotState == null) {
197 this.installSnapshotState = Preconditions.checkNotNull(state);
202 public void clearLeaderInstallSnapshotState() {
203 installSnapshotState = null;
207 public String toString() {
208 return "FollowerLogInformationImpl [id=" + getId() + ", nextIndex=" + nextIndex + ", matchIndex=" + matchIndex
209 + ", lastReplicatedIndex=" + lastReplicatedIndex + ", votingState=" + peerInfo.getVotingState()
210 + ", stopwatch=" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + ", followerTimeoutMillis="
211 + context.getConfigParams().getElectionTimeOutInterval().toMillis() + "]";