Fix remaining CS errors in sal-akka-raft and enable enforcement
[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 org.opendaylight.controller.cluster.raft.persisted.DeleteEntries;
15
16 /**
17  * Implementation of ReplicatedLog used by the RaftActor.
18  */
19 class ReplicatedLogImpl extends AbstractReplicatedLogImpl {
20     private static final int DATA_SIZE_DIVIDER = 5;
21
22     private final Procedure<DeleteEntries> deleteProcedure = NoopProcedure.instance();
23
24     private final RaftActorContext context;
25     private long dataSizeSinceLastSnapshot = 0L;
26
27     private ReplicatedLogImpl(final long snapshotIndex, final long snapshotTerm,
28             final List<ReplicatedLogEntry> unAppliedEntries,
29             final RaftActorContext context) {
30         super(snapshotIndex, snapshotTerm, unAppliedEntries, context.getId());
31         this.context = Preconditions.checkNotNull(context);
32     }
33
34     static ReplicatedLog newInstance(final Snapshot snapshot, final RaftActorContext context) {
35         return new ReplicatedLogImpl(snapshot.getLastAppliedIndex(), snapshot.getLastAppliedTerm(),
36                 snapshot.getUnAppliedEntries(), context);
37     }
38
39     static ReplicatedLog newInstance(final RaftActorContext context) {
40         return new ReplicatedLogImpl(-1L, -1L, Collections.<ReplicatedLogEntry>emptyList(), context);
41     }
42
43     @Override
44     public boolean removeFromAndPersist(final long logEntryIndex) {
45         // FIXME: Maybe this should be done after the command is saved
46         long adjustedIndex = removeFrom(logEntryIndex);
47         if (adjustedIndex >= 0) {
48             context.getPersistenceProvider().persist(new DeleteEntries(adjustedIndex), deleteProcedure);
49             return true;
50         }
51
52         return false;
53     }
54
55     @Override
56     public void captureSnapshotIfReady(final ReplicatedLogEntry replicatedLogEntry) {
57         final ConfigParams config = context.getConfigParams();
58         final long journalSize = replicatedLogEntry.getIndex() + 1;
59         final long dataThreshold = context.getTotalMemory() * config.getSnapshotDataThresholdPercentage() / 100;
60
61         if (journalSize % config.getSnapshotBatchCount() == 0 || getDataSizeForSnapshotCheck() > dataThreshold) {
62             boolean started = context.getSnapshotManager().capture(replicatedLogEntry,
63                     context.getCurrentBehavior().getReplicatedToAllIndex());
64             if (started && !context.hasFollowers()) {
65                 dataSizeSinceLastSnapshot = 0;
66             }
67         }
68     }
69
70     private long getDataSizeForSnapshotCheck() {
71         if (!context.hasFollowers()) {
72             // When we do not have followers we do not maintain an in-memory log
73             // due to this the journalSize will never become anything close to the
74             // snapshot batch count. In fact will mostly be 1.
75             // Similarly since the journal's dataSize depends on the entries in the
76             // journal the journal's dataSize will never reach a value close to the
77             // memory threshold.
78             // By maintaining the dataSize outside the journal we are tracking essentially
79             // what we have written to the disk however since we no longer are in
80             // need of doing a snapshot just for the sake of freeing up memory we adjust
81             // the real size of data by the DATA_SIZE_DIVIDER so that we do not snapshot as often
82             // as if we were maintaining a real snapshot
83             return dataSizeSinceLastSnapshot / DATA_SIZE_DIVIDER;
84         } else {
85             return dataSize();
86         }
87     }
88
89     @Override
90     public void appendAndPersist(final ReplicatedLogEntry replicatedLogEntry) {
91         appendAndPersist(replicatedLogEntry, null);
92     }
93
94     @Override
95     public void appendAndPersist(final ReplicatedLogEntry replicatedLogEntry,
96             final Procedure<ReplicatedLogEntry> callback)  {
97
98         context.getLogger().debug("{}: Append log entry and persist {} ", context.getId(), replicatedLogEntry);
99
100         // FIXME : By adding the replicated log entry to the in-memory journal we are not truly ensuring durability
101         // of the logs
102         if (!append(replicatedLogEntry)) {
103             return;
104         }
105
106         // When persisting events with persist it is guaranteed that the
107         // persistent actor will not receive further commands between the
108         // persist call and the execution(s) of the associated event
109         // handler. This also holds for multiple persist calls in context
110         // of a single command.
111         context.getPersistenceProvider().persist(replicatedLogEntry,
112             param -> {
113                 context.getLogger().debug("{}: persist complete {}", context.getId(), param);
114
115                 int logEntrySize = param.size();
116                 dataSizeSinceLastSnapshot += logEntrySize;
117
118                 if (callback != null) {
119                     callback.apply(param);
120                 }
121             }
122         );
123     }
124 }