Author: adulceanu
Date: Wed Jan 31 11:09:34 2018
New Revision: 1822789
URL: http://svn.apache.org/viewvc?rev=1822789&view=rev
Log:
OAK-6373 - oak-run check should also check checkpoints
Added new --checkpoints and --head options
Modified:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/CheckCommand.java
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Check.java
Modified:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/CheckCommand.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/CheckCommand.java?rev=1822789&r1=1822788&r2=1822789&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/CheckCommand.java
(original)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/CheckCommand.java
Wed Jan 31 11:09:34 2018
@@ -48,6 +48,10 @@ class CheckCommand implements Command {
ArgumentAcceptingOptionSpec<String> filter = parser.accepts(
"filter", "comma separated content paths to be checked")
.withRequiredArg().ofType(String.class).withValuesSeparatedBy(',').defaultsTo("/");
+ OptionSpec<?> head = parser.accepts("head", "checks only latest /root
(i.e without checkpoints)");
+ ArgumentAcceptingOptionSpec<String> cp = parser.accepts(
+ "checkpoints", "checks only specified checkpoints (comma
separated); leave empty to check all")
+
.withOptionalArg().ofType(String.class).withValuesSeparatedBy(',').defaultsTo("/checkpoints");
OptionSpec<?> ioStatistics = parser.accepts("io-stats", "Print I/O
statistics (only for oak-segment-tar)");
OptionSet options = parser.parse(args);
@@ -63,13 +67,20 @@ class CheckCommand implements Command {
String journalFileName = journal.value(options);
long debugLevel = notify.value(options);
Set<String> filterPaths = new
LinkedHashSet<String>(filter.values(options));
+ Set<String> checkpoints = new LinkedHashSet<>();
+ if (options.has(cp) || !options.has(head)) {
+ checkpoints.addAll(cp.values(options));
+ }
if (options.has(deep)) {
printUsage(parser, err, "The --deep option was deprecated! Please
do not use it in the future!"
, "A deep scan of the content tree, traversing every node,
will be performed by default.");
}
- SegmentTarUtils.check(dir, journalFileName, debugLevel,
options.has(bin), filterPaths, options.has(ioStatistics), out, err);
+ boolean checkHead = !options.has(cp) || options.has(head);
+
+ SegmentTarUtils.check(dir, journalFileName, debugLevel,
options.has(bin), checkHead, checkpoints, filterPaths,
+ options.has(ioStatistics), out, err);
}
private void printUsage(OptionParser parser, PrintWriter err, String...
messages) throws IOException {
Modified:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java?rev=1822789&r1=1822788&r2=1822789&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java
(original)
+++
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java
Wed Jan 31 11:09:34 2018
@@ -24,6 +24,8 @@ import static org.apache.jackrabbit.oak.
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
import com.google.common.io.Closer;
@@ -37,7 +39,11 @@ import org.apache.jackrabbit.oak.segment
import org.apache.jackrabbit.oak.segment.file.ReadOnlyFileStore;
import org.apache.jackrabbit.oak.segment.tool.Backup;
import org.apache.jackrabbit.oak.segment.tool.Check;
+import org.apache.jackrabbit.oak.segment.tool.DebugSegments;
+import org.apache.jackrabbit.oak.segment.tool.DebugStore;
+import org.apache.jackrabbit.oak.segment.tool.DebugTars;
import org.apache.jackrabbit.oak.segment.tool.Diff;
+import org.apache.jackrabbit.oak.segment.tool.History;
import org.apache.jackrabbit.oak.segment.tool.Restore;
import org.apache.jackrabbit.oak.segment.tool.Revisions;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
@@ -84,13 +90,80 @@ final class SegmentTarUtils {
.run();
}
- static void check(File dir, String journalFileName, long debugLevel,
boolean checkBinaries, Set<String> filterPaths, boolean ioStatistics,
- PrintWriter outWriter, PrintWriter errWriter) {
+ static void debug(String... args) {
+ File file = new File(args[0]);
+
+ List<String> tars = new ArrayList<>();
+ List<String> segs = new ArrayList<>();
+
+ for (int i = 1; i < args.length; i++) {
+ if (args[i].endsWith(".tar")) {
+ tars.add(args[i]);
+ } else {
+ segs.add(args[i]);
+ }
+ }
+
+ if (tars.size() > 0) {
+ debugTars(file, tars);
+ }
+
+ if (segs.size() > 0) {
+ debugSegments(file, segs);
+ }
+
+ if (tars.isEmpty() && segs.isEmpty()) {
+ debugStore(file);
+ }
+ }
+
+ private static void debugTars(File store, List<String> tars) {
+ DebugTars.Builder builder = DebugTars.builder().withPath(store);
+
+ for (String tar : tars) {
+ builder.withTar(tar);
+ }
+
+ builder.build().run();
+ }
+
+ private static void debugSegments(File store, List<String> segments) {
+ DebugSegments.Builder builder =
DebugSegments.builder().withPath(store);
+
+ for (String segment : segments) {
+ builder.withSegment(segment);
+ }
+
+ builder.build().run();
+ }
+
+ private static void debugStore(File store) {
+ DebugStore.builder()
+ .withPath(store)
+ .build()
+ .run();
+ ;
+ }
+
+ static void history(File directory, File journal, String path, int depth) {
+ History.builder()
+ .withPath(directory)
+ .withJournal(journal)
+ .withNode(path)
+ .withDepth(depth)
+ .build()
+ .run();
+ }
+
+ static void check(File dir, String journalFileName, long debugLevel,
boolean checkBinaries, boolean checkHead, Set<String> checkpoints,
+ Set<String> filterPaths, boolean ioStatistics, PrintWriter
outWriter, PrintWriter errWriter) {
Check.builder()
.withPath(dir)
.withJournal(journalFileName)
.withDebugInterval(debugLevel)
.withCheckBinaries(checkBinaries)
+ .withCheckHead(checkHead)
+ .withCheckpoints(checkpoints)
.withFilterPaths(filterPaths)
.withIOStatistics(ioStatistics)
.withOutWriter(outWriter)
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java?rev=1822789&r1=1822788&r2=1822789&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
(original)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
Wed Jan 31 11:09:34 2018
@@ -19,7 +19,6 @@
package org.apache.jackrabbit.oak.segment.file.tooling;
-import static com.google.common.collect.Maps.newHashMap;
import static java.text.DateFormat.getDateTimeInstance;
import static org.apache.jackrabbit.oak.api.Type.BINARIES;
import static org.apache.jackrabbit.oak.api.Type.BINARY;
@@ -37,24 +36,30 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.MessageFormat;
+import java.util.ArrayList;
import java.util.Date;
-import java.util.HashSet;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
+import com.google.common.collect.Sets;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.segment.SegmentBlob;
+import org.apache.jackrabbit.oak.segment.SegmentNodeStore;
import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders;
import org.apache.jackrabbit.oak.segment.file.FileStore;
import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder;
-import org.apache.jackrabbit.oak.segment.file.tar.IOMonitorAdapter;
import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
import org.apache.jackrabbit.oak.segment.file.JournalEntry;
import org.apache.jackrabbit.oak.segment.file.JournalReader;
import org.apache.jackrabbit.oak.segment.file.ReadOnlyFileStore;
+import org.apache.jackrabbit.oak.segment.file.tar.IOMonitorAdapter;
import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -65,6 +70,10 @@ import org.apache.jackrabbit.oak.spi.sta
*/
public class ConsistencyChecker implements Closeable {
+ private static final String CHECKPOINT_INDENT = " ";
+
+ private static final String NO_INDENT = "";
+
private static class StatisticsIOMonitor extends IOMonitorAdapter {
private final AtomicLong ioOperations = new AtomicLong(0);
@@ -95,6 +104,8 @@ public class ConsistencyChecker implemen
private int nodeCount;
private int propertyCount;
+
+ private int checkCount;
/**
* Run a full traversal consistency check.
@@ -104,18 +115,23 @@ public class ConsistencyChecker implemen
* @param debugInterval number of seconds between printing progress
information to
* the console during the full traversal phase.
* @param checkBinaries if {@code true} full content of binary
properties will be scanned
+ * @param checkHead if {@code true} will check the head
+ * @param checkpoints collection of checkpoints to be checked
* @param filterPaths collection of repository paths to be checked
* @param ioStatistics if {@code true} prints I/O statistics gathered
while consistency
* check was performed
* @param outWriter text output stream writer
* @param errWriter text error stream writer
* @throws IOException
+ * @throws InvalidFileStoreVersionException
*/
public static void checkConsistency(
File directory,
String journalFileName,
long debugInterval,
boolean checkBinaries,
+ boolean checkHead,
+ Set<String> checkpoints,
Set<String> filterPaths,
boolean ioStatistics,
PrintWriter outWriter,
@@ -125,55 +141,122 @@ public class ConsistencyChecker implemen
JournalReader journal = new JournalReader(new File(directory,
journalFileName));
ConsistencyChecker checker = new ConsistencyChecker(directory,
debugInterval, ioStatistics, outWriter, errWriter)
) {
- Map<String, JournalEntry> pathToJournalEntry = newHashMap();
- Map<String, Set<String>> pathToCorruptPaths = newHashMap();
- for (String path : filterPaths) {
- pathToCorruptPaths.put(path, new HashSet<String>());
- }
+ Set<String> checkpointsSet = Sets.newLinkedHashSet();
+ List<PathToCheck> headPaths = new ArrayList<>();
+ Map<String, List<PathToCheck>> checkpointPaths = new HashMap<>();
- int count = 0;
int revisionCount = 0;
+
+ if (!checkpoints.isEmpty()) {
+ checkpointsSet.addAll(checkpoints);
+
+ if (checkpointsSet.remove("/checkpoints")) {
+ checkpointsSet = Sets
+
.newLinkedHashSet(SegmentNodeStoreBuilders.builder(checker.store).build().checkpoints());
+ }
+ }
+
+ for (String path : filterPaths) {
+ if (checkHead) {
+ headPaths.add(new PathToCheck(path, null));
+ checker.checkCount++;
+ }
+
+ for (String checkpoint : checkpointsSet) {
+ List<PathToCheck> pathList =
checkpointPaths.get(checkpoint);
+ if (pathList == null) {
+ pathList = new ArrayList<>();
+ checkpointPaths.put(checkpoint, pathList);
+ }
- while (journal.hasNext() && count < filterPaths.size()) {
+ pathList.add(new PathToCheck(path, checkpoint));
+ checker.checkCount++;
+ }
+ }
+
+ int initialCount = checker.checkCount;
+ JournalEntry lastValidJournalEntry = null;
+
+ while (journal.hasNext() && checker.checkCount > 0) {
JournalEntry journalEntry = journal.next();
- checker.print("Checking revision {0}",
journalEntry.getRevision());
+ String revision = journalEntry.getRevision();
try {
revisionCount++;
+ checker.store.setRevision(revision);
+ boolean overallValid = true;
+
+ SegmentNodeStore sns =
SegmentNodeStoreBuilders.builder(checker.store).build();
- for (String path : filterPaths) {
- if (pathToJournalEntry.get(path) == null) {
-
- Set<String> corruptPaths =
pathToCorruptPaths.get(path);
- String corruptPath =
checker.checkPathAtRevision(journalEntry.getRevision(), corruptPaths, path,
checkBinaries);
-
- if (corruptPath == null) {
- checker.print("Path {0} is consistent", path);
- pathToJournalEntry.put(path, journalEntry);
- count++;
- } else {
- corruptPaths.add(corruptPath);
+ checker.print("\nChecking revision {0}", revision);
+
+ if (checkHead) {
+ boolean mustCheck = headPaths.stream().anyMatch(p ->
p.journalEntry == null);
+
+ if (mustCheck) {
+ checker.print("\nChecking head\n");
+ NodeState root = sns.getRoot();
+ overallValid = overallValid &&
checker.checkPathsAtRoot(headPaths, root, journalEntry, checkBinaries);
+ }
+ }
+
+ if (!checkpointsSet.isEmpty()) {
+ Map<String, Boolean> checkpointsToCheck =
checkpointPaths.entrySet().stream().collect(Collectors.toMap(
+ Map.Entry::getKey, e ->
e.getValue().stream().anyMatch(p -> p.journalEntry == null)));
+ boolean mustCheck =
checkpointsToCheck.values().stream().anyMatch(v -> v == true);
+
+ if (mustCheck) {
+ checker.print("\nChecking checkpoints");
+
+ for (String checkpoint : checkpointsSet) {
+ if (checkpointsToCheck.get(checkpoint)) {
+ checker.print("\nChecking checkpoint {0}",
checkpoint);
+
+ List<PathToCheck> pathList =
checkpointPaths.get(checkpoint);
+ NodeState root = sns.retrieve(checkpoint);
+
+ if (root == null) {
+ checker.print("Checkpoint {0} not
found in this revision!", checkpoint);
+ overallValid = false;
+ } else {
+ overallValid = overallValid &&
checker.checkPathsAtRoot(pathList, root,
+ journalEntry, checkBinaries);
+ }
+ }
}
}
}
+
+ if (overallValid) {
+ lastValidJournalEntry = journalEntry;
+ }
} catch (IllegalArgumentException e) {
- checker.printError("Skipping invalid record id {0}",
journalEntry.getRevision());
+ checker.printError("Skipping invalid record id {0}",
revision);
}
}
- checker.print("Searched through {0} revisions", revisionCount);
+ checker.print("\nSearched through {0} revisions and {1}
checkpoints", revisionCount, checkpointsSet.size());
- if (count == 0) {
+ if (initialCount == checker.checkCount) {
checker.print("No good revision found");
} else {
- for (String path : filterPaths) {
- JournalEntry journalEntry = pathToJournalEntry.get(path);
- String revision = journalEntry != null ?
journalEntry.getRevision() : null;
- long timestamp = journalEntry != null ?
journalEntry.getTimestamp() : -1L;
+ if (checkHead) {
+ checker.print("\nHead");
+ checker.printResults(headPaths, NO_INDENT);
+ }
+
+ if (!checkpointsSet.isEmpty()) {
+ checker.print("\nCheckpoints");
- checker.print("Latest good revision for path {0} is {1}
from {2}", path,
- toString(revision), toString(timestamp));
+ for (String checkpoint : checkpointsSet) {
+ List<PathToCheck> pathList =
checkpointPaths.get(checkpoint);
+ checker.print("- {0}", checkpoint);
+ checker.printResults(pathList, CHECKPOINT_INDENT);
+ }
}
+
+ checker.print("\nOverall");
+ checker.printOverallResults(lastValidJournalEntry);
}
if (ioStatistics) {
@@ -194,6 +277,23 @@ public class ConsistencyChecker implemen
}
}
+ private void printResults(List<PathToCheck> pathList, String indent) {
+ for (PathToCheck ptc : pathList) {
+ String revision = ptc.journalEntry != null ?
ptc.journalEntry.getRevision() : null;
+ long timestamp = ptc.journalEntry != null ?
ptc.journalEntry.getTimestamp() : -1L;
+
+ print("{0}Latest good revision for path {1} is {2} from {3}",
indent, ptc.path,
+ toString(revision), toString(timestamp));
+ }
+ }
+
+ private void printOverallResults(JournalEntry journalEntry) {
+ String revision = journalEntry != null ? journalEntry.getRevision() :
null;
+ long timestamp = journalEntry != null ? journalEntry.getTimestamp() :
-1L;
+
+ print("Latest good revision for paths and checkpoints checked is {0}
from {1}", toString(revision), toString(timestamp));
+ }
+
private static String toString(String revision) {
if (revision != null) {
return revision;
@@ -234,26 +334,50 @@ public class ConsistencyChecker implemen
this.errWriter = errWriter;
}
-
/**
- * Checks the consistency of the supplied {@code paths} at the given
{@code revision},
- * starting first with already known {@code corruptPaths}.
+ * Checks for consistency a list of paths, relative to the same root.
*
- * @param revision revision to be checked
- * @param corruptPaths already known corrupt paths from previous revisions
- * @param path path on which to run consistency check,
- * provided there are no corrupt paths.
+ * @param paths paths to check
+ * @param root root relative to which the paths are retrieved
+ * @param journalEntry entry containing the current revision checked
+ * @param checkBinaries if {@code true} full content of binary
properties will be scanned
+ * @return {@code true}, if the whole list of paths is
consistent
+ */
+ private boolean checkPathsAtRoot(List<PathToCheck> paths, NodeState root,
JournalEntry journalEntry,
+ boolean checkBinaries) {
+ boolean result = true;
+
+ for (PathToCheck ptc : paths) {
+ if (ptc.journalEntry == null) {
+ String corruptPath = checkPathAtRoot(ptc, root, checkBinaries);
+
+ if (corruptPath == null) {
+ print("Path {0} is consistent", ptc.path);
+ ptc.journalEntry = journalEntry;
+ checkCount--;
+ } else {
+ result = false;
+ ptc.corruptPaths.add(corruptPath);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Checks the consistency of the supplied {@code ptc} relative to the
given {@code root}.
+ *
+ * @param ptc path to check, provided there are no corrupt paths.
+ * @param root root relative to which the path is retrieved
* @param checkBinaries if {@code true} full content of binary properties
will be scanned
- * @return {@code null}, if the content tree rooted at path
is consistent
- * in this revision or the path of the first
inconsistency otherwise.
+ * @return {@code null}, if the content tree rooted at path
(possibly under a checkpoint)
+ * is consistent in this revision or the path of the
first inconsistency otherwise.
*/
- public String checkPathAtRevision(String revision, Set<String>
corruptPaths, String path, boolean checkBinaries) {
+ private String checkPathAtRoot(PathToCheck ptc, NodeState root, boolean
checkBinaries) {
String result = null;
-
- store.setRevision(revision);
- NodeState root =
SegmentNodeStoreBuilders.builder(store).build().getRoot();
- for (String corruptPath : corruptPaths) {
+ for (String corruptPath : ptc.corruptPaths) {
try {
NodeWrapper wrapper =
NodeWrapper.deriveTraversableNodeOnPath(root, corruptPath);
result = checkNode(wrapper.node, wrapper.path, checkBinaries);
@@ -269,17 +393,17 @@ public class ConsistencyChecker implemen
nodeCount = 0;
propertyCount = 0;
- print("Checking {0}", path);
+ print("Checking {0}", ptc.path);
try {
- NodeWrapper wrapper =
NodeWrapper.deriveTraversableNodeOnPath(root, path);
+ NodeWrapper wrapper =
NodeWrapper.deriveTraversableNodeOnPath(root, ptc.path);
result = checkNodeAndDescendants(wrapper.node, wrapper.path,
checkBinaries);
print("Checked {0} nodes and {1} properties", nodeCount,
propertyCount);
return result;
} catch (IllegalArgumentException e) {
- printError("Path {0} not found", path);
- return path;
+ printError("Path {0} not found", ptc.path);
+ return ptc.path;
}
}
@@ -380,6 +504,40 @@ public class ConsistencyChecker implemen
}
}
}
+
+ static class PathToCheck {
+ final String path;
+ final String checkpoint;
+
+ JournalEntry journalEntry;
+ Set<String> corruptPaths = new LinkedHashSet<>();
+
+ PathToCheck(String path, String checkpoint) {
+ this.path = path;
+ this.checkpoint = checkpoint;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((checkpoint == null) ? 0 :
checkpoint.hashCode());
+ result = prime * result + ((path == null) ? 0 : path.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ } else if (object instanceof PathToCheck) {
+ PathToCheck that = (PathToCheck) object;
+ return path.equals(that.path) &&
checkpoint.equals(that.checkpoint);
+ } else {
+ return false;
+ }
+ }
+ }
private boolean traverse(Blob blob, boolean checkBinaries) throws
IOException {
if (checkBinaries && !isExternal(blob)) {
@@ -425,8 +583,8 @@ public class ConsistencyChecker implemen
outWriter.println(MessageFormat.format(format, arg1, arg2));
}
- private void print(String format, Object arg1, Object arg2, Object arg3) {
- outWriter.println(MessageFormat.format(format, arg1, arg2, arg3));
+ private void print(String format, Object arg1, Object arg2, Object arg3,
Object arg4) {
+ outWriter.println(MessageFormat.format(format, arg1, arg2, arg3,
arg4));
}
private void printError(String format, Object arg) {
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Check.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Check.java?rev=1822789&r1=1822788&r2=1822789&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Check.java
(original)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Check.java
Wed Jan 31 11:09:34 2018
@@ -53,6 +53,10 @@ public class Check implements Runnable {
private boolean checkBinaries;
+ private boolean checkHead;
+
+ private Set<String> checkpoints;
+
private Set<String> filterPaths;
private boolean ioStatistics;
@@ -116,6 +120,30 @@ public class Check implements Runnable {
}
/**
+ * Instruct the command to check head state.
+ * This parameter is not required and defaults to {@code true}.
+ * @param checkHead if {@code true}, will check the head state.
+ * @return this builder.
+ */
+ public Builder withCheckHead(boolean checkHead) {
+ this.checkHead = checkHead;
+ return this;
+ }
+
+ /**
+ * Instruct the command to check specified checkpoints.
+ * This parameter is not required and defaults to "/checkpoints",
+ * i.e. will check all checkpoints when not explicitly overridden.
+ *
+ * @param checkpoints checkpoints to be checked
+ * @return this builder.
+ */
+ public Builder withCheckpoints(Set<String> checkpoints) {
+ this.checkpoints = checkpoints;
+ return this;
+ }
+
+ /**
* Content paths to be checked. This parameter is not required and
* defaults to "/".
*
@@ -185,6 +213,10 @@ public class Check implements Runnable {
private final boolean checkBinaries;
+ private final boolean checkHead;
+
+ private final Set<String> checkpoints;
+
private final Set<String> filterPaths;
private final boolean ioStatistics;
@@ -197,7 +229,9 @@ public class Check implements Runnable {
this.path = builder.path;
this.journal = builder.journal;
this.debugInterval = builder.debugInterval;
+ this.checkHead = builder.checkHead;
this.checkBinaries = builder.checkBinaries;
+ this.checkpoints = builder.checkpoints;
this.filterPaths = builder.filterPaths;
this.ioStatistics = builder.ioStatistics;
this.outWriter = builder.outWriter;
@@ -207,7 +241,8 @@ public class Check implements Runnable {
@Override
public void run() {
try {
- ConsistencyChecker.checkConsistency(path, journal, debugInterval,
checkBinaries, filterPaths, ioStatistics, outWriter, errWriter);
+ ConsistencyChecker.checkConsistency(path, journal, debugInterval,
checkBinaries, checkHead, checkpoints, filterPaths,
+ ioStatistics, outWriter, errWriter);
} catch (Exception e) {
e.printStackTrace();
}