Author: mreutegg
Date: Wed Jan 29 14:32:11 2014
New Revision: 1562455
URL: http://svn.apache.org/r1562455
Log:
OAK-1361: DocumentNodeState#compareAgainstBaseState too slow
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
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
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java?rev=1562455&r1=1562454&r2=1562455&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
Wed Jan 29 14:32:11 2014
@@ -75,7 +75,7 @@ public class DocumentMK implements Micro
/**
* Enable fast diff operations.
*/
- private static final boolean FAST_DIFF = Boolean.parseBoolean(
+ static final boolean FAST_DIFF = Boolean.parseBoolean(
System.getProperty("oak.documentMK.fastDiff", "true"));
/**
@@ -88,19 +88,9 @@ public class DocumentMK implements Micro
*/
protected final DocumentStore store;
- /**
- * Diff cache.
- */
- private final Cache<String, Diff> diffCache;
- private final CacheStats diffCacheStats;
-
DocumentMK(Builder builder) {
this.nodeStore = builder.getNodeStore();
this.store = nodeStore.getDocumentStore();
-
- diffCache = builder.buildCache(builder.getDiffCacheSize());
- diffCacheStats = new CacheStats(diffCache, "DocumentMk-DiffCache",
- builder.getWeigher(), builder.getDiffCacheSize());
}
public void dispose() {
@@ -163,182 +153,19 @@ public class DocumentMK implements Micro
}
@Override
- public String diff(final String fromRevisionId,
- final String toRevisionId,
- final String path,
- final int depth) throws MicroKernelException {
- String key = fromRevisionId + "-" + toRevisionId + "-" + path + "-" +
depth;
- try {
- return diffCache.get(key, new Callable<Diff>() {
- @Override
- public Diff call() throws Exception {
- return new Diff(diffImpl(fromRevisionId, toRevisionId,
path, depth));
- }
- }).diff;
- } catch (ExecutionException e) {
- if (e.getCause() instanceof MicroKernelException) {
- throw (MicroKernelException) e.getCause();
- } else {
- throw new MicroKernelException(e.getCause());
- }
- }
- }
-
- String diffImpl(String fromRevisionId, String toRevisionId, String path,
- int depth) throws MicroKernelException {
- if (fromRevisionId.equals(toRevisionId)) {
- return "";
- }
+ public String diff(String fromRevisionId,
+ String toRevisionId,
+ String path,
+ int depth) throws MicroKernelException {
if (depth != 0) {
throw new MicroKernelException("Only depth 0 is supported, depth
is " + depth);
}
if (path == null || path.equals("")) {
path = "/";
}
- Revision fromRev = Revision.fromString(fromRevisionId);
- Revision toRev = Revision.fromString(toRevisionId);
- Node from = nodeStore.getNode(path, fromRev);
- Node to = nodeStore.getNode(path, toRev);
-
- if (from == null || to == null) {
- // TODO implement correct behavior if the node does't/didn't exist
- String msg = String.format("Diff is only supported if the node
exists in both cases. " +
- "Node [%s], fromRev [%s] -> %s, toRev [%s] -> %s",
- path, fromRev, from != null, toRev, to != null);
- throw new MicroKernelException(msg);
- }
- JsopWriter w = new JsopStream();
- for (String p : from.getPropertyNames()) {
- // changed or removed properties
- String fromValue = from.getProperty(p);
- String toValue = to.getProperty(p);
- if (!fromValue.equals(toValue)) {
- w.tag('^').key(p);
- if (toValue == null) {
- w.value(null);
- } else {
- w.encodedValue(toValue).newline();
- }
- }
- }
- for (String p : to.getPropertyNames()) {
- // added properties
- if (from.getProperty(p) == null) {
- w.tag('^').key(p).encodedValue(to.getProperty(p)).newline();
- }
- }
- // TODO this does not work well for large child node lists
- // use a document store index instead
- int max = MANY_CHILDREN_THRESHOLD;
- Children fromChildren, toChildren;
- fromChildren = nodeStore.getChildren(from, null, max);
- toChildren = nodeStore.getChildren(to, null, max);
- if (!fromChildren.hasMore && !toChildren.hasMore) {
- diffFewChildren(w, fromChildren, fromRev, toChildren, toRev);
- } else {
- if (FAST_DIFF) {
- diffManyChildren(w, path, fromRev, toRev);
- } else {
- max = Integer.MAX_VALUE;
- fromChildren = nodeStore.getChildren(from, null, max);
- toChildren = nodeStore.getChildren(to, null, max);
- diffFewChildren(w, fromChildren, fromRev, toChildren, toRev);
- }
- }
- return w.toString();
- }
-
- private void diffManyChildren(JsopWriter w, String path, Revision fromRev,
Revision toRev) {
- long minTimestamp = Math.min(fromRev.getTimestamp(),
toRev.getTimestamp());
- long minValue = Commit.getModified(minTimestamp);
- String fromKey = Utils.getKeyLowerLimit(path);
- String toKey = Utils.getKeyUpperLimit(path);
- Set<String> paths = new HashSet<String>();
- for (NodeDocument doc : store.query(Collection.NODES, fromKey, toKey,
- NodeDocument.MODIFIED, minValue, Integer.MAX_VALUE)) {
- paths.add(Utils.getPathFromId(doc.getId()));
- }
- // also consider nodes with not yet stored modifications (OAK-1107)
- Revision minRev = new Revision(minTimestamp, 0,
nodeStore.getClusterId());
- addPathsForDiff(path, paths, nodeStore.getPendingModifications(),
minRev);
- for (Revision r : new Revision[]{fromRev, toRev}) {
- if (r.isBranch()) {
- Branch b = nodeStore.getBranches().getBranch(fromRev);
- if (b != null) {
- addPathsForDiff(path, paths, b.getModifications(r), r);
- }
- }
- }
- for (String p : paths) {
- Node fromNode = nodeStore.getNode(p, fromRev);
- Node toNode = nodeStore.getNode(p, toRev);
- if (fromNode != null) {
- // exists in fromRev
- if (toNode != null) {
- // exists in both revisions
- // check if different
- if
(!fromNode.getLastRevision().equals(toNode.getLastRevision())) {
- w.tag('^').key(p).object().endObject().newline();
- }
- } else {
- // does not exist in toRev -> was removed
- w.tag('-').value(p).newline();
- }
- } else {
- // does not exist in fromRev
- if (toNode != null) {
- // exists in toRev
- w.tag('+').key(p).object().endObject().newline();
- } else {
- // does not exist in either revisions
- // -> do nothing
- }
- }
- }
- }
-
- private static void addPathsForDiff(String path,
- Set<String> paths,
- UnsavedModifications pending,
- Revision minRev) {
- for (String p : pending.getPaths(minRev)) {
- if (PathUtils.denotesRoot(p)) {
- continue;
- }
- String parent = PathUtils.getParentPath(p);
- if (path.equals(parent)) {
- paths.add(p);
- }
- }
+ return nodeStore.diff(fromRevisionId, toRevisionId, path);
}
- private void diffFewChildren(JsopWriter w, Children fromChildren, Revision
fromRev, Children toChildren, Revision toRev) {
- Set<String> childrenSet = new HashSet<String>(toChildren.children);
- for (String n : fromChildren.children) {
- if (!childrenSet.contains(n)) {
- w.tag('-').value(n).newline();
- } else {
- Node n1 = nodeStore.getNode(n, fromRev);
- Node n2 = nodeStore.getNode(n, toRev);
- // this is not fully correct:
- // a change is detected if the node changed recently,
- // even if the revisions are well in the past
- // if this is a problem it would need to be changed
- checkNotNull(n1, "Node at [%s] not found for fromRev [%s]", n,
fromRev);
- checkNotNull(n2, "Node at [%s] not found for toRev [%s]", n,
toRev);
- if (!n1.getId().equals(n2.getId())) {
- w.tag('^').key(n).object().endObject().newline();
- }
- }
- }
- childrenSet = new HashSet<String>(fromChildren.children);
- for (String n : toChildren.children) {
- if (!childrenSet.contains(n)) {
- w.tag('+').key(n).object().endObject().newline();
- }
- }
- }
-
@Override
public boolean nodeExists(String path, String revisionId)
throws MicroKernelException {
@@ -512,22 +339,6 @@ public class DocumentMK implements Micro
return store;
}
- public CacheStats getNodeCacheStats() {
- return nodeStore.getNodeCacheStats();
- }
-
- public CacheStats getNodeChildrenCacheStats() {
- return nodeStore.getNodeChildrenCacheStats();
- }
-
- public CacheStats getDiffCacheStats() {
- return diffCacheStats;
- }
-
- public CacheStats getDocChildrenCacheStats() {
- return nodeStore.getDocChildrenCacheStats();
- }
-
//------------------------------< internal
>--------------------------------
private void parseJsonDiff(Commit commit, String json, String rootPath) {
@@ -628,24 +439,6 @@ public class DocumentMK implements Micro
commit.addNodeDiff(n);
}
- /**
- * A (cached) result of the diff operation.
- */
- private static class Diff implements CacheValue {
-
- final String diff;
-
- Diff(String diff) {
- this.diff = diff;
- }
-
- @Override
- public int getMemory() {
- return diff.length() * 2;
- }
-
- }
-
//----------------------------< Builder
>-----------------------------------
/**
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=1562455&r1=1562454&r2=1562455&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
Wed Jan 29 14:32:11 2014
@@ -23,6 +23,8 @@ import java.util.NoSuchElementException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.apache.jackrabbit.mk.json.JsopReader;
+import org.apache.jackrabbit.mk.json.JsopTokenizer;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
@@ -57,6 +59,12 @@ final class DocumentNodeState extends Ab
*/
static final int MAX_FETCH_SIZE = INITIAL_FETCH_SIZE << 4;
+ /**
+ * Number of child nodes beyond which {@link DocumentNodeStore#}
+ * is used for diffing.
+ */
+ public static final int LOCAL_DIFF_THRESHOLD = 10;
+
private final DocumentNodeStore store;
private final Node node;
@@ -193,12 +201,15 @@ final class DocumentNodeState extends Ab
} else if (base instanceof DocumentNodeState) {
DocumentNodeState mBase = (DocumentNodeState) base;
if (store == mBase.store) {
- if (node.getLastRevision().equals(mBase.node.getLastRevision())
- && getPath().equals(mBase.getPath())) {
- // no differences
- return true;
+ if (getPath().equals(mBase.getPath())) {
+ if
(node.getLastRevision().equals(mBase.node.getLastRevision())) {
+ // no differences
+ return true;
+ } else if (getChildNodeCount(LOCAL_DIFF_THRESHOLD) >
LOCAL_DIFF_THRESHOLD) {
+ // use DocumentNodeStore compare when there are many
children
+ return dispatch(store.diff(this.node, mBase.node),
mBase, diff);
+ }
}
- // TODO: use diff, similar to KernelNodeState
}
}
// fall back to the generic node state diff algorithm
@@ -207,6 +218,82 @@ final class DocumentNodeState extends Ab
//------------------------------< internal
>--------------------------------
+ private boolean dispatch(@Nonnull String jsonDiff,
+ @Nonnull DocumentNodeState base,
+ @Nonnull NodeStateDiff diff) {
+ if (jsonDiff.trim().isEmpty()) {
+ return true;
+ }
+ if (!AbstractNodeState.comparePropertiesAgainstBaseState(this, base,
diff)) {
+ return false;
+ }
+ JsopTokenizer t = new JsopTokenizer(jsonDiff);
+ boolean continueComparison = true;
+ while (continueComparison) {
+ int r = t.read();
+ if (r == JsopReader.END) {
+ break;
+ }
+ switch (r) {
+ case '+': {
+ String path = t.readString();
+ t.read(':');
+ t.read('{');
+ while (t.read() != '}') {
+ // skip properties
+ }
+ String name = PathUtils.getName(path);
+ continueComparison = diff.childNodeAdded(name,
getChildNode(name));
+ break;
+ }
+ case '-': {
+ String path = t.readString();
+ String name = PathUtils.getName(path);
+ continueComparison = diff.childNodeDeleted(name,
base.getChildNode(name));
+ break;
+ }
+ case '^': {
+ String path = t.readString();
+ t.read(':');
+ if (t.matches('{')) {
+ t.read('}');
+ String name = PathUtils.getName(path);
+ continueComparison = diff.childNodeChanged(name,
+ base.getChildNode(name), getChildNode(name));
+ } else if (t.matches('[')) {
+ // ignore multi valued property
+ while (t.read() != ']') {
+ // skip values
+ }
+ } else {
+ // ignore single valued property
+ t.read();
+ }
+ break;
+ }
+ case '>': {
+ String from = t.readString();
+ t.read(':');
+ String to = t.readString();
+ String fromName = PathUtils.getName(from);
+ continueComparison = diff.childNodeDeleted(
+ fromName, base.getChildNode(fromName));
+ if (!continueComparison) {
+ break;
+ }
+ String toName = PathUtils.getName(to);
+ continueComparison = diff.childNodeAdded(
+ toName, getChildNode(toName));
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("jsonDiff: illegal
token '"
+ + t.getToken() + "' at pos: " + t.getLastPos() + '
' + jsonDiff);
+ }
+ }
+ return continueComparison;
+ }
+
/**
* Returns up to {@code limit} child node entries, starting after the given
* {@code name}.
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=1562455&r1=1562454&r2=1562455&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
Wed Jan 29 14:32:11 2014
@@ -19,6 +19,8 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.jackrabbit.oak.api.CommitFailedException.MERGE;
+import static org.apache.jackrabbit.oak.plugins.document.DocumentMK.FAST_DIFF;
+import static
org.apache.jackrabbit.oak.plugins.document.DocumentMK.MANY_CHILDREN_THRESHOLD;
import java.io.Closeable;
import java.io.IOException;
@@ -53,9 +55,12 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.jackrabbit.mk.api.MicroKernelException;
import org.apache.jackrabbit.mk.blobs.BlobStore;
+import org.apache.jackrabbit.mk.json.JsopStream;
+import org.apache.jackrabbit.mk.json.JsopWriter;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.cache.CacheStats;
+import org.apache.jackrabbit.oak.cache.CacheValue;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.kernel.BlobSerializer;
import
org.apache.jackrabbit.oak.plugins.document.util.LoggingDocumentStoreWrapper;
@@ -220,7 +225,13 @@ public final class DocumentNodeStore
*/
private final Cache<String, NodeDocument.Children> docChildrenCache;
private final CacheStats docChildrenCacheStats;
-
+
+ /**
+ * Diff cache.
+ */
+ private final Cache<String, Diff> diffCache;
+ private final CacheStats diffCacheStats;
+
/**
* The blob store.
*/
@@ -288,6 +299,10 @@ public final class DocumentNodeStore
docChildrenCacheStats = new CacheStats(docChildrenCache,
"DocumentMk-DocChildren",
builder.getWeigher(), builder.getDocChildrenCacheSize());
+ diffCache = builder.buildCache(builder.getDiffCacheSize());
+ diffCacheStats = new CacheStats(diffCache, "DocumentMk-DiffCache",
+ builder.getWeigher(), builder.getDiffCacheSize());
+
// check if root node exists
if (store.find(Collection.NODES, Utils.getIdFromPath("/")) == null) {
// root node is missing: repository is not initialized
@@ -471,6 +486,10 @@ public final class DocumentNodeStore
return docChildrenCacheStats;
}
+ public CacheStats getDiffCacheStats() {
+ return diffCacheStats;
+ }
+
public int getPendingWriteCount() {
return unsavedLastRevisions.getPaths().size();
}
@@ -1024,6 +1043,68 @@ public final class DocumentNodeStore
}
/**
+ * Compares the given {@code state} against the {@code base} state and
+ * reports the differences as a json diff string.
+ *
+ * @param node the state to compare.
+ * @param base the base state to compare against.
+ * @return the json diff.
+ */
+ String diff(final @Nonnull Node node,
+ final @Nonnull Node base) {
+ String key = checkNotNull(base).getLastRevision() + "-"
+ + checkNotNull(node).getLastRevision() + "-" + node.getPath();
+ try {
+ return diffCache.get(key, new Callable<Diff>() {
+ @Override
+ public Diff call() throws Exception {
+ return new Diff(diffImpl(base, node));
+ }
+ }).diff;
+ } catch (ExecutionException e) {
+ if (e.getCause() instanceof MicroKernelException) {
+ throw (MicroKernelException) e.getCause();
+ } else {
+ throw new MicroKernelException(e.getCause());
+ }
+ }
+ }
+
+ String diff(@Nonnull final String fromRevisionId,
+ @Nonnull final String toRevisionId,
+ @Nonnull final String path) throws MicroKernelException {
+ if (fromRevisionId.equals(toRevisionId)) {
+ return "";
+ }
+ String key = fromRevisionId + "-" + toRevisionId + "-" + path;
+ try {
+ return diffCache.get(key, new Callable<Diff>() {
+ @Override
+ public Diff call() throws Exception {
+ Revision fromRev = Revision.fromString(fromRevisionId);
+ Revision toRev = Revision.fromString(toRevisionId);
+ Node from = getNode(path, fromRev);
+ Node to = getNode(path, toRev);
+ if (from == null || to == null) {
+ // TODO implement correct behavior if the node
does't/didn't exist
+ String msg = String.format("Diff is only supported if
the node exists in both cases. " +
+ "Node [%s], fromRev [%s] -> %s, toRev [%s] ->
%s",
+ path, fromRev, from != null, toRev, to !=
null);
+ throw new MicroKernelException(msg);
+ }
+ return new Diff(diffImpl(from, to));
+ }
+ }).diff;
+ } catch (ExecutionException e) {
+ if (e.getCause() instanceof MicroKernelException) {
+ throw (MicroKernelException) e.getCause();
+ } else {
+ throw new MicroKernelException(e.getCause());
+ }
+ }
+ }
+
+ /**
* Returns the {@link Blob} with the given blobId.
*
* @param blobId the blobId of the blob.
@@ -1281,6 +1362,143 @@ public final class DocumentNodeStore
//-----------------------------< internal
>---------------------------------
+ private String diffImpl(Node from, Node to)
+ throws MicroKernelException {
+ JsopWriter w = new JsopStream();
+ for (String p : from.getPropertyNames()) {
+ // changed or removed properties
+ String fromValue = from.getProperty(p);
+ String toValue = to.getProperty(p);
+ if (!fromValue.equals(toValue)) {
+ w.tag('^').key(p);
+ if (toValue == null) {
+ w.value(null);
+ } else {
+ w.encodedValue(toValue).newline();
+ }
+ }
+ }
+ for (String p : to.getPropertyNames()) {
+ // added properties
+ if (from.getProperty(p) == null) {
+ w.tag('^').key(p).encodedValue(to.getProperty(p)).newline();
+ }
+ }
+ // TODO this does not work well for large child node lists
+ // use a document store index instead
+ int max = MANY_CHILDREN_THRESHOLD;
+ Node.Children fromChildren, toChildren;
+ fromChildren = getChildren(from, null, max);
+ toChildren = getChildren(to, null, max);
+ if (!fromChildren.hasMore && !toChildren.hasMore) {
+ diffFewChildren(w, fromChildren, from.getLastRevision(),
+ toChildren, to.getLastRevision());
+ } else {
+ if (FAST_DIFF) {
+ diffManyChildren(w, from.getPath(),
+ from.getLastRevision(), to.getLastRevision());
+ } else {
+ max = Integer.MAX_VALUE;
+ fromChildren = getChildren(from, null, max);
+ toChildren = getChildren(to, null, max);
+ diffFewChildren(w, fromChildren, from.getLastRevision(),
+ toChildren, to.getLastRevision());
+ }
+ }
+ return w.toString();
+ }
+
+ private void diffManyChildren(JsopWriter w, String path, Revision fromRev,
Revision toRev) {
+ long minTimestamp = Math.min(fromRev.getTimestamp(),
toRev.getTimestamp());
+ long minValue = Commit.getModified(minTimestamp);
+ String fromKey = Utils.getKeyLowerLimit(path);
+ String toKey = Utils.getKeyUpperLimit(path);
+ Set<String> paths = new HashSet<String>();
+ for (NodeDocument doc : store.query(Collection.NODES, fromKey, toKey,
+ NodeDocument.MODIFIED, minValue, Integer.MAX_VALUE)) {
+ paths.add(Utils.getPathFromId(doc.getId()));
+ }
+ // also consider nodes with not yet stored modifications (OAK-1107)
+ Revision minRev = new Revision(minTimestamp, 0, getClusterId());
+ addPathsForDiff(path, paths, getPendingModifications(), minRev);
+ for (Revision r : new Revision[]{fromRev, toRev}) {
+ if (r.isBranch()) {
+ Branch b = getBranches().getBranch(fromRev);
+ if (b != null) {
+ addPathsForDiff(path, paths, b.getModifications(r), r);
+ }
+ }
+ }
+ for (String p : paths) {
+ Node fromNode = getNode(p, fromRev);
+ Node toNode = getNode(p, toRev);
+ if (fromNode != null) {
+ // exists in fromRev
+ if (toNode != null) {
+ // exists in both revisions
+ // check if different
+ if
(!fromNode.getLastRevision().equals(toNode.getLastRevision())) {
+ w.tag('^').key(p).object().endObject().newline();
+ }
+ } else {
+ // does not exist in toRev -> was removed
+ w.tag('-').value(p).newline();
+ }
+ } else {
+ // does not exist in fromRev
+ if (toNode != null) {
+ // exists in toRev
+ w.tag('+').key(p).object().endObject().newline();
+ } else {
+ // does not exist in either revisions
+ // -> do nothing
+ }
+ }
+ }
+ }
+
+ private static void addPathsForDiff(String path,
+ Set<String> paths,
+ UnsavedModifications pending,
+ Revision minRev) {
+ for (String p : pending.getPaths(minRev)) {
+ if (PathUtils.denotesRoot(p)) {
+ continue;
+ }
+ String parent = PathUtils.getParentPath(p);
+ if (path.equals(parent)) {
+ paths.add(p);
+ }
+ }
+ }
+
+ private void diffFewChildren(JsopWriter w, Node.Children fromChildren,
Revision fromRev, Node.Children toChildren, Revision toRev) {
+ Set<String> childrenSet = new HashSet<String>(toChildren.children);
+ for (String n : fromChildren.children) {
+ if (!childrenSet.contains(n)) {
+ w.tag('-').value(n).newline();
+ } else {
+ Node n1 = getNode(n, fromRev);
+ Node n2 = getNode(n, toRev);
+ // this is not fully correct:
+ // a change is detected if the node changed recently,
+ // even if the revisions are well in the past
+ // if this is a problem it would need to be changed
+ checkNotNull(n1, "Node at [%s] not found for fromRev [%s]", n,
fromRev);
+ checkNotNull(n2, "Node at [%s] not found for toRev [%s]", n,
toRev);
+ if (!n1.getId().equals(n2.getId())) {
+ w.tag('^').key(n).object().endObject().newline();
+ }
+ }
+ }
+ childrenSet = new HashSet<String>(fromChildren.children);
+ for (String n : toChildren.children) {
+ if (!childrenSet.contains(n)) {
+ w.tag('+').key(n).object().endObject().newline();
+ }
+ }
+ }
+
private static String childNodeCacheKey(@Nonnull String path,
@Nonnull Revision readRevision,
@Nullable String name) {
@@ -1333,6 +1551,24 @@ public final class DocumentNodeStore
}
/**
+ * A (cached) result of the diff operation.
+ */
+ private static class Diff implements CacheValue {
+
+ final String diff;
+
+ Diff(String diff) {
+ this.diff = diff;
+ }
+
+ @Override
+ public int getMemory() {
+ return diff.length() * 2;
+ }
+
+ }
+
+ /**
* A background thread.
*/
static class BackgroundOperation implements Runnable {
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java?rev=1562455&r1=1562454&r2=1562455&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
Wed Jan 29 14:32:11 2014
@@ -136,7 +136,7 @@ public class DocumentNodeStoreService {
logger.info("Connected to database {}", mongoDB);
- registerJMXBeans(mk, context);
+ registerJMXBeans(mk.getNodeStore(), context);
NodeStore store;
if (useMK) {
@@ -187,38 +187,36 @@ public class DocumentNodeStoreService {
}
}
- private void registerJMXBeans(DocumentMK mk, BundleContext context) {
+ private void registerJMXBeans(DocumentNodeStore store, BundleContext
context) {
Whiteboard wb = new OsgiWhiteboard(context);
registrations.add(
registerMBean(wb,
CacheStatsMBean.class,
- mk.getNodeCacheStats(),
+ store.getNodeCacheStats(),
CacheStatsMBean.TYPE,
- mk.getNodeCacheStats().getName())
- );
+ store.getNodeCacheStats().getName()));
registrations.add(
registerMBean(wb,
CacheStatsMBean.class,
- mk.getNodeChildrenCacheStats(),
+ store.getNodeChildrenCacheStats(),
CacheStatsMBean.TYPE,
- mk.getNodeChildrenCacheStats().getName())
+ store.getNodeChildrenCacheStats().getName())
);
registrations.add(
registerMBean(wb,
CacheStatsMBean.class,
- mk.getDiffCacheStats(),
+ store.getDiffCacheStats(),
CacheStatsMBean.TYPE,
- mk.getDiffCacheStats().getName())
- );
+ store.getDiffCacheStats().getName()));
registrations.add(
registerMBean(wb,
CacheStatsMBean.class,
- mk.getDocChildrenCacheStats(),
+ store.getDocChildrenCacheStats(),
CacheStatsMBean.TYPE,
- mk.getDocChildrenCacheStats().getName())
+ store.getDocChildrenCacheStats().getName())
);
- DocumentStore ds = mk.getDocumentStore();
+ DocumentStore ds = store.getDocumentStore();
if (ds instanceof MongoDocumentStore) {
MongoDocumentStore mds = (MongoDocumentStore) ds;
registrations.add(