Author: mreutegg
Date: Fri Aug 19 07:30:16 2016
New Revision: 1756876

URL: http://svn.apache.org/viewvc?rev=1756876&view=rev
Log:
OAK-4682: ConcurrentModificationException in JournalEntry.TreeNode

Commit fix and enable test

Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1756876&r1=1756875&r2=1756876&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 Fri Aug 19 07:30:16 2016
@@ -435,7 +435,6 @@ public final class DocumentNodeStore
         } else {
             readOnlyMode = false;
         }
-        this.changes = Collection.JOURNAL.newDocument(s);
         this.executor = builder.getExecutor();
         this.clock = builder.getClock();
 
@@ -459,6 +458,7 @@ public final class DocumentNodeStore
         }
 
         this.store = s;
+        this.changes = newJournalEntry();
         this.clusterId = cid;
         this.branches = new UnmergedBranches();
         this.asyncDelay = builder.getAsyncDelay();
@@ -2015,7 +2015,7 @@ public final class DocumentNodeStore
             public void acquiring(Revision mostRecent) {
                 if (store.create(JOURNAL, 
singletonList(changes.asUpdateOp(mostRecent)))) {
                     // success: start with a new document
-                    changes = JOURNAL.newDocument(getDocumentStore());
+                    changes = newJournalEntry();
                 } else {
                     // fail: log and keep the changes
                     LOG.error("Failed to write to journal, accumulating 
changes for future write (~" + changes.getMemory()
@@ -2027,6 +2027,10 @@ public final class DocumentNodeStore
 
     //-----------------------------< internal 
>---------------------------------
 
+    private JournalEntry newJournalEntry() {
+        return new JournalEntry(store, true);
+    }
+
     /**
      * Performs an initial read of the _lastRevs on the root document and sets
      * the root state.

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java?rev=1756876&r1=1756875&r2=1756876&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java
 Fri Aug 19 07:30:16 2016
@@ -79,8 +79,15 @@ public final class JournalEntry extends
 
     private volatile TreeNode changes = null;
 
+    private boolean concurrent;
+
     JournalEntry(DocumentStore store) {
+        this(store, false);
+    }
+
+    JournalEntry(DocumentStore store, boolean concurrent) {
         this.store = store;
+        this.concurrent = concurrent;
     }
 
     static StringSort newSorter() {
@@ -390,7 +397,7 @@ public final class JournalEntry extends
     @Nonnull
     private TreeNode getChanges() {
         if (changes == null) {
-            TreeNode node = new TreeNode();
+            TreeNode node = new TreeNode(concurrent);
             String c = (String) get(CHANGES);
             if (c != null) {
                 node.parse(new JsopTokenizer(c));
@@ -406,17 +413,23 @@ public final class JournalEntry extends
 
         private Map<String, TreeNode> children = NO_CHILDREN;
 
+        private final MapFactory mapFactory;
         private final TreeNode parent;
         private final String name;
 
         TreeNode() {
-            this(null, "");
+            this(false);
+        }
+
+        TreeNode(boolean concurrent) {
+            this(concurrent ? MapFactory.CONCURRENT : MapFactory.DEFAULT, 
null, "");
         }
 
-        TreeNode(TreeNode parent, String name) {
+        TreeNode(MapFactory mapFactory, TreeNode parent, String name) {
             checkArgument(!name.contains("/"),
                     "name must not contain '/': {}", name);
 
+            this.mapFactory = mapFactory;
             this.parent = parent;
             this.name = name;
         }
@@ -517,11 +530,11 @@ public final class JournalEntry extends
         @Nonnull
         private TreeNode getOrCreate(String name) {
             if (children == NO_CHILDREN) {
-                children = Maps.newHashMap();
+                children = mapFactory.newMap();
             }
             TreeNode c = children.get(name);
             if (c == null) {
-                c = new TreeNode(this, name);
+                c = new TreeNode(mapFactory, this, name);
                 children.put(name, c);
             }
             return c;
@@ -533,4 +546,22 @@ public final class JournalEntry extends
         void node(TreeNode node, String path) throws IOException;
     }
 
+    private interface MapFactory {
+
+        MapFactory DEFAULT = new MapFactory() {
+            @Override
+            public Map<String, TreeNode> newMap() {
+                return Maps.newHashMap();
+            }
+        };
+
+        MapFactory CONCURRENT = new MapFactory() {
+            @Override
+            public Map<String, TreeNode> newMap() {
+                return Maps.newConcurrentMap();
+            }
+        };
+
+        Map<String, TreeNode> newMap();
+    }
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java?rev=1756876&r1=1756875&r2=1756876&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java
 Fri Aug 19 07:30:16 2016
@@ -31,7 +31,6 @@ import org.apache.jackrabbit.oak.commons
 import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
 import org.apache.jackrabbit.oak.commons.sort.StringSort;
 import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.apache.jackrabbit.oak.plugins.document.Collection.JOURNAL;
@@ -219,7 +218,6 @@ public class JournalEntryTest {
     }
 
     // OAK-4682
-    @Ignore
     @Test
     public void concurrentModification() throws Exception {
         DocumentNodeStore store = new DocumentMK.Builder().getNodeStore();


Reply via email to