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;
15 public class FollowerLogInformationImpl implements FollowerLogInformation {
16 private final Stopwatch stopwatch = Stopwatch.createUnstarted();
18 private final RaftActorContext context;
20 private long nextIndex;
22 private long matchIndex;
24 private long lastReplicatedIndex = -1L;
26 private final Stopwatch lastReplicatedStopwatch = Stopwatch.createUnstarted();
28 private short payloadVersion = -1;
30 // Assume the HELIUM_VERSION version initially for backwards compatibility until we obtain the follower's
31 // actual version via AppendEntriesReply. Although we no longer support the Helium version, a pre-Boron
32 // follower will not have the version field in AppendEntriesReply so it will be set to 0 which is
34 private short raftVersion = RaftVersions.HELIUM_VERSION;
36 private final PeerInfo peerInfo;
38 public FollowerLogInformationImpl(PeerInfo peerInfo, long matchIndex, RaftActorContext context) {
39 this.nextIndex = context.getCommitIndex();
40 this.matchIndex = matchIndex;
41 this.context = context;
42 this.peerInfo = Preconditions.checkNotNull(peerInfo);
46 public long incrNextIndex() {
51 public long decrNextIndex() {
56 public boolean setNextIndex(long nextIndex) {
57 if(this.nextIndex != nextIndex) {
58 this.nextIndex = nextIndex;
66 public long incrMatchIndex(){
71 public boolean setMatchIndex(long matchIndex) {
72 if(this.matchIndex != matchIndex) {
73 this.matchIndex = matchIndex;
81 public String getId() {
82 return peerInfo.getId();
86 public long getNextIndex() {
91 public long getMatchIndex() {
96 public boolean isFollowerActive() {
97 if(peerInfo.getVotingState() == VotingState.VOTING_NOT_INITIALIZED) {
101 long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
102 return (stopwatch.isRunning()) &&
103 (elapsed <= context.getConfigParams().getElectionTimeOutInterval().toMillis());
107 public void markFollowerActive() {
108 if (stopwatch.isRunning()) {
115 public void markFollowerInActive() {
116 if (stopwatch.isRunning()) {
122 public long timeSinceLastActivity() {
123 return stopwatch.elapsed(TimeUnit.MILLISECONDS);
127 public boolean okToReplicate() {
128 if(peerInfo.getVotingState() == VotingState.VOTING_NOT_INITIALIZED) {
132 // Return false if we are trying to send duplicate data before the heartbeat interval
133 if(getNextIndex() == lastReplicatedIndex){
134 if(lastReplicatedStopwatch.elapsed(TimeUnit.MILLISECONDS) < context.getConfigParams()
135 .getHeartBeatInterval().toMillis()){
140 resetLastReplicated();
144 private void resetLastReplicated(){
145 lastReplicatedIndex = getNextIndex();
146 if(lastReplicatedStopwatch.isRunning()){
147 lastReplicatedStopwatch.reset();
149 lastReplicatedStopwatch.start();
153 public short getPayloadVersion() {
154 return payloadVersion;
158 public void setPayloadVersion(short payloadVersion) {
159 this.payloadVersion = payloadVersion;
163 public short getRaftVersion() {
168 public void setRaftVersion(short raftVersion) {
169 this.raftVersion = raftVersion;
173 public String toString() {
174 return "FollowerLogInformationImpl [id=" + getId() + ", nextIndex=" + nextIndex + ", matchIndex=" + matchIndex
175 + ", lastReplicatedIndex=" + lastReplicatedIndex + ", votingState=" + peerInfo.getVotingState()
176 + ", stopwatch=" + stopwatch.elapsed(TimeUnit.MILLISECONDS) + ", followerTimeoutMillis="
177 + context.getConfigParams().getElectionTimeOutInterval().toMillis() + "]";