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 boolean decrNextIndex() {
79 public boolean setNextIndex(long nextIndex) {
80 if (this.nextIndex != nextIndex) {
81 this.nextIndex = nextIndex;
89 public long incrMatchIndex() {
94 public boolean setMatchIndex(long matchIndex) {
95 if (this.matchIndex != matchIndex) {
96 this.matchIndex = matchIndex;
104 public String getId() {
105 return peerInfo.getId();
109 public long getNextIndex() {
114 public long getMatchIndex() {
119 public boolean isFollowerActive() {
120 if (peerInfo.getVotingState() == VotingState.VOTING_NOT_INITIALIZED) {
124 long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
125 return stopwatch.isRunning()
126 && elapsed <= context.getConfigParams().getElectionTimeOutInterval().toMillis();
130 public void markFollowerActive() {
131 if (stopwatch.isRunning()) {
138 public void markFollowerInActive() {
139 if (stopwatch.isRunning()) {
145 public long timeSinceLastActivity() {
146 return stopwatch.elapsed(TimeUnit.MILLISECONDS);
150 public boolean okToReplicate() {
151 if (peerInfo.getVotingState() == VotingState.VOTING_NOT_INITIALIZED) {
155 // Return false if we are trying to send duplicate data before the heartbeat interval
156 if (getNextIndex() == lastReplicatedIndex && lastReplicatedStopwatch.elapsed(TimeUnit.MILLISECONDS)
157 < context.getConfigParams().getHeartBeatInterval().toMillis()) {
161 resetLastReplicated();
165 private void resetLastReplicated() {
166 lastReplicatedIndex = getNextIndex();
167 if (lastReplicatedStopwatch.isRunning()) {
168 lastReplicatedStopwatch.reset();
170 lastReplicatedStopwatch.start();
174 public short getPayloadVersion() {
175 return payloadVersion;
179 public void setPayloadVersion(short payloadVersion) {
180 this.payloadVersion = payloadVersion;
184 public short getRaftVersion() {
189 public void setRaftVersion(short raftVersion) {
190 this.raftVersion = raftVersion;
195 public LeaderInstallSnapshotState getInstallSnapshotState() {
196 return installSnapshotState;
200 public void setLeaderInstallSnapshotState(@Nonnull LeaderInstallSnapshotState state) {
201 if (this.installSnapshotState == null) {
202 this.installSnapshotState = Preconditions.checkNotNull(state);
207 public void clearLeaderInstallSnapshotState() {
208 Preconditions.checkState(installSnapshotState != null);
209 installSnapshotState.close();
210 installSnapshotState = null;
214 public String toString() {
215 return "FollowerLogInformationImpl [id=" + getId() + ", nextIndex=" + nextIndex + ", matchIndex=" + matchIndex
216 + ", lastReplicatedIndex=" + lastReplicatedIndex + ", votingState=" + peerInfo.getVotingState()
217 + ", stopwatch=" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + ", followerTimeoutMillis="
218 + context.getConfigParams().getElectionTimeOutInterval().toMillis() + "]";