Author: mreutegg
Date: Mon Oct  5 09:08:16 2015
New Revision: 1706769

URL: http://svn.apache.org/viewvc?rev=1706769&view=rev
Log:
OAK-3455: Improve conflict exception message

CommitFailedException may not have the message, but the DocumentStoreException 
cause must have the it

Added:
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreHelper.java
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1706769&r1=1706768&r2=1706769&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
 Mon Oct  5 09:08:16 2015
@@ -1613,7 +1613,8 @@ public class DocumentNodeStoreTest {
             merge(ns2, b2);
             fail("Must throw CommitFailedException");
         } catch (CommitFailedException e) {
-            assertTrue(e.getMessage().contains("not yet visible"));
+            assertNotNull(e.getCause());
+            assertTrue(e.getCause().getMessage().contains("not yet visible"));
         }
 
     }

Added: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java?rev=1706769&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java
 Mon Oct  5 09:08:16 2015
@@ -0,0 +1,230 @@
+/*
+ * 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.document;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+
+import javax.annotation.Nullable;
+
+import com.google.common.base.Function;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.mongodb.DBCollection;
+import com.mongodb.DBCursor;
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.json.JsopReader;
+import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
+import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore;
+import 
org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStoreHelper;
+import org.apache.jackrabbit.oak.plugins.document.util.Utils;
+
+import static 
org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStoreHelper.convertFromDBObject;
+
+/**
+ * Helper class to access package private method of DocumentNodeStore and other
+ * classes in this package.
+ */
+public class DocumentNodeStoreHelper {
+
+    public static void garbageReport(DocumentNodeStore dns) {
+        System.out.print("Collecting top 100 nodes with most blob garbage ");
+        Stopwatch sw = Stopwatch.createStarted();
+        Iterable<BlobReferences> refs = scan(dns, new 
BlobGarbageSizeComparator(), 100);
+        for (BlobReferences br : refs) {
+            System.out.println(br);
+        }
+        System.out.println("Collected in " + sw.stop());
+    }
+
+    private static Iterable<BlobReferences> scan(DocumentNodeStore store,
+                                                 Comparator<BlobReferences> 
comparator,
+                                                 int num) {
+        long totalGarbage = 0;
+        Iterable<NodeDocument> docs = getDocuments(store.getDocumentStore());
+        PriorityQueue<BlobReferences> queue = new 
PriorityQueue<BlobReferences>(num, comparator);
+        List<Blob> blobs = Lists.newArrayList();
+        long docCount = 0;
+        for (NodeDocument doc : docs) {
+            if (++docCount % 10000 == 0) {
+                System.out.print(".");
+            }
+            blobs.clear();
+            BlobReferences refs = collectReferences(doc, store);
+            totalGarbage += refs.garbageSize;
+            queue.add(refs);
+            if (queue.size() > num) {
+                queue.remove();
+            }
+        }
+
+        System.out.println();
+        List<BlobReferences> refs = Lists.newArrayList();
+        refs.addAll(queue);
+        Collections.sort(refs, Collections.reverseOrder(comparator));
+        System.out.println("Total garbage size: " + 
FileUtils.byteCountToDisplaySize(totalGarbage));
+        System.out.println("Total number of nodes with blob references: " + 
docCount);
+        System.out.println("total referenced / old referenced / # blob 
references / path");
+        return refs;
+    }
+
+    private static BlobReferences collectReferences(NodeDocument doc,
+                                                    DocumentNodeStore ns) {
+        long blobSize = 0;
+        long garbageSize = 0;
+        int numBlobs = 0;
+
+        List<Blob> blobs = Lists.newArrayList();
+        Revision head = ns.getHeadRevision();
+        boolean exists = doc.getNodeAtRevision(ns, head, null) != null;
+        for (String key : doc.keySet()) {
+            if (!Utils.isPropertyName(key)) {
+                continue;
+            }
+            boolean foundValid = false;
+            Map<Revision, String> valueMap = doc.getLocalMap(key);
+            for (Map.Entry<Revision, String> entry : valueMap.entrySet()) {
+                blobs.clear();
+                String v = entry.getValue();
+                if (v != null) {
+                    loadValue(v, blobs, ns);
+                }
+                blobSize += size(blobs);
+                if (foundValid) {
+                    garbageSize += size(blobs);
+                } else if (doc.isCommitted(entry.getKey())) {
+                    foundValid = true;
+                } else {
+                    garbageSize += size(blobs);
+                }
+                numBlobs += blobs.size();
+            }
+        }
+        return new BlobReferences(doc.getPath(), blobSize, numBlobs, 
garbageSize, exists);
+    }
+
+    private static Iterable<NodeDocument> getDocuments(DocumentStore store) {
+        if (store instanceof MongoDocumentStore) {
+            // optimized implementation for MongoDocumentStore
+            final MongoDocumentStore mds = (MongoDocumentStore) store;
+            DBCollection dbCol = MongoDocumentStoreHelper.getDBCollection(
+                    mds, Collection.NODES);
+            DBObject query = QueryBuilder.start(NodeDocument.HAS_BINARY_FLAG)
+                    .is(NodeDocument.HAS_BINARY_VAL)
+                    .get();
+            DBCursor cursor = dbCol.find(query);
+            return Iterables.transform(cursor, new Function<DBObject, 
NodeDocument>() {
+                @Nullable
+                @Override
+                public NodeDocument apply(DBObject input) {
+                    return convertFromDBObject(mds, Collection.NODES, input);
+                }
+            });
+        } else {
+            return Utils.getSelectedDocuments(store,
+                    NodeDocument.HAS_BINARY_FLAG, NodeDocument.HAS_BINARY_VAL);
+        }
+    }
+
+
+    private static long size(Iterable<Blob> blobs) {
+        long size = 0;
+        for (Blob b : blobs) {
+            size += b.length();
+        }
+        return size;
+    }
+
+    private static void loadValue(String v, java.util.Collection<Blob> blobs,
+                                  DocumentNodeStore nodeStore) {
+        JsopReader reader = new JsopTokenizer(v);
+        PropertyState p;
+        if (reader.matches('[')) {
+            p = DocumentPropertyState.readArrayProperty("x", nodeStore, 
reader);
+            if (p.getType() == Type.BINARIES) {
+                for (int i = 0; i < p.count(); i++) {
+                    Blob b = p.getValue(Type.BINARY, i);
+                    blobs.add(b);
+                }
+            }
+        } else {
+            p = DocumentPropertyState.readProperty("x", nodeStore, reader);
+            if (p.getType() == Type.BINARY) {
+                Blob b = p.getValue(Type.BINARY);
+                blobs.add(b);
+            }
+        }
+    }
+
+    private static class BlobReferences {
+
+        final String path;
+        final long blobSize;
+        final long garbageSize;
+        final int numBlobs;
+        final boolean exists;
+
+        public BlobReferences(String path,
+                              long blobSize,
+                              int numBlobs,
+                              long garbageSize,
+                              boolean exists) {
+            this.path = path;
+            this.blobSize = blobSize;
+            this.garbageSize = garbageSize;
+            this.numBlobs = numBlobs;
+            this.exists = exists;
+        }
+
+        @Override
+        public String toString() {
+            String s = FileUtils.byteCountToDisplaySize(blobSize) + "\t"
+                    + FileUtils.byteCountToDisplaySize(garbageSize) + "\t"
+                    + numBlobs + "\t"
+                    + path;
+            if (!exists) {
+                s += "\t(deleted)";
+            }
+            return s;
+        }
+    }
+
+    private static class BlobGarbageSizeComparator
+            implements Comparator<BlobReferences> {
+
+        @Override
+        public int compare(BlobReferences o1, BlobReferences o2) {
+            int c = Long.compare(o1.garbageSize, o2.garbageSize);
+            if (c != 0) {
+                return c;
+            }
+            return o1.path.compareTo(o2.path);
+        }
+    }
+}

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

Modified: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreHelper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreHelper.java?rev=1706769&r1=1706768&r2=1706769&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreHelper.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreHelper.java
 Mon Oct  5 09:08:16 2015
@@ -27,6 +27,7 @@ import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
 import com.mongodb.WriteResult;
 
+import org.apache.jackrabbit.oak.plugins.document.Collection;
 import org.apache.jackrabbit.oak.plugins.document.Document;
 import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
 import org.apache.jackrabbit.oak.plugins.document.Revision;
@@ -92,4 +93,14 @@ public class MongoDocumentStoreHelper {
         
     }
 
+    public static <T extends Document> DBCollection getDBCollection(
+            MongoDocumentStore store, Collection<T> c) {
+        return store.getDBCollection(c);
+    }
+
+    public static <T extends Document> T convertFromDBObject(
+            MongoDocumentStore store, Collection<T> col, DBObject obj) {
+        return store.convertFromDBObject(col, obj);
+    }
+
 }

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=1706769&r1=1706768&r2=1706769&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 Oct  5 09:08:16 2015
@@ -81,6 +81,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.backup.FileStoreRestore;
 import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreHelper;
 import org.apache.jackrabbit.oak.plugins.document.LastRevRecoveryAgent;
 import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
 import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore;
@@ -194,6 +195,9 @@ public final class Main {
             case TIKA:
                 TextExtractorMain.main(args);
                 break;
+            case GARBAGE:
+                garbage(args);
+                break;
             case HELP:
             default:
                 System.err.print("Available run modes: ");
@@ -422,6 +426,7 @@ public final class Main {
             closer.register(asCloseable(mongo));
             DocumentNodeStore store = new DocumentMK.Builder()
                     .setMongoDB(mongo.getDB())
+                    .setLeaseCheck(false)
                     .setClusterId(clusterId.value(options)).getNodeStore();
             closer.register(asCloseable(store));
             return store;
@@ -698,6 +703,25 @@ public final class Main {
         }
     }
 
+    private static void garbage(String[] args) throws IOException {
+        Closer closer = Closer.create();
+        String h = "garbage mongodb://host:port/database";
+        try {
+            NodeStore store = bootstrapNodeStore(args, closer, h);
+            if (!(store instanceof DocumentNodeStore)) {
+                System.err.println("Garbage mode only available for 
DocumentNodeStore");
+                System.exit(1);
+            }
+            DocumentNodeStore dns = (DocumentNodeStore) store;
+
+            DocumentNodeStoreHelper.garbageReport(dns);
+        } catch (Throwable e) {
+            throw closer.rethrow(e);
+        } finally {
+            closer.close();
+        }
+    }
+
     private static void debug(String[] args) throws IOException {
         if (args.length == 0) {
             System.err.println("usage: debug <path> [id...]");
@@ -1150,7 +1174,8 @@ public final class Main {
         CHECKPOINTS("checkpoints"),
         RECOVERY("recovery"),
         REPAIR("repair"),
-        TIKA("tika");
+        TIKA("tika"),
+        GARBAGE("garbage");
 
         private final String name;
 


Reply via email to