You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by mr...@apache.org on 2013/09/30 21:50:20 UTC

svn commit: r1527751 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk: Document.java MongoDocumentStore.java NodeDocument.java

Author: mreutegg
Date: Mon Sep 30 19:50:20 2013
New Revision: 1527751

URL: http://svn.apache.org/r1527751
Log:
OAK-1044: Reduce traffic between MongoMK and MongoDB

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Document.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Document.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Document.java?rev=1527751&r1=1527750&r2=1527751&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Document.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/Document.java Mon Sep 30 19:50:20 2013
@@ -44,6 +44,12 @@ public class Document implements CacheVa
     static final String ID = "_id";
 
     /**
+     * The modification count on the document. This is an long value
+     * incremented on every modification.
+     */
+    static final String MOD_COUNT = "_modCount";
+
+    /**
      * The data of this document.
      */
     protected Map<String, Object> data = Maps.newHashMap();
@@ -62,6 +68,15 @@ public class Document implements CacheVa
     }
 
     /**
+     * @return the modification count of this document or <code>null</code> if
+     *         none is set.
+     */
+    @CheckForNull
+    public Number getModCount() {
+        return (Number) get(MOD_COUNT);
+    }
+
+    /**
      * Gets the data for the given <code>key</code>.
      *
      * @param key the key.

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java?rev=1527751&r1=1527750&r2=1527751&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoDocumentStore.java Mon Sep 30 19:50:20 2013
@@ -269,12 +269,15 @@ public class MongoDocumentStore implemen
                                                  boolean upsert,
                                                  boolean checkConditions) {
         DBCollection dbCollection = getDBCollection(collection);
-        QueryBuilder query = getByKeyQuery(updateOp.id);
 
         BasicDBObject setUpdates = new BasicDBObject();
         BasicDBObject incUpdates = new BasicDBObject();
         BasicDBObject unsetUpdates = new BasicDBObject();
 
+        // always increment modCount
+        updateOp.increment(Document.MOD_COUNT, 1);
+
+        // other updates
         for (Entry<Key, Operation> entry : updateOp.changes.entrySet()) {
             Key k = entry.getKey();
             if (k.getName().equals(Document.ID)) {
@@ -299,12 +302,6 @@ public class MongoDocumentStore implemen
                     unsetUpdates.append(k.toString(), "1");
                     break;
                 }
-                case CONTAINS_MAP_ENTRY: {
-                    if (checkConditions) {
-                        query.and(k.toString()).exists(op.value);
-                    }
-                    break;
-                }
             }
         }
 
@@ -323,28 +320,49 @@ public class MongoDocumentStore implemen
         //         WriteConcern.SAFE);
         // return null;
 
+        // get modCount of cached document
+        Number modCount = null;
+        @SuppressWarnings("unchecked")
+        T cachedDoc = (T) nodesCache.getIfPresent(updateOp.getId());
+        if (cachedDoc != null) {
+            modCount = cachedDoc.getModCount();
+        }
+
+
         long start = start();
         try {
-            DBObject oldNode = dbCollection.findAndModify(query.get(), null /*fields*/,
+            // perform a conditional update with limited result
+            // if we have a matching modCount
+            if (modCount != null) {
+                QueryBuilder query = createQueryForUpdate(updateOp, checkConditions);
+                query.and(Document.MOD_COUNT).is(modCount);
+                DBObject fields = new BasicDBObject();
+                // return _id only
+                fields.put("_id", 1);
+
+                DBObject oldNode = dbCollection.findAndModify(query.get(), fields,
+                        null /*sort*/, false /*remove*/, update, false /*returnNew*/,
+                        false /*upsert*/);
+                if (oldNode != null) {
+                    // success, update cached document
+                    // FIXME: ensure consistent cache update
+                    applyToCache(collection, cachedDoc, updateOp);
+                    // return previously cached document
+                    return cachedDoc;
+                }
+            }
+
+            // conditional update failed or not possible
+            // perform operation and get complete document
+            QueryBuilder query = createQueryForUpdate(updateOp, checkConditions);
+            DBObject oldNode = dbCollection.findAndModify(query.get(), null,
                     null /*sort*/, false /*remove*/, update, false /*returnNew*/,
-                    upsert /*upsert*/);
+                    upsert);
             if (checkConditions && oldNode == null) {
                 return null;
             }
             T oldDoc = convertFromDBObject(collection, oldNode);
-            
-            // cache the new document
-            if (collection == Collection.NODES) {
-                T newDoc = collection.newDocument(this);
-                if (oldDoc != null) {
-                    oldDoc.deepCopy(newDoc);
-                    oldDoc.seal();
-                }
-                String key = updateOp.getId();
-                MemoryDocumentStore.applyChanges(newDoc, updateOp, comparator);
-                newDoc.seal();
-                nodesCache.put(key, (NodeDocument) newDoc);
-            }
+            applyToCache(collection, oldDoc, updateOp);
             return oldDoc;
         } catch (Exception e) {
             throw new MicroKernelException(e);
@@ -381,6 +399,7 @@ public class MongoDocumentStore implemen
         for (int i = 0; i < updateOps.size(); i++) {
             inserts[i] = new BasicDBObject();
             UpdateOp update = updateOps.get(i);
+            update.increment(Document.MOD_COUNT, 1);
             T target = collection.newDocument(this);
             MemoryDocumentStore.applyChanges(target, update, comparator);
             docs.add(target);
@@ -511,4 +530,42 @@ public class MongoDocumentStore implemen
         return nodesCache.getIfPresent(key) != null;
     }
 
+
+    private <T extends Document> void applyToCache(@Nonnull Collection<T> collection,
+                                                   @Nullable T oldDoc,
+                                                   @Nonnull UpdateOp updateOp) {
+        // cache the new document
+        if (collection == Collection.NODES) {
+            T newDoc = collection.newDocument(this);
+            if (oldDoc != null) {
+                oldDoc.deepCopy(newDoc);
+                oldDoc.seal();
+            }
+            String key = updateOp.getId();
+            MemoryDocumentStore.applyChanges(newDoc, updateOp, comparator);
+            newDoc.seal();
+            nodesCache.put(key, (NodeDocument) newDoc);
+        }
+    }
+
+    @Nonnull
+    private QueryBuilder createQueryForUpdate(UpdateOp updateOp,
+                                              boolean checkConditions) {
+        QueryBuilder query = getByKeyQuery(updateOp.id);
+
+        for (Entry<Key, Operation> entry : updateOp.changes.entrySet()) {
+            Key k = entry.getKey();
+            Operation op = entry.getValue();
+            switch (op.type) {
+                case CONTAINS_MAP_ENTRY: {
+                    if (checkConditions) {
+                        query.and(k.toString()).exists(op.value);
+                    }
+                    break;
+                }
+            }
+        }
+        return query;
+    }
+
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java?rev=1527751&r1=1527750&r2=1527751&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java Mon Sep 30 19:50:20 2013
@@ -129,7 +129,7 @@ public class NodeDocument extends Docume
      */
     private static final Set<String> IGNORE_ON_SPLIT =
             Collections.unmodifiableSet(new HashSet<String>(
-                    Arrays.asList(ID, MODIFIED, PREVIOUS, LAST_REV)));
+                    Arrays.asList(ID, MOD_COUNT, MODIFIED, PREVIOUS, LAST_REV)));
 
     final DocumentStore store;