Author: amitj
Date: Wed Nov 29 06:24:11 2017
New Revision: 1816600

URL: http://svn.apache.org/viewvc?rev=1816600&view=rev
Log:
OAK-6865: Account for active deletion in oak-run datastorecheck

- Added a repoHome option to the command which is mandatory --consistency and 
--track
- Now --track does not take any parameter

Modified:
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/DataStoreCheckCommand.java
    
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/DataStoreCheckTest.java

Modified: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/DataStoreCheckCommand.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/DataStoreCheckCommand.java?rev=1816600&r1=1816599&r2=1816600&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/DataStoreCheckCommand.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/DataStoreCheckCommand.java
 Wed Nov 29 06:24:11 2017
@@ -19,8 +19,10 @@ package org.apache.jackrabbit.oak.run;
 import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR;
 import static com.google.common.base.Stopwatch.createStarted;
 import static com.google.common.io.Closeables.close;
+import static java.io.File.createTempFile;
 import static java.util.Arrays.asList;
 import static org.apache.commons.io.FileUtils.forceDelete;
+import static org.apache.commons.io.FileUtils.listFiles;
 import static org.apache.jackrabbit.oak.commons.FileIOUtils.sort;
 import static org.apache.jackrabbit.oak.commons.FileIOUtils.writeAsLine;
 import static org.apache.jackrabbit.oak.commons.FileIOUtils.writeStrings;
@@ -29,6 +31,8 @@ import java.io.BufferedWriter;
 import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Map;
@@ -39,6 +43,8 @@ import javax.annotation.Nullable;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.filefilter.FileFilterUtils;
+import org.apache.jackrabbit.oak.commons.FileIOUtils;
 import 
org.apache.jackrabbit.oak.commons.FileIOUtils.FileLineDifferenceIterator;
 import org.apache.jackrabbit.oak.run.commons.Command;
 import org.apache.jackrabbit.oak.plugins.blob.BlobReferenceRetriever;
@@ -79,7 +85,8 @@ public class DataStoreCheckCommand imple
 
         String helpStr =
             "datastorecheck [--id] [--ref] [--consistency] [--store 
<path>|<mongo_uri>] "
-                + "[--s3ds <s3ds_config>|--fds <fds_config>|--azureblobds 
<azureblobds_config>] [--dump <path>]";
+                + "[--s3ds <s3ds_config>|--fds <fds_config>|--azureblobds 
<azureblobds_config>]"
+                + " [--dump <path>] [--repoHome <repo_home>] [--track]";
 
         Closer closer = Closer.create();
         try {
@@ -96,8 +103,12 @@ public class DataStoreCheckCommand imple
                 .withRequiredArg().ofType(String.class);
 
             // Optional argument to specify tracking
-            ArgumentAcceptingOptionSpec<String> track = 
parser.accepts("track", "Local repository home folder")
-                .withRequiredArg().ofType(String.class);
+            OptionSpecBuilder trackOverride = parser.accepts("track", "Force 
override tracked ids");
+
+            // Required argument for --consistency to specify tracking folder 
(otherwise can have inconsistencies)
+            ArgumentAcceptingOptionSpec<String> repoHome = 
parser.accepts("repoHome", "Local repository home folder")
+                .requiredIf(trackOverride, 
consistencyOp).withRequiredArg().ofType(String.class);
+
 
             OptionSpec<?> help = parser.acceptsAll(asList("h", "?", "help"),
                 "show help").forHelp();
@@ -106,12 +117,16 @@ public class DataStoreCheckCommand imple
             idOp.requiredUnless(refOp, consistencyOp);
             refOp.requiredUnless(idOp, consistencyOp);
             consistencyOp.requiredUnless(idOp, refOp);
+            trackOverride.availableIf(idOp, consistencyOp);
 
             OptionSet options = null;
             try {
                 options = parser.parse(args);
             } catch (Exception e) {
                 System.err.println(e);
+                System.err.println(Arrays.toString(args));
+                System.err.println();
+                System.err.println("Options :");
                 parser.printHelpOn(System.err);
                 return;
             }
@@ -163,9 +178,9 @@ public class DataStoreCheckCommand imple
                 File dumpFile = register.createFile(idOp, dumpPath);
                 retrieveBlobIds(blobStore, dumpFile);
 
-                // If track path specified copy the file to the location
-                if (options.has(track)) {
-                    String trackPath = options.valueOf(track);
+                // If track path and track override specified copy the file to 
the location
+                if (options.has(repoHome) && options.has(trackOverride)) {
+                    String trackPath = options.valueOf(repoHome);
                     File trackingFileParent = new 
File(FilenameUtils.concat(trackPath, "blobids"));
                     File trackingFile = new File(trackingFileParent,
                         "blob-" + String.valueOf(System.currentTimeMillis()) + 
".gen");
@@ -180,7 +195,7 @@ public class DataStoreCheckCommand imple
 
             if (options.has(consistencyOp)) {
                 checkConsistency(register.get(idOp), register.get(refOp),
-                    register.createFile(consistencyOp, dumpPath));
+                    register.createFile(consistencyOp, dumpPath), 
options.valueOf(repoHome));
             }
         } catch (Throwable t) {
             t.printStackTrace();
@@ -225,7 +240,7 @@ public class DataStoreCheckCommand imple
         }
     }
 
-    private static void checkConsistency(File ids, File refs, File missing) 
throws IOException {
+    private static void checkConsistency(File ids, File refs, File missing, 
String trackRoot) throws IOException {
         System.out.println("Starting consistency check");
         Stopwatch watch = createStarted();
 
@@ -238,7 +253,39 @@ public class DataStoreCheckCommand imple
                 }
                 return "";
             }});
-        long candidates = writeStrings(iter, missing, true);
+
+
+        // write the candidates identified to a temp file
+        File candTemp = createTempFile("candTemp", null);
+        int candidates = writeStrings(iter, candTemp, true);
+
+        try {
+            // retrieve the .del file from track directory
+            File trackingFileParent = new File(FilenameUtils.concat(trackRoot, 
"blobids"));
+            if (trackingFileParent.exists()) {
+                Collection<File> files =
+                    listFiles(trackingFileParent, 
FileFilterUtils.suffixFileFilter(".del"), null);
+
+                // If a delete file is present filter the tracked deleted ids
+                if (!files.isEmpty()) {
+                    File delFile = files.iterator().next();
+                    FileLineDifferenceIterator filteringIter = new 
FileLineDifferenceIterator(delFile, candTemp, new Function<String, String>() {
+                        @Nullable @Override public String apply(@Nullable 
String input) {
+                            if (input != null) {
+                                return input.split(DELIM)[0];
+                            }
+                            return "";
+                        }
+                    });
+                    candidates = FileIOUtils.writeStrings(filteringIter, 
missing, true);
+                }
+            } else {
+                System.out.println("Skipping active deleted tracked as 
parameter [repoHome] : [" + trackRoot + "] incorrect");
+                FileUtils.copyFile(candTemp, missing);
+            }
+        } finally {
+            FileUtils.forceDelete(candTemp);
+        }
 
         System.out.println("Consistency check found " + candidates + " missing 
blobs");
         if (candidates > 0) {

Modified: 
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/DataStoreCheckTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/DataStoreCheckTest.java?rev=1816600&r1=1816599&r2=1816600&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/DataStoreCheckTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-run/src/test/java/org/apache/jackrabbit/oak/run/DataStoreCheckTest.java
 Wed Nov 29 06:24:11 2017
@@ -40,6 +40,7 @@ import java.util.Set;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import joptsimple.internal.Strings;
@@ -179,13 +180,15 @@ public class DataStoreCheckTest {
     @Test
     public void testCorrect() throws Exception {
         File dump = temporaryFolder.newFolder();
+        File repoHome = temporaryFolder.newFolder();
         setupDataStore.close();
-        testAllParams(dump);
+        testAllParams(dump, repoHome);
     }
 
     @Test
     public void testConsistency() throws Exception {
         File dump = temporaryFolder.newFolder();
+        File repoHome = temporaryFolder.newFolder();
 
         Random rand = new Random();
         String deletedBlobId = Iterables.get(blobsAdded, 
rand.nextInt(blobsAdded.size()));
@@ -194,18 +197,49 @@ public class DataStoreCheckTest {
         assertEquals(1, count);
         setupDataStore.close();
 
-        testAllParams(dump);
+        testAllParams(dump, repoHome);
 
         assertFileEquals(dump, "[id]", blobsAdded);
         assertFileEquals(dump, "[ref]", Sets.union(blobsAdded, 
Sets.newHashSet(deletedBlobId)));
         assertFileEquals(dump, "[consistency]", 
Sets.newHashSet(deletedBlobId));
     }
 
-    private void testAllParams(File dump) throws Exception {
+    @Test
+    public void testConsistencyWithDeleteTracker() throws Exception {
+        File dump = temporaryFolder.newFolder();
+        File repoHome = temporaryFolder.newFolder();
+
+        File trackerFolder = new File(repoHome, "blobids");
+        FileUtils.forceMkdir(trackerFolder);
+
+        File delTracker = new File(trackerFolder, "activedeletions.del");
+        Random rand = new Random();
+        String deletedBlobId = Iterables.get(blobsAdded, 
rand.nextInt(blobsAdded.size()));
+        blobsAdded.remove(deletedBlobId);
+        long count = 
setupDataStore.countDeleteChunks(ImmutableList.of(deletedBlobId), 0);
+
+        String activeDeletedBlobId = Iterables.get(blobsAdded, 
rand.nextInt(blobsAdded.size()));
+        blobsAdded.remove(activeDeletedBlobId);
+        count += 
setupDataStore.countDeleteChunks(ImmutableList.of(activeDeletedBlobId), 0);
+        assertEquals(2, count);
+
+        // artificially put the deleted id in the tracked .del file
+        
FileIOUtils.writeStrings(Iterators.singletonIterator(activeDeletedBlobId), 
delTracker, false);
+
+        setupDataStore.close();
+
+        testAllParams(dump, repoHome);
+
+        assertFileEquals(dump, "[id]", blobsAdded);
+        assertFileEquals(dump, "[ref]", Sets.union(blobsAdded, 
Sets.newHashSet(deletedBlobId, activeDeletedBlobId)));
+        assertFileEquals(dump, "[consistency]", 
Sets.newHashSet(deletedBlobId));
+    }
+
+    private void testAllParams(File dump, File repoHome) throws Exception {
         DataStoreCheckCommand checkCommand = new DataStoreCheckCommand();
         List<String> argsList = Lists
             .newArrayList("--id", "--ref", "--consistency", "--" + dsOption, 
cfgFilePath, "--store", storePath,
-                "--dump", dump.getAbsolutePath());
+                "--dump", dump.getAbsolutePath(), "--repoHome", 
repoHome.getAbsolutePath());
 
         checkCommand.execute(argsList.toArray(new String[0]));
     }
@@ -227,7 +261,7 @@ public class DataStoreCheckTest {
         File dump = temporaryFolder.newFolder();
         List<String> argsList = Lists
             .newArrayList("--id", "--ref", "--consistency", "--store", 
storePath,
-                "--dump", dump.getAbsolutePath());
+                "--dump", dump.getAbsolutePath(), "--repoHome", 
temporaryFolder.newFolder().getAbsolutePath());
         testIncorrectParams(argsList, Lists.newArrayList("Operation not 
defined for SegmentNodeStore without external datastore"));
 
     }
@@ -238,15 +272,46 @@ public class DataStoreCheckTest {
         File dump = temporaryFolder.newFolder();
         List<String> argsList = Lists
             .newArrayList("--consistency", "--" + dsOption, cfgFilePath,
-                "--dump", dump.getAbsolutePath());
+                "--dump", dump.getAbsolutePath(), "--repoHome", 
temporaryFolder.newFolder().getAbsolutePath());
         testIncorrectParams(argsList, Lists.newArrayList("Missing required 
option(s) [store]"));
 
         argsList = Lists
             .newArrayList("--ref", "--" + dsOption, cfgFilePath,
-                "--dump", dump.getAbsolutePath());
+                "--dump", dump.getAbsolutePath(), "--repoHome", 
temporaryFolder.newFolder().getAbsolutePath());
         testIncorrectParams(argsList, Lists.newArrayList("Missing required 
option(s) [store]"));
     }
 
+    @Test
+    public void testTrackWithRefs() throws Exception {
+        setupDataStore.close();
+        File dump = temporaryFolder.newFolder();
+        List<String> argsList = Lists
+            .newArrayList("--ref", "--store", storePath,
+                "--dump", dump.getAbsolutePath(), "--track", "--repoHome", 
temporaryFolder.newFolder().getAbsolutePath());
+        testIncorrectParams(argsList,
+            Lists.newArrayList("Option(s) [track] are unavailable given other 
options on the command line"));
+    }
+
+    @Test
+    public void testConsistencyNoRepo() throws Exception {
+        setupDataStore.close();
+        File dump = temporaryFolder.newFolder();
+        List<String> argsList = Lists
+            .newArrayList("--id", "--ref", "--consistency", "--store", 
storePath,
+                "--dump", dump.getAbsolutePath());
+        testIncorrectParams(argsList, Lists.newArrayList("Missing required 
option(s) [repoHome]"));
+    }
+
+    @Test
+    public void testTrackNoRepo() throws Exception {
+        setupDataStore.close();
+        File dump = temporaryFolder.newFolder();
+        List<String> argsList = Lists
+            .newArrayList("--id", "--ref", "--consistency", "--store", 
storePath,
+                "--dump", dump.getAbsolutePath(), "--track");
+        testIncorrectParams(argsList, Lists.newArrayList("Missing required 
option(s) [repoHome]"));
+    }
+
     public static void testIncorrectParams(List<String> argList, 
ArrayList<String> assertMsg) throws Exception {
         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
         System.setErr(new PrintStream(buffer, true, UTF_8.toString()));


Reply via email to