Fix checkstyle reported by odlparent-3.0.0
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / main / java / org / opendaylight / controller / cluster / raft / ReplicatedLogImpl.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.raft;
9
10 import akka.japi.Procedure;
11 import com.google.common.base.Preconditions;
12 import java.util.Collections;
13 import java.util.List;
14 import javax.annotation.Nonnull;
15 import javax.annotation.Nullable;
16 import org.opendaylight.controller.cluster.raft.persisted.DeleteEntries;
17 import org.opendaylight.controller.cluster.raft.persisted.Snapshot;
18
19 /**
20  * Implementation of ReplicatedLog used by the RaftActor.
21  */
22 final class ReplicatedLogImpl extends AbstractReplicatedLogImpl {
23     private static final int DATA_SIZE_DIVIDER = 5;
24
25     private final RaftActorContext context;
26     private long dataSizeSinceLastSnapshot = 0L;
27
28     private ReplicatedLogImpl(final long snapshotIndex, final long snapshotTerm,
29             final List<ReplicatedLogEntry> unAppliedEntries,
30             final RaftActorContext context) {
31         super(snapshotIndex, snapshotTerm, unAppliedEntries, context.getId());
32         this.context = Preconditions.checkNotNull(context);
33     }
34
35     static ReplicatedLog newInstance(final Snapshot snapshot, final RaftActorContext context) {
36         return new ReplicatedLogImpl(snapshot.getLastAppliedIndex(), snapshot.getLastAppliedTerm(),
37                 snapshot.getUnAppliedEntries(), context);
38     }
39
40     static ReplicatedLog newInstance(final RaftActorContext context) {
41         return new ReplicatedLogImpl(-1L, -1L, Collections.<ReplicatedLogEntry>emptyList(), context);
42     }
43
44     @Override
45     public boolean removeFromAndPersist(final long logEntryIndex) {
46         // FIXME: Maybe this should be done after the command is saved
47         long adjustedIndex = removeFrom(logEntryIndex);
48         if (adjustedIndex >= 0) {
49             context.getPersistenceProvider().persist(new DeleteEntries(adjustedIndex), NoopProcedure.instance());
50             return true;
51         }
52
53         return false;
54     }
55
56     @Override
57     public boolean shouldCaptureSnapshot(final long logIndex) {
58         final ConfigParams config = context.getConfigParams();
59         final long journalSize = logIndex + 1;
60         final long dataThreshold = context.getTotalMemory() * config.getSnapshotDataThresholdPercentage() / 100;
61
62         return journalSize % config.getSnapshotBatchCount() == 0 || getDataSizeForSnapshotCheck() > dataThreshold;
63     }
64
65     @Override
66     public void captureSnapshotIfReady(final ReplicatedLogEntry replicatedLogEntry) {
67         if (shouldCaptureSnapshot(replicatedLogEntry.getIndex())) {
68             boolean started = context.getSnapshotManager().capture(replicatedLogEntry,
69                     context.getCurrentBehavior().getReplicatedToAllIndex());
70             if (started && !context.hasFollowers()) {
71                 dataSizeSinceLastSnapshot = 0;
72             }
73         }
74     }
75
76     private long getDataSizeForSnapshotCheck() {
77         if (!context.hasFollowers()) {
78             // When we do not have followers we do not maintain an in-memory log
79             // due to this the journalSize will never become anything close to the
80             // snapshot batch count. In fact will mostly be 1.
81             // Similarly since the journal's dataSize depends on the entries in the
82             // journal the journal's dataSize will never reach a value close to the
83             // memory threshold.
84             // By maintaining the dataSize outside the journal we are tracking essentially
85             // what we have written to the disk however since we no longer are in
86             // need of doing a snapshot just for the sake of freeing up memory we adjust
87             // the real size of data by the DATA_SIZE_DIVIDER so that we do not snapshot as often
88             // as if we were maintaining a real snapshot
89             return dataSizeSinceLastSnapshot / DATA_SIZE_DIVIDER;
90         } else {
91             return dataSize();
92         }
93     }
94
95     @Override
96     public boolean appendAndPersist(@Nonnull final ReplicatedLogEntry replicatedLogEntry,
97             @Nullable final Procedure<ReplicatedLogEntry> callback, final boolean doAsync)  {
98
99         context.getLogger().debug("{}: Append log entry and persist {} ", context.getId(), replicatedLogEntry);
100
101         if (!append(replicatedLogEntry)) {
102             return false;
103         }
104
105         Procedure<ReplicatedLogEntry> persistCallback = persistedLogEntry -> {
106             context.getLogger().debug("{}: persist complete {}", context.getId(), persistedLogEntry);
107
108             dataSizeSinceLastSnapshot += persistedLogEntry.size();
109
110             if (callback != null) {
111                 callback.apply(persistedLogEntry);
112             }
113         };
114
115         if (doAsync) {
116             context.getPersistenceProvider().persistAsync(replicatedLogEntry, persistCallback);
117         } else {
118             context.getPersistenceProvider().persist(replicatedLogEntry, persistCallback);
119         }
120
121         return true;
122     }
123 }