Index: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (revision 1450177) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (working copy) @@ -65,7 +65,7 @@ /** * Maximum number of child nodes kept in memory. */ - static final int MAX_CHILD_NODE_NAMES = 10000; + static final int MAX_CHILD_NODE_NAMES = 1000; private final MicroKernel kernel; @@ -278,11 +278,12 @@ return; // no differences } else if (id != null && id.equals(kbase.id)) { return; // no differences - } else if (path.equals(kbase.path) && !path.equals("/")) { + } else if (path.equals(kbase.path) + && childNodeCount > MAX_CHILD_NODE_NAMES) { + // use MK.diff() when there are 'many' child nodes String jsonDiff = kernel.diff(kbase.getRevision(), revision, path, 0); - if (!hasChanges(jsonDiff)) { - return; // no differences - } + processJsonDiff(jsonDiff, kbase, diff); + return; } } } @@ -349,6 +350,81 @@ return !journal.trim().isEmpty(); } + /** + * Process the given JSON diff, which is the diff of of the base + * node state to this node state. + * + * @param jsonDiff the JSON diff. + * @param base the base node state. + * @param diff where diffs are reported to. + */ + private void processJsonDiff(String jsonDiff, + KernelNodeState base, + NodeStateDiff diff) { + if (!hasChanges(jsonDiff)) { + return; + } + comparePropertiesAgainstBaseState(base, diff); + JsopTokenizer t = new JsopTokenizer(jsonDiff); + while (true) { + 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); + diff.childNodeAdded(name, getChildNode(name)); + break; + } + case '-': { + String path = t.readString(); + String name = PathUtils.getName(path); + diff.childNodeDeleted(name, base.getChildNode(name)); + break; + } + case '^': { + String path = t.readString(); + t.read(':'); + if (t.matches('{')) { + t.read('}'); + String name = PathUtils.getName(path); + 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); + diff.childNodeDeleted(fromName, base.getChildNode(fromName)); + String toName = PathUtils.getName(to); + diff.childNodeAdded(toName, getChildNode(toName)); + break; + } + default: + throw new IllegalArgumentException("jsonDiff: illegal token '" + + t.getToken() + "' at pos: " + t.getLastPos() + " " + jsonDiff); + } + } + } + private Iterable getChildNodeEntries( final long offset, final int count) { return new Iterable() { Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java (revision 1450177) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java (working copy) @@ -98,25 +98,7 @@ */ @Override public void compareAgainstBaseState(NodeState base, NodeStateDiff diff) { - Set baseProperties = new HashSet(); - for (PropertyState beforeProperty : base.getProperties()) { - String name = beforeProperty.getName(); - PropertyState afterProperty = getProperty(name); - if (afterProperty == null) { - diff.propertyDeleted(beforeProperty); - } else { - baseProperties.add(name); - if (!beforeProperty.equals(afterProperty)) { - diff.propertyChanged(beforeProperty, afterProperty); - } - } - } - for (PropertyState afterProperty : getProperties()) { - if (!baseProperties.contains(afterProperty.getName())) { - diff.propertyAdded(afterProperty); - } - } - + comparePropertiesAgainstBaseState(base, diff); Set baseChildNodes = new HashSet(); for (ChildNodeEntry beforeCNE : base.getChildNodeEntries()) { String name = beforeCNE.getName(); @@ -219,6 +201,35 @@ return 0; } + /** + * Compares the properties of base state with this + * state. + * + * @param base the base node state. + * @param diff the node state diff. + */ + protected void comparePropertiesAgainstBaseState(NodeState base, + NodeStateDiff diff) { + Set baseProperties = new HashSet(); + for (PropertyState beforeProperty : base.getProperties()) { + String name = beforeProperty.getName(); + PropertyState afterProperty = getProperty(name); + if (afterProperty == null) { + diff.propertyDeleted(beforeProperty); + } else { + baseProperties.add(name); + if (!beforeProperty.equals(afterProperty)) { + diff.propertyChanged(beforeProperty, afterProperty); + } + } + } + for (PropertyState afterProperty : getProperties()) { + if (!baseProperties.contains(afterProperty.getName())) { + diff.propertyAdded(afterProperty); + } + } + } + //-----------------------------------------------------------< private >-- private static long count(Iterable iterable) {