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 2014/12/10 18:04:37 UTC

svn commit: r1644479 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ oak-run/src/main/js/

Author: mreutegg
Date: Wed Dec 10 17:04:37 2014
New Revision: 1644479

URL: http://svn.apache.org/r1644479
Log:
OAK-2342: Clean up collision markers

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java
    jackrabbit/oak/trunk/oak-run/src/main/js/oak-mongo.js

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java?rev=1644479&r1=1644478&r2=1644479&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java Wed Dec 10 17:04:37 2014
@@ -583,7 +583,7 @@ public final class NodeDocument extends
      * @param context the revision context.
      * @return count of the revision entries purged
      */
-    public int purgeUncommittedRevisions(RevisionContext context) {
+    int purgeUncommittedRevisions(RevisionContext context) {
         // only look at revisions in this document.
         // uncommitted revisions are not split off
         Map<Revision, String> valueMap = getLocalRevisions();
@@ -599,6 +599,31 @@ public final class NodeDocument extends
             }
         }
 
+        if (op.hasChanges()) {
+            store.findAndUpdate(Collection.NODES, op);
+        }
+        return purgeCount;
+    }
+
+    /**
+     * Purge collision markers with the local clusterId on this document. Use
+     * only on start when there are no ongoing or pending commits.
+     *
+     * @param context the revision context.
+     * @return the number of removed collision markers.
+     */
+    int purgeCollisionMarkers(RevisionContext context) {
+        Map<Revision, String> valueMap = getLocalMap(COLLISIONS);
+        UpdateOp op = new UpdateOp(getId(), false);
+        int purgeCount = 0;
+        for (Map.Entry<Revision, String> commit : valueMap.entrySet()) {
+            Revision r = commit.getKey();
+            if (r.getClusterId() == context.getClusterId()) {
+                purgeCount++;
+                removeCollision(op, r);
+            }
+        }
+
         if (op.hasChanges()) {
             store.findAndUpdate(Collection.NODES, op);
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java?rev=1644479&r1=1644478&r2=1644479&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java Wed Dec 10 17:04:37 2014
@@ -80,6 +80,10 @@ class UnmergedBranches {
         if (purgeCount > 0) {
             log.info("Purged [{}] uncommitted branch revision entries", purgeCount);
         }
+        purgeCount = doc.purgeCollisionMarkers(context);
+        if (purgeCount > 0) {
+            log.info("Purged [{}] collision markers", purgeCount);
+        }
     }
 
     /**

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java?rev=1644479&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java Wed Dec 10 17:04:37 2014
@@ -0,0 +1,81 @@
+/*
+ * 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.concurrent.atomic.AtomicInteger;
+
+import org.apache.jackrabbit.oak.plugins.document.util.Utils;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
+import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.COLLISIONS;
+import static org.apache.jackrabbit.oak.plugins.document.util.Utils.getIdFromPath;
+import static org.junit.Assert.assertEquals;
+
+public class CollisionTest {
+
+    private static final AtomicInteger COUNTER = new AtomicInteger();
+
+    // OAK-2342
+    @Test
+    public void purge() throws Exception {
+        DocumentMK mk1 = new DocumentMK.Builder().setClusterId(1).open();
+        DocumentNodeStore ns1 = mk1.getNodeStore();
+        DocumentStore store = ns1.getDocumentStore();
+
+        DocumentMK mk2 = new DocumentMK.Builder().setClusterId(2)
+                .setDocumentStore(store).open();
+        DocumentNodeStore ns2 = mk2.getNodeStore();
+
+        createCollision(mk1);
+        createCollision(mk2);
+
+        String id = getIdFromPath("/");
+        assertEquals(2, store.find(NODES, id).getLocalMap(COLLISIONS).size());
+
+        // restart node store
+        ns1.dispose();
+        mk1 = new DocumentMK.Builder().setClusterId(1)
+                .setDocumentStore(store).open();
+        ns1 = mk1.getNodeStore();
+
+        // must purge collision for clusterId 1
+        assertEquals(1, store.find(NODES, id).getLocalMap(COLLISIONS).size());
+        ns1.dispose();
+
+        // restart other node store
+        ns2.dispose();
+        mk2 = new DocumentMK.Builder().setClusterId(2)
+                .setDocumentStore(store).open();
+        ns2 = mk2.getNodeStore();
+
+        // must purge collision for clusterId 2
+        assertEquals(0, store.find(NODES, id).getLocalMap(COLLISIONS).size());
+        ns2.dispose();
+    }
+
+    private void createCollision(DocumentMK mk) throws Exception {
+        String nodeName = "test-" + COUNTER.getAndIncrement();
+        // create branch
+        String b = mk.branch(null);
+        mk.commit("/", "+\"" + nodeName + "\":{\"p\":\"a\"}", b, null);
+
+        // commit a change resulting in a collision on branch
+        mk.commit("/", "+\"" + nodeName + "\":{\"p\":\"b\"}", null, null);
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-run/src/main/js/oak-mongo.js
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/js/oak-mongo.js?rev=1644479&r1=1644478&r2=1644479&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/js/oak-mongo.js (original)
+++ jackrabbit/oak/trunk/oak-run/src/main/js/oak-mongo.js Wed Dec 10 17:04:37 2014
@@ -262,6 +262,51 @@ var oak = (function(global){
         }
     }
 
+    /**
+     * Removes all collision markers on the document with the given path and
+     * clusterId.
+     */
+    api.removeCollisions = function(path, clusterId) {
+        if (path === undefined) {
+            print("No path specified");
+            return;
+        }
+        if (clusterId === undefined) {
+            print("No clusterId specified");
+            return;
+        }
+        // refuse to remove when clusterId is marked active
+        var clusterNode = db.clusterNodes.findOne({_id: clusterId.toString()});
+        if (clusterNode && clusterNode.state == "ACTIVE") {
+            print("Cluster node with id " + clusterId + " is active!");
+            print("Can only remove collisions for inactive cluster node.");
+            return;
+        }
+
+        var doc = db.nodes.findOne({_id: pathDepth(path) + ":" + path});
+        if (!doc) {
+            print("No document for path: " + path);
+            return;
+        }
+        var unset = {};
+        var r;
+        var num = 0;
+        for (r in doc._collisions) {
+            if (new Revision(r).getClusterId() == clusterId) {
+                unset["_collisions." + r] = "";
+                num++;
+            }
+        }
+        if (num > 0) {
+            var update = {};
+            update["$inc"] = {_modCount: 1};
+            update["$unset"] = unset;
+            return db.nodes.update({_id: pathDepth(path) + ":" + path}, update);
+        } else {
+            print("No collisions found for clusterId " + clusterId);
+        }
+    }
+
     //~--------------------------------------------------< internal >
 
     var checkOrFixLastRevs = function(path, clusterId, dryRun) {
@@ -341,6 +386,10 @@ var oak = (function(global){
         return new Date(this.timestamp);
     }
 
+    Revision.prototype.getClusterId = function() {
+        return this.clusterId;
+    }
+
     var pathDepth = function(path){
         if(path === '/'){
             return 0;