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 {