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.Stopwatch;
12 import java.util.concurrent.TimeUnit;
13 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
15 public class FollowerLogInformationImpl implements FollowerLogInformation {
16 private static final AtomicLongFieldUpdater<FollowerLogInformationImpl> NEXT_INDEX_UPDATER = AtomicLongFieldUpdater.newUpdater(FollowerLogInformationImpl.class, "nextIndex");
17 private static final AtomicLongFieldUpdater<FollowerLogInformationImpl> MATCH_INDEX_UPDATER = AtomicLongFieldUpdater.newUpdater(FollowerLogInformationImpl.class, "matchIndex");
19 private final String id;
21 private final Stopwatch stopwatch = Stopwatch.createUnstarted();
23 private final RaftActorContext context;
25 private volatile long nextIndex;
27 private volatile long matchIndex;
29 private long lastReplicatedIndex = -1L;
31 private final Stopwatch lastReplicatedStopwatch = Stopwatch.createUnstarted();
34 public FollowerLogInformationImpl(String id, long matchIndex, RaftActorContext context) {
36 this.nextIndex = context.getCommitIndex();
37 this.matchIndex = matchIndex;
38 this.context = context;
42 public long incrNextIndex(){
43 return NEXT_INDEX_UPDATER.incrementAndGet(this);
47 public long decrNextIndex() {
48 return NEXT_INDEX_UPDATER.decrementAndGet(this);
52 public boolean setNextIndex(long nextIndex) {
53 if(this.nextIndex != nextIndex) {
54 this.nextIndex = nextIndex;
62 public long incrMatchIndex(){
63 return MATCH_INDEX_UPDATER.incrementAndGet(this);
67 public boolean setMatchIndex(long matchIndex) {
68 if(this.matchIndex != matchIndex) {
69 this.matchIndex = matchIndex;
77 public String getId() {
82 public long getNextIndex() {
87 public long getMatchIndex() {
92 public boolean isFollowerActive() {
93 long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
94 return (stopwatch.isRunning()) &&
95 (elapsed <= context.getConfigParams().getElectionTimeOutInterval().toMillis());
99 public void markFollowerActive() {
100 if (stopwatch.isRunning()) {
107 public void markFollowerInActive() {
108 if (stopwatch.isRunning()) {
114 public long timeSinceLastActivity() {
115 return stopwatch.elapsed(TimeUnit.MILLISECONDS);
119 public boolean okToReplicate() {
120 // Return false if we are trying to send duplicate data before the heartbeat interval
121 if(getNextIndex() == lastReplicatedIndex){
122 if(lastReplicatedStopwatch.elapsed(TimeUnit.MILLISECONDS) < context.getConfigParams()
123 .getHeartBeatInterval().toMillis()){
128 resetLastReplicated();
132 private void resetLastReplicated(){
133 lastReplicatedIndex = getNextIndex();
134 if(lastReplicatedStopwatch.isRunning()){
135 lastReplicatedStopwatch.reset();
137 lastReplicatedStopwatch.start();
141 public String toString() {
142 StringBuilder builder = new StringBuilder();
143 builder.append("FollowerLogInformationImpl [id=").append(id).append(", nextIndex=").append(nextIndex)
144 .append(", matchIndex=").append(matchIndex).append(", stopwatch=")
145 .append(stopwatch.elapsed(TimeUnit.MILLISECONDS))
146 .append(", followerTimeoutMillis=")
147 .append(context.getConfigParams().getElectionTimeOutInterval().toMillis()).append("]");
148 return builder.toString();