Author: alexparvulescu Date: Fri Dec 18 10:11:35 2015 New Revision: 1720744
URL: http://svn.apache.org/viewvc?rev=1720744&view=rev Log: OAK-3804 Add tarmk revision recovery listing to oak-run Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreRevisionRecovery.java (with props) Modified: jackrabbit/oak/trunk/oak-run/README.md jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java Modified: jackrabbit/oak/trunk/oak-run/README.md URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/README.md?rev=1720744&r1=1720743&r2=1720744&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-run/README.md (original) +++ jackrabbit/oak/trunk/oak-run/README.md Fri Dec 18 10:11:35 2015 @@ -5,27 +5,28 @@ This jar contains everything you need fo The following runmodes are currently available: - * backup : Backup an existing Oak repository. - * restore : Restore a backup of an Oak repository. - * benchmark : Run benchmark tests against different Oak repository fixtures. - * debug : Print status information about an Oak repository. - * compact : Segment compaction on a TarMK repository. - * upgrade : Migrate existing Jackrabbit 2.x repository to Oak. - * server : Run the Oak Server. - * console : Start an interactive console. - * explore : Starts a GUI browser based on java swing. - * graph : Export the segment graph of a segment store to a file. - * history : Trace the history of a node - * check : Check the FileStore for inconsistencies - * primary : Run a TarMK Cold Standby primary instance - * standby : Run a TarMK Cold Standby standby instance - * scalability : Run scalability tests against different Oak repository fixtures. - * recovery : Run a _lastRev recovery on a MongoMK repository - * 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 + * backup : Backup an existing Oak repository. + * restore : Restore a backup of an Oak repository. + * benchmark : Run benchmark tests against different Oak repository fixtures. + * debug : Print status information about an Oak repository. + * compact : Segment compaction on a TarMK repository. + * upgrade : Migrate existing Jackrabbit 2.x repository to Oak. + * server : Run the Oak Server. + * console : Start an interactive console. + * explore : Starts a GUI browser based on java swing. + * graph : Export the segment graph of a segment store to a file. + * history : Trace the history of a node + * check : Check the FileStore for inconsistencies + * primary : Run a TarMK Cold Standby primary instance + * standby : Run a TarMK Cold Standby standby instance + * scalability : Run scalability tests against different Oak repository fixtures. + * recovery : Run a _lastRev recovery on a MongoMK repository + * checkpoints : Manage checkpoints + * tika : Performs text extraction + * garbage : Identifies blob garbage on a DocumentMK repository + * tarmkdiff : Show changes between revisions on TarMk + * tarmkrecovery : Lists candidates for head journal entries + * help : Print a list of available runmodes Some of the features related to Jackrabbit 2.x are provided by oak-run-jr2 jar. See @@ -932,6 +933,19 @@ Output sample - lastUpdated<DATE> = 2015-11-19T10:45:18.027-05:00 + lastUpdated<DATE> = 2015-11-19T10:47:25.167-05:00 +<a name="tarmkrecovery"></a> +Oak TarMK Revision Recovery +--------------------------- + +Lists candidates for head journal entries. Uses a read-only store, so no updates will be performed on target repository. + + $ java -jar oak-run-*.jar tarmkrecovery path/to/repository [--version-v10] + +The following options are available: + + --version-v10 - Uses V10 version repository reading (see OAK-2527) + + License ------- Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreRevisionRecovery.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreRevisionRecovery.java?rev=1720744&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreRevisionRecovery.java (added) +++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreRevisionRecovery.java Fri Dec 18 10:11:35 2015 @@ -0,0 +1,214 @@ +/* + * 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.file; + +import static com.google.common.collect.Maps.newTreeMap; +import static com.google.common.collect.Sets.difference; +import static java.util.Arrays.asList; +import static java.util.Collections.reverseOrder; +import static java.util.Collections.sort; +import static org.apache.jackrabbit.oak.plugins.segment.FileStoreHelper.readRevisions; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.SortedMap; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; + +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import joptsimple.OptionSpec; + +import org.apache.jackrabbit.oak.plugins.segment.RecordId; +import org.apache.jackrabbit.oak.plugins.segment.RecordType; +import org.apache.jackrabbit.oak.plugins.segment.Segment; +import org.apache.jackrabbit.oak.plugins.segment.SegmentId; +import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState; +import org.apache.jackrabbit.oak.plugins.segment.SegmentNotFoundException; +import org.apache.jackrabbit.oak.plugins.segment.SegmentVersion; +import org.apache.jackrabbit.oak.plugins.segment.file.FileStore.ReadOnlyStore; +import org.apache.jackrabbit.oak.plugins.segment.memory.MemoryStore; + +import com.google.common.collect.ImmutableSet; + +public class FileStoreRevisionRecovery { + + @SuppressWarnings("deprecation") + public static void main(String[] args) throws Exception { + if (args.length == 0) { + System.out + .println("java -jar oak-run-*.jar tarmkrecovery <path/to/repository> [--version-v10]"); + 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<?> v10 = parser + .accepts("version-v10", "Use V10 for reading"); + + 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); + } + + SegmentVersion version; + if (options.has(v10)) { + version = SegmentVersion.V_10; + System.out.println("Store(V10) " + store); + } else { + version = SegmentVersion.V_11; + System.out.println("Store " + store); + } + + SortedMap<String, UUID> candidates = candidateSegments(store); + SortedMap<String, String> roots = extractRoots(store, candidates, + version); + + for (Entry<String, String> r : roots.entrySet()) { + System.out.println(r.getValue()); // + " @ " + r.getKey()); + } + } + + private static SortedMap<String, String> extractRoots(File dir, + SortedMap<String, UUID> candidates, final SegmentVersion version) + throws IOException { + + ReadOnlyStore store = new ReadOnlyStore(dir) { + @Override + public SegmentVersion getVersion() { + return version; + } + }; + + final SortedMap<String, String> roots = newTreeMap(reverseOrder()); + + for (Entry<String, UUID> c : candidates.entrySet()) { + UUID uid = c.getValue(); + SegmentId id = new SegmentId(store.getTracker(), + uid.getMostSignificantBits(), uid.getLeastSignificantBits()); + try { + Segment s = store.readSegment(id); + for (int r = 0; r < s.getRootCount(); r++) { + if (s.getRootType(r) == RecordType.NODE) { + int offset = s.getRootOffset(r); + RecordId nodeId = new RecordId(s.getSegmentId(), offset); + if (isRoot(nodeId)) { + roots.put(c.getKey() + "." + offset, + nodeId.toString10()); + } + } + } + } catch (SegmentNotFoundException ex) { + System.out.println(ex.getMessage()); + } + } + return roots; + } + + private static Set<String> ROOT_NAMES = ImmutableSet.of("root", + "checkpoints"); + + private static boolean isRoot(RecordId nodeId) { + SegmentNodeState sns = new SegmentNodeState(nodeId); + Set<String> childNames = ImmutableSet.copyOf(sns.getChildNodeNames()); + return sns.getPropertyCount() == 0 && childNames.size() == 2 + && difference(ROOT_NAMES, childNames).isEmpty(); + } + + private static SortedMap<String, UUID> candidateSegments(File store) + throws IOException { + + List<String> revs = readRevisions(store); + if (revs.isEmpty()) { + System.out.println("No revisions found."); + return newTreeMap(); + } + String head = revs.iterator().next(); + System.out.println("Current head revision " + head); + final UUID headSegment = extractSegmentId(head); + + List<String> tars = listTars(store); + // <tar+offset, UUID> + final SortedMap<String, UUID> candidates = newTreeMap(reverseOrder()); + + for (final String tar : tars) { + final AtomicLong threshold = new AtomicLong(-1); + TarReader r = TarReader.open(new File(store, tar), true); + + // first identify the offset beyond which we need to include + // segments + r.accept(new TarEntryVisitor() { + @Override + public void visit(long msb, long lsb, File file, int offset, + int size) { + if (msb == headSegment.getMostSignificantBits() + && lsb == headSegment.getLeastSignificantBits()) { + threshold.set(offset); + } + } + }); + r.accept(new TarEntryVisitor() { + @Override + public void visit(long msb, long lsb, File file, int offset, + int size) { + if (offset >= threshold.get() + && SegmentId.isDataSegmentId(lsb)) { + candidates.put(tar + "." + offset, new UUID(msb, lsb)); + } + } + }); + if (threshold.get() >= 0) { + break; + } + } + return candidates; + } + + private static UUID extractSegmentId(String record) throws IOException { + RecordId head = RecordId.fromString(new MemoryStore().getTracker(), + record); + return UUID.fromString(head.getSegmentId().toString()); + } + + private static List<String> listTars(File store) { + List<String> files = asList(store.list(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".tar"); + } + })); + sort(files, reverseOrder()); + return files; + } +} Propchange: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreRevisionRecovery.java ------------------------------------------------------------------------------ svn:mime-type = text/plain 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=1720744&r1=1720743&r2=1720744&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 Fri Dec 18 10:11:35 2015 @@ -113,6 +113,7 @@ import org.apache.jackrabbit.oak.plugins import org.apache.jackrabbit.oak.plugins.segment.compaction.CompactionStrategy.CleanupType; import org.apache.jackrabbit.oak.plugins.segment.file.FileStore; import org.apache.jackrabbit.oak.plugins.segment.file.FileStore.ReadOnlyStore; +import org.apache.jackrabbit.oak.plugins.segment.file.FileStoreRevisionRecovery; import org.apache.jackrabbit.oak.plugins.segment.file.JournalReader; import org.apache.jackrabbit.oak.plugins.segment.file.tooling.RevisionHistory; import org.apache.jackrabbit.oak.plugins.segment.file.tooling.RevisionHistory.HistoryElement; @@ -223,6 +224,9 @@ public final class Main { case TARMKDIFF: FileStoreDiff.main(args); break; + case TARMKRECOVERY: + FileStoreRevisionRecovery.main(args); + break; case HELP: default: System.err.print("Available run modes: "); @@ -1326,7 +1330,8 @@ public final class Main { REPAIR("repair"), TIKA("tika"), GARBAGE("garbage"), - TARMKDIFF("tarmkdiff"); + TARMKDIFF("tarmkdiff"), + TARMKRECOVERY("tarmkrecovery"); private final String name;
