Author: mreutegg
Date: Thu Nov 29 09:27:09 2018
New Revision: 1847703

URL: http://svn.apache.org/viewvc?rev=1847703&view=rev
Log:
OAK-7869: Commit queue stuck when input stream of blob blocks

Added:
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Changes.java
   (with props)
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilder.java
   (with props)
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilderTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UpdateOp.java
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitQueueTest.java
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitRootUpdateTest.java
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitTest.java
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreIT.java
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java

Added: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Changes.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Changes.java?rev=1847703&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Changes.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Changes.java
 Thu Nov 29 09:27:09 2018
@@ -0,0 +1,35 @@
+/*
+ * 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 org.jetbrains.annotations.NotNull;
+
+/**
+ * Abstraction for changes to be committed.
+ */
+interface Changes {
+
+    /**
+     * Applies the changes to the passed {@link CommitBuilder} by calling the
+     * appropriate methods on the builder.
+     *
+     * @param commitBuilder the commit builder.
+     */
+    void with(@NotNull CommitBuilder commitBuilder);
+}

Propchange: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Changes.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
 Thu Nov 29 09:27:09 2018
@@ -23,18 +23,17 @@ import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
-import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.commons.json.JsopStream;
 import org.apache.jackrabbit.oak.commons.json.JsopWriter;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -71,14 +70,14 @@ public class Commit {
      * List of all node paths which have been modified in this commit. In 
addition to the nodes
      * which are actually changed it also contains there parent node paths
      */
-    private HashSet<String> modifiedNodes = new HashSet<String>();
+    private final HashSet<String> modifiedNodes = new HashSet<String>();
 
-    private HashSet<String> addedNodes = new HashSet<String>();
-    private HashSet<String> removedNodes = new HashSet<String>();
+    private final HashSet<String> addedNodes = new HashSet<String>();
+    private final HashSet<String> removedNodes = new HashSet<String>();
 
     /** Set of all nodes which have binary properties. **/
-    private HashSet<String> nodesWithBinaries = Sets.newHashSet();
-    private HashMap<String, String> bundledNodes = Maps.newHashMap();
+    private final HashSet<String> nodesWithBinaries = Sets.newHashSet();
+    private final HashMap<String, String> bundledNodes = Maps.newHashMap();
 
     /**
      * Create a new Commit.
@@ -96,10 +95,26 @@ public class Commit {
         this.baseRevision = baseRevision;
     }
 
+    Commit(@NotNull DocumentNodeStore nodeStore,
+           @NotNull Revision revision,
+           @Nullable RevisionVector baseRevision,
+           @NotNull Map<String, UpdateOp> operations,
+           @NotNull Set<String> addedNodes,
+           @NotNull Set<String> removedNodes,
+           @NotNull Set<String> nodesWithBinaries,
+           @NotNull Map<String, String> bundledNodes) {
+        this(nodeStore, revision, baseRevision);
+        this.operations.putAll(operations);
+        this.addedNodes.addAll(addedNodes);
+        this.removedNodes.addAll(removedNodes);
+        this.nodesWithBinaries.addAll(nodesWithBinaries);
+        this.bundledNodes.putAll(bundledNodes);
+    }
+
     UpdateOp getUpdateOperationForNode(String path) {
         UpdateOp op = operations.get(path);
         if (op == null) {
-            op = createUpdateOp(path, revision, getBranch() != null);
+            op = createUpdateOp(path, revision, isBranchCommit());
             operations.put(path, op);
         }
         return op;
@@ -150,35 +165,6 @@ public class Commit {
         return modifiedNodes;
     }
 
-    void updateProperty(String path, String propertyName, String value) {
-        UpdateOp op = getUpdateOperationForNode(path);
-        String key = Utils.escapePropertyName(propertyName);
-        op.setMapEntry(key, revision, value);
-    }
-
-    void addBundledNode(String path, String bundlingRootPath) {
-        bundledNodes.put(path, bundlingRootPath);
-    }
-
-    void markNodeHavingBinary(String path) {
-        this.nodesWithBinaries.add(path);
-    }
-
-    void addNode(DocumentNodeState n) {
-        String path = n.getPath();
-        if (operations.containsKey(path)) {
-            String msg = "Node already added: " + path;
-            LOG.error(msg);
-            throw new DocumentStoreException(msg);
-        }
-        UpdateOp op = n.asOperation(revision);
-        if (getBranch() != null) {
-            NodeDocument.setBranchCommit(op, revision);
-        }
-        operations.put(path, op);
-        addedNodes.add(path);
-    }
-
     boolean isEmpty() {
         return operations.isEmpty();
     }
@@ -713,6 +699,13 @@ public class Commit {
     }
 
     /**
+     * @return {@code true} if this is a branch commit.
+     */
+    private boolean isBranchCommit() {
+        return baseRevision != null && baseRevision.isBranch();
+    }
+
+    /**
      * Applies the lastRev updates to the {@link LastRevTracker} of the
      * DocumentNodeStore.
      *
@@ -830,16 +823,6 @@ public class Commit {
         }
     }
 
-    public void removeNode(String path, NodeState state) {
-        removedNodes.add(path);
-        UpdateOp op = getUpdateOperationForNode(path);
-        op.setDelete(true);
-        NodeDocument.setDeleted(op, revision, true);
-        for (PropertyState p : state.getProperties()) {
-            updateProperty(path, p.getName(), null);
-        }
-    }
-
     private boolean isBundled(String path) {
         return bundledNodes.containsKey(path);
     }

Added: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilder.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilder.java?rev=1847703&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilder.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilder.java
 Thu Nov 29 09:27:09 2018
@@ -0,0 +1,302 @@
+/*
+ * 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.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.collect.Maps;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.document.util.Utils;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A builder for a commit, translating modifications into {@link UpdateOp}s.
+ */
+class CommitBuilder {
+
+    /** A marker revision when the commit is initially built */
+    static final Revision PSEUDO_COMMIT_REVISION = new 
Revision(Long.MIN_VALUE, 0, 0);
+
+    private final DocumentNodeStore nodeStore;
+    private final Revision revision;
+    private final RevisionVector baseRevision;
+    private final Map<String, UpdateOp> operations = new LinkedHashMap<>();
+
+    private final Set<String> addedNodes = new HashSet<>();
+    private final Set<String> removedNodes = new HashSet<>();
+
+    /** Set of all nodes which have binary properties. **/
+    private final Set<String> nodesWithBinaries = new HashSet<>();
+    private final Map<String, String> bundledNodes = new HashMap<>();
+
+    /**
+     * Creates a new builder with a pseudo commit revision. Building the commit
+     * must be done by calling {@link #build(Revision)}.
+     *
+     * @param nodeStore the node store.
+     * @param baseRevision the base revision if available.
+     */
+    CommitBuilder(@NotNull DocumentNodeStore nodeStore,
+                  @Nullable RevisionVector baseRevision) {
+        this(nodeStore, PSEUDO_COMMIT_REVISION, baseRevision);
+    }
+
+    /**
+     * Creates a new builder with the given commit {@code revision}.
+     *
+     * @param nodeStore the node store.
+     * @param revision the commit revision.
+     * @param baseRevision the base revision of the commit or {@code null} if
+     *          none is set.
+     */
+    CommitBuilder(@NotNull DocumentNodeStore nodeStore,
+                  @NotNull Revision revision,
+                  @Nullable RevisionVector baseRevision) {
+        this.nodeStore = checkNotNull(nodeStore);
+        this.revision = checkNotNull(revision);
+        this.baseRevision = baseRevision;
+    }
+
+    /**
+     * @return the commit revision.
+     */
+    @NotNull
+    Revision getRevision() {
+        return revision;
+    }
+
+    /**
+     * @return the base revision or {@code null} if none is set.
+     */
+    @Nullable
+    RevisionVector getBaseRevision() {
+        return baseRevision;
+    }
+
+    /**
+     * Add a node to the commit with the given path.
+     *
+     * @param path the path of the node to add.
+     * @return {@code this} builder.
+     */
+    @NotNull
+    CommitBuilder addNode(@NotNull String path) {
+        addNode(new DocumentNodeState(nodeStore, path, new 
RevisionVector(revision)));
+        return this;
+    }
+
+    /**
+     * Add a the given node and its properties to the commit.
+     *
+     * @param node the node state to add.
+     * @return {@code this} builder.
+     * @throws DocumentStoreException if there's already a modification for
+     *      a node at the given {@code path} in this commit builder.
+     */
+    @NotNull
+    CommitBuilder addNode(@NotNull DocumentNodeState node)
+            throws DocumentStoreException {
+        checkNotNull(node);
+
+        String path = node.getPath();
+        UpdateOp op = node.asOperation(revision);
+        if (operations.containsKey(path)) {
+            String msg = "Node already added: " + path;
+            throw new DocumentStoreException(msg);
+        }
+        if (isBranchCommit()) {
+            NodeDocument.setBranchCommit(op, revision);
+        }
+        operations.put(path, op);
+        addedNodes.add(path);
+        return this;
+    }
+
+    /**
+     * Instructs the commit builder that the bundling root of the node at
+     * {@code path} is at {@code bundlingRootPath}.
+     *
+     * @param path the path of a node.
+     * @param bundlingRootPath the bundling root for the node.
+     * @return {@code this} builder.
+     */
+    @NotNull
+    CommitBuilder addBundledNode(@NotNull String path,
+                                 @NotNull String bundlingRootPath) {
+        checkNotNull(path);
+        checkNotNull(bundlingRootPath);
+
+        bundledNodes.put(path, bundlingRootPath);
+        return this;
+    }
+
+    /**
+     * Removes a node in this commit.
+     *
+     * @param path the path of the node to remove.
+     * @param state the node state representing the node to remove.
+     * @return {@code this} builder.
+     * @throws DocumentStoreException if there's already a modification for
+     *      a node at the given {@code path} in this commit builder.
+     */
+    @NotNull
+    CommitBuilder removeNode(@NotNull String path,
+                             @NotNull NodeState state)
+            throws DocumentStoreException {
+        checkNotNull(path);
+        checkNotNull(state);
+
+        if (operations.containsKey(path)) {
+            String msg = "Node already removed: " + path;
+            throw new DocumentStoreException(msg);
+        }
+        removedNodes.add(path);
+        UpdateOp op = getUpdateOperationForNode(path);
+        op.setDelete(true);
+        NodeDocument.setDeleted(op, revision, true);
+        for (PropertyState p : state.getProperties()) {
+            updateProperty(path, p.getName(), null);
+        }
+        return this;
+    }
+
+    /**
+     * Updates a property to a given value.
+     *
+     * @param path the path of the node.
+     * @param propertyName the name of the property.
+     * @param value the value of the property.
+     * @return {@code this} builder.
+     */
+    @NotNull
+    CommitBuilder updateProperty(@NotNull String path,
+                                 @NotNull String propertyName,
+                                 @Nullable String value) {
+        checkNotNull(path);
+        checkNotNull(propertyName);
+
+        UpdateOp op = getUpdateOperationForNode(path);
+        String key = Utils.escapePropertyName(propertyName);
+        op.setMapEntry(key, revision, value);
+        return this;
+    }
+
+    /**
+     * Instructs the commit builder that the node at the given {@code path} has
+     * a reference to a binary.
+     *
+     * @param path the path of the node.
+     * @return {@code this} builder.
+     */
+    @NotNull
+    CommitBuilder markNodeHavingBinary(@NotNull String path) {
+        checkNotNull(path);
+
+        nodesWithBinaries.add(path);
+        return this;
+    }
+
+    /**
+     * Builds the commit with the modifications.
+     *
+     * @return {@code this} builder.
+     * @throws IllegalStateException if this builder was created without an
+     *      explicit commit revision and {@link #build(Revision)} should have
+     *      been called instead.
+     */
+    @NotNull
+    Commit build() {
+        if (PSEUDO_COMMIT_REVISION.equals(revision)) {
+            String msg = "Cannot build a commit with a pseudo commit revision";
+            throw new IllegalStateException(msg);
+        }
+        return new Commit(nodeStore, revision, baseRevision, operations,
+                addedNodes, removedNodes, nodesWithBinaries, bundledNodes);
+    }
+
+    /**
+     * Builds the commit with the modifications and the given commit revision.
+     *
+     * @param revision the commit revision.
+     * @return {@code this} builder.
+     */
+    @NotNull
+    Commit build(@NotNull Revision revision) {
+        checkNotNull(revision);
+
+        Revision from = this.revision;
+        Map<String, UpdateOp> operations = Maps.transformValues(
+                this.operations, op -> rewrite(op, from, revision));
+        return new Commit(nodeStore, revision, baseRevision, operations,
+                addedNodes, removedNodes, nodesWithBinaries, bundledNodes);
+    }
+
+    //-------------------------< internal 
>-------------------------------------
+
+    private UpdateOp getUpdateOperationForNode(String path) {
+        UpdateOp op = operations.get(path);
+        if (op == null) {
+            op = createUpdateOp(path, revision, isBranchCommit());
+            operations.put(path, op);
+        }
+        return op;
+    }
+
+    private static UpdateOp createUpdateOp(String path,
+                                           Revision revision,
+                                           boolean isBranch) {
+        String id = Utils.getIdFromPath(path);
+        UpdateOp op = new UpdateOp(id, false);
+        NodeDocument.setModified(op, revision);
+        if (isBranch) {
+            NodeDocument.setBranchCommit(op, revision);
+        }
+        return op;
+    }
+
+    /**
+     * @return {@code true} if this is a branch commit.
+     */
+    private boolean isBranchCommit() {
+        return baseRevision != null && baseRevision.isBranch();
+    }
+
+    private static UpdateOp rewrite(UpdateOp up, Revision from, Revision to) {
+        Map<UpdateOp.Key, UpdateOp.Operation> changes = Maps.newHashMap();
+        for (Map.Entry<UpdateOp.Key, UpdateOp.Operation> entry : 
up.getChanges().entrySet()) {
+            UpdateOp.Key k = entry.getKey();
+            UpdateOp.Operation op = entry.getValue();
+            if (from.equals(k.getRevision())) {
+                k = new UpdateOp.Key(k.getName(), to);
+            } else if (NodeDocument.MODIFIED_IN_SECS.equals(k.getName())) {
+                op = new UpdateOp.Operation(op.type, 
NodeDocument.getModifiedInSecs(to.getTimestamp()));
+            }
+            changes.put(k, op);
+        }
+
+        return new UpdateOp(up.getId(), up.isNew(), up.isDelete(), changes, 
null);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java
 Thu Nov 29 09:27:09 2018
@@ -40,7 +40,7 @@ class CommitDiff implements NodeStateDif
 
     private final DocumentNodeStore store;
 
-    private final Commit commit;
+    private final CommitBuilder commit;
 
     private final JsopBuilder builder;
 
@@ -48,16 +48,19 @@ class CommitDiff implements NodeStateDif
 
     private final BundlingHandler bundlingHandler;
 
-    CommitDiff(@NotNull DocumentNodeStore store, @NotNull Commit commit,
+    CommitDiff(@NotNull DocumentNodeStore store,
+               @NotNull CommitBuilder commitBuilder,
                @NotNull BlobSerializer blobs) {
-        this(checkNotNull(store), checkNotNull(commit), 
store.getBundlingConfigHandler().newBundlingHandler(),
+        this(checkNotNull(store), checkNotNull(commitBuilder),
+                store.getBundlingConfigHandler().newBundlingHandler(),
                 new JsopBuilder(), checkNotNull(blobs));
     }
 
-    private CommitDiff(DocumentNodeStore store, Commit commit, BundlingHandler 
bundlingHandler,
-               JsopBuilder builder, BlobSerializer blobs) {
+    private CommitDiff(DocumentNodeStore store, CommitBuilder commitBuilder,
+                       BundlingHandler bundlingHandler, JsopBuilder builder,
+                       BlobSerializer blobs) {
         this.store = store;
-        this.commit = commit;
+        this.commit = commitBuilder;
         this.bundlingHandler = bundlingHandler;
         this.builder = builder;
         this.blobs = blobs;
@@ -86,8 +89,7 @@ class CommitDiff implements NodeStateDif
     public boolean childNodeAdded(String name, NodeState after) {
         BundlingHandler child = bundlingHandler.childAdded(name, after);
         if (child.isBundlingRoot()) {
-            commit.addNode(new DocumentNodeState(store, 
child.getRootBundlePath(),
-                    new RevisionVector(commit.getRevision())));
+            commit.addNode(child.getRootBundlePath());
         }
         setOrTouchChildrenFlag(child);
         return after.compareAgainstBaseState(EMPTY_NODE,

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 Thu Nov 29 09:27:09 2018
@@ -490,7 +490,7 @@ public final class DocumentNodeStore
 
     /**
      * A set of non-branch commit revisions that are currently in progress. A
-     * revision is added to this set when {@link 
#newTrunkCommit(RevisionVector)}
+     * revision is added to this set when {@link #newTrunkCommit(Changes, 
RevisionVector)}
      * is called and removed when the commit either:
      * <ul>
      *     <li>Succeeds with {@link #done(Commit, boolean, CommitInfo)}</li>
@@ -604,17 +604,17 @@ public final class DocumentNodeStore
         if (rootDoc == null) {
             // root node is missing: repository is not initialized
             Revision commitRev = newRevision();
-            Commit commit = new Commit(this, commitRev, null);
             RevisionVector head = new RevisionVector(commitRev);
-            DocumentNodeState n = new DocumentNodeState(this, "/", head);
-            commit.addNode(n);
+            Commit commit = new CommitBuilder(this, commitRev, null)
+                    .addNode("/")
+                    .build();
             try {
                 commit.applyToDocumentStore();
             } catch (ConflictException e) {
                 throw new IllegalStateException("Conflict while creating root 
document", e);
             }
             unsavedLastRevisions.put("/", commitRev);
-            sweepRevisions = sweepRevisions.pmax(new 
RevisionVector(commitRev));
+            sweepRevisions = sweepRevisions.pmax(head);
             setRoot(head);
             // make sure _lastRev is written back to store
             backgroundWrite();
@@ -823,6 +823,7 @@ public final class DocumentNodeStore
      * {@link #done(Commit, boolean, CommitInfo)} or {@link #canceled(Commit)},
      * depending on the result of the commit.
      *
+     * @param changes the changes to commit.
      * @param base the base revision for the commit or <code>null</code> if the
      *             commit should use the current head revision as base.
      * @param branch the branch instance if this is a branch commit. The life
@@ -833,15 +834,16 @@ public final class DocumentNodeStore
      * @return a new commit.
      */
     @NotNull
-    Commit newCommit(@Nullable RevisionVector base,
+    Commit newCommit(@NotNull Changes changes,
+                     @Nullable RevisionVector base,
                      @Nullable DocumentNodeStoreBranch branch) {
         if (base == null) {
             base = getHeadRevision();
         }
         if (base.isBranch()) {
-            return newBranchCommit(base, branch);
+            return newBranchCommit(changes, base, branch);
         } else {
-            return newTrunkCommit(base);
+            return newTrunkCommit(changes, base);
         }
     }
 
@@ -2380,7 +2382,7 @@ public final class DocumentNodeStore
             // head was not updated for more than a minute
             // create an empty commit that updates the head
             boolean success = false;
-            Commit c = newTrunkCommit(getHeadRevision());
+            Commit c = newTrunkCommit(nop -> {}, getHeadRevision());
             try {
                 done(c, false, CommitInfo.EMPTY);
                 success = true;
@@ -2640,17 +2642,21 @@ public final class DocumentNodeStore
         setRoot(headRevision);
     }
 
-    @NotNull
-    private Commit newTrunkCommit(@NotNull RevisionVector base) {
+    private Commit newTrunkCommit(@NotNull Changes changes,
+                                  @NotNull RevisionVector base) {
         checkArgument(!checkNotNull(base).isBranch(),
                 "base must not be a branch revision: " + base);
 
+        // build commit before revision is created by the commit queue 
(OAK-7869)
+        CommitBuilder commitBuilder = new CommitBuilder(this, base);
+        changes.with(commitBuilder);
+
         boolean success = false;
         Commit c;
         backgroundOperationLock.readLock().lock();
         try {
             checkOpen();
-            c = new Commit(this, commitQueue.createRevision(), base);
+            c = commitBuilder.build(commitQueue.createRevision());
             inDoubtTrunkCommits.add(c.getRevision());
             success = true;
         } finally {
@@ -2662,13 +2668,14 @@ public final class DocumentNodeStore
     }
 
     @NotNull
-    private Commit newBranchCommit(@NotNull RevisionVector base,
+    private Commit newBranchCommit(@NotNull Changes changes,
+                                   @NotNull RevisionVector base,
                                    @Nullable DocumentNodeStoreBranch branch) {
         checkArgument(checkNotNull(base).isBranch(),
                 "base must be a branch revision: " + base);
 
         checkOpen();
-        Commit c = new Commit(this, newRevision(), base);
+        Revision commitRevision = newRevision();
         if (isDisableBranches()) {
             // Regular branch commits do not need to acquire the background
             // operation lock because the head is not updated and no pending
@@ -2677,7 +2684,7 @@ public final class DocumentNodeStore
             // must be acquired.
             backgroundOperationLock.readLock().lock();
         } else {
-            Revision rev = c.getRevision().asBranchRevision();
+            Revision rev = commitRevision.asBranchRevision();
             // remember branch commit
             Branch b = getBranches().getBranch(base);
             if (b == null) {
@@ -2691,7 +2698,9 @@ public final class DocumentNodeStore
                 b.addCommit(rev);
             }
         }
-        return c;
+        CommitBuilder commitBuilder = new CommitBuilder(this, commitRevision, 
base);
+        changes.with(commitBuilder);
+        return commitBuilder.build();
     }
 
     /**

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
 Thu Nov 29 09:27:09 2018
@@ -254,10 +254,6 @@ class DocumentNodeStoreBranch implements
         return lock;
     }
 
-    private interface Changes {
-        void with(Commit c);
-    }
-
     /**
      * Persists the changes between {@code toPersist} and {@code base}
      * to the underlying store.
@@ -278,9 +274,9 @@ class DocumentNodeStoreBranch implements
             throws ConflictException, DocumentStoreException {
         return persist(new Changes() {
             @Override
-            public void with(Commit c) {
+            public void with(@NotNull CommitBuilder commitBuilder) {
                 toPersist.compareAgainstBaseState(base,
-                        new CommitDiff(store, c, store.getBlobSerializer()));
+                        new CommitDiff(store, commitBuilder, 
store.getBlobSerializer()));
             }
         }, base, info);
     }
@@ -303,10 +299,9 @@ class DocumentNodeStoreBranch implements
                                       @NotNull CommitInfo info)
             throws ConflictException, DocumentStoreException {
         boolean success = false;
-        Commit c = store.newCommit(base.getRootRevision(), this);
+        Commit c = store.newCommit(op, base.getRootRevision(), this);
         RevisionVector rev;
         try {
-            op.with(c);
             if (c.isEmpty()) {
                 // no changes to persist. return base state and let
                 // finally clause cancel the commit

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UpdateOp.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UpdateOp.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UpdateOp.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UpdateOp.java
 Thu Nov 29 09:27:09 2018
@@ -52,9 +52,11 @@ public final class UpdateOp {
         this(id, isNew, false, new HashMap<Key, Operation>(), null);
     }
 
-    private UpdateOp(@NotNull String id, boolean isNew, boolean isDelete,
-                     @NotNull Map<Key, Operation> changes,
-                     @Nullable Map<Key, Condition> conditions) {
+    UpdateOp(@NotNull String id,
+             boolean isNew,
+             boolean isDelete,
+             @NotNull Map<Key, Operation> changes,
+             @Nullable Map<Key, Condition> conditions) {
         this.id = checkNotNull(id, "id must not be null");
         this.isNew = isNew;
         this.isDelete = isDelete;

Added: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilderTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilderTest.java?rev=1847703&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilderTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitBuilderTest.java
 Thu Nov 29 09:27:09 2018
@@ -0,0 +1,281 @@
+/*
+ * 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 org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.oak.plugins.document.TestUtils.merge;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class CommitBuilderTest {
+
+    @Rule
+    public DocumentMKBuilderProvider builderProvider = new 
DocumentMKBuilderProvider();
+
+    private DocumentNodeStore ns;
+
+    @Before
+    public void before() {
+        ns = builderProvider.newBuilder().build();
+    }
+
+    @Test
+    public void empty() {
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        assertNull(builder.getBaseRevision());
+        assertEquals(CommitBuilder.PSEUDO_COMMIT_REVISION, 
builder.getRevision());
+        try {
+            builder.build();
+            fail("CommitBuilder.build() must fail when the builder " +
+                    "was created without a commit revision");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+        Revision r = ns.newRevision();
+        Commit c = builder.build(r);
+        assertNotNull(c);
+        assertEquals(r, c.getRevision());
+        assertNull(c.getBaseRevision());
+        assertFalse(c.getModifiedPaths().iterator().hasNext());
+        assertTrue(c.isEmpty());
+    }
+
+    @Test
+    public void emptyWithBaseRevision() {
+        RevisionVector baseRev = ns.getHeadRevision();
+        CommitBuilder builder = new CommitBuilder(ns, baseRev);
+        assertEquals(baseRev, builder.getBaseRevision());
+        Commit c = builder.build(ns.newRevision());
+        assertNotNull(c);
+        assertEquals(baseRev, c.getBaseRevision());
+    }
+
+    @Test
+    public void buildWithNullRevision() {
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        try {
+            builder.build(null);
+            expectNPE();
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void addNode() {
+        RevisionVector baseRev = ns.getHeadRevision();
+        CommitBuilder builder = new CommitBuilder(ns, baseRev);
+        builder.addNode("/foo");
+        Commit c = builder.build(ns.newRevision());
+        assertNotNull(c);
+        assertFalse(c.isEmpty());
+    }
+
+    @Test
+    public void addNodeTwice() {
+        RevisionVector baseRev = ns.getHeadRevision();
+        CommitBuilder builder = new CommitBuilder(ns, baseRev);
+        builder.addNode("/foo");
+        try {
+            builder.addNode("/foo");
+            fail("Must fail with DocumentStoreException");
+        } catch (DocumentStoreException e) {
+            assertThat(e.getMessage(), containsString("already added"));
+        }
+    }
+
+    @Test
+    public void addNodePathNull() {
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        try {
+            builder.addNode((String) null);
+            expectNPE();
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void addNodeStateNull() {
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        try {
+            builder.addNode((DocumentNodeState) null);
+            expectNPE();
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void addNodeState() {
+        String path = "/foo";
+        DocumentNodeState foo = addNode("foo");
+
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        builder.addNode(foo);
+        Commit c = builder.build(ns.newRevision());
+        UpdateOp up = c.getUpdateOperationForNode(path);
+        UpdateOp.Operation op = up.getChanges().get(
+                new UpdateOp.Key("_deleted", c.getRevision()));
+        assertNotNull(op);
+    }
+
+    @Test
+    public void branchCommit() {
+        RevisionVector baseRev = ns.getHeadRevision()
+                .update(ns.newRevision().asBranchRevision());
+        CommitBuilder builder = new CommitBuilder(ns, baseRev);
+        builder.addNode("/foo");
+        Revision commitRev = ns.newRevision();
+        Commit c = builder.build(commitRev);
+        UpdateOp up = c.getUpdateOperationForNode("/foo");
+        UpdateOp.Operation op = up.getChanges().get(
+                new UpdateOp.Key("_bc", commitRev));
+        assertNotNull(op);
+    }
+
+    @Test
+    public void removeNode() {
+        DocumentNodeState bar = addNode("bar");
+
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        String path = "/bar";
+
+        builder.removeNode(path, bar);
+        Commit c = builder.build(ns.newRevision());
+        UpdateOp up = c.getUpdateOperationForNode(path);
+        UpdateOp.Operation op = up.getChanges().get(
+                new UpdateOp.Key("_deleted", c.getRevision()));
+        assertNotNull(op);
+    }
+
+    @Test
+    public void removeNodeTwice() {
+        DocumentNodeState bar = addNode("bar");
+
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        String path = "/bar";
+
+        builder.removeNode(path, bar);
+        try {
+            builder.removeNode(path, bar);
+            fail("Must throw DocumentStoreException");
+        } catch (DocumentStoreException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void removeNodePathNull() {
+        DocumentNodeState bar = addNode("bar");
+
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        try {
+            builder.removeNode(null, bar);
+            expectNPE();
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void removeNodeStateNull() {
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        try {
+            builder.removeNode("/bar", null);
+            expectNPE();
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void updateProperty() {
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        builder.updateProperty("/foo", "p", "v");
+        Commit c = builder.build(ns.newRevision());
+        UpdateOp up = c.getUpdateOperationForNode("/foo");
+        UpdateOp.Operation op = up.getChanges().get(
+                new UpdateOp.Key("p", c.getRevision()));
+        assertNotNull(op);
+    }
+
+    @Test
+    public void updatePropertyValueNull() {
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        builder.updateProperty("/foo", "p", null);
+        Commit c = builder.build(ns.newRevision());
+        UpdateOp up = c.getUpdateOperationForNode("/foo");
+        UpdateOp.Operation op = up.getChanges().get(
+                new UpdateOp.Key("p", c.getRevision()));
+        assertNotNull(op);
+    }
+
+    @Test
+    public void updatePropertyPathNull() {
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        try {
+            builder.updateProperty(null, "p", "v");
+            expectNPE();
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void updatePropertyPropertyNull() {
+        CommitBuilder builder = new CommitBuilder(ns, null);
+        try {
+            builder.updateProperty("/foo", null, "v");
+            expectNPE();
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    private static void expectNPE() {
+        fail("NullPointerException expected");
+    }
+
+    private DocumentNodeState addNode(String name) {
+        NodeBuilder nb = ns.getRoot().builder();
+        assertTrue(nb.child(name).isNew());
+        try {
+            merge(ns, nb);
+        } catch (CommitFailedException e) {
+            fail(e.getMessage());
+        }
+        NodeState child = ns.getRoot().getChildNode(name);
+        assertTrue(child.exists());
+        assertTrue(child instanceof DocumentNodeState);
+        return (DocumentNodeState) child;
+    }
+}

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

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitQueueTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitQueueTest.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitQueueTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitQueueTest.java
 Thu Nov 29 09:27:09 2018
@@ -95,7 +95,7 @@ public class CommitQueueTest {
                 public void run() {
                     try {
                         for (int i = 0; i < COMMITS_PER_WRITER; i++) {
-                            Commit commit = store.newCommit(null, null);
+                            Commit commit = store.newCommit(nop -> {}, null, 
null);
                             try {
                                 Thread.sleep(0, random.nextInt(1000));
                             } catch (InterruptedException e) {
@@ -189,7 +189,7 @@ public class CommitQueueTest {
         final DocumentNodeStore ds = 
builderProvider.newBuilder().getNodeStore();
 
         // simulate start of a branch commit
-        Commit c = 
ds.newCommit(ds.getHeadRevision().asBranchRevision(ds.getClusterId()), null);
+        Commit c = ds.newCommit(nop -> {}, 
ds.getHeadRevision().asBranchRevision(ds.getClusterId()), null);
 
         Thread t = new Thread(new Runnable() {
             @Override

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitRootUpdateTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitRootUpdateTest.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitRootUpdateTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitRootUpdateTest.java
 Thu Nov 29 09:27:09 2018
@@ -80,10 +80,11 @@ public class CommitRootUpdateTest {
 
         throwAfterUpdate.set(true);
         boolean success = false;
-        Commit c = ns.newCommit(ns.getHeadRevision(), null);
+        Commit c = ns.newCommit(changes -> {
+            changes.addNode("/foo/node");
+            changes.addNode("/bar/node");
+        }, ns.getHeadRevision(), null);
         try {
-            c.addNode(new DocumentNodeState(ns, "/foo/node", 
c.getBaseRevision()));
-            c.addNode(new DocumentNodeState(ns, "/bar/node", 
c.getBaseRevision()));
             c.apply();
             success = true;
         } finally {
@@ -136,9 +137,10 @@ public class CommitRootUpdateTest {
 
         throwAfterUpdate.set(true);
         boolean success = false;
-        Commit c = ns.newCommit(ns.getHeadRevision(), null);
+        Commit c = ns.newCommit(
+                changes -> changes.updateProperty("/foo", "p", "v"),
+                ns.getHeadRevision(), null);
         try {
-            c.updateProperty("/foo", "p", "v");
             c.apply();
             success = true;
         } finally {

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitTest.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CommitTest.java
 Thu Nov 29 09:27:09 2018
@@ -58,10 +58,10 @@ public class CommitTest {
         ns.merge(b, EmptyHook.INSTANCE, CommitInfo.EMPTY);
 
         // this commit should fail
-        Commit c = ns.newCommit(ns.getHeadRevision(), null);
+        Commit c = ns.newCommit(changes -> {
+            changes.addNode("/foo/baz");
+        }, ns.getHeadRevision(), null);
         try {
-            c.addNode(new DocumentNodeState(ns, "/foo/baz",
-                    new RevisionVector(c.getRevision())));
             UpdateOp op = c.getUpdateOperationForNode("/bar");
             op.setMapEntry("p", c.getRevision(), "v");
             try {
@@ -93,19 +93,17 @@ public class CommitTest {
         ns.merge(b, EmptyHook.INSTANCE, CommitInfo.EMPTY);
 
         // this commit should fail
-        Commit c = ns.newCommit(ns.getHeadRevision(), null);
+        Commit c = ns.newCommit(changes -> {
+            changes.addNode("/foo");
+        }, ns.getHeadRevision(), null);
         try {
-            c.addNode(new DocumentNodeState(ns, "/foo",
-                    new RevisionVector(c.getRevision())));
-            try {
-                c.apply();
-                ns.done(c, false, CommitInfo.EMPTY);
-                fail("commit must fail");
-            } catch (ConflictException e) {
-                // expected
-                assertTrue("Unexpected exception message: " + e.getMessage(),
-                        e.getMessage().contains("older than base"));
-            }
+            c.apply();
+            ns.done(c, false, CommitInfo.EMPTY);
+            fail("commit must fail");
+        } catch (ConflictException e) {
+            // expected
+            assertTrue("Unexpected exception message: " + e.getMessage(),
+                    e.getMessage().contains("older than base"));
         } finally {
             ns.canceled(c);
         }
@@ -118,9 +116,10 @@ public class CommitTest {
         DocumentNodeStore ns = builderProvider.newBuilder().getNodeStore();
 
         // this branch commit must fail with a DocumentStoreException
-        Commit c = 
ns.newCommit(ns.getHeadRevision().asBranchRevision(ns.getClusterId()), null);
+        Commit c = ns.newCommit(changes -> {
+            changes.removeNode("/foo", EMPTY_NODE);
+        }, ns.getHeadRevision().asBranchRevision(ns.getClusterId()), null);
         try {
-            c.removeNode("/foo", EMPTY_NODE);
             try {
                 c.apply();
                 fail("commit must fail");

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
 Thu Nov 29 09:27:09 2018
@@ -27,7 +27,6 @@ import javax.sql.DataSource;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.commons.json.JsopReader;
@@ -207,13 +206,13 @@ public class DocumentMK {
     public String commit(String rootPath, String jsonDiff, String baseRevId,
             String message) throws DocumentStoreException {
         boolean success = false;
-        boolean isBranch;
+        RevisionVector baseRev = baseRevId != null ? 
RevisionVector.fromString(baseRevId) : nodeStore.getHeadRevision();
+        boolean isBranch = baseRev.isBranch();
         RevisionVector rev;
-        Commit commit = nodeStore.newCommit(baseRevId != null ? 
RevisionVector.fromString(baseRevId) : null, null);
+        Commit commit = nodeStore.newCommit(
+                changes -> parseJsonDiff(changes, jsonDiff, rootPath),
+                baseRev, null);
         try {
-            RevisionVector baseRev = commit.getBaseRevision();
-            isBranch = baseRev != null && baseRev.isBranch();
-            parseJsonDiff(commit, jsonDiff, rootPath);
             commit.apply();
             rev = nodeStore.done(commit, isBranch, CommitInfo.EMPTY);
             success = true;
@@ -312,7 +311,7 @@ public class DocumentMK {
 
     //------------------------------< internal 
>--------------------------------
 
-    private void parseJsonDiff(Commit commit, String json, String rootPath) {
+    private void parseJsonDiff(CommitBuilder commit, String json, String 
rootPath) {
         RevisionVector baseRev = commit.getBaseRevision();
         String baseRevId = baseRev != null ? baseRev.toString() : null;
         Set<String> added = Sets.newHashSet();
@@ -335,7 +334,6 @@ public class DocumentMK {
                     if (toRemove == null) {
                         throw new DocumentStoreException("Node not found: " + 
path + " in revision " + baseRevId);
                     }
-                    commit.removeNode(path, toRemove);
                     markAsDeleted(toRemove, commit, true);
                     break;
                 case '^':
@@ -389,7 +387,7 @@ public class DocumentMK {
         }
     }
 
-    private void parseAddNode(Commit commit, JsopReader t, String path) {
+    private void parseAddNode(CommitBuilder commit, JsopReader t, String path) 
{
         List<PropertyState> props = Lists.newArrayList();
         if (!t.matches('}')) {
             do {
@@ -410,15 +408,15 @@ public class DocumentMK {
         commit.addNode(n);
     }
 
-    private void copyNode(DocumentNodeState source, String targetPath, Commit 
commit) {
+    private void copyNode(DocumentNodeState source, String targetPath, 
CommitBuilder commit) {
         moveOrCopyNode(false, source, targetPath, commit);
     }
 
-    private void moveNode(DocumentNodeState source, String targetPath, Commit 
commit) {
+    private void moveNode(DocumentNodeState source, String targetPath, 
CommitBuilder commit) {
         moveOrCopyNode(true, source, targetPath, commit);
     }
 
-    private void markAsDeleted(DocumentNodeState node, Commit commit, boolean 
subTreeAlso) {
+    private void markAsDeleted(DocumentNodeState node, CommitBuilder commit, 
boolean subTreeAlso) {
         commit.removeNode(node.getPath(), node);
 
         if (subTreeAlso) {
@@ -432,7 +430,7 @@ public class DocumentMK {
     private void moveOrCopyNode(boolean move,
                                 DocumentNodeState source,
                                 String targetPath,
-                                Commit commit) {
+                                CommitBuilder commit) {
         RevisionVector destRevision = 
commit.getBaseRevision().update(commit.getRevision());
         DocumentNodeState newNode = new DocumentNodeState(nodeStore, 
targetPath, destRevision,
                 source.getProperties(), false, null);

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreIT.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreIT.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreIT.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreIT.java
 Thu Nov 29 09:27:09 2018
@@ -28,6 +28,7 @@ import com.google.common.util.concurrent
 
 import org.apache.jackrabbit.oak.json.JsopDiff;
 import 
org.apache.jackrabbit.oak.plugins.document.util.TimingDocumentStoreWrapper;
+import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.plugins.memory.AbstractBlob;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
@@ -35,7 +36,6 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.stats.Clock;
 import org.jetbrains.annotations.NotNull;
 import org.junit.After;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -63,6 +63,13 @@ public class DocumentNodeStoreIT extends
     @After
     public void tearDown() {
         Revision.resetClockToDefault();
+        markDocumentsForCleanup();
+    }
+
+    private void markDocumentsForCleanup() {
+        for (NodeDocument doc : Utils.getAllDocuments(ds)) {
+            removeMe.add(doc.getId());
+        }
     }
 
     @Test
@@ -82,6 +89,7 @@ public class DocumentNodeStoreIT extends
                 .setDocumentStore(docStore).setClusterId(1)
                 .setAsyncDelay(0).clock(clock)
                 .build();
+        removeMeClusterNodes.add("1");
         NodeBuilder builder1 = ns1.getRoot().builder();
         builder1.child("node");
         removeMe.add(getIdFromPath("/node"));
@@ -96,6 +104,7 @@ public class DocumentNodeStoreIT extends
         DocumentNodeStore ns2 = new DocumentMK.Builder()
                 .setDocumentStore(docStore).setClusterId(2)
                 .setAsyncDelay(0).clock(clock).getNodeStore();
+        removeMeClusterNodes.add("2");
 
         NodeBuilder builder2 = ns2.getRoot().builder();
         builder2.child("node").child("child-a");
@@ -134,13 +143,13 @@ public class DocumentNodeStoreIT extends
         ns2.dispose();
     }
 
-    @Ignore("OAK-7869")
     @Test
     public void blockingBlob() throws Exception {
         ExecutorService updateExecutor = newSingleThreadExecutor();
         ExecutorService commitExecutor = newSingleThreadExecutor();
         DocumentNodeStore store = builderProvider.newBuilder()
                 .setDocumentStore(ds).build();
+        removeMeClusterNodes.add("" + store.getClusterId());
         try {
 
             // A blob whose stream blocks on read

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1847703&r1=1847702&r2=1847703&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
 Thu Nov 29 09:27:09 2018
@@ -295,12 +295,11 @@ public class DocumentNodeStoreTest {
             @Override
             public void run() {
                 try {
-                    Revision r = store.newRevision();
-                    Commit c = new Commit(store, r, head);
-                    c.addNode(new DocumentNodeState(store, 
"/newConflictingNode", new RevisionVector(r)));
-                    c.addNode(new DocumentNodeState(store, "/deletedNode", new 
RevisionVector(r)));
-                    c.updateProperty("/updateNode", "foo", "baz");
-                    c.apply();
+                    new CommitBuilder(store, store.newRevision(), head)
+                            .addNode("/newConflictingNode")
+                            .addNode("/deletedNode")
+                            .updateProperty("/updateNode", "foo", "baz")
+                            .build().apply();
                 } catch (Exception e) {
                     exceptions.add(e);
                 }
@@ -314,9 +313,10 @@ public class DocumentNodeStoreTest {
         created.acquireUninterruptibly();
         // commit will succeed and add collision marker to writer commit
         Revision r = store.newRevision();
-        Commit c = new Commit(store, r, head);
-        c.addNode(new DocumentNodeState(store, "/newConflictingNode", new 
RevisionVector(r)));
-        c.addNode(new DocumentNodeState(store, "/newNonConflictingNode", new 
RevisionVector(r)));
+        Commit c = new CommitBuilder(store, r, head)
+                .addNode("/newConflictingNode")
+                .addNode("/newNonConflictingNode")
+                .build();
         c.apply();
         // allow writer to continue
         s.release();
@@ -2436,7 +2436,7 @@ public class DocumentNodeStoreTest {
         final List<Commit> commits = new ArrayList<Commit>();
         for (int i = 0; i < 10; i++) {
             Revision revision = ds.newRevision();
-            Commit commit = ds.newCommit(new RevisionVector(revision), 
ds.createBranch(root));
+            Commit commit = ds.newCommit(nop -> {}, new 
RevisionVector(revision), ds.createBranch(root));
             commits.add(commit);
             revisions.add(revision);
         }


Reply via email to