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