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;
