Author: chetanm
Date: Tue Jun 21 06:17:31 2016
New Revision: 1749424

URL: http://svn.apache.org/viewvc?rev=1749424&view=rev
Log:
OAK-4180 - Use another NodeStore as a local cache for a remote Document store

Refactor to extract out AbstractDocumentNodeState which moves out those methods 
which are required for Document model to work.

Also introduced NodeStateDiffer which exposes the comparison logic as a 
pluggable extension. With default using full comparison. With DocumentNodeStore 
supporting an optimized comparison path

Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentNodeState.java
   (with props)
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeStateDiffer.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentNodeState.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentNodeState.java?rev=1749424&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentNodeState.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentNodeState.java
 Tue Jun 21 06:17:31 2016
@@ -0,0 +1,152 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
+import org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState;
+import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
+import org.apache.jackrabbit.oak.spi.state.EqualsDiff;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.apache.jackrabbit.oak.util.PerfLogger;
+import org.slf4j.LoggerFactory;
+
+import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+
+public abstract class AbstractDocumentNodeState extends AbstractNodeState {
+    private static final PerfLogger perfLogger = new PerfLogger(
+            LoggerFactory.getLogger(AbstractDocumentNodeState.class.getName()
+                    + ".perf"));
+    protected final NodeStateDiffer differ;
+
+    protected AbstractDocumentNodeState(NodeStateDiffer differ) {
+        this.differ = differ;
+    }
+
+    public abstract String getPath();
+
+    public abstract RevisionVector getRevision();
+
+    public abstract RevisionVector getLastRevision();
+
+    public abstract RevisionVector getRootRevision();
+
+    public abstract boolean isFromExternalChange();
+
+    /**
+     * Creates a copy of this {@code DocumentNodeState} with the
+     * {@link #rootRevision} set to the given {@code root} revision. This 
method
+     * returns {@code this} instance if the given {@code root} revision is
+     * the same as the one in this instance and the {@link #fromExternalChange}
+     * flags are equal.
+     *
+     * @param root the root revision for the copy of this node state.
+     * @param externalChange if the {@link #fromExternalChange} flag must be
+     *                       set on the returned node state.
+     * @return a copy of this node state with the given root revision and
+     *          external change flag.
+     */
+    public abstract AbstractDocumentNodeState withRootRevision(@Nonnull 
RevisionVector root,
+                                               boolean externalChange);
+
+    public abstract boolean hasNoChildren();
+
+    //--------------------------< NodeState 
>-----------------------------------
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        } else if (that instanceof AbstractDocumentNodeState) {
+            AbstractDocumentNodeState other = (AbstractDocumentNodeState) that;
+            if (!getPath().equals(other.getPath())) {
+                // path does not match: not equals
+                // (even if the properties are equal)
+                return false;
+            }
+            if (revisionEquals(other)) {
+                return true;
+            }
+            // revision does not match: might still be equals
+        } else if (that instanceof ModifiedNodeState) {
+            ModifiedNodeState modified = (ModifiedNodeState) that;
+            if (modified.getBaseState() == this) {
+                return EqualsDiff.equals(this, modified);
+            }
+        }
+        if (that instanceof NodeState) {
+            return AbstractNodeState.equals(this, (NodeState) that);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean compareAgainstBaseState(NodeState base, NodeStateDiff diff) 
{
+        if (this == base) {
+            return true;
+        } else if (base == EMPTY_NODE || !base.exists()) {
+            // special case
+            return EmptyNodeState.compareAgainstEmptyState(this, diff);
+        } else if (base instanceof AbstractDocumentNodeState) {
+            AbstractDocumentNodeState mBase = (AbstractDocumentNodeState) base;
+            if (getPath().equals(mBase.getPath())){
+                if (revisionEquals(mBase)) {
+                    // no differences
+                    return true;
+                } else {
+                    // use DocumentNodeStore compare
+                    final long start = perfLogger.start();
+                    try {
+                        return differ.compare(this, mBase, diff);
+                    } finally {
+                        if (start > 0) {
+                            perfLogger
+                                    .end(start,
+                                            1,
+                                            "compareAgainstBaseState, path={}, 
readRevision={}, lastRevision={}, base.path={}, base.readRevision={}, 
base.lastRevision={}",
+                                            getPath(), getRevision(), 
getLastRevision(),
+                                            mBase.getPath(), 
mBase.getRevision(),
+                                            mBase.getLastRevision());
+                        }
+                    }
+                }
+            }
+        }
+        // fall back to the generic node state diff algorithm
+        return super.compareAgainstBaseState(base, diff);
+    }
+
+    //------------------------------< internal 
>--------------------------------
+
+    /**
+     * Returns {@code true} if this state has the same revision as the
+     * {@code other} state. This method first compares the {@link 
#readRevision}
+     * and then the {@link #lastRevision}.
+     *
+     * @param other the other state to compare with.
+     * @return {@code true} if the revisions are equal, {@code false} 
otherwise.
+     */
+    private boolean revisionEquals(AbstractDocumentNodeState other) {
+        return this.getRevision().equals(other.getRevision())
+                || this.getLastRevision().equals(other.getLastRevision());
+    }
+}

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

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java?rev=1749424&r1=1749423&r2=1749424&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
 Tue Jun 21 06:17:31 2016
@@ -40,14 +40,10 @@ import org.apache.jackrabbit.oak.json.Js
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
-import org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState;
 import org.apache.jackrabbit.oak.spi.state.AbstractChildNodeEntry;
-import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
-import org.apache.jackrabbit.oak.spi.state.EqualsDiff;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
 import org.apache.jackrabbit.oak.util.PerfLogger;
 import org.slf4j.LoggerFactory;
 
@@ -57,12 +53,11 @@ import com.google.common.collect.Iterato
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static 
org.apache.jackrabbit.oak.commons.StringUtils.estimateMemoryUsage;
-import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 
 /**
  * A {@link NodeState} implementation for the {@link DocumentNodeStore}.
  */
-public class DocumentNodeState extends AbstractNodeState implements CacheValue 
{
+public class DocumentNodeState extends AbstractDocumentNodeState implements 
CacheValue {
 
     private static final PerfLogger perfLogger = new PerfLogger(
             LoggerFactory.getLogger(DocumentNodeState.class.getName()
@@ -110,6 +105,7 @@ public class DocumentNodeState extends A
                               @Nullable RevisionVector lastRevision,
                               @Nullable RevisionVector rootRevision,
                               boolean fromExternalChange) {
+        super(store);
         this.store = checkNotNull(store);
         this.path = checkNotNull(path);
         this.readRevision = checkNotNull(readRevision);
@@ -133,7 +129,8 @@ public class DocumentNodeState extends A
      * @return a copy of this node state with the given root revision and
      *          external change flag.
      */
-    private DocumentNodeState withRootRevision(@Nonnull RevisionVector root,
+    @Override
+    public DocumentNodeState withRootRevision(@Nonnull RevisionVector root,
                                                boolean externalChange) {
         if (rootRevision.equals(root) && fromExternalChange == externalChange) 
{
             return this;
@@ -157,12 +154,16 @@ public class DocumentNodeState extends A
      * @return {@code true} if this node state was created as a result of an
      *          external change; {@code false} otherwise.
      */
-    boolean isFromExternalChange() {
+    @Override
+    public boolean isFromExternalChange() {
         return fromExternalChange;
     }
 
+    //--------------------------< AbstractDocumentNodeState 
>-----------------------------------
+
+    @Override
     @Nonnull
-    RevisionVector getRevision() {
+    public RevisionVector getRevision() {
         return readRevision;
     }
 
@@ -178,39 +179,23 @@ public class DocumentNodeState extends A
      *          same value as returned by {@link #getRevision()}.
      */
     @Nonnull
-    RevisionVector getRootRevision() {
+    public RevisionVector getRootRevision() {
         return rootRevision;
     }
 
-    //--------------------------< NodeState 
>-----------------------------------
+    @Override
+    public String getPath() {
+        return path;
+    }
 
     @Override
-    public boolean equals(Object that) {
-        if (this == that) {
-            return true;
-        } else if (that instanceof DocumentNodeState) {
-            DocumentNodeState other = (DocumentNodeState) that;
-            if (!getPath().equals(other.getPath())) {
-                // path does not match: not equals
-                // (even if the properties are equal)
-                return false;
-            }
-            if (revisionEquals(other)) {
-                return true;
-            }
-            // revision does not match: might still be equals
-        } else if (that instanceof ModifiedNodeState) {
-            ModifiedNodeState modified = (ModifiedNodeState) that;
-            if (modified.getBaseState() == this) {
-                return EqualsDiff.equals(this, modified);
-            }
-        }
-        if (that instanceof NodeState) {
-            return AbstractNodeState.equals(this, (NodeState) that);
-        }
-        return false;
+    public RevisionVector getLastRevision() {
+        return lastRevision;
     }
 
+    //--------------------------< NodeState 
>-----------------------------------
+
+
     @Override
     public boolean exists() {
         return true;
@@ -328,42 +313,6 @@ public class DocumentNodeState extends A
         }
     }
 
-    @Override
-    public boolean compareAgainstBaseState(NodeState base, NodeStateDiff diff) 
{
-        if (this == base) {
-            return true;
-        } else if (base == EMPTY_NODE || !base.exists()) {
-            // special case
-            return EmptyNodeState.compareAgainstEmptyState(this, diff);
-        } else if (base instanceof DocumentNodeState) {
-            DocumentNodeState mBase = (DocumentNodeState) base;
-            if (store == mBase.store) {
-                if (getPath().equals(mBase.getPath())) {
-                    if (revisionEquals(mBase)) {
-                        // no differences
-                        return true;
-                    } else {
-                        // use DocumentNodeStore compare
-                        final long start = perfLogger.start();
-                        try {
-                            return store.compare(this, mBase, diff);
-                        } finally {
-                            perfLogger
-                                    .end(start,
-                                            1,
-                                            "compareAgainstBaseState, path={}, 
readRevision={}, lastRevision={}, base.path={}, base.readRevision={}, 
base.lastRevision={}",
-                                            path, readRevision, lastRevision,
-                                            mBase.path, mBase.readRevision,
-                                            mBase.lastRevision);
-                        }
-                    }
-                }
-            }
-        }
-        // fall back to the generic node state diff algorithm
-        return super.compareAgainstBaseState(base, diff);
-    }
-
     void setProperty(String propertyName, String value) {
         if (value == null) {
             properties.remove(propertyName);
@@ -397,7 +346,8 @@ public class DocumentNodeState extends A
         newNode.properties.putAll(properties);
     }
 
-    boolean hasNoChildren() {
+    @Override
+    public boolean hasNoChildren() {
         return !hasChildren;
     }
 
@@ -431,10 +381,6 @@ public class DocumentNodeState extends A
         return op;
     }
 
-    String getPath() {
-        return path;
-    }
-
     String getId() {
         return path + "@" + lastRevision;
     }
@@ -452,10 +398,6 @@ public class DocumentNodeState extends A
         this.lastRevision = lastRevision;
     }
 
-    RevisionVector getLastRevision() {
-        return lastRevision;
-    }
-
     @Override
     public int getMemory() {
         int size = 40 // shallow
@@ -517,10 +459,10 @@ public class DocumentNodeState extends A
     @Nonnull
     private Iterable<ChildNodeEntry> getChildNodeEntries(@Nullable String name,
                                                          int limit) {
-        Iterable<DocumentNodeState> children = store.getChildNodes(this, name, 
limit);
-        return Iterables.transform(children, new Function<DocumentNodeState, 
ChildNodeEntry>() {
+        Iterable<? extends AbstractDocumentNodeState> children = 
store.getChildNodes(this, name, limit);
+        return Iterables.transform(children, new 
Function<AbstractDocumentNodeState, ChildNodeEntry>() {
             @Override
-            public ChildNodeEntry apply(final DocumentNodeState input) {
+            public ChildNodeEntry apply(final AbstractDocumentNodeState input) 
{
                 return new AbstractChildNodeEntry() {
                     @Nonnull
                     @Override

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=1749424&r1=1749423&r2=1749424&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
 Tue Jun 21 06:17:31 2016
@@ -127,7 +127,7 @@ import org.slf4j.LoggerFactory;
  * Implementation of a NodeStore on {@link DocumentStore}.
  */
 public final class DocumentNodeStore
-        implements NodeStore, RevisionContext, Observable, Clusterable {
+        implements NodeStore, RevisionContext, Observable, Clusterable, 
NodeStateDiffer {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(DocumentNodeStore.class);
 
@@ -910,7 +910,7 @@ public final class DocumentNodeStore
         }
     }
 
-    DocumentNodeState.Children getChildren(@Nonnull final DocumentNodeState 
parent,
+    DocumentNodeState.Children getChildren(@Nonnull final 
AbstractDocumentNodeState parent,
                               @Nullable final String name,
                               final int limit)
             throws DocumentStoreException {
@@ -959,7 +959,7 @@ public final class DocumentNodeStore
      * @param limit the maximum number of child nodes to return.
      * @return the children of {@code parent}.
      */
-    DocumentNodeState.Children readChildren(DocumentNodeState parent,
+    DocumentNodeState.Children readChildren(AbstractDocumentNodeState parent,
                                             String name, int limit) {
         String queriedName = name;
         String path = parent.getPath();
@@ -1494,8 +1494,9 @@ public final class DocumentNodeStore
      *         {@code false} if it was aborted as requested by the handler
      *         (see the {@link NodeStateDiff} contract for more details)
      */
-    boolean compare(@Nonnull final DocumentNodeState node,
-                    @Nonnull final DocumentNodeState base,
+    @Override
+    public boolean compare(@Nonnull final AbstractDocumentNodeState node,
+                    @Nonnull final AbstractDocumentNodeState base,
                     @Nonnull NodeStateDiff diff) {
         if (!AbstractNodeState.comparePropertiesAgainstBaseState(node, base, 
diff)) {
             return false;
@@ -2169,8 +2170,8 @@ public final class DocumentNodeStore
     }
 
     private boolean dispatch(@Nonnull final String jsonDiff,
-                             @Nonnull final DocumentNodeState node,
-                             @Nonnull final DocumentNodeState base,
+                             @Nonnull final AbstractDocumentNodeState node,
+                             @Nonnull final AbstractDocumentNodeState base,
                              @Nonnull final NodeStateDiff diff) {
         return DiffCache.parseJsopDiff(jsonDiff, new DiffCache.Diff() {
             @Override
@@ -2249,7 +2250,7 @@ public final class DocumentNodeStore
         return false;
     }
 
-    private String diffImpl(DocumentNodeState from, DocumentNodeState to)
+    private String diffImpl(AbstractDocumentNodeState from, 
AbstractDocumentNodeState to)
             throws DocumentStoreException {
         JsopWriter w = new JsopStream();
         // TODO this does not work well for large child node lists

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeStateDiffer.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeStateDiffer.java?rev=1749424&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeStateDiffer.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeStateDiffer.java
 Tue Jun 21 06:17:31 2016
@@ -0,0 +1,50 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+
+public interface NodeStateDiffer {
+    NodeStateDiffer DEFAULT_DIFFER = new NodeStateDiffer() {
+        @Override
+        public boolean compare(@Nonnull AbstractDocumentNodeState node,
+                               @Nonnull AbstractDocumentNodeState base, 
@Nonnull NodeStateDiff diff) {
+            return node.compareAgainstBaseState(base, diff);
+        }
+    };
+
+
+    /**
+     * Compares the given {@code node} against the {@code base} state and
+     * reports the differences to the {@link NodeStateDiff}.
+     *
+     * @param node the node to compare.
+     * @param base the base node to compare against.
+     * @param diff handler of node state differences
+     * @return {@code true} if the full diff was performed, or
+     *         {@code false} if it was aborted as requested by the handler
+     *         (see the {@link NodeStateDiff} contract for more details)
+     */
+    boolean compare(@Nonnull final AbstractDocumentNodeState node,
+                    @Nonnull final AbstractDocumentNodeState base,
+                    @Nonnull NodeStateDiff diff);
+}

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


Reply via email to