Author: mreutegg
Date: Fri Feb 21 20:07:52 2014
New Revision: 1570693

URL: http://svn.apache.org/r1570693
Log:
OAK-1460: :childOrder out of sync when node is made orderable concurrently

Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ChildOrderConflictHandler.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ChildOrderConflictHandler.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ChildOrderConflictHandler.java?rev=1570693&r1=1570692&r2=1570693&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ChildOrderConflictHandler.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ChildOrderConflictHandler.java
 Fri Feb 21 20:07:52 2014
@@ -45,7 +45,8 @@ public class ChildOrderConflictHandler e
         if (isChildOrderProperty(ours)) {
             // two sessions concurrently called orderBefore() on a Tree
             // that was previously unordered.
-            return Resolution.THEIRS;
+            merge(parent, ours, theirs);
+            return Resolution.MERGED;
         } else {
             return handler.addExistingProperty(parent, ours, theirs);
         }
@@ -75,11 +76,11 @@ public class ChildOrderConflictHandler e
     }
 
     private static void merge(NodeBuilder parent, PropertyState ours, 
PropertyState theirs) {
-        Set<String> theirOrder = 
Sets.newHashSet(theirs.getValue(Type.STRINGS));
-        PropertyBuilder<String> merged = 
PropertyBuilder.array(Type.STRING).assignFrom(theirs);
+        Set<String> theirOrder = Sets.newHashSet(theirs.getValue(Type.NAMES));
+        PropertyBuilder<String> merged = 
PropertyBuilder.array(Type.NAME).assignFrom(theirs);
 
         // Append child node names from ours that are not in theirs
-        for (String ourChild : ours.getValue(Type.STRINGS)) {
+        for (String ourChild : ours.getValue(Type.NAMES)) {
             if (!theirOrder.contains(ourChild)) {
                 merged.addValue(ourChild);
             }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java?rev=1570693&r1=1570692&r2=1570693&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java
 Fri Feb 21 20:07:52 2014
@@ -23,8 +23,10 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import java.util.List;
 import java.util.Set;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import org.apache.jackrabbit.oak.NodeStoreFixture;
 import org.apache.jackrabbit.oak.Oak;
@@ -412,6 +414,49 @@ public class TreeTest extends OakBaseTes
     }
 
     @Test
+    public void concurrentAddChildMakeOrderable() throws Exception {
+        ContentSession s1 = repository.login(null, null);
+        try {
+            Root r1 = s1.getLatestRoot();
+            Tree t1 = r1.getTree("/");
+            t1.addChild("node1");
+            t1.addChild("node2");
+            r1.commit();
+            ContentSession s2 = repository.login(null, null);
+            try {
+                Root r2 = s2.getLatestRoot();
+                Tree t2 = r2.getTree("/");
+
+                t1 = r1.getTree("/");
+                // node3 from s1
+                t1.addChild("node3").orderBefore(null);
+                r1.commit();
+
+                // get current sequence of child names
+                List<String> names = Lists.newArrayList();
+                for (Tree t : r1.getTree("/").getChildren()) {
+                    names.add(t.getName());
+                }
+
+                // node4 from s2
+                t2.addChild("node4").orderBefore(null);
+                r2.commit();
+
+                names.add("node4");
+
+                t1 = s1.getLatestRoot().getTree("/");
+                assertSequence(
+                        t1.getChildren(), names.toArray(new 
String[names.size()]));
+            } finally {
+                s2.close();
+            }
+        } finally {
+            s1.close();
+        }
+
+    }
+
+    @Test
     public void concurrentAddChild() throws Exception {
         ContentSession s1 = repository.login(null, null);
         try {


Reply via email to