diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapEntry.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapEntry.java index 842fa58..849fe61 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapEntry.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapEntry.java @@ -60,7 +60,7 @@ class MapEntry extends AbstractChildNodeEntry @Override @Nonnull public SegmentNodeState getNodeState() { checkState(value != null); - return new SegmentNodeState(value); + return new SegmentNodeState(value, name); } //---------------------------------------------------------< Map.Entry >-- diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java index 30fe9d5..5e24b75 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java @@ -59,8 +59,16 @@ public class SegmentNodeState extends Record implements NodeState { private volatile Template template = null; + private final String name; + + @Deprecated public SegmentNodeState(RecordId id) { + this(id, null); + } + + public SegmentNodeState(RecordId id, String name) { super(id); + this.name = name; } RecordId getTemplateId() { @@ -376,8 +384,32 @@ public class SegmentNodeState extends Record implements NodeState { } } + private volatile String lastMissingChildNodeName = null; + private volatile SegmentNodeState lastChildNode = null; + @Override @Nonnull public NodeState getChildNode(@Nonnull String name) { + if (name.equals(lastMissingChildNodeName)) { + return MISSING_NODE; + } else { + SegmentNodeState lastChildNodeRefCopy = lastChildNode; + if (lastChildNodeRefCopy != null && name.equals(lastChildNodeRefCopy.name)) { + return lastChildNodeRefCopy; + } else { + SegmentNodeState childNode = internalGetChildNode(name); + if (childNode == null) { + checkValidName(name); + lastMissingChildNodeName = name; + return MISSING_NODE; + } else { + lastChildNode = childNode; + return childNode; + } + } + } + } + + private SegmentNodeState internalGetChildNode(@Nonnull String name) { String childName = getTemplate().getChildName(); if (childName == Template.MANY_CHILD_NODES) { MapEntry child = getChildNodeMap().getEntry(name); @@ -388,10 +420,9 @@ public class SegmentNodeState extends Record implements NodeState { && childName.equals(name)) { Segment segment = getSegment(); RecordId childNodeId = segment.readRecordId(getOffset(0, 1)); - return new SegmentNodeState(childNodeId); + return new SegmentNodeState(childNodeId, name); } - checkValidName(name); - return MISSING_NODE; + return null; } @Override @Nonnull