Author: alexparvulescu
Date: Mon Nov 23 10:57:10 2015
New Revision: 1715759

URL: http://svn.apache.org/viewvc?rev=1715759&view=rev
Log:
OAK-3665 Oak Run TarMK revision diff


Added:
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreDiff.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java
    jackrabbit/oak/trunk/oak-run/README.md
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/Explorer.java
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/NodeStoreTree.java
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreHelper.java
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java?rev=1715759&r1=1715758&r2=1715759&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java
 Mon Nov 23 10:57:10 2015
@@ -1343,11 +1343,18 @@ public class FileStore implements Segmen
      * All write methods are no-ops.
      */
     public static class ReadOnlyStore extends FileStore {
+
         public ReadOnlyStore(File directory) throws IOException {
             super(null, directory, EMPTY_NODE, -1, 0, MEMORY_MAPPING_DEFAULT,
                     GCMonitor.EMPTY, true);
         }
 
+        public ReadOnlyStore(File directory, BlobStore blobStore)
+                throws IOException {
+            super(blobStore, directory, EMPTY_NODE, -1, 0,
+                    MEMORY_MAPPING_DEFAULT, GCMonitor.EMPTY, true);
+        }
+
         /**
          * Go to the specified {@code revision}
          *

Modified: jackrabbit/oak/trunk/oak-run/README.md
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/README.md?rev=1715759&r1=1715758&r2=1715759&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/README.md (original)
+++ jackrabbit/oak/trunk/oak-run/README.md Mon Nov 23 10:57:10 2015
@@ -23,6 +23,7 @@ The following runmodes are currently ava
     * checkpoints : Manage checkpoints
     * tika        : Performs text extraction
     * garbage     : Identifies blob garbage on a DocumentMK repository
+    * tarmkdiff   : Show changes between revisions on TarMk
     * help        : Print a list of available runmodes
     
 
@@ -857,6 +858,60 @@ can be dumped to a file
 
 [1]: http://jackrabbit.apache.org/oak/docs/oak-mongo-js/oak.html
 
+<a name="tarmkdiff"></a>
+Oak TarMK Revision Diff
+-----------------------
+
+Show changes between revisions on TarMk. It uses a read-only store, so it can 
also be used on a running system without the need to shut down.
+
+    $ java -jar oak-run-*.jar tarmkdiff path/to/repository [–-list] 
[–-diff=R0..R1] [–-incremental] [–-ignore-snfes] 
[–-output=/path/to/output/file]
+
+The following options are available:
+
+    --list           - Lists the existing revisions. will ignore other params 
if this is provided
+    --diff           - Revision diff interval. Ex '–-diff=R0..R1'. 'HEAD' 
can be used to reference the latest head revision, ie. '–-diff=R0..HEAD'
+    --incremental    - Runs diffs between each subsequent revisions in the 
provided interval (false by default)
+    --ignore-snfes   - Ignores SegmentNotFoundExceptions and continues running 
the diff (experimental) (false by default)
+    --path           - Filter diff by given path
+    --output         - Output file name (generated randomly if not provided)
+
+Output sample
+
+    rev 
7583946d-1817-4716-a05c-660ee52ddce0.ff94..c238cd7d-87a0-4cca-aa14-80b75e8ab81d.fb3e
+    ^ /oak:index
+    ^ /oak:index/lucene
+    ^ /oak:index/lucene/:data
+    - /oak:index/lucene/:data/_3729.cfs
+    + /oak:index/lucene/:data/_372d.si
+        + blobSize<LONG> = 1047552
+        + jcr:lastModified<LONG> = 1447948037017
+        + jcr:data<BINARIES>[1] = [252 bytes]
+    - /oak:index/lucene/:data/segments_37bv
+    + /oak:index/lucene/:data/_372d.cfe
+        + blobSize<LONG> = 1047552
+        + jcr:lastModified<LONG> = 1447948037017
+        + jcr:data<BINARIES>[1] = [224 bytes]
+    - /oak:index/lucene/:data/_3729.si
+    - /oak:index/lucene/:data/_3729.cfe
+    + /oak:index/lucene/:data/_372d.cfs
+        + blobSize<LONG> = 1047552
+        + jcr:lastModified<LONG> = 1447948037017
+        + jcr:data<BINARIES>[1] = [907 bytes]
+    + /oak:index/lucene/:data/segments_37bz
+        + blobSize<LONG> = 1047552
+        + jcr:lastModified<LONG> = 1447948045167
+        + jcr:data<BINARIES>[1] = [863 bytes]
+    ^ /oak:index/lucene/:data/segments.gen
+        ^ jcr:lastModified
+          - jcr:lastModified<LONG> = 1447947918027
+          + jcr:lastModified<LONG> = 1447948045167
+        ^ jcr:data
+          - jcr:data<BINARIES>[1] = [20 bytes]
+          + jcr:data<BINARIES>[1] = [20 bytes]
+    ^ /oak:index/lucene/:status
+        ^ lastUpdated
+          - lastUpdated<DATE> = 2015-11-19T10:45:18.027-05:00
+          + lastUpdated<DATE> = 2015-11-19T10:47:25.167-05:00
 
 License
 -------

Modified: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/Explorer.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/Explorer.java?rev=1715759&r1=1715758&r2=1715759&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/Explorer.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/Explorer.java
 Mon Nov 23 10:57:10 2015
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.explorer;
 
+import static 
org.apache.jackrabbit.oak.plugins.segment.FileStoreHelper.readRevisions;
+
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.Insets;
@@ -42,9 +44,6 @@ import javax.swing.UIManager;
 import javax.swing.UIManager.LookAndFeelInfo;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.jackrabbit.oak.plugins.segment.file.JournalReader;
-
-import com.google.common.collect.Lists;
 
 /**
  * NodeStore explorer
@@ -66,7 +65,7 @@ public class Explorer {
             System.exit(1);
         }
 
-        final String path = args[0];
+        final File path = new File(args[0]);
         final boolean skipSizeCheck = args.length == 2
                 && skip.equalsIgnoreCase(args[1]);
 
@@ -96,7 +95,7 @@ public class Explorer {
         }
     }
 
-    private void createAndShowGUI(final String path, boolean skipSizeCheck)
+    private void createAndShowGUI(final File path, boolean skipSizeCheck)
             throws IOException {
 
         JTextArea log = new JTextArea(5, 20);
@@ -149,33 +148,7 @@ public class Explorer {
         menuCompaction.addActionListener(new ActionListener() {
             @Override
             public void actionPerformed(ActionEvent ev) {
-                List<String> revs = new ArrayList<String>();
-
-                File journal = new File(path, "journal.log");
-                if (!journal.exists()) {
-                    return;
-                }
-
-                JournalReader journalReader = null;
-                try {
-                    journalReader = new JournalReader(journal);
-                    try {
-                        revs = Lists.newArrayList(journalReader.iterator());
-                    } finally {
-                        journalReader.close();
-                    }
-                } catch (IOException e) {
-                    e.printStackTrace();
-                    return;
-                } finally {
-                    try {
-                        if (journalReader != null) {
-                            journalReader.close();
-                        }
-                    } catch (IOException e) {
-                    }
-                }
-
+                List<String> revs = readRevisions(path);
                 String s = (String) JOptionPane.showInputDialog(frame,
                         "Revert to a specified revision", "Time Machine",
                         JOptionPane.PLAIN_MESSAGE, null, revs.toArray(),
@@ -192,7 +165,7 @@ public class Explorer {
             @Override
             public void actionPerformed(ActionEvent ev) {
                 List<String> tarFiles = new ArrayList<String>();
-                for (File f : new File(path).listFiles()) {
+                for (File f : path.listFiles()) {
                     if (f.getName().endsWith(".tar")) {
                         tarFiles.add(f.getName());
                     }

Modified: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/NodeStoreTree.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/NodeStoreTree.java?rev=1715759&r1=1715758&r2=1715759&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/NodeStoreTree.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/NodeStoreTree.java
 Mon Nov 23 10:57:10 2015
@@ -83,7 +83,7 @@ public class NodeStoreTree extends JPane
     private final static int MAX_CHAR_DISPLAY = Integer.getInteger(
             "max.char.display", 60);
 
-    private final String path;
+    private final File path;
     private ReadOnlyStore store;
     private Map<String, Set<UUID>> index;
 
@@ -94,7 +94,7 @@ public class NodeStoreTree extends JPane
     private Map<RecordIdKey, Long[]> sizeCache;
     private final boolean skipSizeCheck;
 
-    public NodeStoreTree(String path, JTextArea log, boolean skipSizeCheck)
+    public NodeStoreTree(File path, JTextArea log, boolean skipSizeCheck)
             throws IOException {
         super(new GridLayout(1, 0));
         this.path = path;
@@ -115,7 +115,7 @@ public class NodeStoreTree extends JPane
     }
 
     private void refreshStore() throws IOException {
-        this.store = new ReadOnlyStore(new File(path));
+        this.store = new ReadOnlyStore(path);
     }
 
     private void refreshModel() {

Added: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreDiff.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreDiff.java?rev=1715759&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreDiff.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreDiff.java
 Mon Nov 23 10:57:10 2015
@@ -0,0 +1,375 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.segment;
+
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Lists.reverse;
+import static java.util.Arrays.asList;
+import static org.apache.commons.io.FileUtils.byteCountToDisplaySize;
+import static org.apache.jackrabbit.oak.api.Type.BINARIES;
+import static org.apache.jackrabbit.oak.api.Type.BINARY;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
+import static org.apache.jackrabbit.oak.commons.PathUtils.elements;
+import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.MISSING_NODE;
+import static 
org.apache.jackrabbit.oak.plugins.segment.FileStoreHelper.readRevisions;
+import static org.apache.jackrabbit.oak.plugins.segment.RecordId.fromString;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.List;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+import joptsimple.OptionSpec;
+
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.segment.file.FileStore.ReadOnlyStore;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+
+import com.google.common.base.Function;
+
+public class FileStoreDiff {
+
+    public static void main(String[] args) throws Exception {
+        if (args.length == 0) {
+            System.out
+                    .println("java -jar oak-diff-*.jar <path/to/repository> 
[–-list] [–-diff=R0..R1] [–-incremental] [–-ignore-snfes] 
[–-output=/path/to/output/file]");
+            System.exit(0);
+        }
+        OptionParser parser = new OptionParser();
+        OptionSpec<?> help = parser.acceptsAll(asList("h", "?", "help"),
+                "show help").forHelp();
+
+        OptionSpec<File> storeO = parser.nonOptions(
+                "Path to segment store (required)").ofType(File.class);
+        OptionSpec<File> outO = parser
+                .accepts("output", "Output file")
+                .withRequiredArg()
+                .ofType(File.class)
+                .defaultsTo(
+                        new File("diff_" + System.currentTimeMillis() + 
".log"));
+        OptionSpec<?> listOnlyO = parser.accepts("list",
+                "Lists available revisions");
+        OptionSpec<String> intervalO = parser
+                .accepts(
+                        "diff",
+                        "Revision diff interval. Ex '–-diff=R0..R1'. 'HEAD' 
can be used to reference the latest head revision, ie. '–-diff=R0..HEAD'")
+                .withRequiredArg().ofType(String.class);
+        OptionSpec<?> incrementalO = parser
+                .accepts("incremental",
+                        "Runs diffs between each subsequent revisions in the 
provided interval");
+        OptionSpec<String> pathO = parser
+                .accepts("path", "Filter diff by given path").withRequiredArg()
+                .ofType(String.class).defaultsTo("/");
+        OptionSpec<?> isgnoreSNFEsO = parser
+                .accepts(
+                        "ignore-snfes",
+                        "Ignores SegmentNotFoundExceptions and continues 
running the diff (experimental)");
+
+        OptionSet options = parser.parse(args);
+
+        if (options.has(help)) {
+            parser.printHelpOn(System.out);
+            System.exit(0);
+        }
+
+        File store = storeO.value(options);
+        if (store == null) {
+            parser.printHelpOn(System.out);
+            System.exit(0);
+        }
+        File out = outO.value(options);
+        if (options.has(listOnlyO)) {
+            listRevs(store, out);
+        } else {
+            diff(store, intervalO.value(options), options.has(incrementalO),
+                    out, pathO.value(options), options.has(isgnoreSNFEsO));
+        }
+    }
+
+    private static void listRevs(File store, File out) throws IOException {
+        System.out.println("Store " + store);
+        System.out.println("Writing revisions to " + out);
+        List<String> revs = readRevisions(store);
+        if (revs.isEmpty()) {
+            System.out.println("No revisions found.");
+            return;
+        }
+        PrintWriter pw = new PrintWriter(out);
+        try {
+            for (String r : revs) {
+                pw.println(r);
+            }
+        } finally {
+            pw.close();
+        }
+    }
+
+    private static void diff(File dir, String interval, boolean incremental,
+            File out, String filter, boolean ignoreSNFEs) throws IOException {
+        System.out.println("Store " + dir);
+        System.out.println("Writing diff to " + out);
+        String[] tokens = interval.trim().split("\\.\\.");
+        if (tokens.length != 2) {
+            System.out.println("Error parsing revision interval '" + interval
+                    + "'.");
+            return;
+        }
+        ReadOnlyStore store = new ReadOnlyStore(dir, new DummyBlobStore());
+        RecordId idL = null;
+        RecordId idR = null;
+        try {
+            if (tokens[0].equalsIgnoreCase("head")) {
+                idL = store.getHead().getRecordId();
+            } else {
+                idL = fromString(store.getTracker(), tokens[0]);
+            }
+            if (tokens[1].equalsIgnoreCase("head")) {
+                idR = store.getHead().getRecordId();
+            } else {
+                idR = fromString(store.getTracker(), tokens[1]);
+            }
+        } catch (IllegalArgumentException ex) {
+            System.out.println("Error parsing revision interval '" + interval
+                    + "': " + ex.getMessage());
+            ex.printStackTrace();
+            return;
+        }
+
+        long start = System.currentTimeMillis();
+        PrintWriter pw = new PrintWriter(out);
+        try {
+            if (incremental) {
+                List<String> revs = readRevisions(dir);
+                System.out.println("Generating diff between " + idL + " and "
+                        + idR + " incrementally. Found " + revs.size()
+                        + " revisions.");
+
+                int s = revs.indexOf(idL.toString10());
+                int e = revs.indexOf(idR.toString10());
+                if (s == -1 || e == -1) {
+                    System.out
+                            .println("Unable to match input revisions with 
FileStore.");
+                    return;
+                }
+                List<String> revDiffs = revs.subList(Math.min(s, e),
+                        Math.max(s, e) + 1);
+                if (s > e) {
+                    // reverse list
+                    revDiffs = reverse(revDiffs);
+                }
+                if (revDiffs.size() < 2) {
+                    System.out.println("Nothing to diff: " + revDiffs);
+                    return;
+                }
+                Iterator<String> revDiffsIt = revDiffs.iterator();
+                RecordId idLt = fromString(store.getTracker(),
+                        revDiffsIt.next());
+                while (revDiffsIt.hasNext()) {
+                    RecordId idRt = fromString(store.getTracker(),
+                            revDiffsIt.next());
+                    boolean good = diff(store, idLt, idRt, filter, pw);
+                    idLt = idRt;
+                    if (!good && !ignoreSNFEs) {
+                        break;
+                    }
+                }
+            } else {
+                System.out.println("Generating diff between " + idL + " and "
+                        + idR);
+                diff(store, idL, idR, filter, pw);
+            }
+        } finally {
+            pw.close();
+        }
+        long dur = System.currentTimeMillis() - start;
+        System.out.println("Finished in " + dur + " ms.");
+    }
+
+    private static boolean diff(ReadOnlyStore store, RecordId idL,
+            RecordId idR, String filter, PrintWriter pw) throws IOException {
+        pw.println("rev " + idL + ".." + idR);
+        try {
+            NodeState before = new SegmentNodeState(idL).getChildNode("root");
+            NodeState after = new SegmentNodeState(idR).getChildNode("root");
+            for (String name : elements(filter)) {
+                before = before.getChildNode(name);
+                after = after.getChildNode(name);
+            }
+            after.compareAgainstBaseState(before, new PrintingDiff(pw, 
filter));
+            return true;
+        } catch (SegmentNotFoundException ex) {
+            System.out.println(ex.getMessage());
+            pw.println("#SNFE " + ex.getSegmentId());
+            return false;
+        }
+    }
+
+    private static final class PrintingDiff implements NodeStateDiff {
+
+        private final PrintWriter pw;
+        private final String path;
+        private final boolean skipProps;
+
+        public PrintingDiff(PrintWriter pw, String path) {
+            this(pw, path, false);
+        }
+
+        private PrintingDiff(PrintWriter pw, String path, boolean skipProps) {
+            this.pw = pw;
+            this.path = path;
+            this.skipProps = skipProps;
+        }
+
+        @Override
+        public boolean propertyAdded(PropertyState after) {
+            if (!skipProps) {
+                pw.println("    + " + toString(after));
+            }
+            return true;
+        }
+
+        @Override
+        public boolean propertyChanged(PropertyState before, PropertyState 
after) {
+            if (!skipProps) {
+                pw.println("    ^ " + before.getName());
+                pw.println("      - " + toString(before));
+                pw.println("      + " + toString(after));
+            }
+            return true;
+        }
+
+        @Override
+        public boolean propertyDeleted(PropertyState before) {
+            if (!skipProps) {
+                pw.println("    - " + toString(before));
+            }
+            return true;
+        }
+
+        @Override
+        public boolean childNodeAdded(String name, NodeState after) {
+            String p = concat(path, name);
+            pw.println("+ " + p);
+            return after.compareAgainstBaseState(EMPTY_NODE, new PrintingDiff(
+                    pw, p));
+        }
+
+        @Override
+        public boolean childNodeChanged(String name, NodeState before,
+                NodeState after) {
+            String p = concat(path, name);
+            pw.println("^ " + p);
+            return after.compareAgainstBaseState(before,
+                    new PrintingDiff(pw, p));
+        }
+
+        @Override
+        public boolean childNodeDeleted(String name, NodeState before) {
+            String p = concat(path, name);
+            pw.println("- " + p);
+            return MISSING_NODE.compareAgainstBaseState(before,
+                    new PrintingDiff(pw, p, true));
+        }
+
+        private static String toString(PropertyState ps) {
+            StringBuilder val = new StringBuilder();
+            if (ps.getType() == BINARY) {
+                String v = new BlobLengthF().apply(ps.getValue(BINARY));
+                val.append(" = {" + v + "}");
+            } else if (ps.getType() == BINARIES) {
+                String v = transform(ps.getValue(BINARIES), new BlobLengthF())
+                        .toString();
+                val.append("[" + ps.count() + "] = " + v);
+            } else if (ps.isArray()) {
+                val.append("[" + ps.count() + "] = ");
+                val.append(ps.getValue(STRINGS));
+            } else {
+                val.append(" = " + ps.getValue(STRING));
+            }
+            return ps.getName() + "<" + ps.getType() + ">" + val.toString();
+        }
+    }
+
+    private static class BlobLengthF implements Function<Blob, String> {
+
+        @Override
+        public String apply(Blob b) {
+            return safeGetLength(b);
+        }
+
+        public static String safeGetLength(Blob b) {
+            try {
+                return byteCountToDisplaySize(b.length());
+            } catch (IllegalStateException e) {
+                // missing BlobStore probably
+            }
+            return "[N/A]";
+        }
+    }
+
+    private static class DummyBlobStore implements BlobStore {
+        @Override
+        public String writeBlob(InputStream in) throws IOException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int readBlob(String blobId, long pos, byte[] buff, int off,
+                int length) throws IOException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public long getBlobLength(String blobId) throws IOException {
+            // best effort length extraction
+            int indexOfSep = blobId.lastIndexOf("#");
+            if (indexOfSep != -1) {
+                return Long.valueOf(blobId.substring(indexOfSep + 1));
+            }
+            return -1;
+        }
+
+        @Override
+        public InputStream getInputStream(String blobId) throws IOException {
+            return new ByteArrayInputStream(new byte[0]);
+        }
+
+        @Override
+        public String getBlobId(String reference) {
+            return reference;
+        }
+
+        @Override
+        public String getReference(String blobId) {
+            return blobId;
+        }
+    }
+
+}

Propchange: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreDiff.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreHelper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreHelper.java?rev=1715759&r1=1715758&r2=1715759&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreHelper.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/FileStoreHelper.java
 Mon Nov 23 10:57:10 2015
@@ -42,13 +42,12 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.UUID;
 
-import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.json.JsonObject;
 import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
 import org.apache.jackrabbit.oak.plugins.segment.file.FileStore;
 import org.apache.jackrabbit.oak.plugins.segment.file.FileStore.ReadOnlyStore;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.plugins.segment.file.JournalReader;
 
 public final class FileStoreHelper {
 
@@ -237,31 +236,6 @@ public final class FileStoreHelper {
         }
     }
 
-    private static void collectSegments(SegmentNodeState root, Map<UUID, 
Set<UUID>> graph) {
-        UUID nodeId = root.getRecordId().asUUID();
-        Set<UUID> refs = graph.get(nodeId);
-        if (refs == null) {
-            refs = newHashSet();
-            graph.put(nodeId, refs);
-        }
-
-        for (PropertyState propertyState : root.getProperties()) {
-            if (propertyState instanceof SegmentPropertyState) {
-                SegmentPropertyState sps = (SegmentPropertyState) 
propertyState;
-                refs.add(sps.getRecordId().getSegmentId().asUUID());
-            }
-
-        }
-
-        for (ChildNodeEntry childNodeEntry : root.getChildNodeEntries()) {
-            if (childNodeEntry.getNodeState() instanceof SegmentNodeState) {
-                SegmentNodeState child = (SegmentNodeState) 
childNodeEntry.getNodeState();
-                refs.add(child.getRecordId().getSegmentId().asUUID());
-                collectSegments(child, graph);
-            }
-        }
-    }
-
     private static void writeNode(UUID node, PrintWriter writer, boolean 
inHead, Date epoch, SegmentTracker tracker) {
         Map<String, String> sInfo = getSegmentInfo(node, tracker);
         if (sInfo == null) {
@@ -303,4 +277,32 @@ public final class FileStoreHelper {
         }
     }
 
+    public static List<String> readRevisions(File store) {
+        File journal = new File(store, "journal.log");
+        if (!journal.exists()) {
+            return newArrayList();
+        }
+
+        List<String> revs = newArrayList();
+        JournalReader journalReader = null;
+        try {
+            journalReader = new JournalReader(journal);
+            try {
+                revs = newArrayList(journalReader.iterator());
+            } finally {
+                journalReader.close();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (journalReader != null) {
+                    journalReader.close();
+                }
+            } catch (IOException e) {
+            }
+        }
+        return revs;
+    }
+
 }

Modified: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java?rev=1715759&r1=1715758&r2=1715759&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
 Mon Nov 23 10:57:10 2015
@@ -98,6 +98,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.document.util.MapDBMapFactory;
 import org.apache.jackrabbit.oak.plugins.document.util.MapFactory;
 import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
+import org.apache.jackrabbit.oak.plugins.segment.FileStoreDiff;
 import org.apache.jackrabbit.oak.plugins.segment.FileStoreHelper;
 import org.apache.jackrabbit.oak.plugins.segment.PCMAnalyser;
 import org.apache.jackrabbit.oak.plugins.segment.RecordId;
@@ -213,6 +214,9 @@ public final class Main {
             case GARBAGE:
                 garbage(args);
                 break;
+            case TARMKDIFF:
+                FileStoreDiff.main(args);
+                break;
             case HELP:
             default:
                 System.err.print("Available run modes: ");
@@ -1262,7 +1266,8 @@ public final class Main {
         RECOVERY("recovery"),
         REPAIR("repair"),
         TIKA("tika"),
-        GARBAGE("garbage");
+        GARBAGE("garbage"),
+        TARMKDIFF("tarmkdiff");
 
         private final String name;
 


Reply via email to