Author: amitj
Date: Thu Jan 28 06:32:40 2016
New Revision: 1727254
URL: http://svn.apache.org/viewvc?rev=1727254&view=rev
Log:
OAK-3936: [oak-run] Option to dump blob references
Added a command 'dumpdatastorerefs' to dump all available blob references.
Modified:
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
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=1727254&r1=1727253&r2=1727254&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
Thu Jan 28 06:32:40 2016
@@ -29,6 +29,7 @@ import static org.apache.jackrabbit.oak.
import static
org.apache.jackrabbit.oak.plugins.segment.file.tooling.ConsistencyChecker.checkConsistency;
import static org.slf4j.LoggerFactory.getLogger;
+import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
@@ -43,6 +44,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -53,18 +55,24 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.jcr.Repository;
+import com.google.common.base.Charsets;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import com.google.common.base.Joiner;
+import com.google.common.base.StandardSystemProperty;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Maps;
import com.google.common.collect.Queues;
import com.google.common.io.Closer;
+import com.google.common.io.Files;
import com.google.common.util.concurrent.AbstractScheduledService;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
@@ -90,6 +98,9 @@ import org.apache.jackrabbit.oak.jcr.Jcr
import org.apache.jackrabbit.oak.json.JsopDiff;
import org.apache.jackrabbit.oak.plugins.backup.FileStoreBackup;
import org.apache.jackrabbit.oak.plugins.backup.FileStoreRestore;
+import org.apache.jackrabbit.oak.plugins.blob.BlobReferenceRetriever;
+import org.apache.jackrabbit.oak.plugins.blob.ReferenceCollector;
+import
org.apache.jackrabbit.oak.plugins.document.DocumentBlobReferenceRetriever;
import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreHelper;
@@ -107,6 +118,7 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.segment.RecordId;
import org.apache.jackrabbit.oak.plugins.segment.RecordUsageAnalyser;
import org.apache.jackrabbit.oak.plugins.segment.Segment;
+import org.apache.jackrabbit.oak.plugins.segment.SegmentBlobReferenceRetriever;
import org.apache.jackrabbit.oak.plugins.segment.SegmentId;
import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState;
import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore;
@@ -126,6 +138,8 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.remote.content.ContentRemoteRepository;
import org.apache.jackrabbit.oak.remote.http.RemoteServlet;
import org.apache.jackrabbit.oak.scalability.ScalabilityRunner;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
@@ -230,6 +244,9 @@ public final class Main {
case TARMKRECOVERY:
FileStoreRevisionRecovery.main(args);
break;
+ case DUMPDATASTOREREFS:
+ dumpBlobRefs(args);
+ break;
case HELP:
default:
System.err.print("Available run modes: ");
@@ -1259,6 +1276,102 @@ public final class Main {
startOakServer(oakFixture, uri, cIds);
}
+ private static void dumpBlobRefs(String[] args) throws IOException {
+ if (args.length == 0) {
+ System.out
+ .println("usage: dumpdatastorerefs {<path>|<mongo-uri>}
<dump_path>]");
+ System.exit(1);
+ }
+
+ Closer closer = Closer.create();
+ try {
+ BlobReferenceRetriever marker = null;
+ BlobStore blobStore = null;
+
+ if (args[0].startsWith(MongoURI.MONGODB_PREFIX)) {
+ MongoClientURI uri = new MongoClientURI(args[0]);
+ MongoClient client = new MongoClient(uri);
+ final DocumentNodeStore store = new
DocumentMK.Builder().setMongoDB(client.getDB(uri.getDatabase())).getNodeStore();
+ blobStore = store.getBlobStore();
+ closer.register(new Closeable() {
+ @Override public void close() throws IOException {
+ store.dispose();
+ }
+ });
+ marker = new DocumentBlobReferenceRetriever(store);
+ } else if (isValidFileStore(args[0])) {
+ final FileStore store = new FileStore(new File(args[0]), 256,
TAR_STORAGE_MEMORY_MAPPED);
+ closer.register(new Closeable() {
+ @Override public void close() throws IOException {
+ store.close();
+ }
+ });
+ marker = new SegmentBlobReferenceRetriever(store.getTracker());
+ } else {
+ failWith("Invalid FileStore directory " + args[0]);
+ return;
+ }
+
+ String dumpPath = StandardSystemProperty.JAVA_IO_TMPDIR.value();
+ if (args.length == 2) {
+ dumpPath = args[1];
+ }
+ File dumpFile = new File(dumpPath, "marked-" +
System.currentTimeMillis());
+ final BufferedWriter writer = Files.newWriter(dumpFile,
Charsets.UTF_8);
+ final AtomicInteger count = new AtomicInteger();
+ try {
+ final List<String> idBatch =
Lists.newArrayListWithCapacity(1024);
+ final Joiner delimJoiner = Joiner.on(",").skipNulls();
+ final GarbageCollectableBlobStore gcBlobStore =
+ (blobStore != null && blobStore instanceof
GarbageCollectableBlobStore
+ ? (GarbageCollectableBlobStore) blobStore
+ : null);
+ marker.collectReferences(
+ new ReferenceCollector() {
+ @Override
+ public void addReference(String blobId, String nodeId)
{
+ try {
+ Iterator<String> idIter = null;
+ if (gcBlobStore != null) {
+ idIter = gcBlobStore.resolveChunks(blobId);
+ } else{
+ idIter =
Iterators.singletonIterator(blobId);
+ }
+
+ while (idIter.hasNext()) {
+ String id = idIter.next();
+ idBatch.add(delimJoiner.join(id, nodeId));
+ count.getAndIncrement();
+ if (idBatch.size() >= 1024) {
+
writer.append(Joiner.on(StandardSystemProperty.LINE_SEPARATOR.value()).join(idBatch));
+
writer.append(StandardSystemProperty.LINE_SEPARATOR.value());
+ writer.flush();
+ idBatch.clear();
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Error in
retrieving references", e);
+ }
+ }
+ }
+ );
+ if (!idBatch.isEmpty()) {
+
writer.append(Joiner.on(StandardSystemProperty.LINE_SEPARATOR.value()).join(idBatch));
+
writer.append(StandardSystemProperty.LINE_SEPARATOR.value());
+ writer.flush();
+ idBatch.clear();
+ }
+ System.out.println(count.get() + " DataStore references dumped
in " + dumpFile);
+ } finally {
+ IOUtils.closeQuietly(writer);
+ }
+ } catch (Throwable t) {
+ System.err.println(t.getMessage());
+ } finally {
+ closer.close();
+ }
+ }
+
private static void startOakServer(OakFixture oakFixture, String uri,
List<Integer> cIds) throws Exception {
Map<Oak, String> m;
if (cIds.isEmpty()) {
@@ -1375,7 +1488,8 @@ public final class Main {
TIKA("tika"),
GARBAGE("garbage"),
TARMKDIFF("tarmkdiff"),
- TARMKRECOVERY("tarmkrecovery");
+ TARMKRECOVERY("tarmkrecovery"),
+ DUMPDATASTOREREFS("dumpdatastorerefs");
private final String name;