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 md...@apache.org on 2012/05/21 19:37:45 UTC
svn commit: r1341123 - in /jackrabbit/oak/trunk:
oak-core/src/main/java/org/apache/jackrabbit/oak/api/
oak-core/src/main/java/org/apache/jackrabbit/oak/core/
oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/
oak-jcr/src/main/java/org/apache/jack...
Author: mduerig
Date: Mon May 21 17:37:44 2012
New Revision: 1341123
URL: http://svn.apache.org/viewvc?rev=1341123&view=rev
Log:
OAK-106: Use NodeStateBuilder instances to record changes in TreeImpl
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyDelegate.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java?rev=1341123&r1=1341122&r2=1341123&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Root.java Mon May 21 17:37:44 2012
@@ -64,9 +64,9 @@ public interface Root {
void rebase();
/**
- * Clear all changes made to this root
+ * Reverts all changes made to this root.
*/
- void clear();
+ void revert();
/**
* Atomically apply all changes made to the tree beneath this root to the
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java?rev=1341123&r1=1341122&r2=1341123&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java Mon May 21 17:37:44 2012
@@ -42,6 +42,12 @@ import static org.apache.jackrabbit.oak.
public class RootImpl implements Root {
static final Logger log = LoggerFactory.getLogger(RootImpl.class);
+ /**
+ * Number of {@link #setWorkspaceRootState(NodeState)} calls for which changes
+ * are kept in memory.
+ */
+ private static final int PURGE_LIMIT = 100;
+
/** The underlying store to which this root belongs */
private final NodeStore store;
@@ -54,6 +60,35 @@ public class RootImpl implements Root {
/** Current branch this root operates on */
private NodeStoreBranch branch;
+ /** Lazily initialised builder for the root node state of this workspace */
+ private NodeStateBuilder workspaceBuilder;
+
+ /**
+ * Number of {@link #setWorkspaceRootState(NodeState)} occurred so since the lase
+ * purge.
+ */
+ private int modCount;
+
+ /**
+ * Listeners which needs to be modified as soon as {@link #purgePendingChanges()}
+ * is called. Listeners are removed from this list after being called. If further
+ * notifications are required, they need to explicitly re-register.
+ *
+ * The {@link TreeImpl} instances us this mechanism to dispose of its associated
+ * {@link NodeStateBuilder} on purge. Keeping a reference on those {@code TreeImpl}
+ * instances {@code NodeStateBuilder} (i.e. those which are modified) prevents them
+ * from being prematurely garbage collected.
+ */
+ private List<PurgeListener> purgePurgeListeners = new ArrayList<PurgeListener>();
+
+ /**
+ * Purge listener.
+ * @see #purgePurgeListeners
+ */
+ public interface PurgeListener {
+ void purged();
+ }
+
/**
* New instance bases on a given {@link NodeStore} and a workspace
* @param store node store
@@ -68,6 +103,7 @@ public class RootImpl implements Root {
@Override
public boolean move(String sourcePath, String destPath) {
+ purgePendingChanges();
TreeImpl source = getChild(sourcePath);
if (source == null) {
return false;
@@ -92,6 +128,7 @@ public class RootImpl implements Root {
@Override
public boolean copy(String sourcePath, String destPath) {
+ purgePendingChanges();
return branch.copy(
PathUtils.concat(workspaceName, sourcePath),
PathUtils.concat(workspaceName, destPath));
@@ -104,7 +141,7 @@ public class RootImpl implements Root {
@Override
public void rebase() {
- root.clear();
+ purgePendingChanges();
NodeState base = getWorkspaceBaseState();
NodeState head = getWorkspaceRootState();
branch = store.branch();
@@ -112,21 +149,35 @@ public class RootImpl implements Root {
}
@Override
- public void clear() {
- root.clear();
- branch = store.branch();
+ public void revert() {
+ workspaceBuilder = null;
+ root.revert();
}
@Override
public void commit() throws CommitFailedException {
+ purgePendingChanges();
+ NodeState base = getWorkspaceRootState();
branch.merge();
- root.clear();
branch = store.branch();
+ root.saved();
+ NodeState head = getWorkspaceRootState();
+ merge(base, head, getRoot());
}
@Override
public boolean hasPendingChanges() {
- return !branch.getBase().equals(branch.getRoot());
+ return !getWorkspaceBaseState().equals(getWorkspaceRootState());
+ }
+
+ /**
+ * Add a {@code PurgeListener} to this instance. Listeners are automatically
+ * unregistered after having been called. If further notifications are required,
+ * they need to explicitly re-register.
+ * @param purgeListener listener
+ */
+ public void addListener(PurgeListener purgeListener) {
+ purgePurgeListeners.add(purgeListener);
}
/**
@@ -134,7 +185,9 @@ public class RootImpl implements Root {
* @return root node state
*/
public NodeState getWorkspaceRootState() {
- return branch.getRoot().getChildNode(workspaceName);
+ return workspaceBuilder == null
+ ? branch.getRoot().getChildNode(workspaceName)
+ : workspaceBuilder.getNodeState();
}
/**
@@ -164,9 +217,23 @@ public class RootImpl implements Root {
* @param nodeState node state representing the modified workspace
*/
public void setWorkspaceRootState(NodeState nodeState) {
- NodeStateBuilder builder = getBuilder(branch.getRoot());
- builder.setNode(workspaceName, nodeState);
- branch.setRoot(builder.getNodeState());
+ getWorkspaceBuilder().setNode(workspaceName, nodeState);
+ modCount++;
+ if (needsPurging()) {
+ purgePendingChanges();
+ }
+ }
+
+ /**
+ * Purge all pending changes to the underlying {@link NodeStoreBranch}.
+ * All registered {@link PurgeListener}s are notified.
+ */
+ public void purgePendingChanges() {
+ if (workspaceBuilder != null) {
+ branch.setRoot(workspaceBuilder.getNodeState());
+ workspaceBuilder = null;
+ notifyListeners();
+ }
}
/**
@@ -184,6 +251,38 @@ public class RootImpl implements Root {
//------------------------------------------------------------< private >---
+ // TODO better way to determine purge limit
+ private boolean needsPurging() {
+ if (modCount > PURGE_LIMIT) {
+ modCount = 0;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ /**
+ * Lazily initialise the {@code NodeStateBuilder} associated with the
+ * root node of the current workspace.
+ * @return
+ */
+ private synchronized NodeStateBuilder getWorkspaceBuilder() {
+ if (workspaceBuilder == null) {
+ workspaceBuilder = getBuilder(branch.getRoot());
+ }
+ return workspaceBuilder;
+ }
+
+ private void notifyListeners() {
+ List<PurgeListener> purgeListeners = this.purgePurgeListeners;
+ this.purgePurgeListeners = new ArrayList<PurgeListener>();
+
+ for (PurgeListener purgeListener : purgeListeners) {
+ purgeListener.purged();
+ }
+ }
+
private TreeImpl getRoot() {
return root;
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java?rev=1341123&r1=1341122&r2=1341123&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java Mon May 21 17:37:44 2012
@@ -22,6 +22,7 @@ import org.apache.commons.collections.ma
import org.apache.jackrabbit.oak.api.CoreValue;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.core.RootImpl.PurgeListener;
import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStateBuilder;
@@ -38,7 +39,7 @@ import java.util.concurrent.locks.Reentr
import static org.apache.jackrabbit.oak.plugins.memory.MemoryNodeState.EMPTY_NODE;
-public class TreeImpl implements Tree {
+public class TreeImpl implements Tree, PurgeListener {
/** Underlying {@code Root} of this {@code Tree} instance */
private final RootImpl root;
@@ -49,6 +50,9 @@ public class TreeImpl implements Tree {
/** Name of this tree */
private String name;
+ /** Lazily initialised {@code NodeStateBuilder} for the underyling node state */
+ protected NodeStateBuilder nodeStateBuilder;
+
private final Children children = new Children();
private TreeImpl(RootImpl root, TreeImpl parent, String name) {
@@ -60,13 +64,15 @@ public class TreeImpl implements Tree {
static TreeImpl createRoot(final RootImpl root) {
return new TreeImpl(root, null, "") {
@Override
- protected NodeState getNodeState() {
- return root.getWorkspaceRootState();
+ protected NodeState getBaseState() {
+ return root.getWorkspaceBaseState();
}
@Override
- protected NodeState getBaseState() {
- return root.getWorkspaceBaseState();
+ protected NodeState getNodeState() {
+ return nodeStateBuilder == null
+ ? root.getWorkspaceRootState()
+ : nodeStateBuilder.getNodeState();
}
@Override
@@ -322,18 +328,49 @@ public class TreeImpl implements Tree {
return true;
}
- //------------------------------------------------------------< protected >---
+ //------------------------------------------------------------< internal >---
- protected NodeState getNodeState() {
- return parent.getNodeState().getChildNode(name);
+ /**
+ * Revert all changes to this instance and its child instances.
+ */
+ public void revert() {
+ for (TreeImpl child : children) {
+ // TODO revert changes done to this instance
+ child.revert();
+ }
+ nodeStateBuilder = null;
+ children.clear();
+ }
+
+ /**
+ * Remove revert info for this instance and all its child instances.
+ */
+ public void saved() {
+ for (TreeImpl child : children) {
+ // TODO clear records of changes done to this instance
+ child.saved();
+ }
+ nodeStateBuilder = null;
+ children.clear();
}
+ //------------------------------------------------------------< RootImpl.Listener >---
+
+ @Override
+ public void purged() {
+ nodeStateBuilder = null;
+ }
+
+ //------------------------------------------------------------< protected >---
+
protected NodeState getBaseState() {
return parent.getBaseState().getChildNode(name);
}
- protected NodeStateBuilder getNodeStateBuilder() {
- return root.getBuilder(getNodeState());
+ protected NodeState getNodeState() {
+ return nodeStateBuilder == null
+ ? parent.getNodeState().getChildNode(name)
+ : nodeStateBuilder.getNodeState();
}
protected void updateParentState(NodeState childState) {
@@ -342,14 +379,16 @@ public class TreeImpl implements Tree {
parent.updateParentState(parentBuilder.getNodeState());
}
- //------------------------------------------------------------< internal >---
+ //------------------------------------------------------------< private >---
- void clear() {
- children.clear();
+ private synchronized NodeStateBuilder getNodeStateBuilder() {
+ if (nodeStateBuilder == null) {
+ nodeStateBuilder = root.getBuilder(getNodeState());
+ root.addListener(this);
+ }
+ return nodeStateBuilder;
}
- //------------------------------------------------------------< private >---
-
private void buildPath(StringBuilder sb) {
if (parent != null) {
parent.buildPath(sb);
@@ -397,7 +436,7 @@ public class TreeImpl implements Tree {
return !isDirty[0];
}
- private static class Children {
+ private static class Children implements Iterable<TreeImpl> {
@SuppressWarnings("unchecked")
private final Map<String, TreeImpl> children = new ReferenceMap();
private final Lock readLock;
@@ -437,11 +476,13 @@ public class TreeImpl implements Tree {
}
public void clear() {
- for (TreeImpl child : children.values()) {
- child.clear();
- }
children.clear();
}
+
+ @Override
+ public Iterator<TreeImpl> iterator() {
+ return children.values().iterator();
+ }
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java?rev=1341123&r1=1341122&r2=1341123&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java Mon May 21 17:37:44 2012
@@ -22,11 +22,6 @@ import static org.apache.jackrabbit.oak.
*/
class KernelNodeStoreBranch implements NodeStoreBranch {
- /**
- * Number of {@link #setRoot(NodeState)} for which changes are kept in memory.
- */
- private static final int PURGE_LIMIT = 100;
-
/** The underlying store to which this branch belongs */
private final KernelNodeStore store;
@@ -43,9 +38,6 @@ class KernelNodeStoreBranch implements N
/** Last state which was committed to this branch */
private NodeState committed;
- /** Number of {@link #setRoot(NodeState)} occurred so since the lase purge */
- private int modCount;
-
KernelNodeStoreBranch(KernelNodeStore store) {
this.store = store;
@@ -69,10 +61,7 @@ class KernelNodeStoreBranch implements N
@Override
public void setRoot(NodeState newRoot) {
currentRoot = newRoot;
- modCount++;
- if (needsPurging()) {
- purge(buildJsop());
- }
+ save(buildJsop());
}
@Override
@@ -91,7 +80,7 @@ class KernelNodeStoreBranch implements N
return false;
}
- purge(buildJsop() + ">\"" + source + "\":\"" + target + '"');
+ save(buildJsop() + ">\"" + source + "\":\"" + target + '"');
return true;
}
@@ -111,13 +100,13 @@ class KernelNodeStoreBranch implements N
return false;
}
- purge(buildJsop() + "*\"" + source + "\":\"" + target + '"');
+ save(buildJsop() + "*\"" + source + "\":\"" + target + '"');
return true;
}
@Override
public KernelNodeState merge() throws CommitFailedException {
- purge(buildJsop());
+ save(buildJsop());
// TODO rebase, call commitHook (OAK-100)
MicroKernel kernel = getKernel();
String mergedRevision;
@@ -155,7 +144,7 @@ class KernelNodeStoreBranch implements N
return node;
}
- private void purge(String jsop) {
+ private void save(String jsop) {
MicroKernel kernel = getKernel();
branchRevision = kernel.commit("/", jsop, branchRevision, null);
currentRoot = new KernelNodeState(kernel, getValueFactory(), "/", branchRevision);
@@ -238,15 +227,4 @@ class KernelNodeStoreBranch implements N
}
});
}
-
- // TODO better way to determine purge limit
- private boolean needsPurging() {
- if (modCount > PURGE_LIMIT) {
- modCount = 0;
- return true;
- }
- else {
- return false;
- }
- }
}
Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java?rev=1341123&r1=1341122&r2=1341123&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java Mon May 21 17:37:44 2012
@@ -24,11 +24,10 @@ import org.apache.jackrabbit.oak.commons
import org.apache.jackrabbit.oak.util.Function1;
import org.apache.jackrabbit.oak.util.Iterators;
-import java.util.Iterator;
-import java.util.List;
-
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import java.util.Iterator;
+import java.util.List;
/**
* {@code NodeDelegate} serve as internal representations of {@code Node}s.
@@ -234,6 +233,7 @@ public class NodeDelegate extends ItemDe
}
private synchronized Tree getTree() {
+ // TODO: this should not be necessary anymore once TreeImpl.revert and TreeImpl.saved are implemented
return tree = sessionDelegate.getTree(tree.getPath());
}
Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyDelegate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyDelegate.java?rev=1341123&r1=1341122&r2=1341123&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyDelegate.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyDelegate.java Mon May 21 17:37:44 2012
@@ -242,6 +242,7 @@ public class PropertyDelegate extends It
}
private synchronized void resolve() {
+ // TODO: this should not be necessary anymore once TreeImpl.revert and TreeImpl.saved are implemented
parent = sessionDelegate.getTree(parent.getPath());
if (parent == null) {
Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java?rev=1341123&r1=1341122&r2=1341123&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java Mon May 21 17:37:44 2012
@@ -148,12 +148,10 @@ public class SessionDelegate {
}
public void refresh(boolean keepChanges) {
- if (keepChanges) {
- root.rebase();
- }
- else {
- root.clear();
+ if (!keepChanges) {
+ root.revert();
}
+ root.rebase();
}
/**