You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2012/10/20 23:38:25 UTC
svn commit: r1400521 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java
Author: jukka
Date: Sat Oct 20 21:38:25 2012
New Revision: 1400521
URL: http://svn.apache.org/viewvc?rev=1400521&view=rev
Log:
OAK-170: Child node state builder
Improved state tracking in node builders, including internal
revision counters to optimize the common case where no changes
have been made.
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java?rev=1400521&r1=1400520&r2=1400521&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java Sat Oct 20 21:38:25 2012
@@ -76,16 +76,28 @@ public class MemoryNodeBuilder implement
ImmutableMap.<String, NodeState>of());
/**
- * Parent state builder reference, or {@code null} once this builder
- * has been connected.
+ * Parent builder, or {@code null} for a root builder.
*/
- private MemoryNodeBuilder parent;
+ private final MemoryNodeBuilder parent;
/**
- * Name of this child node within the parent builder, or {@code null}
- * once this builder has been connected.
+ * Name of this child node within the parent builder,
+ * or {@code null} for a root builder.
*/
- private String name;
+ private final String name;
+
+ /**
+ * Root builder, or {@code this} for the root itself.
+ */
+ private final MemoryNodeBuilder root;
+
+ /**
+ * Internal revision counter that is incremented in the root builder
+ * whenever anything changes in the tree below. Each builder instance
+ * has its own copy of the revision counter, for quickly checking whether
+ * any state changes are needed.
+ */
+ private long revision;
/**
* The read state of this builder. Originally the immutable base state
@@ -111,6 +123,10 @@ public class MemoryNodeBuilder implement
MemoryNodeBuilder parent, String name, NodeState base) {
this.parent = checkNotNull(parent);
this.name = checkNotNull(name);
+
+ this.root = parent.root;
+ this.revision = parent.revision;
+
this.readState = checkNotNull(base);
this.writeState = null;
}
@@ -123,51 +139,60 @@ public class MemoryNodeBuilder implement
public MemoryNodeBuilder(NodeState base) {
this.parent = null;
this.name = null;
+
+ this.root = this;
+ this.revision = 0;
+
MutableNodeState mstate = new MutableNodeState(checkNotNull(base));
this.readState = mstate;
this.writeState = mstate;
}
private NodeState read() {
- if (writeState == null) {
+ if (revision != root.revision) {
+ assert(parent != null); // root never gets here
parent.read();
MutableNodeState pstate = parent.writeState;
if (pstate != null) {
MutableNodeState mstate = pstate.nodes.get(name);
- if (mstate == null && pstate.nodes.containsKey(name)) {
- throw new IllegalStateException(
- "This builder refers to a node that has"
- + " been removed from its parent.");
- }
- if (mstate != null) {
- parent = null;
- name = null;
+ if (mstate == null) {
+ if (pstate.nodes.containsKey(name)) {
+ throw new IllegalStateException(
+ "This node has been removed.");
+ }
+ } else if (mstate != writeState) {
readState = mstate;
writeState = mstate;
}
}
+ revision = root.revision;
}
return readState;
}
private MutableNodeState write() {
- if (writeState == null) {
- MutableNodeState pstate = parent.write();
+ return write(root.revision + 1);
+ }
+
+ private MutableNodeState write(long newRevision) {
+ if (writeState == null || revision != root.revision) {
+ assert(parent != null); // root never gets here
+ MutableNodeState pstate = parent.write(newRevision);
MutableNodeState mstate = pstate.nodes.get(name);
if (mstate == null) {
if (pstate.nodes.containsKey(name)) {
throw new IllegalStateException(
- "This builder refers to a node that has"
- + " been removed from its parent.");
+ "This node has been removed.");
}
mstate = new MutableNodeState(readState);
pstate.nodes.put(name, mstate);
}
- parent = null;
- name = null;
- readState = mstate;
- writeState = mstate;
+ if (mstate != writeState) {
+ readState = mstate;
+ writeState = mstate;
+ }
}
+ revision = newRevision;
return writeState;
}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java?rev=1400521&r1=1400520&r2=1400521&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java Sat Oct 20 21:38:25 2012
@@ -60,10 +60,10 @@ public class MemoryNodeBuilderTest {
NodeBuilder childB = root.child("x");
childB.setProperty("test", "foo");
+
childA.setProperty("test", "bar");
- assertEquals(
- "bar",
- childB.getProperty("test").getValue(STRING));
+ assertEquals("bar", childA.getProperty("test").getValue(STRING));
+ assertEquals("bar", childB.getProperty("test").getValue(STRING));
}
@Test
@@ -73,8 +73,14 @@ public class MemoryNodeBuilderTest {
NodeBuilder childB = root.child("x");
childB.setProperty("test", "foo");
+
childA.removeProperty("test");
+ assertNull(childA.getProperty("test"));
assertNull(childB.getProperty("test"));
+
+ childA.setProperty("test", "bar");
+ assertEquals("bar", childA.getProperty("test").getValue(STRING));
+ assertEquals("bar", childB.getProperty("test").getValue(STRING));
}
@Test
@@ -84,18 +90,28 @@ public class MemoryNodeBuilderTest {
NodeBuilder childB = root.child("x");
assertFalse(childA.hasChildNode("test"));
+ assertFalse(childB.hasChildNode("test"));
+
childB.child("test");
assertTrue(childA.hasChildNode("test"));
+ assertTrue(childB.hasChildNode("test"));
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testConnectOnRemoveNode() {
NodeBuilder root = new MemoryNodeBuilder(BASE);
NodeBuilder child = root.child("x");
root.removeNode("x");
- child.getChildNodeCount(); // should throw ISE
- fail();
+ try {
+ child.getChildNodeCount();
+ fail();
+ } catch (IllegalStateException e) {
+ // expected
+ }
+
+ root.child("x");
+ assertEquals(0, child.getChildNodeCount()); // reconnect!
}
}