Author: manik.surtani(a)jboss.com
Date: 2008-07-28 06:56:29 -0400 (Mon, 28 Jul 2008)
New Revision: 6414
Added:
core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/LegacyGravitateDataCommand.java
core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommand.java
core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferGenerator.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferIntegrator.java
core/trunk/src/test/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommandTest.java
core/trunk/src/test/java/org/jboss/cache/profiling/MemoryFootprintTest.java
Removed:
core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java
core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java
Modified:
core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java
core/trunk/src/main/java/org/jboss/cache/DataContainer.java
core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java
core/trunk/src/main/java/org/jboss/cache/InternalNode.java
core/trunk/src/main/java/org/jboss/cache/NodeFactory.java
core/trunk/src/main/java/org/jboss/cache/NodeSPI.java
core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java
core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java
core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
core/trunk/src/main/java/org/jboss/cache/commands/OptimisticCommandsFactoryImpl.java
core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/PessGetChildrenNamesCommand.java
core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/LegacyEvictCommand.java
core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java
core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java
core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java
core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java
core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java
core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java
core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
core/trunk/src/main/java/org/jboss/cache/invocation/NodeInvocationDelegate.java
core/trunk/src/main/java/org/jboss/cache/lock/LockUtil.java
core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java
core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java
core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java
core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java
core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java
core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java
core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNode.java
core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNodeImpl.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferManager.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferManager.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferGenerator.java
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferIntegrator.java
core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java
core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java
core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java
core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java
core/trunk/src/test/java/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java
core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java
core/trunk/src/test/java/org/jboss/cache/statetransfer/StateTransferTestBase.java
core/trunk/src/test/java/org/jboss/cache/util/ImmutableListCopyTest.java
core/trunk/src/test/java/org/jboss/cache/util/TestingUtil.java
Log:
Whole bunch of performance enhancements and bug fixes
Modified: core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/AbstractNode.java 2008-07-28 10:29:41 UTC
(rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/AbstractNode.java 2008-07-28 10:56:29 UTC
(rev 6414)
@@ -5,7 +5,13 @@
import static org.jboss.cache.AbstractNode.NodeFlags.REMOVED;
import static org.jboss.cache.AbstractNode.NodeFlags.RESIDENT;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.lock.IdentityLock;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentMap;
/**
@@ -15,7 +21,8 @@
*/
public abstract class AbstractNode<K, V>
{
- protected volatile ConcurrentMap<Object, Node<K, V>> children;
+ protected volatile ConcurrentMap children; // purposefully NOT genericized yet, since
UnversionedNode and PessimisticUnversionedNode will both store different types.
+
protected Fqn fqn;
/**
* Flags placed on the node. Replaces older 'boolean' flags.
@@ -133,36 +140,38 @@
return isFlagSet(REMOVED);
}
+ public void setResident(boolean resident)
+ {
+ setFlag(RESIDENT, resident);
+ }
+
public void setRemoved(boolean marker)
{
markAsRemoved(marker, false);
}
- public void markAsRemoved(boolean marker, boolean recursive)
+ public abstract void markAsRemoved(boolean marker, boolean recursive);
+
+ public boolean isResident()
{
- setFlag(REMOVED, marker);
+ return isFlagSet(RESIDENT);
+ }
- if (recursive && children != null)
- {
- synchronized (this)
- {
- for (Node<?, ?> child : children.values())
- {
- ((NodeSPI) child).markAsDeleted(marker, true);
- }
- }
- }
+ @SuppressWarnings("deprecation")
+ public IdentityLock getLock()
+ {
+ throw new UnsupportedOperationException("Not supported in this
implementation!");
}
- public void setResident(boolean resident)
+ // versioning
+ public void setVersion(DataVersion version)
{
- setFlag(RESIDENT, resident);
+ throw new UnsupportedOperationException("Versioning not supported");
}
-
- public boolean isResident()
+ public DataVersion getVersion()
{
- return isFlagSet(RESIDENT);
+ throw new UnsupportedOperationException("Versioning not supported");
}
@Override
@@ -181,4 +190,126 @@
{
return fqn.hashCode();
}
+
+ // ----- default no-op impls of child manipulation methods
+
+ public InternalNode<K, V> getChild(Fqn f)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public InternalNode<K, V> getChild(Object childName)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public Set<InternalNode<K, V>> getChildren()
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public Set<InternalNode<K, V>> getChildren(boolean
includeMarkedForRemoval)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public Map<Object, InternalNode<K, V>> getChildrenMap()
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public void addChild(Object nodeName, InternalNode<K, V> nodeToAdd)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public void addChild(InternalNode<K, V> child)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public InternalNode<K, V> addChild(Fqn f)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public InternalNode<K, V> addChild(Fqn f, boolean notify)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public InternalNode<K, V> addChild(Object o, boolean notify)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public void setChildrenMap(ConcurrentMap<Object, InternalNode<K, V>>
children)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public InternalNode<K, V> getOrCreateChild(Object childName, InvocationContext
ctx)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public NodeSPI<K, V> getChildDirect(Fqn fqn)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public NodeSPI<K, V> getChildDirect(Object childName)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public Set<NodeSPI<K, V>> getChildrenDirect()
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public Set<NodeSPI<K, V>> getChildrenDirect(boolean
includeMarkedForRemoval)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public Map<Object, Node<K, V>> getChildrenMapDirect()
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public void addChildDirect(Object nodeName, Node<K, V> nodeToAdd)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public void addChildDirect(NodeSPI<K, V> child)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public NodeSPI<K, V> addChildDirect(Fqn f)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public NodeSPI<K, V> addChildDirect(Fqn f, boolean notify)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public NodeSPI<K, V> addChildDirect(Object o, boolean notify)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
+
+ public NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx)
+ {
+ throw new UnsupportedOperationException("Not supported in " +
getClass().getSimpleName());
+ }
}
Modified: core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java 2008-07-28 10:29:41
UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java 2008-07-28 10:56:29
UTC (rev 6414)
@@ -85,6 +85,11 @@
return initializeNodeInvocationDelegate(internal);
}
+ public InternalNode<K, V> createInternalNode(Fqn fqn)
+ {
+ throw new UnsupportedOperationException("Unsupported in this implementation
(" + getClass().getSimpleName() + ")!");
+ }
+
public NodeSPI<K, V> createNode(Object childName, NodeSPI<K, V> parent)
{
UnversionedNode<K, V> internal = createInternalNode(childName,
Fqn.fromRelativeElements(parent.getFqn(), childName), parent, null);
@@ -111,7 +116,7 @@
return createNode(Fqn.ROOT, null);
}
- public NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V>
internalNode, boolean wrapWithNodeReference)
+ private NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V>
internalNode, boolean wrapWithNodeReference)
{
if (wrapWithNodeReference)
throw new UnsupportedOperationException("wrapWithNodeReferences is not
supported in this impl!");
@@ -121,7 +126,7 @@
return nid;
}
- public NodeSPI<K, V> createAndRegister(Fqn fqn, NodeSPI<K, V> parent,
InvocationContext ctx, boolean attachToParent)
+ public InternalNode<K, V> createAndRegister(Fqn fqn, InternalNode<K, V>
parent, InvocationContext ctx, boolean attachToParent)
{
throw new UnsupportedOperationException("Unsupported in this implementation
(" + getClass().getSimpleName() + ")!");
}
Modified: core/trunk/src/main/java/org/jboss/cache/DataContainer.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainer.java 2008-07-28 10:29:41 UTC
(rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainer.java 2008-07-28 10:56:29 UTC
(rev 6414)
@@ -34,7 +34,9 @@
*
* @param fqn Fully qualified name for the corresponding node.
* @return Node referenced by the given Fqn, or null if the node cannot be found or if
there is an exception.
+ * @deprecated Note that this only supports legacy locking schemes (OL and PL) and
will be removed when those schemes are removed.
*/
+ @Deprecated
NodeSPI peek(Fqn fqn);
/**
@@ -43,7 +45,9 @@
* @param fqn Fqn to find
* @param includeDeletedNodes if true, deleted nodes are considered
* @return the node, if found, or null otherwise.
+ * @deprecated Note that this only supports legacy locking schemes (OL and PL) and
will be removed when those schemes are removed.
*/
+ @Deprecated
NodeSPI peek(Fqn fqn, boolean includeDeletedNodes);
/**
@@ -54,7 +58,9 @@
* @param includeDeletedNodes if true, deleted nodes are also considered
* @param includeInvalidNodes if true, invalid nodes are also considered
* @return the node, if found, or null otherwise.
+ * @deprecated Note that this only supports legacy locking schemes (OL and PL) and
will be removed when those schemes are removed.
*/
+ @Deprecated
NodeSPI peek(Fqn fqn, boolean includeDeletedNodes, boolean includeInvalidNodes);
/**
@@ -188,5 +194,12 @@
*
* @param nodeInvocationDelegate
*/
- void setRoot(NodeSPI nodeInvocationDelegate);
+ // TODO: 3.0.0: FIx this so that it can take in a NodeSPI for OL/PL and an
InternalNode for MVCC
+ void setRoot(Object nodeInvocationDelegate);
+
+ /**
+ * @param fqn fqn to check
+ * @return true if the node exists and is marked as resident, false otherwise.
+ */
+ boolean isResident(Fqn fqn);
}
Modified: core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java 2008-07-28 10:29:41
UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java 2008-07-28 10:56:29
UTC (rev 6414)
@@ -3,6 +3,8 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.factories.annotations.NonVolatile;
import org.jboss.cache.factories.annotations.Start;
@@ -33,7 +35,8 @@
/**
* Root node.
*/
- private volatile NodeSPI root;
+ private volatile NodeInvocationDelegate root;
+ private volatile InternalNode rootInternal;
/**
* Set<Fqn> of Fqns of the topmost node of internal regions that should
@@ -43,9 +46,11 @@
private NodeFactory nodeFactory;
private LockManager lockManager;
private BuddyFqnTransformer buddyFqnTransformer;
+ private Configuration config;
+ private boolean usingMvcc;
@Inject
- public void injectDependencies(NodeFactory nodeFactory, LockManager lockManager,
BuddyFqnTransformer transformer)
+ public void injectDependencies(NodeFactory nodeFactory, LockManager lockManager,
BuddyFqnTransformer transformer, Configuration configuration)
{
setDependencies(nodeFactory, lockManager);
@@ -55,6 +60,7 @@
//TODO - remove setDependencies method at this point
createRootNode();
this.buddyFqnTransformer = transformer;
+ config = configuration;
}
public void setDependencies(NodeFactory nodeFactory, LockManager lockManager)
@@ -66,29 +72,42 @@
@Start(priority = 12)
public void createRootNode()
{
- if (trace) log.trace("Starting data container");
+ usingMvcc = config != null && config.getNodeLockingScheme() ==
NodeLockingScheme.MVCC;
+ if (trace) log.trace("Starting data container. Using MVCC? " +
usingMvcc);
// create a new root temporarily.
NodeSPI tempRoot = nodeFactory.createRootNode();
// if we don't already have a root or the new (temp) root is of a different
class (optimistic vs pessimistic) to
// the current root, then we use the new one.
- Class currentRootType = root == null ? null : ((NodeInvocationDelegate)
root).getDelegationTarget().getClass();
- Class tempRootType = ((NodeInvocationDelegate)
tempRoot).getDelegationTarget().getClass();
+ Class currentRootType = root == null ? null :
root.getDelegationTarget().getClass();
+ Class tempRootType = tempRoot.getDelegationTarget().getClass();
if (!tempRootType.equals(currentRootType))
{
if (trace) log.trace("Setting root node to an instance of " +
tempRootType);
setRoot(tempRoot);
}
- root.setChildrenLoaded(true);
+
+ if (usingMvcc && rootInternal == null) setRoot(root); // sets the
"internal root"
+
+ if (root != null) root.setChildrenLoaded(true);
+ if (rootInternal != null) rootInternal.setChildrenLoaded(true);
}
@Stop(priority = 100)
public void stop()
{
// empty in-memory state
- root.clearDataDirect();
- root.removeChildrenDirect();
+ if (root != null)
+ {
+ root.clearDataDirect();
+ root.removeChildrenDirect();
+ }
+ else if (rootInternal != null)
+ {
+ rootInternal.clear();
+ rootInternal.removeChildren();
+ }
}
public NodeSPI getRoot()
@@ -101,13 +120,42 @@
*
* @param root node
*/
- public void setRoot(NodeSPI root)
+ public void setRoot(Object root)
{
- if (root == null || !root.getFqn().isRoot())
- throw new CacheException("Attempting to set an invalid node [" + root
+ "] as a root node!");
- this.root = root;
+ if (root == null) throw new CacheException("Attempting to set an invalid node
[" + root + "] as a root node!");
+ // Mega-Ugh!
+ if (usingMvcc && root instanceof InternalNode)
+ {
+ if (log.isDebugEnabled()) log.debug("Setting rootInternal to " +
root);
+ rootInternal = (InternalNode) root;
+ this.root = null;
+ }
+ else
+ {
+ this.root = (NodeInvocationDelegate) root;
+ if (usingMvcc)
+ {
+ if (log.isDebugEnabled()) log.debug("Setting rootInternal to " +
this.root.getDelegationTarget());
+ rootInternal = this.root.getDelegationTarget();
+ this.root = null;
+ }
+ }
}
+ public boolean isResident(Fqn fqn)
+ {
+ if (usingMvcc)
+ {
+ InternalNode in = peekInternalNode(fqn, false);
+ return in != null && in.isResident();
+ }
+ else
+ {
+ NodeSPI<?, ?> nodeSPI = peek(fqn, false, false);
+ return nodeSPI != null && nodeSPI.isResident();
+ }
+ }
+
public void registerInternalFqn(Fqn fqn)
{
internalFqns.add(fqn);
@@ -150,15 +198,23 @@
public boolean exists(Fqn fqn)
{
- return peek(fqn, false, false) != null;
+ return usingMvcc ? peekInternalNode(fqn, false) != null : peek(fqn, false, false)
!= null;
}
public boolean hasChildren(Fqn fqn)
{
if (fqn == null) return false;
- NodeSPI n = peek(fqn);
- return n != null && n.hasChildrenDirect();
+ if (usingMvcc)
+ {
+ InternalNode in = peekInternalNode(fqn, false);
+ return in != null && in.hasChildren();
+ }
+ else
+ {
+ NodeSPI n = peek(fqn);
+ return n != null && n.hasChildrenDirect();
+ }
}
public List<NodeData> buildNodeData(List<NodeData> list, NodeSPI node,
boolean mapSafe)
@@ -175,31 +231,62 @@
public List<Fqn> getNodesForEviction(Fqn fqn, boolean recursive)
{
List<Fqn> result = new ArrayList<Fqn>();
- NodeSPI node = peek(fqn, false);
- if (recursive)
+ if (usingMvcc)
{
- if (node != null) recursiveAddEvictionNodes(node, result);
+ InternalNode node = peekInternalNode(fqn, false);
+ if (recursive)
+ {
+ if (node != null) recursiveAddEvictionNodes(node, result);
+ }
+ else
+ {
+ if (node == null)
+ {
+ result.add(fqn);
+ return result;
+ }
+ if (fqn.isRoot())
+ {
+ for (Object childName : node.getChildrenNames())
+ {
+ if (!node.isResident()) result.add(Fqn.fromRelativeElements(fqn,
childName));
+ }
+ }
+ else if (!node.isResident())
+ {
+ result.add(fqn);
+ }
+ }
+ return result;
}
else
{
- if (node == null)
+ NodeSPI node = peek(fqn, false);
+ if (recursive)
{
- result.add(fqn);
- return result;
+ if (node != null) recursiveAddEvictionNodes(node, result);
}
- if (fqn.isRoot())
+ else
{
- for (Object childName : node.getChildrenNamesDirect())
+ if (node == null)
{
- if (!node.isResident()) result.add(Fqn.fromRelativeElements(fqn,
childName));
+ result.add(fqn);
+ return result;
}
+ if (fqn.isRoot())
+ {
+ for (Object childName : node.getChildrenNamesDirect())
+ {
+ if (!node.isResident()) result.add(Fqn.fromRelativeElements(fqn,
childName));
+ }
+ }
+ else if (!node.isResident())
+ {
+ result.add(fqn);
+ }
}
- else if (!node.isResident())
- {
- result.add(fqn);
- }
+ return result;
}
- return result;
}
private void recursiveAddEvictionNodes(NodeSPI<?, ?> node, List<Fqn>
result)
@@ -215,6 +302,19 @@
}
}
+ private void recursiveAddEvictionNodes(InternalNode<?, ?> node, List<Fqn>
result)
+ {
+ for (InternalNode child : node.getChildren())
+ {
+ recursiveAddEvictionNodes(child, result);
+ }
+ Fqn fqn = node.getFqn();
+ if (!fqn.isRoot() && !node.isResident())
+ {
+ result.add(fqn);
+ }
+ }
+
@Override
public String toString()
{
@@ -306,7 +406,10 @@
public String printDetails()
{
StringBuilder sb = new StringBuilder();
- root.printDetails(sb, 0);
+ if (root == null)
+ rootInternal.printDetails(sb, 0);
+ else
+ root.printDetails(sb, 0);
sb.append("\n");
return sb.toString();
}
@@ -324,7 +427,7 @@
public int getNumberOfAttributes(Fqn fqn)
{
- return numAttributes(peek(fqn));
+ return usingMvcc ? numAttributes(peekInternalNode(fqn, false)) :
numAttributes(peek(fqn));
}
private int numAttributes(NodeSPI n)
@@ -338,13 +441,71 @@
return count;
}
+ private int numAttributes(InternalNode n)
+ {
+ int count = 0;
+ for (Object child : n.getChildren())
+ {
+ count += numAttributes((NodeSPI) child);
+ }
+ count += n.getData().size();
+ return count;
+ }
+
public int getNumberOfAttributes()
{
- return numAttributes(root);
+ return usingMvcc ? numAttributes(rootInternal) : numAttributes(root);
}
public boolean removeFromDataStructure(Fqn f, boolean skipMarkerCheck)
{
+ return usingMvcc ? removeMvcc(f, skipMarkerCheck) : removeLegacy(f,
skipMarkerCheck);
+ }
+
+ private boolean removeMvcc(Fqn f, boolean skipMarkerCheck)
+ {
+ InternalNode n = peekInternalNode(f, true);
+ if (n == null)
+ {
+ return false;
+ }
+
+ if (trace) log.trace("Performing a real remove for node " + f + ",
marked for removal.");
+ if (skipMarkerCheck || n.isRemoved())
+ {
+ if (n.getFqn().isRoot())
+ {
+ // do not actually delete; just remove deletion marker
+ n.setRemoved(true);
+
+ // mark the node to be removed (and all children) as invalid so anyone
holding a direct reference to it will
+ // be aware that it is no longer valid.
+ n.setValid(false, true);
+ n.setValid(true, false);
+
+ // but now remove all children, since the call has been to
remove("/")
+ n.removeChildren();
+ return true;
+ }
+ else
+ {
+ // mark the node to be removed (and all children) as invalid so anyone
holding a direct reference to it will
+ // be aware that it is no longer valid.
+ n.setValid(false, true);
+ InternalNode parent = peekInternalNode(f.getParent(), true);
+ return parent.removeChild(n.getFqn().getLastElement());
+ }
+ }
+ else
+ {
+ if (log.isDebugEnabled()) log.debug("Node " + f + " NOT marked
for removal as expected, not removing!");
+ return false;
+ }
+ }
+
+
+ private boolean removeLegacy(Fqn f, boolean skipMarkerCheck)
+ {
NodeSPI n = peek(f, true);
if (n == null)
{
@@ -395,23 +556,29 @@
public boolean evict(Fqn fqn)
{
- if (peek(fqn, false, true) == null) return true;
+ if (!exists(fqn)) return true;
if (hasChildren(fqn))
{
if (trace)
log.trace("removing DATA as node has children: evict(" + fqn +
")");
- removeData(fqn);
+ if (usingMvcc)
+ removeData(fqn);
+ else
+ removeDataLegacy(fqn);
return false;
}
else
{
if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn +
")");
- removeNode(fqn);
+ if (usingMvcc)
+ removeNode(fqn);
+ else
+ removeNodeLegacy(fqn);
return true;
}
}
- private void removeNode(Fqn fqn)
+ private void removeNodeLegacy(Fqn fqn)
{
NodeSPI targetNode = peek(fqn, false, true);
if (targetNode == null) return;
@@ -424,8 +591,21 @@
}
}
- private void removeData(Fqn fqn)
+ private void removeNode(Fqn fqn)
{
+ InternalNode targetNode = peekInternalNode(fqn, true);
+ if (targetNode == null) return;
+ InternalNode parentNode = peekInternalNode(fqn.getParent(), true);
+ targetNode.setValid(false, false);
+ if (parentNode != null)
+ {
+ parentNode.removeChild(fqn.getLastElement());
+ parentNode.setChildrenLoaded(false);
+ }
+ }
+
+ private void removeDataLegacy(Fqn fqn)
+ {
NodeSPI n = peek(fqn);
if (n == null)
{
@@ -436,6 +616,18 @@
n.setDataLoaded(false);
}
+ private void removeData(Fqn fqn)
+ {
+ InternalNode n = peekInternalNode(fqn, false);
+ if (n == null)
+ {
+ log.warn("node " + fqn + " not found");
+ return;
+ }
+ n.clear();
+ n.setDataLoaded(false);
+ }
+
public Object[] createNodes(Fqn fqn)
{
List<NodeSPI> result = new ArrayList<NodeSPI>(fqn.size());
@@ -465,12 +657,25 @@
return new Object[]{result, n};
}
- public InternalNode peekInternalNode(Fqn f, boolean includeInvalidNodes)
+ public InternalNode peekInternalNode(Fqn fqn, boolean includeInvalidNodes)
{
- // Yuck!
- NodeSPI nodeSPI = peek(f, false, includeInvalidNodes);
- if (nodeSPI == null) return null;
- return ((NodeInvocationDelegate) nodeSPI).getDelegationTarget();
+ if (fqn == null || fqn.size() == 0) return rootInternal;
+ InternalNode n = rootInternal;
+ int fqnSize = fqn.size();
+ for (int i = 0; i < fqnSize; i++)
+ {
+ Object obj = fqn.get(i);
+ n = n.getChild(obj);
+ if (n == null)
+ {
+ return null;
+ }
+ else if (!includeInvalidNodes && !n.isValid())
+ {
+ return null;
+ }
+ }
+ return n;
}
public void setBuddyFqnTransformer(BuddyFqnTransformer buddyFqnTransformer)
Modified: core/trunk/src/main/java/org/jboss/cache/InternalNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/InternalNode.java 2008-07-28 10:29:41 UTC
(rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/InternalNode.java 2008-07-28 10:56:29 UTC
(rev 6414)
@@ -1,11 +1,13 @@
package org.jboss.cache;
+import org.jboss.cache.invocation.InvocationContext;
import org.jboss.cache.lock.NodeLock;
import org.jboss.cache.optimistic.DataVersion;
import org.jboss.cache.transaction.GlobalTransaction;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
/**
* An internal node interface, that represents nodes that directly form the tree
structure in the cache. This is as opposed
@@ -57,36 +59,78 @@
boolean hasChildren();
- NodeSPI<K, V> getChild(Fqn fqn);
+ // ***************** Old legacy methods that assume that the child map maintained
contains NodeSPIs. These are still retained to support Optimistic and Pessimistic Locking
***************
- NodeSPI<K, V> getChild(Object childName);
+ @Deprecated
+ NodeSPI<K, V> getChildDirect(Fqn fqn);
- Set<NodeSPI<K, V>> getChildren();
+ @Deprecated
+ NodeSPI<K, V> getChildDirect(Object childName);
- Set<NodeSPI<K, V>> getChildren(boolean includeMarkedForRemoval);
+ @Deprecated
+ Set<NodeSPI<K, V>> getChildrenDirect();
+ @Deprecated
+ Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval);
+
+ @Deprecated
+ Map<Object, Node<K, V>> getChildrenMapDirect();
+
+ @Deprecated
+ void setChildrenMapDirect(Map<Object, Node<K, V>> children);
+
+ @Deprecated
+ void addChildDirect(Object nodeName, Node<K, V> nodeToAdd);
+
+ @Deprecated
+ void addChildDirect(NodeSPI<K, V> child);
+
+ @Deprecated
+ NodeSPI<K, V> addChildDirect(Fqn f);
+
+ @Deprecated
+ NodeSPI<K, V> addChildDirect(Fqn f, boolean notify);
+
+ @Deprecated
+ NodeSPI<K, V> addChildDirect(Object o, boolean notify);
+
/**
* @deprecated should use the {@link org.jboss.cache.NodeFactory} instead.
*/
@Deprecated
NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx);
- Set<Object> getChildrenNames();
+ // ***************** End old legacy methods. See new versions below, which are
supported by MVCC. *********************************
- Map<Object, Node<K, V>> getChildrenMap();
+ InternalNode<K, V> getChild(Fqn f);
- void setChildrenMap(Map<Object, Node<K, V>> children);
+ InternalNode<K, V> getChild(Object childName);
- void addChild(NodeSPI<K, V> child);
+ Set<InternalNode<K, V>> getChildren();
- void addChild(Object nodeName, Node<K, V> nodeToAdd);
+ Set<InternalNode<K, V>> getChildren(boolean includeMarkedForRemoval);
- NodeSPI<K, V> addChild(Fqn f);
+ ConcurrentMap<Object, InternalNode<K, V>> getChildrenMap();
- NodeSPI<K, V> addChild(Fqn f, boolean notify);
+ void setChildrenMap(ConcurrentMap<Object, InternalNode<K, V>> children);
- NodeSPI<K, V> addChild(Object o, boolean notify);
+ void addChild(Object nodeName, InternalNode<K, V> nodeToAdd);
+ void addChild(InternalNode<K, V> child);
+
+ InternalNode<K, V> addChild(Fqn f);
+
+ InternalNode<K, V> addChild(Fqn f, boolean notify);
+
+ InternalNode<K, V> addChild(Object o, boolean notify);
+
+ InternalNode<K, V> getOrCreateChild(Object childName, InvocationContext ctx);
+
+ // *****************End new methods *****************
+
+
+ Set<Object> getChildrenNames();
+
void removeChildren();
boolean removeChild(Object childName);
Modified: core/trunk/src/main/java/org/jboss/cache/NodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeFactory.java 2008-07-28 10:29:41 UTC (rev
6413)
+++ core/trunk/src/main/java/org/jboss/cache/NodeFactory.java 2008-07-28 10:56:29 UTC (rev
6414)
@@ -77,9 +77,16 @@
* @param attachToParent if true, the node is registered in the parent's child
map. If false, it is not.
* @return a new node, or the existing node if one existed.
*/
- NodeSPI<K, V> createAndRegister(Fqn fqn, NodeSPI<K, V> parent,
InvocationContext ctx, boolean attachToParent);
+ InternalNode<K, V> createAndRegister(Fqn fqn, InternalNode<K, V> parent,
InvocationContext ctx, boolean attachToParent);
NodeSPI<K, V> createRootNode();
- NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V>
internalNode, boolean wrapWithNodeReference);
+ /**
+ * Creates an internal node. Similar to {@link #createNode(Fqn, NodeSPI)} except that
the resultant node is not wrapped
+ * in a {@link org.jboss.cache.invocation.NodeInvocationDelegate}.
+ *
+ * @param childFqn
+ * @return
+ */
+ InternalNode<K, V> createInternalNode(Fqn childFqn);
}
Modified: core/trunk/src/main/java/org/jboss/cache/NodeSPI.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeSPI.java 2008-07-28 10:29:41 UTC (rev
6413)
+++ core/trunk/src/main/java/org/jboss/cache/NodeSPI.java 2008-07-28 10:56:29 UTC (rev
6414)
@@ -7,6 +7,7 @@
package org.jboss.cache;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.cache.invocation.InvocationContext;
import org.jboss.cache.lock.NodeLock;
import org.jboss.cache.optimistic.DataVersion;
import org.jboss.cache.transaction.GlobalTransaction;
@@ -496,4 +497,67 @@
* @since 2.1.0
*/
void setValid(boolean valid, boolean recursive);
+
+ /**
+ * @return true if the node is a null marker node. Only used with MVCC.
+ */
+ boolean isNullNode();
+
+ /**
+ * Marks a node for updating. Internally, this creates a copy of the delegate and
performs any checks necessary to
+ * maintain isolation level.
+ * <p/>
+ * Only used with MVCC.
+ *
+ * @param ctx invocation context
+ * @param container data container
+ * @param nodeFactory node factory for creating new nodes/copies.
+ * @param writeSkewCheck if true, and the node supports write skew checking, nodes are
tested for write skews.
+ */
+ void markForUpdate(InvocationContext ctx, DataContainer container, NodeFactory
nodeFactory, boolean writeSkewCheck);
+
+ /**
+ * Commits any updates made on this node to the underlying data structure, making it
visible to all other transactions.
+ * <p/>
+ * Only used with MVCC.
+ *
+ * @param ctx invocation context
+ * @param container data container
+ * @param nodeFactory node factory
+ */
+ void commitUpdate(InvocationContext ctx, DataContainer container, NodeFactory
nodeFactory);
+
+ /**
+ * Only used with MVCC.
+ * <p/>
+ *
+ * @return true if this node has been marked for update, false otherwise.
+ */
+ boolean isChanged();
+
+ /**
+ * Only used with MVCC.
+ * <p/>
+ *
+ * @return true if this node has been newly created in the current scope.
+ */
+ boolean isCreated();
+
+ InternalNode getDelegationTarget();
+
+ /**
+ * Sets the created flag on a node.
+ * <p/>
+ * Only used with MVCC.
+ *
+ * @param created flag
+ */
+ void setCreated(boolean created);
+
+ /**
+ * Rolls back any changes made to a node.
+ * <p/>
+ * Only used with MVCC.
+ */
+ void rollbackUpdate();
}
Modified: core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -1,13 +1,20 @@
package org.jboss.cache;
+import static org.jboss.cache.AbstractNode.NodeFlags.VALID;
import org.jboss.cache.commands.write.CreateNodeCommand;
import org.jboss.cache.invocation.InvocationContext;
import org.jboss.cache.lock.IdentityLock;
import org.jboss.cache.lock.LockStrategyFactory;
+import org.jboss.cache.marshall.MarshalledValue;
import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.util.ImmutableSetCopy;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
/**
* UnversionedNode specific to pessimistic locking, with legacy code.
@@ -38,8 +45,19 @@
this.data = new HashMap<K, V>();
setLockForChildInsertRemove(cache != null && cache.getConfiguration() !=
null && cache.getConfiguration().isLockParentForChildInsertRemove());
+
+
}
+ /**
+ * @return a genericized version of the child map.
+ */
+ @SuppressWarnings("unchecked")
+ private ConcurrentMap<Object, Node<K, V>> children()
+ {
+ return children;
+ }
+
// ------ lock-per-node paradigm
public void injectLockStrategyFactory(LockStrategyFactory lockStrategyFactory)
@@ -94,22 +112,21 @@
// ------ legacy addChild methods that used a lot of implicit locks.
@Override
- public void addChild(NodeSPI<K, V> child)
+ public void addChildDirect(NodeSPI<K, V> child)
{
Fqn childFqn = child.getFqn();
if (childFqn.isDirectChildOf(fqn))
{
synchronized (this)
{
- children.put(child.getFqn().getLastElement(), child);
+ children().put(child.getFqn().getLastElement(), child);
}
}
else
throw new CacheException("Attempting to add a child [" +
child.getFqn() + "] to [" + getFqn() + "]. Can only add direct
children.");
}
- @Override
- protected NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction
gtx, boolean createIfNotExists, boolean notify)
+ private NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx,
boolean createIfNotExists, boolean notify)
{
NodeSPI<K, V> child;
if (childName == null)
@@ -117,7 +134,7 @@
throw new IllegalArgumentException("null child name");
}
- child = (NodeSPI<K, V>) children.get(childName);
+ child = (NodeSPI<K, V>) children().get(childName);
InvocationContext ctx = cache.getInvocationContext();
if (createIfNotExists && child == null)
{
@@ -133,12 +150,12 @@
{
// check again to see if the child exists
// after acquiring exclusive lock
- child = (NodeSPI<K, V>) children.get(childName);
+ child = (NodeSPI<K, V>) children().get(childName);
if (child == null)
{
if (notify) cache.getNotifier().notifyNodeCreated(childFqn, true, ctx);
child = newChild;
- children.put(childName, child);
+ children().put(childName, child);
}
}
@@ -156,6 +173,218 @@
}
}
return child;
+ }
+ @Override
+ public NodeSPI<K, V> addChildDirect(Fqn f, boolean notify)
+ {
+ if (f.size() == 1)
+ {
+ GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
+ return getOrCreateChild(f.getLastElement(), gtx, true, notify);
+ }
+ else
+ {
+ throw new UnsupportedOperationException("Cannot directly create children
which aren't directly under the current node.");
+ }
}
+
+ @Override
+ public NodeSPI<K, V> addChildDirect(Object o, boolean notify)
+ {
+ GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
+ return getOrCreateChild(o, gtx, true, notify);
+ }
+
+ @Override
+ public NodeSPI<K, V> getChildDirect(Fqn fqn)
+ {
+ if (fqn.size() == 1)
+ {
+ return getChildDirect(fqn.getLastElement());
+ }
+ else
+ {
+ NodeSPI<K, V> currentNode = delegate;
+ for (int i = 0; i < fqn.size(); i++)
+ {
+ Object nextChildName = fqn.get(i);
+ currentNode = currentNode.getChildDirect(nextChildName);
+ if (currentNode == null) return null;
+ }
+ return currentNode;
+ }
+ }
+
+ @Override
+ public NodeSPI<K, V> getChildDirect(Object childName)
+ {
+ if (childName == null) return null;
+ return (NodeSPI<K, V>) children().get(childName);
+ }
+
+ @Override
+ public Set<NodeSPI<K, V>> getChildrenDirect()
+ {
+ // strip out deleted child nodes...
+ if (children == null || children.size() == 0) return Collections.emptySet();
+
+ Set<NodeSPI<K, V>> exclDeleted = new HashSet<NodeSPI<K,
V>>();
+ for (Node<K, V> n : children().values())
+ {
+ NodeSPI<K, V> spi = (NodeSPI<K, V>) n;
+ if (!spi.isDeleted()) exclDeleted.add(spi);
+ }
+ exclDeleted = Collections.unmodifiableSet(exclDeleted);
+ return exclDeleted;
+ }
+
+ @Override
+ public Map<Object, Node<K, V>> getChildrenMapDirect()
+ {
+ return children();
+ }
+
+ @Override
+ public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
+ {
+ if (children == null)
+ this.children = null;
+ else
+ {
+ this.children.clear();
+ this.children().putAll(children);
+ }
+ }
+
+ @Override
+ public void addChildDirect(Object nodeName, Node<K, V> nodeToAdd)
+ {
+ if (nodeName != null)
+ {
+ children().put(nodeName, nodeToAdd);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Set<NodeSPI<K, V>> getChildrenDirect(boolean
includeMarkedForRemoval)
+ {
+ if (includeMarkedForRemoval)
+ {
+ if (children != null && !children.isEmpty())
+ {
+ return new ImmutableSetCopy(children.values());
+ }
+ else
+ {
+ return Collections.emptySet();
+ }
+ }
+ else
+ {
+ return getChildrenDirect();
+ }
+ }
+
+ @Override
+ public NodeSPI<K, V> addChildDirect(Fqn f)
+ {
+ return addChildDirect(f, true);
+ }
+
+ @Override
+ public NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx)
+ {
+ return getOrCreateChild(childName, gtx, true, true);
+ }
+
+ @Override
+ public void markAsRemoved(boolean marker, boolean recursive)
+ {
+ setFlag(NodeFlags.REMOVED, marker);
+
+ if (recursive && children != null)
+ {
+ synchronized (this)
+ {
+ for (Node<?, ?> child : children().values())
+ {
+ ((NodeSPI) child).markAsDeleted(marker, true);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setValid(boolean valid, boolean recursive)
+ {
+ setFlag(VALID, valid);
+
+ if (trace) log.trace("Marking node " + getFqn() + " as " +
(valid ? "" : "in") + "valid");
+ if (recursive)
+ {
+ for (Node<K, V> child : children().values())
+ {
+ ((NodeSPI<K, V>) child).setValid(valid, recursive);
+ }
+ }
+ }
+
+ @Override
+ public void setFqn(Fqn fqn)
+ {
+ if (trace)
+ {
+ log.trace(getFqn() + " set FQN " + fqn);
+ }
+ this.fqn = fqn;
+
+ if (children == null)
+ {
+ return;
+ }
+
+ // invoke children
+ for (Map.Entry<Object, ? extends Node<K, V>> me :
children().entrySet())
+ {
+ NodeSPI<K, V> n = (NodeSPI<K, V>) me.getValue();
+ Fqn cfqn = Fqn.fromRelativeElements(fqn, me.getKey());
+ n.setFqn(cfqn);
+ }
+ }
+
+ @Override
+ public void releaseObjectReferences(boolean recursive)
+ {
+ if (recursive && children != null)
+ {
+ for (Node<K, V> child : children().values())
+ {
+ child.releaseObjectReferences(recursive);
+ }
+ }
+
+ if (data != null)
+ {
+ for (K key : data.keySet())
+ {
+ // get the key first, before attempting to serialize stuff since data.get()
may deserialize the key if doing
+ // a hashcode() or equals().
+
+ Object value = data.get(key);
+ if (key instanceof MarshalledValue)
+ {
+ ((MarshalledValue) key).compact(true, true);
+ }
+
+ if (value instanceof MarshalledValue)
+ {
+ ((MarshalledValue) value).compact(true, true);
+ }
+
+ }
+ }
+ }
+
}
Modified: core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java 2008-07-28 10:29:41 UTC
(rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java 2008-07-28 10:56:29 UTC
(rev 6414)
@@ -10,6 +10,7 @@
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.commands.ReplicableCommand;
import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
import org.jboss.cache.config.RuntimeConfig;
import org.jboss.cache.factories.ComponentRegistry;
import org.jboss.cache.factories.annotations.Inject;
@@ -328,6 +329,7 @@
}
+ @Deprecated
private void removeLocksForDeadMembers(NodeSPI node, List deadMembers)
{
Set<GlobalTransaction> deadOwners = new HashSet<GlobalTransaction>();
@@ -344,7 +346,7 @@
for (GlobalTransaction deadOwner : deadOwners)
{
boolean localTx = deadOwner.getAddress().equals(getLocalAddress());
- boolean broken = LockUtil.breakTransactionLock(node, lockManager, deadOwner,
localTx, txTable, txManager);
+ boolean broken = LockUtil.breakTransactionLock(node.getFqn(), lockManager,
deadOwner, localTx, txTable, txManager);
if (broken && trace) log.trace("Broke lock for node " +
node.getFqn() + " held by " + deadOwner);
}
@@ -356,6 +358,31 @@
}
}
+
+ /**
+ * Only used with MVCC.
+ */
+ private void removeLocksForDeadMembers(InternalNode<?, ?> node, List
deadMembers)
+ {
+ Set<GlobalTransaction> deadOwners = new HashSet<GlobalTransaction>();
+ Object owner = lockManager.getWriteOwner(node.getFqn());
+
+ if (isLockOwnerDead(owner, deadMembers)) deadOwners.add((GlobalTransaction)
owner);
+
+ // MVCC won't have any read locks.
+
+ for (GlobalTransaction deadOwner : deadOwners)
+ {
+ boolean localTx = deadOwner.getAddress().equals(getLocalAddress());
+ boolean broken = LockUtil.breakTransactionLock(node.getFqn(), lockManager,
deadOwner, localTx, txTable, txManager);
+
+ if (broken && trace) log.trace("Broke lock for node " +
node.getFqn() + " held by " + deadOwner);
+ }
+
+ // Recursively unlock children
+ for (InternalNode child : node.getChildren()) removeLocksForDeadMembers(child,
deadMembers);
+ }
+
private boolean isLockOwnerDead(Object owner, List deadMembers)
{
boolean result = false;
@@ -590,7 +617,20 @@
// and roll back any tx and break any locks
List<Address> removed = new ArrayList<Address>(members);
removed.removeAll(newMembers);
- removeLocksForDeadMembers(spi.getRoot(), removed);
+ NodeSPI root = spi.getRoot();
+ if (root != null)
+ {
+ // UGH!!! What a shameless hack!
+ if (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
+ {
+
+ removeLocksForDeadMembers(root.getDelegationTarget(), removed);
+ }
+ else
+ {
+ removeLocksForDeadMembers(root, removed);
+ }
+ }
}
members = new ArrayList<Address>(newMembers); // defensive copy.
Modified: core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java 2008-07-28 10:29:41
UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java 2008-07-28 10:56:29
UTC (rev 6414)
@@ -337,19 +337,11 @@
private void activateRegion(Fqn fqn, boolean suppressRegionNotEmptyException)
{
// Check whether the node already exists and has data
- Node subtreeRoot = cache.peek(fqn, false, false);
+ Node subtreeRoot = cache.getNode(fqn); // NOTE this used to be a peek!
- /*
- * Commented out on Nov 16,2006 Manik&Vladimir
- *
- * if (!(cache.isNodeEmpty(subtreeRoot)))
- {
- throw new RegionNotEmptyException("Node " + subtreeRoot.getFqn() +
" already exists and is not empty");
- }*/
-
if (isActivatingDeactivating(fqn))
{
- throw new CacheException("Region " + subtreeRoot.getFqn() + " is
already being activated/deactivated");
+ throw new CacheException("Region " + fqn + " is already being
activated/deactivated");
}
if (log.isDebugEnabled())
Modified: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2008-07-28 10:29:41 UTC
(rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2008-07-28 10:56:29 UTC
(rev 6414)
@@ -12,10 +12,7 @@
import org.jboss.cache.commands.CommandsFactory;
import org.jboss.cache.commands.write.CreateNodeCommand;
import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.lock.IdentityLock;
import org.jboss.cache.marshall.MarshalledValue;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.transaction.GlobalTransaction;
import org.jboss.cache.util.ImmutableSetCopy;
import org.jboss.cache.util.concurrent.SelfInitializingConcurrentHashMap;
@@ -25,6 +22,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
/**
* Basic data node class. Throws {@link UnsupportedOperationException} for
version-specific methods like {@link #getVersion()} and
@@ -42,11 +40,6 @@
protected static final boolean trace = log.isTraceEnabled();
/**
- * A reference of the CacheImpl instance.
- */
-// transient CacheSPI<K, V> cache;
-
- /**
* Map of general data keys to values.
*/
protected HashMap<K, V> data;
@@ -81,15 +74,16 @@
this.cache = cache;
setLockForChildInsertRemove(lockForChildInsertRemove);
this.fqn = fqn;
+
// if this is a root node, create the child map.
if (fqn.isRoot())
{
- children = new ConcurrentHashMap<Object, Node<K, V>>(64, .5f, 16);
+ children = new ConcurrentHashMap<Object, InternalNode<K, V>>(64,
.5f, 16);
}
else
{
// this always needs to be initialized. The actual cost of the
ConcurrentHashMap, however, is deferred.
- children = new SelfInitializingConcurrentHashMap<Object, Node<K,
V>>();
+ children = new SelfInitializingConcurrentHashMap<Object, InternalNode<K,
V>>();
}
}
@@ -164,12 +158,6 @@
return data == null ? null : data.get(key);
}
- @SuppressWarnings("deprecation")
- public IdentityLock getLock()
- {
- throw new UnsupportedOperationException("Not supported in this
implementation!");
- }
-
public Map<K, V> getData()
{
if (data == null) return Collections.emptyMap();
@@ -182,27 +170,146 @@
return data.put(key, value);
}
- public NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx)
+ @Override
+ public InternalNode<K, V> getOrCreateChild(Object childName, InvocationContext
ctx)
{
- return getOrCreateChild(childName, gtx, true, true);
+ return getOrCreateChild(childName, ctx, true, true);
}
- protected NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction
gtx, boolean createIfNotExists, boolean notify)
+ @Override
+ public InternalNode<K, V> getChild(Fqn f)
{
- NodeSPI<K, V> child;
- if (childName == null)
+ if (fqn.size() == 1)
{
- throw new IllegalArgumentException("null child name");
+ return getChild(fqn.getLastElement());
}
+ else
+ {
+ InternalNode<K, V> currentNode = this;
+ for (int i = 0; i < fqn.size(); i++)
+ {
+ Object nextChildName = fqn.get(i);
+ currentNode = currentNode.getChild(nextChildName);
+ if (currentNode == null) return null;
+ }
+ return currentNode;
+ }
+ }
- child = (NodeSPI<K, V>) children.get(childName);
- InvocationContext ctx = cache.getInvocationContext();
+ @Override
+ public InternalNode<K, V> getChild(Object childName)
+ {
+ if (childName == null) return null;
+ return children().get(childName);
+ }
+
+ @Override
+ public Set<InternalNode<K, V>> getChildren()
+ {
+ // strip out deleted child nodes...
+ if (children.isEmpty()) return Collections.emptySet();
+
+ Set<InternalNode<K, V>> exclDeleted = new HashSet<InternalNode<K,
V>>();
+ for (InternalNode<K, V> n : children().values())
+ {
+ if (!n.isRemoved()) exclDeleted.add(n);
+ }
+ exclDeleted = Collections.unmodifiableSet(exclDeleted);
+ return exclDeleted;
+ }
+
+ @Override
+ public Set<InternalNode<K, V>> getChildren(boolean
includeMarkedForRemoval)
+ {
+ if (includeMarkedForRemoval)
+ {
+ if (!children.isEmpty())
+ {
+ return new ImmutableSetCopy<InternalNode<K,
V>>(children().values());
+ }
+ else
+ {
+ return Collections.emptySet();
+ }
+ }
+ else
+ {
+ return getChildren();
+ }
+ }
+
+ @Override
+ public ConcurrentMap<Object, InternalNode<K, V>> getChildrenMap()
+ {
+ return children();
+ }
+
+ @Override
+ public void setChildrenMap(ConcurrentMap<Object, InternalNode<K, V>>
children)
+ {
+ this.children = children;
+ }
+
+ @Override
+ public void addChild(Object nodeName, InternalNode<K, V> nodeToAdd)
+ {
+ if (nodeName != null)
+ {
+ children().put(nodeName, nodeToAdd);
+ }
+ }
+
+ @Override
+ public void addChild(InternalNode<K, V> child)
+ {
+ Fqn childFqn = child.getFqn();
+ if (childFqn.isDirectChildOf(fqn))
+ {
+ children().put(childFqn.getLastElement(), child);
+ }
+ else
+ {
+ throw new CacheException("Attempting to add a child [" + childFqn +
"] to [" + fqn + "]. Can only add direct children.");
+ }
+ }
+
+ public InternalNode<K, V> addChild(Fqn f)
+ {
+ return addChild(f, true);
+ }
+
+ @Override
+ public InternalNode<K, V> addChild(Fqn f, boolean notify)
+ {
+ if (f.size() == 1)
+ {
+ return getOrCreateChild(f.getLastElement(), cache.getInvocationContext(), true,
notify);
+ }
+ else
+ {
+ throw new UnsupportedOperationException("Cannot directly create children
which aren't directly under the current node.");
+ }
+ }
+
+ @Override
+ public InternalNode<K, V> addChild(Object o, boolean notify)
+ {
+ return getOrCreateChild(o, cache.getInvocationContext(), true, notify);
+ }
+
+ private InternalNode<K, V> getOrCreateChild(Object childName, InvocationContext
ctx, boolean createIfNotExists, boolean notify)
+ {
+ InternalNode<K, V> child;
+ if (childName == null) throw new IllegalArgumentException("null child
name");
+
+ child = children().get(childName);
+
if (createIfNotExists && child == null)
{
Fqn childFqn = Fqn.fromRelativeElements(fqn, childName);
- NodeSPI<K, V> newChild = nodeFactory.createNode(childFqn, delegate);
+ InternalNode<K, V> newChild = nodeFactory.createInternalNode(childFqn);
- child = (NodeSPI<K, V>) children.putIfAbsent(childName, newChild);
+ child = children().putIfAbsent(childName, newChild);
if (child == null)
{
@@ -211,7 +318,7 @@
if (trace) log.trace("created child: fqn=" + childFqn);
- if (gtx != null)
+ if (ctx.getTransactionContext() != null)
{
CreateNodeCommand createNodeCommand =
commandsFactory.buildCreateNodeCommand(childFqn);
ctx.getTransactionContext().addModification(createNodeCommand);
@@ -298,7 +405,7 @@
sb.append("]");
}
}
- if (children != null && !children.isEmpty())
+ if (!children.isEmpty())
{
if (trace)
{
@@ -337,71 +444,14 @@
return sb.toString();
}
- public void addChild(NodeSPI<K, V> child)
- {
- Fqn childFqn = child.getFqn();
- if (childFqn.isDirectChildOf(fqn))
- {
- children.put(childFqn.getLastElement(), child);
- }
- else
- {
- throw new CacheException("Attempting to add a child [" + childFqn +
"] to [" + fqn + "]. Can only add direct children.");
- }
- }
-
- public NodeSPI<K, V> addChild(Fqn f)
- {
- return addChild(f, true);
- }
-
- public NodeSPI<K, V> addChild(Fqn f, boolean notify)
- {
- if (f.size() == 1)
- {
- GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
- return getOrCreateChild(f.getLastElement(), gtx, true, notify);
- }
- else
- {
- throw new UnsupportedOperationException("Cannot directly create children
which aren't directly under the current node.");
- }
-
- }
-
- public NodeSPI<K, V> addChild(Object childName, boolean notify)
- {
- GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
- return getOrCreateChild(childName, gtx, true, notify);
- }
-
public void clear()
{
if (data != null) data.clear();
}
- public NodeSPI<K, V> getChild(Fqn fqn)
- {
- if (fqn.size() == 1)
- {
- return getChild(fqn.getLastElement());
- }
- else
- {
- NodeSPI<K, V> currentNode = delegate;
- for (int i = 0; i < fqn.size(); i++)
- {
- Object nextChildName = fqn.get(i);
- currentNode = currentNode.getChildDirect(nextChildName);
- if (currentNode == null) return null;
- }
- return currentNode;
- }
- }
-
public Set<Object> getChildrenNames()
{
- return children == null ? Collections.emptySet() : new
HashSet<Object>(children.keySet());
+ return children.isEmpty() ? Collections.emptySet() : new
ImmutableSetCopy<Object>(children.keySet());
}
public Set<K> getKeys()
@@ -415,7 +465,7 @@
public boolean removeChild(Object childName)
{
- return children != null && children.remove(childName) != null;
+ return children.remove(childName) != null;
}
public boolean removeChild(Fqn f)
@@ -426,27 +476,11 @@
}
else
{
- NodeSPI<K, V> child = getChild(f);
+ NodeSPI<K, V> child = getChildDirect(f);
return child != null &&
child.getParentDirect().removeChildDirect(f.getLastElement());
}
}
- public Map<Object, Node<K, V>> getChildrenMap()
- {
- return children;
- }
-
- public void setChildrenMap(Map<Object, Node<K, V>> children)
- {
- if (children == null)
- this.children = null;
- else
- {
- this.children.clear();
- this.children.putAll(children);
- }
- }
-
public void putAll(Map<K, V> data)
{
if (data != null)
@@ -458,24 +492,17 @@
public void removeChildren()
{
- if (children != null)
- {
- children.clear();
- }
- children = null;
+ children.clear();
}
- // versioning
-
- public void setVersion(DataVersion
- version)
+ public void markAsRemoved(boolean marker, boolean recursive)
{
- throw new UnsupportedOperationException("Versioning not supported");
- }
+ setFlag(REMOVED, marker);
- public DataVersion getVersion()
- {
- throw new UnsupportedOperationException("Versioning not supported");
+ if (recursive)
+ {
+ for (InternalNode<K, V> child : children().values())
child.markAsRemoved(marker, true);
+ }
}
private void printIndent(StringBuilder sb, int indent)
@@ -489,14 +516,6 @@
}
}
- public void addChild(Object childName, Node<K, V> n)
- {
- if (childName != null)
- {
- children.put(childName, n);
- }
- }
-
/**
* Returns the name of this node.
*/
@@ -513,66 +532,20 @@
}
this.fqn = fqn;
- if (children == null)
- {
- return;
- }
-
// invoke children
- for (Map.Entry<Object, ? extends Node<K, V>> me : children.entrySet())
+ for (Map.Entry<Object, InternalNode<K, V>> me : children().entrySet())
{
- NodeSPI<K, V> n = (NodeSPI<K, V>) me.getValue();
+ InternalNode<K, V> n = me.getValue();
Fqn cfqn = Fqn.fromRelativeElements(fqn, me.getKey());
n.setFqn(cfqn);
}
}
- public NodeSPI<K, V> getChild(Object childName)
- {
- if (childName == null) return null;
- return (NodeSPI<K, V>) (children == null ? null : children.get(childName));
- }
-
- public Set<NodeSPI<K, V>> getChildren()
- {
- // strip out deleted child nodes...
- if (children == null || children.size() == 0) return Collections.emptySet();
-
- Set<NodeSPI<K, V>> exclDeleted = new HashSet<NodeSPI<K,
V>>();
- for (Node<K, V> n : children.values())
- {
- NodeSPI<K, V> spi = (NodeSPI<K, V>) n;
- if (!spi.isDeleted()) exclDeleted.add(spi);
- }
- exclDeleted = Collections.unmodifiableSet(exclDeleted);
- return exclDeleted;
- }
-
public boolean hasChildren()
{
- return children != null && children.size() != 0;
+ return !children.isEmpty();
}
- @SuppressWarnings("unchecked")
- public Set<NodeSPI<K, V>> getChildren(boolean includeMarkedForRemoval)
- {
- if (includeMarkedForRemoval)
- {
- if (children != null && !children.isEmpty())
- {
- return new ImmutableSetCopy(children.values());
- }
- else
- {
- return Collections.emptySet();
- }
- }
- else
- {
- return getChildren();
- }
- }
-
/**
* Adds details of the node into a map as strings.
*/
@@ -587,14 +560,7 @@
sb.append(fqn.getLastElement());
sb.append(" ");
sb.append(data);
- if (children != null)
- {
- for (Node<K, V> n : children.values())
- {
- sb.append("\n");
- ((NodeSPI<K, V>) n).printDetails(sb, indent);
- }
- }
+ sb.append(children);
}
/**
@@ -625,9 +591,9 @@
if (trace) log.trace("Marking node " + getFqn() + " as " +
(valid ? "" : "in") + "valid");
if (recursive)
{
- for (Node<K, V> child : children.values())
+ for (InternalNode<K, V> child : children().values())
{
- ((NodeSPI<K, V>) child).setValid(valid, recursive);
+ child.setValid(valid, recursive);
}
}
}
@@ -685,9 +651,9 @@
public void releaseObjectReferences(boolean recursive)
{
- if (recursive && children != null)
+ if (recursive)
{
- for (Node<?, ?> child : children.values())
+ for (InternalNode<K, V> child : children().values())
{
child.releaseObjectReferences(recursive);
}
@@ -714,4 +680,13 @@
}
}
}
+
+ /**
+ * @return genericized version of the child map
+ */
+ @SuppressWarnings("unchecked")
+ private ConcurrentMap<Object, InternalNode<K, V>> children()
+ {
+ return children;
+ }
}
Modified:
core/trunk/src/main/java/org/jboss/cache/commands/OptimisticCommandsFactoryImpl.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/commands/OptimisticCommandsFactoryImpl.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/commands/OptimisticCommandsFactoryImpl.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -1,10 +1,12 @@
package org.jboss.cache.commands;
import org.jboss.cache.Fqn;
+import org.jboss.cache.commands.legacy.read.LegacyGravitateDataCommand;
import org.jboss.cache.commands.legacy.write.LegacyEvictCommand;
+import org.jboss.cache.commands.legacy.write.VersionedInvalidateCommand;
+import org.jboss.cache.commands.read.GravitateDataCommand;
import org.jboss.cache.commands.write.EvictCommand;
import org.jboss.cache.commands.write.InvalidateCommand;
-import org.jboss.cache.commands.write.VersionedInvalidateCommand;
/**
* Extends the default commands factory impl for optimistic locking.
@@ -32,12 +34,27 @@
}
@Override
+ public GravitateDataCommand buildGravitateDataCommand(Fqn fqn, Boolean
searchSubtrees)
+ {
+ LegacyGravitateDataCommand command = new LegacyGravitateDataCommand(fqn,
searchSubtrees, rpcManager.getLocalAddress());
+ command.initialize(dataContainer, cacheSpi, buddyFqnTransformer);
+ return command;
+ }
+
+ @Override
public ReplicableCommand fromStream(int id, Object[] parameters)
{
ReplicableCommand command;
boolean skipSetParams = false;
switch (id)
{
+ case GravitateDataCommand.METHOD_ID:
+ {
+ LegacyGravitateDataCommand returnValue = new
LegacyGravitateDataCommand(rpcManager.getLocalAddress());
+ returnValue.initialize(dataContainer, cacheSpi, buddyFqnTransformer);
+ command = returnValue;
+ break;
+ }
case InvalidateCommand.METHOD_ID:
{
VersionedInvalidateCommand returnValue = new
VersionedInvalidateCommand(null);
Added:
core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/LegacyGravitateDataCommand.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/LegacyGravitateDataCommand.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/LegacyGravitateDataCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -0,0 +1,39 @@
+package org.jboss.cache.commands.legacy.read;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.commands.read.GravitateDataCommand;
+import org.jgroups.Address;
+
+import java.util.Set;
+
+/**
+ * Legacy version that uses old data container peeks
+ *
+ * @author Manik Surtani (<a
href="mailto:manik@jboss.org">manik@jboss.org</a>)
+ * @since 3.0
+ */
+public class LegacyGravitateDataCommand extends GravitateDataCommand
+{
+ public LegacyGravitateDataCommand(Fqn fqn, boolean searchSubtrees, Address
localAddress)
+ {
+ super(fqn, searchSubtrees, localAddress);
+ }
+
+ public LegacyGravitateDataCommand(Address localAddress)
+ {
+ super(localAddress);
+ }
+
+ /**
+ * @return a Set of child node names that hang directly off the backup tree root, or
null if the backup tree root doesn't exist.
+ */
+ @Override
+ protected Set<Object> getBackupRoots()
+ {
+ NodeSPI backupSubtree = dataContainer.peek(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
+ if (backupSubtree == null) return null;
+ return backupSubtree.getChildrenNamesDirect();
+ }
+}
Modified:
core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/PessGetChildrenNamesCommand.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/PessGetChildrenNamesCommand.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/PessGetChildrenNamesCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -1,12 +1,15 @@
package org.jboss.cache.commands.legacy.read;
import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.read.GetChildrenNamesCommand;
import org.jboss.cache.invocation.InvocationContext;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
public class PessGetChildrenNamesCommand extends GetChildrenNamesCommand
@@ -20,8 +23,26 @@
super(fqn);
}
- protected Set<Object> getCorrectedChildNames(Collection<NodeSPI<?,
?>> children, InvocationContext ctx)
+ /**
+ * Retrieves the names of children for a specific Fqn.
+ *
+ * @param ctx invocation context
+ * @return a Set<Object> of child names, for a given Fqn, or null if the Fqn
refers to a node that does not exist.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object perform(InvocationContext ctx)
{
+ NodeSPI<?, ?> n = fqn == null ? null : ctx.lookUpNode(fqn);
+ if (n == null || n.isDeleted()) return null;
+ Map<Object, ? extends Node<?, ?>> childrenMap =
n.getChildrenMapDirect();
+ Collection<NodeSPI<?, ?>> children = (Collection<NodeSPI<?,
?>>) ((childrenMap == null || childrenMap.isEmpty()) ? Collections.emptySet() :
childrenMap.values());
+
+ return getCorrectedChildNames(children, ctx);
+ }
+
+ private Set<Object> getCorrectedChildNames(Collection<NodeSPI<?, ?>>
children, InvocationContext ctx)
+ {
// prune deleted children - JBCACHE-1136
Set<Object> childNames = new HashSet<Object>();
for (NodeSPI child : children)
Modified:
core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/LegacyEvictCommand.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/LegacyEvictCommand.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/LegacyEvictCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -36,4 +36,38 @@
return dataContainer.getNodesForEviction(fqn, true);
}
+ @Override
+ protected boolean evictNode(Fqn fqn, InvocationContext ctx, NodeSPI node)
+ {
+ notifier.notifyNodeEvicted(fqn, true, ctx);
+ try
+ {
+ if (node == null) return true;
+ if (node.hasChildrenDirect() || fqn.isRoot())
+ {
+ if (trace) log.trace("removing DATA as node has children: evict(" +
fqn + ")");
+ node.clearDataDirect();
+ node.setDataLoaded(false);
+ return false;
+ }
+ else
+ {
+ if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn
+ ")");
+ NodeSPI parentNode = lookupForEviction(ctx, fqn.getParent());
+
+ if (parentNode != null)
+ {
+ parentNode.removeChildDirect(fqn.getLastElement());
+ parentNode.setChildrenLoaded(false);
+ }
+ node.setValid(false, false);
+ node.markAsDeleted(true);
+ return true;
+ }
+ }
+ finally
+ {
+ notifier.notifyNodeEvicted(fqn, false, ctx);
+ }
+ }
}
Copied:
core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommand.java
(from rev 6358,
core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java)
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommand.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -0,0 +1,182 @@
+package org.jboss.cache.commands.legacy.write;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.commands.VersionedDataCommand;
+import org.jboss.cache.commands.write.InvalidateCommand;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.optimistic.DataVersioningException;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.Collections;
+
+/**
+ * Behaves like {@link org.jboss.cache.commands.write.InvalidateCommand}. Also,
potentially throws a cache exception if
+ * data versioning is used and the node in memory has a newer data version than what is
passed in.
+ * <p/>
+ * Finally, the data version of the in-memory node is updated to the version being
evicted to prevent versions
+ * going out of sync.
+ * <p/>
+ *
+ * @author Mircea.Markus(a)jboss.com
+ * @since 2.2
+ */
+public class VersionedInvalidateCommand extends InvalidateCommand implements
VersionedDataCommand
+{
+ private static final Log log = LogFactory.getLog(VersionedInvalidateCommand.class);
+ private static final boolean trace = log.isTraceEnabled();
+
+ /*
+ dependencies
+ */
+ private TransactionManager transactionManager;
+
+ /**
+ * Params.
+ */
+ protected GlobalTransaction globalTransaction;
+ private DataVersion dataVersion;
+
+ public VersionedInvalidateCommand(Fqn fqn)
+ {
+ super(fqn);
+ }
+
+ public VersionedInvalidateCommand()
+ {
+ }
+
+ public void initialize(TransactionManager txManager)
+ {
+ this.transactionManager = txManager;
+ }
+
+ @Override
+ public Object perform(InvocationContext ctx)
+ {
+ NodeSPI node = enforceNodeLoading();
+ if (trace) log.trace("Invalidating fqn:" + fqn);
+ if (node == null)
+ {
+ // check if a tombstone already exists
+ NodeSPI nodeSPI = dataContainer.peek(fqn, true, true);
+ if (nodeSPI == null)
+ {
+ if (dataVersion == null)
+ {
+ if (trace)
+ log.trace("Would have created a tombstone since the node
doesn't exist, but the version to invalidate is null and hence cannot create a
tombstone!");
+ return null;
+ }
+ createTombstone(ctx);
+ nodeSPI = (NodeSPI) dataContainer.getRoot().getChild(fqn);
+ }
+ node = nodeSPI;
+ }
+ else if (node.getVersion() == null)
+ {
+ throw new NullPointerException("Node " + node.getFqn() + " has a
null data version, and is of type " + node.getClass().getSimpleName() + ". This
command expects versioned nodes.");
+ }
+ else
+ if (dataVersion != null && node.getVersion().newerThan(dataVersion)) //
dataVersion *could* be null if the invalidate was triggered by removing a node that did
not exist in the first place.
+ {
+ String errMsg = new StringBuilder("Node found, but version is not equal to
or less than the expected [").append(dataVersion).append("]. Is
[").append(node.getVersion()).append("] instead!").toString();
+ log.warn(errMsg);
+ throw new DataVersioningException(errMsg);
+ }
+
+ removeData(node, ctx);
+ invalidateNode(node);
+ node.setVersion(dataVersion);
+ return null;
+ }
+
+ protected void createTombstone(InvocationContext ctx)
+ {
+ if (trace)
+ log.trace("Node doesn't exist; creating a tombstone with data version
" + dataVersion);
+ // create the node we need.
+ Option o = ctx.getOptionOverrides();
+ boolean origCacheModeLocal = o.isCacheModeLocal();
+ o.setCacheModeLocal(true);
+ o.setDataVersion(dataVersion);
+ // if we are in a tx this call should happen outside of any tx
+ try
+ {
+ Transaction suspended = null;
+ if (transactionManager != null)
+ {
+ suspended = transactionManager.suspend();
+ }
+ spi.put(fqn, Collections.emptyMap());
+ if (suspended != null) transactionManager.resume(suspended);
+ ctx.getOptionOverrides().setCacheModeLocal(origCacheModeLocal);
+ }
+ catch (Exception e)
+ {
+ log.error("Unable to create tombstone!", e);
+ }
+ }
+
+ protected void removeData(NodeSPI n, InvocationContext ctx) throws CacheException
+ {
+ notifier.notifyNodeEvicted(fqn, true, ctx);
+ n.clearDataDirect();
+ n.setDataLoaded(false);
+ notifier.notifyNodeEvicted(fqn, false, ctx);
+ }
+
+ public DataVersion getDataVersion()
+ {
+ return dataVersion;
+ }
+
+ public void setDataVersion(DataVersion dataVersion)
+ {
+ this.dataVersion = dataVersion;
+ }
+
+ public GlobalTransaction getGlobalTransaction()
+ {
+ return globalTransaction;
+ }
+
+ public void setGlobalTransaction(GlobalTransaction gtx)
+ {
+ this.globalTransaction = gtx;
+ }
+
+ public boolean isVersioned()
+ {
+ return dataVersion != null;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "OptimisticInvalidateCommand{" +
+ "dataVersion=" + dataVersion +
+ " ,fqn=" + fqn +
+ '}';
+ }
+
+ @Override
+ public Object[] getParameters()
+ {
+ return new Object[]{fqn, dataVersion};
+ }
+
+ @Override
+ public void setParameters(int commandId, Object[] args)
+ {
+ fqn = (Fqn) args[0];
+ dataVersion = (DataVersion) args[1];
+ }
+}
Modified:
core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -3,7 +3,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.Fqn;
-import org.jboss.cache.Node;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.Visitor;
import org.jboss.cache.invocation.InvocationContext;
@@ -48,10 +48,10 @@
@SuppressWarnings("unchecked")
public Object perform(InvocationContext ctx)
{
- NodeSPI<?, ?> n = fqn == null ? null : ctx.lookUpNode(fqn);
+ ReadCommittedNode n = (ReadCommittedNode) (fqn == null ? null :
ctx.lookUpNode(fqn));
if (n == null || n.isDeleted()) return null;
- Map<Object, ? extends Node<?, ?>> childrenMap =
n.getChildrenMapDirect();
- Collection<NodeSPI<?, ?>> children = (Collection<NodeSPI<?,
?>>) ((childrenMap == null || childrenMap.isEmpty()) ? Collections.emptySet() :
childrenMap.values());
+ Map<Object, InternalNode<?, ?>> childrenMap =
n.getDelegationTarget().getChildrenMap();
+ Collection<InternalNode> children = (Collection<InternalNode>)
((childrenMap == null || childrenMap.isEmpty()) ? Collections.emptySet() :
childrenMap.values());
return getCorrectedChildNames(children, ctx);
}
@@ -64,11 +64,11 @@
* @param ctx invocation context
* @return a set of valid children names.
*/
- protected Set<Object> getCorrectedChildNames(Collection<NodeSPI<?,
?>> children, InvocationContext ctx)
+ private Set<Object> getCorrectedChildNames(Collection<InternalNode>
children, InvocationContext ctx)
{
Set<Object> childNames = new HashSet<Object>();
- for (NodeSPI realChild : children)
+ for (InternalNode realChild : children)
{
Fqn childFqn = realChild.getFqn();
NodeSPI childNode = ctx.lookUpNode(childFqn);
Modified:
core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -5,6 +5,7 @@
import org.jboss.cache.CacheSPI;
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.Node;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
@@ -93,55 +94,53 @@
if (actualNode == null && searchSubtrees)
{
log.trace("Looking at backup trees.");
- NodeSPI backupSubtree =
dataContainer.peek(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
- if (backupSubtree != null)
+
+ // need to loop through backupSubtree's children
+ Set allGroupNames = getBackupRoots();
+ if (allGroupNames != null)
{
- // need to loop through backupSubtree's children
- Set allGroupNames = backupSubtree.getChildrenNamesDirect();
- if (allGroupNames != null)
+ for (Object groupName : allGroupNames)
{
- for (Object groupName : allGroupNames)
+ // groupName is the name of a buddy group since all child names in
this
+ // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
+ Fqn backupRoot =
Fqn.fromRelativeElements(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, (String) groupName);
+ if (buddyFqnTransformer.isDeadBackupRoot(backupRoot))
{
- // groupName is the name of a buddy group since all child names in
this
- // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
- Fqn backupRoot =
Fqn.fromRelativeElements(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, (String) groupName);
- if (buddyFqnTransformer.isDeadBackupRoot(backupRoot))
+ Set<Integer> deadChildNames = new
TreeSet<Integer>(spi.getChildrenNames(backupRoot));
+ Integer[] elems = deadChildNames.toArray(new
Integer[deadChildNames.size()]);
+
+ // these are integers. we need to start with the highest/most
recent.
+ for (int i = elems.length - 1; i > -1; i--)
{
- Set<Integer> deadChildNames = new
TreeSet<Integer>(spi.getChildrenNames(backupRoot));
- Integer[] elems = deadChildNames.toArray(new
Integer[deadChildNames.size()]);
+ Integer versionOfDefunctData = elems[i];
+ backupNodeFqn =
Fqn.fromRelativeFqn(Fqn.fromRelativeElements(backupRoot, versionOfDefunctData), fqn);
- // these are integers. we need to start with the highest/most
recent.
- for (int i = elems.length - 1; i > -1; i--)
- {
- Integer versionOfDefunctData = elems[i];
- backupNodeFqn =
Fqn.fromRelativeFqn(Fqn.fromRelativeElements(backupRoot, versionOfDefunctData), fqn);
-
- // use a get() call into the cache to make sure cache loading
takes place.
- ctx.getOptionOverrides().setSkipDataGravitation(true);
- actualNode = spi.peek(backupNodeFqn, false);
- ctx.getOptionOverrides().setSkipDataGravitation(false);
-
- // break out of the inner loop searching through the dead
node's various backups
- if (actualNode != null) break;
- }
- }
- else
- {
- backupNodeFqn = Fqn.fromRelativeFqn(backupRoot, fqn);
// use a get() call into the cache to make sure cache loading
takes place.
ctx.getOptionOverrides().setSkipDataGravitation(true);
- actualNode = spi.getNode(backupNodeFqn);
+ actualNode = spi.peek(backupNodeFqn, false);
ctx.getOptionOverrides().setSkipDataGravitation(false);
+
+ // break out of the inner loop searching through the dead
node's various backups
+ if (actualNode != null) break;
}
+ }
+ else
+ {
+ backupNodeFqn = Fqn.fromRelativeFqn(backupRoot, fqn);
+ // use a get() call into the cache to make sure cache loading takes
place.
+ ctx.getOptionOverrides().setSkipDataGravitation(true);
+ actualNode = spi.getNode(backupNodeFqn);
+ ctx.getOptionOverrides().setSkipDataGravitation(false);
+ }
- if (trace)
- log.trace("Looking for " + backupNodeFqn + ".
Search result: " + actualNode);
+ if (trace)
+ log.trace("Looking for " + backupNodeFqn + ". Search
result: " + actualNode);
- // break out of outer loop searching through all available backups.
- if (actualNode != null) break;
- }
+ // break out of outer loop searching through all available backups.
+ if (actualNode != null) break;
}
}
+
}
if (actualNode == null)
@@ -174,6 +173,16 @@
}
}
+ /**
+ * @return a Set of child node names that hang directly off the backup tree root, or
null if the backup tree root doesn't exist.
+ */
+ protected Set<Object> getBackupRoots()
+ {
+ InternalNode backupSubtree =
dataContainer.peekInternalNode(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, false);
+ if (backupSubtree == null) return null;
+ return backupSubtree.getChildrenNames();
+ }
+
public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
{
return visitor.visitGravitateDataCommand(ctx, this);
Modified:
core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -4,7 +4,6 @@
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeSPI;
import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
import org.jboss.cache.buddyreplication.BuddyManager;
import org.jboss.cache.commands.CommandsFactory;
@@ -88,20 +87,18 @@
// if this is a DIRECT child of a DEAD buddy backup region, then remove
the empty dead region structural node.
if (buddyFqnTransformer.isDeadBackupFqn(backup) &&
buddyFqnTransformer.isDeadBackupRoot(backup.getAncestor(backup.size() - 2)))
{
- NodeSPI deadBackupRoot = dataContainer.peek(backup.getParent(), false);
// ctx.lookUpNode(backup.getParent());
- if (deadBackupRoot.getChildrenMapDirect().isEmpty())
+ Fqn deadBackupRootFqn = backup.getParent();
+ if (!dataContainer.hasChildren(deadBackupRootFqn))
{
- if (trace) log.trace("Removing dead backup region " +
deadBackupRoot.getFqn());
- executeRemove(gtx, deadBackupRoot.getFqn());
+ if (trace) log.trace("Removing dead backup region " +
deadBackupRootFqn);
+ executeRemove(gtx, deadBackupRootFqn);
// now check the grand parent and see if we are free of versions
-
-// deadBackupRoot =
ctx.lookUpNode(deadBackupRoot.getFqn().getParent());
- deadBackupRoot =
dataContainer.peek(deadBackupRoot.getFqn().getParent(), false);
- if (deadBackupRoot.getChildrenMapDirect().isEmpty())
+ deadBackupRootFqn = deadBackupRootFqn.getParent();
+ if (!dataContainer.hasChildren(deadBackupRootFqn))
{
- if (trace) log.trace("Removing dead backup region " +
deadBackupRoot.getFqn());
- executeRemove(gtx, deadBackupRoot.getFqn());
+ if (trace) log.trace("Removing dead backup region " +
deadBackupRootFqn);
+ executeRemove(gtx, deadBackupRootFqn);
}
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -4,10 +4,12 @@
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.Visitor;
import org.jboss.cache.commands.read.AbstractDataCommand;
import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.mvcc.ReadCommittedNode;
import org.jboss.cache.notifications.Notifier;
import java.util.Collection;
@@ -28,8 +30,8 @@
private boolean recursive = false;
protected Notifier notifier;
- private static final Log log = LogFactory.getLog(EvictCommand.class);
- private static final boolean trace = log.isTraceEnabled();
+ protected static final Log log = LogFactory.getLog(EvictCommand.class);
+ protected static final boolean trace = log.isTraceEnabled();
private List<Fqn> nodesToEvict;
public EvictCommand(Fqn fqn)
@@ -102,7 +104,7 @@
return nodesToEvict;
}
- boolean evictNode(Fqn fqn, InvocationContext ctx, NodeSPI node)
+ protected boolean evictNode(Fqn fqn, InvocationContext ctx, NodeSPI node)
{
notifier.notifyNodeEvicted(fqn, true, ctx);
try
@@ -118,15 +120,17 @@
else
{
if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn
+ ")");
- NodeSPI parentNode = lookupInAllScopes(ctx, fqn.getParent());
+ InternalNode parentNode = lookupInAllScopes(ctx, fqn.getParent());
if (parentNode != null)
{
- parentNode.removeChildDirect(fqn.getLastElement());
+ parentNode.removeChild(fqn.getLastElement());
parentNode.setChildrenLoaded(false);
}
node.setValid(false, false);
node.markAsDeleted(true);
+ node.setDataLoaded(false);
+ node.getDelegationTarget().clear();
return true;
}
}
@@ -136,14 +140,14 @@
}
}
- private NodeSPI lookupInAllScopes(InvocationContext ctx, Fqn fqn)
+ private InternalNode lookupInAllScopes(InvocationContext ctx, Fqn fqn)
{
- NodeSPI nodeSPI = lookupForEviction(ctx, fqn);
+ ReadCommittedNode nodeSPI = (ReadCommittedNode) lookupForEviction(ctx, fqn);
if (nodeSPI == null)
{
- nodeSPI = dataContainer.peek(fqn);
+ return dataContainer.peekInternalNode(fqn, true);
}
- return nodeSPI;
+ return nodeSPI.getDelegationTarget();
}
protected NodeSPI lookupForEviction(InvocationContext ctx, Fqn fqn)
Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -4,6 +4,7 @@
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.Visitor;
import org.jboss.cache.commands.WriteCommand;
@@ -67,7 +68,7 @@
*/
public Object perform(InvocationContext ctx)
{
- if (to.isDirectChildOf(fqn))
+ if (fqn.isDirectChildOf(to))
{
if (log.isDebugEnabled()) log.debug("Attempting to move " + fqn +
" onto itself. Nothing to do.");
return null;
@@ -99,10 +100,10 @@
{
if (trace) log.trace("Moving " + oldNode.getFqn() + " to " +
newNode.getFqn());
// start deep.
- Map<Object, NodeSPI> children = oldNode.getChildrenMapDirect();
+ Map<Object, InternalNode> children =
oldNode.getDelegationTarget().getChildrenMap();
if (children != null && !children.isEmpty())
{
- for (NodeSPI child : children.values())
+ for (InternalNode child : children.values())
{
Fqn childFqn = child.getFqn();
Fqn newChildFqn = childFqn.replaceAncestor(oldNode.getFqn(),
newNode.getFqn());
@@ -111,7 +112,7 @@
}
// now swap the data for the current node.
- newNode.putAllDirect(oldNode.getDataDirect());
+ newNode.getDelegationTarget().putAll(oldNode.getDelegationTarget().getData());
oldNode.markAsDeleted(true);
}
Deleted:
core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -1,181 +0,0 @@
-package org.jboss.cache.commands.write;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.CacheException;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeSPI;
-import org.jboss.cache.commands.VersionedDataCommand;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.optimistic.DataVersioningException;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.util.Collections;
-
-/**
- * Behaves like {@link org.jboss.cache.commands.write.InvalidateCommand}. Also,
potentially throws a cache exception if
- * data versioning is used and the node in memory has a newer data version than what is
passed in.
- * <p/>
- * Finally, the data version of the in-memory node is updated to the version being
evicted to prevent versions
- * going out of sync.
- * <p/>
- *
- * @author Mircea.Markus(a)jboss.com
- * @since 2.2
- */
-public class VersionedInvalidateCommand extends InvalidateCommand implements
VersionedDataCommand
-{
- private static final Log log = LogFactory.getLog(VersionedInvalidateCommand.class);
- private static final boolean trace = log.isTraceEnabled();
-
- /*
- dependencies
- */
- private TransactionManager transactionManager;
-
- /**
- * Params.
- */
- protected GlobalTransaction globalTransaction;
- private DataVersion dataVersion;
-
- public VersionedInvalidateCommand(Fqn fqn)
- {
- super(fqn);
- }
-
- public VersionedInvalidateCommand()
- {
- }
-
- public void initialize(TransactionManager txManager)
- {
- this.transactionManager = txManager;
- }
-
- @Override
- public Object perform(InvocationContext ctx)
- {
- NodeSPI node = enforceNodeLoading();
- if (trace) log.trace("Invalidating fqn:" + fqn);
- if (node == null)
- {
- // check if a tombstone already exists
- NodeSPI nodeSPI = dataContainer.peek(fqn, true, true);
- if (nodeSPI == null)
- {
- if (dataVersion == null)
- {
- if (trace)
- log.trace("Would have created a tombstone since the node
doesn't exist, but the version to invalidate is null and hence cannot create a
tombstone!");
- return null;
- }
- createTombstone(ctx);
- nodeSPI = (NodeSPI) dataContainer.getRoot().getChild(fqn);
- }
- node = nodeSPI;
- }
- else if (node.getVersion() == null)
- {
- throw new NullPointerException("Node " + node.getFqn() + " has a
null data version, and is of type " + node.getClass().getSimpleName() + ". This
command expects versioned nodes.");
- }
- else
- if (dataVersion != null && node.getVersion().newerThan(dataVersion)) //
dataVersion *could* be null if the invalidate was triggered by removing a node that did
not exist in the first place.
- {
- String errMsg = new StringBuilder("Node found, but version is not equal to
or less than the expected [").append(dataVersion).append("]. Is
[").append(node.getVersion()).append("] instead!").toString();
- log.warn(errMsg);
- throw new DataVersioningException(errMsg);
- }
-
- removeData(node, ctx);
- invalidateNode(node);
- node.setVersion(dataVersion);
- return null;
- }
-
- protected void createTombstone(InvocationContext ctx)
- {
- if (trace)
- log.trace("Node doesn't exist; creating a tombstone with data version
" + dataVersion);
- // create the node we need.
- Option o = ctx.getOptionOverrides();
- boolean origCacheModeLocal = o.isCacheModeLocal();
- o.setCacheModeLocal(true);
- o.setDataVersion(dataVersion);
- // if we are in a tx this call should happen outside of any tx
- try
- {
- Transaction suspended = null;
- if (transactionManager != null)
- {
- suspended = transactionManager.suspend();
- }
- spi.put(fqn, Collections.emptyMap());
- if (suspended != null) transactionManager.resume(suspended);
- ctx.getOptionOverrides().setCacheModeLocal(origCacheModeLocal);
- }
- catch (Exception e)
- {
- log.error("Unable to create tombstone!", e);
- }
- }
-
- protected void removeData(NodeSPI n, InvocationContext ctx) throws CacheException
- {
- notifier.notifyNodeEvicted(fqn, true, ctx);
- n.clearDataDirect();
- n.setDataLoaded(false);
- notifier.notifyNodeEvicted(fqn, false, ctx);
- }
-
- public DataVersion getDataVersion()
- {
- return dataVersion;
- }
-
- public void setDataVersion(DataVersion dataVersion)
- {
- this.dataVersion = dataVersion;
- }
-
- public GlobalTransaction getGlobalTransaction()
- {
- return globalTransaction;
- }
-
- public void setGlobalTransaction(GlobalTransaction gtx)
- {
- this.globalTransaction = gtx;
- }
-
- public boolean isVersioned()
- {
- return dataVersion != null;
- }
-
- @Override
- public String toString()
- {
- return "OptimisticInvalidateCommand{" +
- "dataVersion=" + dataVersion +
- " ,fqn=" + fqn +
- '}';
- }
-
- @Override
- public Object[] getParameters()
- {
- return new Object[]{fqn, dataVersion};
- }
-
- @Override
- public void setParameters(int commandId, Object[] args)
- {
- fqn = (Fqn) args[0];
- dataVersion = (DataVersion) args[1];
- }
-}
Modified: core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -177,6 +177,7 @@
s.add(ContextMetaFactory.class);
s.add(NodeMetaFactory.class);
s.add(StateTransferManagerFactory.class);
+ s.add(StateTransferFactory.class);
s.add(RegionManagerFactory.class);
s.add(NodeMetaFactory.class);
s.add(CommandsMetaFactory.class);
Copied: core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java (from
rev 6358,
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -0,0 +1,55 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at
gnu.org.
+ */
+package org.jboss.cache.factories;
+
+import org.jboss.cache.factories.annotations.DefaultFactoryFor;
+import org.jboss.cache.statetransfer.DefaultStateTransferGenerator;
+import org.jboss.cache.statetransfer.DefaultStateTransferIntegrator;
+import org.jboss.cache.statetransfer.LegacyStateTransferGenerator;
+import org.jboss.cache.statetransfer.LegacyStateTransferIntegrator;
+import org.jboss.cache.statetransfer.StateTransferGenerator;
+import org.jboss.cache.statetransfer.StateTransferIntegrator;
+
+/**
+ * Factory class able to create {@link
org.jboss.cache.statetransfer.StateTransferGenerator} and
+ * {@link org.jboss.cache.statetransfer.StateTransferIntegrator} instances.
+ * <p/>
+ * Updated in 3.0.0 to extend ComponentFactory, etc.
+ * <p/>
+ *
+ * @author <a href="brian.stansberry(a)jboss.com">Brian
Stansberry</a>
+ * @author Manik Surtani
+ * @version $Revision$
+ */
+@DefaultFactoryFor(classes = {StateTransferGenerator.class,
StateTransferIntegrator.class})
+public class StateTransferFactory extends ComponentFactory
+{
+ protected <T> T construct(Class<T> componentType)
+ {
+
+ if (componentType.equals(StateTransferIntegrator.class))
+ {
+ switch (configuration.getNodeLockingScheme())
+ {
+ case MVCC:
+ return (T) new DefaultStateTransferIntegrator();
+ default:
+ return (T) new LegacyStateTransferIntegrator();
+ }
+ }
+ else
+ {
+ switch (configuration.getNodeLockingScheme())
+ {
+ case MVCC:
+ return (T) new DefaultStateTransferGenerator();
+ default:
+ return (T) new LegacyStateTransferGenerator();
+ }
+ }
+ }
+}
Property changes on:
core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Modified:
core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -1,8 +1,8 @@
package org.jboss.cache.interceptors;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.Modification;
-import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.AbstractVisitor;
import org.jboss.cache.commands.read.GetChildrenNamesCommand;
import org.jboss.cache.commands.read.GetKeyValueCommand;
@@ -95,7 +95,7 @@
public Object visitGetChildrenNamesCommand(InvocationContext ctx,
GetChildrenNamesCommand command) throws Throwable
{
Object returnValue = super.visitGetChildrenNamesCommand(ctx, command);
- removeNodeFromCacheLoader(ctx, command.getFqn());
+ removeNodeFromCacheLoader(command.getFqn());
return returnValue;
}
@@ -103,7 +103,7 @@
public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command)
throws Throwable
{
Object returnValue = super.visitGetKeysCommand(ctx, command);
- removeNodeFromCacheLoader(ctx, command.getFqn());
+ removeNodeFromCacheLoader(command.getFqn());
return returnValue;
}
@@ -111,7 +111,7 @@
public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command)
throws Throwable
{
Object returnValue = super.visitGetNodeCommand(ctx, command);
- removeNodeFromCacheLoader(ctx, command.getFqn());
+ removeNodeFromCacheLoader(command.getFqn());
return returnValue;
}
@@ -119,7 +119,7 @@
public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand
command) throws Throwable
{
Object returnValue = super.visitGetKeyValueCommand(ctx, command);
- removeNodeFromCacheLoader(ctx, command.getFqn());
+ removeNodeFromCacheLoader(command.getFqn());
return returnValue;
}
@@ -133,7 +133,7 @@
public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand
command) throws Throwable
{
Object returnValue = super.visitPutKeyValueCommand(ctx, command);
- removeNodeFromCacheLoader(ctx, command.getFqn());
+ removeNodeFromCacheLoader(command.getFqn());
return returnValue;
}
@@ -141,7 +141,7 @@
public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command)
throws Throwable
{
Object returnValue = super.visitPutDataMapCommand(ctx, command);
- removeNodeFromCacheLoader(ctx, command.getFqn());
+ removeNodeFromCacheLoader(command.getFqn());
return returnValue;
}
@@ -149,7 +149,7 @@
public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command)
throws Throwable
{
Object returnValue = super.visitRemoveKeyCommand(ctx, command);
- removeNodeFromCacheLoader(ctx, command.getFqn());
+ removeNodeFromCacheLoader(command.getFqn());
return returnValue;
}
@@ -160,8 +160,8 @@
if (trace)
log.trace("This is a move operation; removing the FROM node from the
loader, no activation processing needed.");
loader.remove(command.getFqn());
- removeNodeFromCacheLoader(ctx, command.getFqn().getParent());
- removeNodeFromCacheLoader(ctx, command.getTo());
+ removeNodeFromCacheLoader(command.getFqn().getParent());
+ removeNodeFromCacheLoader(command.getTo());
return returnValue;
}
@@ -172,13 +172,13 @@
* AND it was found in the cache loader (nodeLoaded = true).
* Then notify the listeners that the node has been activated.
*/
- private void removeNodeFromCacheLoader(InvocationContext ctx, Fqn fqn) throws
Throwable
+ private void removeNodeFromCacheLoader(Fqn fqn) throws Throwable
{
- NodeSPI n;
- if (((n = dataContainer.peek(fqn, true, false)) != null) &&
n.isDataLoaded() && loader.exists(fqn))
+ InternalNode n;
+ if (((n = dataContainer.peekInternalNode(fqn, true)) != null) &&
n.isDataLoaded() && loader.exists(fqn))
{
// node not null and attributes have been loaded?
- if (!n.getChildrenDirect().isEmpty())
+ if (n.hasChildren())
{
boolean result = childrenLoaded(n);
if (result)
@@ -195,13 +195,13 @@
}
}
- private static boolean childrenLoaded(NodeSPI<?, ?> node)
+ private static boolean childrenLoaded(InternalNode<?, ?> node)
{
if (!node.isChildrenLoaded())
{
return false;
}
- for (NodeSPI child : node.getChildrenDirect())
+ for (InternalNode child : node.getChildren())
{
if (!child.isDataLoaded())
{
@@ -342,24 +342,24 @@
private void handlePutCommand(InvocationContext ctx, Fqn fqn)
throws Exception
{
- if (fqn != null && dataContainer.peek(fqn, false, false) != null
&& loader.exists(fqn))
+ if (fqn != null && dataContainer.exists(fqn) &&
loader.exists(fqn))
{
- NodeSPI n = dataContainer.peek(fqn, true, false);// don't load
+ InternalNode n = dataContainer.peekInternalNode(fqn, true);// don't load
// node not null and attributes have been loaded?
if (n != null && n.isDataLoaded())
{
// has children?
boolean result = childrenLoaded(n);
- if (!n.getChildrenDirect().isEmpty() && result)
+ if (n.hasChildren() && result)
{
// children have been loaded, remove the node
- addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+ addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
txActs++;
}
// doesn't have children, check the cache loader
else if (loaderNoChildren(fqn))
{
- addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+ addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
txActs++;
}
}
Modified:
core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -3,6 +3,7 @@
import org.jboss.cache.CacheException;
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.read.GetChildrenNamesCommand;
import org.jboss.cache.commands.read.GetDataMapCommand;
@@ -155,8 +156,7 @@
if (fqn != null)
{
loadIfNeeded(ctx, fqn, null, false, false, false, false, false, true, true);
- NodeSPI n = dataContainer.peek(fqn, true, true);
- loadChildren(fqn, n, false, false, ctx);
+ loadChildren(fqn, dataContainer.peekInternalNode(fqn, true), false, false,
ctx);
}
return invokeNextInterceptor(ctx, command);
}
@@ -266,7 +266,8 @@
if (n == null && loader.exists(fqn))
{
// just create a dummy node in memory
- n = helper.wrapNodeForWriting(ctx, fqn, true, true, true, false, false);
// won't create any nodes but will acquire locks.
+ n = helper.wrapNodeForWriting(ctx, fqn, true, true, true, false, false);
+ n.setDataLoaded(false);
}
if (!bypassLoadingData)
{
@@ -276,9 +277,9 @@
}
// The complete list of children aren't known without loading them
- if (recursive)
+ if (recursive && n != null)
{
- loadChildren(fqn, n, recursive, isMove, ctx);
+ loadChildren(fqn, n.getDelegationTarget(), recursive, isMove, ctx);
}
}
@@ -288,7 +289,7 @@
* @param node may be null if the node was not found.
* @param ctxt
*/
- private void loadChildren(Fqn fqn, NodeSPI node, boolean recursive, boolean isMove,
InvocationContext ctxt) throws Throwable
+ private void loadChildren(Fqn fqn, InternalNode node, boolean recursive, boolean
isMove, InvocationContext ctxt) throws Throwable
{
if (node != null && node.isChildrenLoaded())
@@ -320,7 +321,7 @@
{
if (useCacheStore)
{
- node.removeChildrenDirect();//getChildrenMapDirect().clear();
+ node.removeChildren();
}
node.setChildrenLoaded(true);
}
@@ -330,7 +331,8 @@
// Create if node had not been created already
if (node == null)
{
- node = helper.wrapNodeForWriting(ctxt, fqn, true, true, true, false, false);
+ NodeSPI temp = helper.wrapNodeForWriting(ctxt, fqn, true, true, true, false,
false);
+ node = temp.getDelegationTarget();
}
// Create one DataNode per child, mark as UNINITIALIZED
@@ -340,6 +342,7 @@
// create child if it didn't exist
NodeSPI child = helper.wrapNodeForWriting(ctxt, childFqn, true, true, true,
false, false);
+ if (child.isCreated()) child.setDataLoaded(false);
if ((isMove || isActivation) && recursive)
{
// load data for children as well!
@@ -349,7 +352,7 @@
if (recursive)
{
- loadChildren(child.getFqn(), child, true, isMove, ctxt);
+ loadChildren(child.getFqn(), child.getDelegationTarget(), true, isMove,
ctxt);
}
}
node.setChildrenLoaded(true);
Modified:
core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -160,7 +160,7 @@
}
else
{
- if (dataContainer.peek(command.getFqn(), false, false) == null)
+ if (!dataContainer.exists(command.getFqn()))
{
// gravitation is necessary.
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -9,7 +9,6 @@
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeSPI;
import org.jboss.cache.Region;
import org.jboss.cache.RegionManager;
import org.jboss.cache.commands.read.GetDataMapCommand;
@@ -237,12 +236,8 @@
return;
}
- NodeSPI<?, ?> nodeSPI = dataContainer.peek(event.getFqn(), false, false);
//we do not trigger eviction events for resident nodes
- if (nodeSPI != null && nodeSPI.isResident())
- {
- return;
- }
+ if (dataContainer.isResident(event.getFqn())) return;
region.putNodeEvent(event);
Modified:
core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -11,6 +11,7 @@
import org.jboss.cache.commands.CommandsFactory;
import org.jboss.cache.commands.VisitableCommand;
import org.jboss.cache.commands.WriteCommand;
+import org.jboss.cache.commands.legacy.write.VersionedInvalidateCommand;
import org.jboss.cache.commands.tx.CommitCommand;
import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
import org.jboss.cache.commands.tx.PrepareCommand;
@@ -23,7 +24,6 @@
import org.jboss.cache.commands.write.PutKeyValueCommand;
import org.jboss.cache.commands.write.RemoveKeyCommand;
import org.jboss.cache.commands.write.RemoveNodeCommand;
-import org.jboss.cache.commands.write.VersionedInvalidateCommand;
import org.jboss.cache.config.Configuration.NodeLockingScheme;
import org.jboss.cache.config.Option;
import org.jboss.cache.factories.annotations.Inject;
Modified:
core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -2,6 +2,7 @@
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.NodeFactory;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.commands.VisitableCommand;
@@ -30,7 +31,6 @@
import org.jboss.cache.invocation.InvocationContext;
import org.jboss.cache.lock.LockManager;
import org.jboss.cache.mvcc.MVCCNodeHelper;
-import org.jboss.cache.mvcc.ReadCommittedNode;
import java.util.Collections;
import java.util.LinkedList;
@@ -130,11 +130,11 @@
if (command.getFqn().isRoot())
{
// special treatment - deal with all of root's kids instead.
- Map<Object, NodeSPI> children =
dataContainer.peek(Fqn.ROOT).getChildrenMapDirect();
+ Map<Object, InternalNode> children =
dataContainer.peekInternalNode(Fqn.ROOT, false).getChildrenMap();
if (children != null && !children.isEmpty())
{
fqnsToEvict = new LinkedList<Fqn>();
- for (NodeSPI child : children.values())
+ for (InternalNode child : children.values())
fqnsToEvict.addAll(helper.wrapNodesForWriting(ctx, child.getFqn()));
}
else
@@ -155,7 +155,7 @@
{
if (command.getFqn().isRoot())
{
- Map<Object, NodeSPI> children =
dataContainer.peek(Fqn.ROOT).getChildrenMapDirect();
+ Map<Object, NodeSPI> children = dataContainer.peekInternalNode(Fqn.ROOT,
false).getChildrenMap();
if (children != null && !children.isEmpty())
{
for (NodeSPI child : children.values())
@@ -329,7 +329,7 @@
{
Fqn f = it.previous();
// for each of these, swap refs
- ReadCommittedNode rcn = (ReadCommittedNode) ctx.lookUpNode(f);
+ NodeSPI rcn = ctx.lookUpNode(f);
if (rcn != null) rcn.commitUpdate(ctx, dataContainer, nodeFactory); //
could be null with read-committed
// and then unlock
if (trace) log.trace("Releasing lock on [" + f + "] for
thread " + owner);
@@ -363,7 +363,7 @@
while (it.hasPrevious())
{
Fqn f = it.previous();
- ReadCommittedNode rcn = (ReadCommittedNode) ctx.lookUpNode(f);
+ NodeSPI rcn = ctx.lookUpNode(f);
if (rcn != null) // could be null with read-committed
{
if (commit)
Modified:
core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -30,12 +30,14 @@
import org.jboss.cache.commands.write.RemoveKeyCommand;
import org.jboss.cache.commands.write.RemoveNodeCommand;
import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
import org.jboss.cache.config.Option;
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.factories.annotations.NonVolatile;
import org.jboss.cache.interceptors.base.CommandInterceptor;
import org.jboss.cache.loader.CacheLoaderManager;
import org.jboss.cache.marshall.Marshaller;
+import org.jboss.cache.mvcc.MVCCNodeHelper;
import org.jboss.cache.notifications.Notifier;
import org.jboss.cache.statetransfer.StateTransferManager;
import org.jboss.cache.transaction.GlobalTransaction;
@@ -74,12 +76,13 @@
private Marshaller marshaller;
private DataContainer dataContainer;
private CommandsFactory commandsFactory;
+ private MVCCNodeHelper mvccHelper;
@Inject
public void initialize(StateTransferManager stateTransferManager, CacheLoaderManager
cacheLoaderManager, Notifier notifier,
TransactionManager transactionManager, BuddyManager
buddyManager, TransactionTable transactionTable,
RPCManager rpcManager, RegionManager regionManager, Marshaller
marshaller,
- CommandsFactory commandsFactory, DataContainer dataContainer)
+ CommandsFactory commandsFactory, DataContainer dataContainer,
MVCCNodeHelper mvccHelper)
{
this.stateTransferManager = stateTransferManager;
this.cacheLoaderManager = cacheLoaderManager;
@@ -92,6 +95,7 @@
this.marshaller = marshaller;
this.dataContainer = dataContainer;
this.commandsFactory = commandsFactory;
+ this.mvccHelper = mvccHelper;
}
private void reset()
@@ -248,15 +252,37 @@
@SuppressWarnings("unchecked")
public NodeSPI<K, V> peek(Fqn fqn, boolean includeDeletedNodes, boolean
includeInvalidNodes)
{
- return (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes,
includeInvalidNodes);
+ // TODO: clean this up somehow! Anyway, this method should NOT be used outside of
testing frameworks.
+ return (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
+ ? mvccPeek(fqn)
+ : (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes,
includeInvalidNodes);
}
@SuppressWarnings("unchecked")
public NodeSPI<K, V> peek(Fqn fqn, boolean includeDeletedNodes)
{
- return (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes);
+ // TODO: clean this up somehow! Anyway, this method should NOT be used outside of
testing frameworks.
+ return (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
+ ? mvccPeek(fqn)
+ : (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes);
}
+ @SuppressWarnings("unchecked")
+ private NodeSPI<K, V> mvccPeek(Fqn f)
+ {
+ NodeSPI<K, V> n;
+ try
+ {
+ n = mvccHelper.wrapNodeForReading(getInvocationContext(), f);
+ }
+ catch (InterruptedException e)
+ {
+ throw new CacheException(e);
+ }
+ if (n == null || n.isNullNode()) return null;
+ return n;
+ }
+
public void addCacheListener(Object listener)
{
notifier.addCacheListener(listener);
Modified: core/trunk/src/main/java/org/jboss/cache/invocation/NodeInvocationDelegate.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/invocation/NodeInvocationDelegate.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/invocation/NodeInvocationDelegate.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -4,9 +4,11 @@
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
import org.jboss.cache.InternalNode;
import org.jboss.cache.Node;
+import org.jboss.cache.NodeFactory;
import org.jboss.cache.NodeNotValidException;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.config.Option;
@@ -71,12 +73,12 @@
public Map<Object, Node<K, V>> getChildrenMapDirect()
{
- return node.getChildrenMap();
+ return node.getChildrenMapDirect();
}
public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
{
- node.setChildrenMap(children);
+ node.setChildrenMapDirect(children);
}
public NodeSPI<K, V> getOrCreateChild(Object name, GlobalTransaction tx)
@@ -112,7 +114,7 @@
public void addChild(Object nodeName, Node<K, V> nodeToAdd)
{
- node.addChild(nodeName, nodeToAdd);
+ node.addChildDirect(nodeName, nodeToAdd);
}
public void printDetails(StringBuilder sb, int indent)
@@ -137,7 +139,7 @@
public Set<NodeSPI<K, V>> getChildrenDirect()
{
- return node.getChildren();
+ return node.getChildrenDirect();
}
public void removeChildrenDirect()
@@ -147,37 +149,37 @@
public Set<NodeSPI<K, V>> getChildrenDirect(boolean
includeMarkedAsDeleted)
{
- return node.getChildren(includeMarkedAsDeleted);
+ return node.getChildrenDirect(includeMarkedAsDeleted);
}
public NodeSPI<K, V> getChildDirect(Object childName)
{
- return node.getChild(childName);
+ return node.getChildDirect(childName);
}
public NodeSPI<K, V> addChildDirect(Fqn childName)
{
- return node.addChild(childName);
+ return node.addChildDirect(childName);
}
public NodeSPI<K, V> addChildDirect(Fqn f, boolean notify)
{
- return node.addChild(f, notify);
+ return node.addChildDirect(f, notify);
}
public NodeSPI<K, V> addChildDirect(Object childName, boolean notify)
{
- return node.addChild(childName, notify);
+ return node.addChildDirect(childName, notify);
}
public void addChildDirect(NodeSPI<K, V> child)
{
- node.addChild(child);
+ node.addChildDirect(child);
}
public NodeSPI<K, V> getChildDirect(Fqn childName)
{
- return node.getChild(childName);
+ return node.getChildDirect(childName);
}
public boolean removeChildDirect(Fqn fqn)
@@ -516,4 +518,41 @@
{
return (node != null ? node.hashCode() : 0);
}
+
+ // -------------- NO OP methods so that subclasses can work. Specifically for MVCC,
todo: rethink once we drop PL/OL support -----------
+ public boolean isNullNode()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void markForUpdate(InvocationContext ctx, DataContainer container, NodeFactory
nodeFactory, boolean writeSkewCheck)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void commitUpdate(InvocationContext ctx, DataContainer container, NodeFactory
nodeFactory)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isChanged()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isCreated()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setCreated(boolean b)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void rollbackUpdate()
+ {
+ throw new UnsupportedOperationException();
+ }
+
}
Modified: core/trunk/src/main/java/org/jboss/cache/lock/LockUtil.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/LockUtil.java 2008-07-28 10:29:41 UTC
(rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/lock/LockUtil.java 2008-07-28 10:56:29 UTC
(rev 6414)
@@ -28,7 +28,7 @@
int STATUS_BROKEN = Integer.MIN_VALUE;
}
- public static boolean breakTransactionLock(NodeSPI node,
+ public static boolean breakTransactionLock(Fqn fqn,
LockManager lockManager,
GlobalTransaction gtx,
boolean localTx,
@@ -38,9 +38,9 @@
int tryCount = 0;
int lastStatus = TransactionLockStatus.STATUS_BROKEN;
- while (!broken && lockManager.ownsLock(node.getFqn(), gtx))
+ while (!broken && lockManager.ownsLock(fqn, gtx))
{
- int status = breakTransactionLock(gtx, node, lockManager, tx_table, tm, localTx,
lastStatus, tryCount);
+ int status = breakTransactionLock(gtx, fqn, lockManager, tx_table, tm, localTx,
lastStatus, tryCount);
if (status == TransactionLockStatus.STATUS_BROKEN)
{
broken = true;
@@ -82,7 +82,7 @@
* if the lock held by gtx was forcibly broken.
*/
private static int breakTransactionLock(GlobalTransaction gtx,
- NodeSPI node, LockManager lockManager,
+ Fqn fqn, LockManager lockManager,
TransactionTable transactionTable,
TransactionManager tm,
boolean localTx,
@@ -131,7 +131,7 @@
{
// Something is wrong; our initial rollback call
// didn't generate a valid state change; just force it
- lockManager.unlock(node.getFqn(), gtx);
+ lockManager.unlock(fqn, gtx);
status = TransactionLockStatus.STATUS_BROKEN;
}
break;
@@ -148,7 +148,7 @@
case Status.STATUS_COMMITTED:
case Status.STATUS_ROLLEDBACK:
case Status.STATUS_NO_TRANSACTION:
- lockManager.unlock(node.getFqn(), gtx);
+ lockManager.unlock(fqn, gtx);
status = TransactionLockStatus.STATUS_BROKEN;
break;
@@ -180,14 +180,14 @@
// fall through and release
default:
- lockManager.unlock(node.getFqn(), gtx);
+ lockManager.unlock(fqn, gtx);
status = TransactionLockStatus.STATUS_BROKEN;
}
}
catch (Exception e)
{
log.error("Exception breaking locks held by " + gtx, e);
- lockManager.unlock(node.getFqn(), gtx);
+ lockManager.unlock(fqn, gtx);
status = TransactionLockStatus.STATUS_BROKEN;
}
}
@@ -195,10 +195,10 @@
{
// Race condition; globalTransaction was cleared from txTable.
// Just double check if globalTransaction still holds a lock
- if (lockManager.ownsLock(node.getFqn(), gtx))
+ if (lockManager.ownsLock(fqn, gtx))
{
// perhaps we should throw an exception?
- lockManager.unlock(node.getFqn(), gtx);
+ lockManager.unlock(fqn, gtx);
status = TransactionLockStatus.STATUS_BROKEN;
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java 2008-07-28 10:29:41
UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java 2008-07-28 10:56:29
UTC (rev 6414)
@@ -6,6 +6,7 @@
import org.jboss.cache.CacheSPI;
import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.Node;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.factories.annotations.Inject;
@@ -21,6 +22,7 @@
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
+import java.util.Map;
import java.util.Set;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.locks.Lock;
@@ -134,7 +136,7 @@
}
}
- protected boolean lockRecursively(Node<?, ?> node, long timeoutMillis, boolean
excludeInternalFqns, InvocationContext ctx) throws InterruptedException
+ private boolean lockRecursively(InternalNode node, long timeoutMillis, boolean
excludeInternalFqns, InvocationContext ctx) throws InterruptedException
{
if (excludeInternalFqns && internalFqns.contains(node.getFqn()))
return true; // this will stop the recursion from proceeding down this subtree.
@@ -148,19 +150,17 @@
// need to recursively walk through the node's children and acquire locks.
This needs to happen using API methods
// since any cache loading will need to happen.
- Set<? extends Node<?, ?>> children = node.getChildren();
+ //Set<InternalNode> children = node.getChildren();
+ Map<Object, InternalNode> children = node.getChildrenMap();
try
{
- if (children != null)
+ for (InternalNode child : children.values())
{
- for (Node child : children)
+ locked = lockRecursively(child, timeoutMillis, excludeInternalFqns, ctx);
+ if (!locked)
{
- locked = lockRecursively(child, timeoutMillis, excludeInternalFqns, ctx);
- if (!locked)
- {
- needToUnlock = true;
- break;
- }
+ needToUnlock = true;
+ break;
}
}
}
@@ -168,7 +168,7 @@
{
if (needToUnlock)
{
- for (Node child : children)
+ for (InternalNode child : children.values())
{
Fqn childFqn = child.getFqn();
unlock(childFqn, null);
@@ -184,30 +184,30 @@
public boolean lockAll(NodeSPI node, LockType lockType, Object owner) throws
InterruptedException
{
if (lockType == READ) return true; // we don't support read locks. TODO:
enforce this with an assertion
- return lockRecursively(node, lockAcquisitionTimeout, false, null);
+ return lockRecursively(node.getDelegationTarget(), lockAcquisitionTimeout, false,
null);
}
public boolean lockAll(NodeSPI node, LockType lockType, Object owner, long timeout)
throws InterruptedException
{
if (lockType == READ) return true; // we don't support read locks. TODO:
enforce this with an assertion
- return lockRecursively(node, timeout, false, null);
+ return lockRecursively(node.getDelegationTarget(), timeout, false, null);
}
public boolean lockAll(NodeSPI node, LockType lockType, Object owner, long timeout,
boolean excludeInternalFqns) throws InterruptedException
{
if (lockType == READ) return true; // we don't support read locks. TODO:
enforce this with an assertion
- return lockRecursively(node, timeout, excludeInternalFqns, null);
+ return lockRecursively(node.getDelegationTarget(), timeout, excludeInternalFqns,
null);
}
public boolean lockAllAndRecord(NodeSPI node, LockType lockType, InvocationContext
ctx) throws InterruptedException
{
if (lockType == READ) return true; // we don't support read locks. TODO:
enforce this with an assertion
- return lockRecursively(node, ctx.getLockAcquisitionTimeout(lockAcquisitionTimeout),
false, ctx);
+ return lockRecursively(node.getDelegationTarget(),
ctx.getLockAcquisitionTimeout(lockAcquisitionTimeout), false, ctx);
}
public boolean lockAllAndRecord(Fqn fqn, LockType lockType, InvocationContext ctx)
throws InterruptedException
{
- return lockAllAndRecord(dataContainer.peek(fqn, false), lockType, ctx);
+ return lockRecursively(dataContainer.peekInternalNode(fqn, false),
ctx.getLockAcquisitionTimeout(lockAcquisitionTimeout), false, ctx);
}
public void unlockAll(NodeSPI<?, ?> node, Object owner)
Modified: core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -17,8 +17,10 @@
/**
* @author Mircea.Markus(a)jboss.com
* @since 2.2
+ * @deprecated since this is specific to legacy locking schemes
*/
@SuppressWarnings("deprecation")
+@Deprecated
public class NodeBasedLockManager extends AbstractLockManager
{
private static final Log log = LogFactory.getLog(NodeBasedLockManager.class);
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java 2008-07-28 10:29:41
UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java 2008-07-28 10:56:29
UTC (rev 6414)
@@ -58,31 +58,46 @@
return rcn;
}
- private NodeSPI<K, V> initializeNodeInvocationDelegate(UnversionedNode<K,
V> internal)
+// private NodeSPI<K, V> initializeNodeInvocationDelegate(UnversionedNode<K,
V> internal)
+// {
+// internal.injectDependencies(cache, commandsFactory, this);
+//
+// // always assume that new nodes do not have data loaded
+// internal.setDataLoaded(false);
+// NodeSPI<K, V> nid = createNodeInvocationDelegate(internal,
!useRepeatableRead);
+//
+// // back reference
+// internal.setDelegate(nid);
+// return nid;
+// }
+
+ @Override
+ public NodeSPI<K, V> createNode(Fqn fqn, NodeSPI<K, V> parent, Map<K,
V> data)
{
- internal.injectDependencies(cache, commandsFactory, this);
+// UnversionedNode<K, V> internal = new UnversionedNode<K, V>(fqn,
cache, lockChildForInsertRemove, data);
+// return initializeNodeInvocationDelegate(internal);
+ throw new UnsupportedOperationException();
+ }
- // always assume that new nodes do not have data loaded
- internal.setDataLoaded(false);
- NodeSPI<K, V> nid = createNodeInvocationDelegate(internal,
!useRepeatableRead);
-
- // back reference
- internal.setDelegate(nid);
- return nid;
+ @Override
+ public NodeSPI<K, V> createNode(Fqn fqn, NodeSPI<K, V> parent)
+ {
+// UnversionedNode<K, V> internal = new UnversionedNode<K, V>(fqn,
cache, lockChildForInsertRemove);
+// return initializeNodeInvocationDelegate(internal);
+ throw new UnsupportedOperationException();
}
@Override
- public NodeSPI<K, V> createNode(Fqn fqn, NodeSPI<K, V> parent, Map<K,
V> data)
+ public NodeSPI<K, V> createRootNode()
{
- UnversionedNode<K, V> internal = new UnversionedNode<K, V>(fqn, cache,
lockChildForInsertRemove, data);
- return initializeNodeInvocationDelegate(internal);
+ return createWrappedNode(createInternalNode(Fqn.ROOT));
}
@Override
- public NodeSPI<K, V> createNode(Fqn fqn, NodeSPI<K, V> parent)
+ public InternalNode<K, V> createInternalNode(Fqn fqn)
{
- UnversionedNode<K, V> internal = new UnversionedNode<K, V>(fqn, cache,
lockChildForInsertRemove);
- return initializeNodeInvocationDelegate(internal);
+ UnversionedNode<K, V> un = new UnversionedNode<K, V>(fqn, cache,
lockChildForInsertRemove);
+ return useRepeatableRead ? un : new NodeReference<K, V>(un);
}
@Override
@@ -97,30 +112,30 @@
return createNode(Fqn.fromRelativeElements(parent.getFqn(), childName), parent);
}
- @Override
- public NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V>
internalNode, boolean wrapWithNodeReference)
- {
- if (wrapWithNodeReference && internalNode instanceof NodeReference)
- throw new IllegalArgumentException("Cannot wrap a NodeReference with a
NodeReference!");
- if (wrapWithNodeReference && useRepeatableRead)
- throw new IllegalArgumentException("Cannot use NodeReferences with
RepeatableRead!");
- if (wrapWithNodeReference) internalNode = new NodeReference<K,
V>(internalNode);
- return super.createNodeInvocationDelegate(internalNode, false);
- }
+// @Override
+// protected NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V>
internalNode, boolean wrapWithNodeReference)
+// {
+// if (wrapWithNodeReference && internalNode instanceof NodeReference)
+// throw new IllegalArgumentException("Cannot wrap a NodeReference with a
NodeReference!");
+// if (wrapWithNodeReference && useRepeatableRead)
+// throw new IllegalArgumentException("Cannot use NodeReferences with
RepeatableRead!");
+// if (wrapWithNodeReference) internalNode = new NodeReference<K,
V>(internalNode);
+// return super.createNodeInvocationDelegate(internalNode, false);
+// }
@Override
- public NodeSPI<K, V> createAndRegister(Fqn fqn, NodeSPI<K, V> parent,
InvocationContext ctx, boolean attachToParent)
+ public InternalNode<K, V> createAndRegister(Fqn fqn, InternalNode<K, V>
parent, InvocationContext ctx, boolean attachToParent)
{
- NodeSPI<K, V> child;
+ InternalNode<K, V> child;
if (fqn == null) throw new IllegalArgumentException("null child fqn");
- child = dataContainer.peek(fqn, false);
+ child = dataContainer.peekInternalNode(fqn, false);
if (child == null)
{
cache.getNotifier().notifyNodeCreated(fqn, true, ctx);
- NodeSPI<K, V> newChild = createNode(fqn, parent);
- if (attachToParent) parent.addChildDirect(newChild);
+ InternalNode<K, V> newChild = createInternalNode(fqn);
+ if (attachToParent) parent.addChild(newChild);
// addChild actually succeeded!
child = newChild;
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java 2008-07-28 10:29:41
UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java 2008-07-28 10:56:29
UTC (rev 6414)
@@ -13,8 +13,6 @@
import org.jboss.cache.factories.annotations.NonVolatile;
import org.jboss.cache.factories.annotations.Start;
import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.invocation.NodeInvocationDelegate;
-import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.lock.LockManager;
import static org.jboss.cache.lock.LockType.WRITE;
import org.jboss.cache.lock.TimeoutException;
@@ -95,12 +93,12 @@
* @return read committed node, or null if one is not found.
* @throws InterruptedException if write locks are forced and the lock manager is
interrupted.
*/
- public ReadCommittedNode wrapNodeForReading(InvocationContext ctx, Fqn fqn) throws
InterruptedException
+ public NodeSPI wrapNodeForReading(InvocationContext ctx, Fqn fqn) throws
InterruptedException
{
return wrapNodeForReading(ctx, fqn, ctx.getOptionOverrides().isForceWriteLock());
}
- private ReadCommittedNode wrapNodeForReading(InvocationContext ctx, Fqn f, boolean
writeLockForced) throws InterruptedException
+ private NodeSPI wrapNodeForReading(InvocationContext ctx, Fqn f, boolean
writeLockForced) throws InterruptedException
{
NodeSPI n;
if (writeLockForced)
@@ -120,7 +118,7 @@
else
{
if (trace) log.trace("Node " + f + " is already in
context.");
- return (ReadCommittedNode) n;
+ return n;
}
}
@@ -166,10 +164,10 @@
* @param force if true, will force the write lock even if the node is
null.
* @return a wrapped node, or null.
*/
- public ReadCommittedNode wrapNodeForWriting(InvocationContext context, Fqn fqn,
boolean lockForWriting, boolean createIfAbsent, boolean includeInvalidNodes, boolean
forRemoval, boolean force) throws InterruptedException
+ public NodeSPI wrapNodeForWriting(InvocationContext context, Fqn fqn, boolean
lockForWriting, boolean createIfAbsent, boolean includeInvalidNodes, boolean forRemoval,
boolean force) throws InterruptedException
{
Fqn parentFqn = null;
- ReadCommittedNode n = (ReadCommittedNode) context.lookUpNode(fqn);
+ NodeSPI n = context.lookUpNode(fqn);
if (createIfAbsent && n != null && n.isNullNode()) n = null;
if (n != null) // exists in context! Just acquire lock if needed, and wrap.
{
@@ -209,7 +207,7 @@
parentFqn = fqn.getParent();
NodeSPI parent = wrapNodeForWriting(context, parentFqn, false,
createIfAbsent, false, false, false);
// do we need to lock the parent to create children?
- boolean parentLockNeeded = isParentLockNeeded(parent);
+ boolean parentLockNeeded = isParentLockNeeded(parent.getDelegationTarget());
// get a lock on the parent.
if (parentLockNeeded && acquireLock(context, parentFqn))
{
@@ -219,13 +217,12 @@
// now to lock and create the node. Lock first to prevent concurrent
creation!
acquireLock(context, fqn);
-// NodeSPI temp = nodeFactory.createAndRegister(fqn, null, context, false);
+ in = nodeFactory.createAndRegister(fqn, null, context, false);
- NodeSPI temp = parent.getOrCreateChild(fqn.getLastElement(),
context.getGlobalTransaction());
- parent.removeChildDirect(fqn.getLastElement());
+// NodeSPI temp = parent.getOrCreateChild(fqn.getLastElement(),
context.getGlobalTransaction());
+// parent.removeChildDirect(fqn.getLastElement());
+// in = ((NodeInvocationDelegate) temp).getDelegationTarget();
-
- in = ((NodeInvocationDelegate) temp).getDelegationTarget();
n = nodeFactory.createWrappedNode(in);
n.setCreated(true);
context.putLookedUpNode(fqn, n);
@@ -280,19 +277,21 @@
if (parentLockNeeded && (needToCopyNode || needToCopyParent))
{
ReadCommittedNode parent = (ReadCommittedNode) ctx.lookUpNode(parentFqn);
-
parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(node.getDelegationTarget(),
configuration.getIsolationLevel() == IsolationLevel.READ_COMMITTED));
+ parent.getDelegationTarget().addChild(node.getDelegationTarget());
+
+//
parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(node.getDelegationTarget(),
configuration.getIsolationLevel() == IsolationLevel.READ_COMMITTED));
}
// now deal with children.
- Map childMap = node.getChildrenMapDirect();
+// Map childMap = node.getChildrenMapDirect();
+ Map<Object, InternalNode<?, ?>> childMap =
node.getDelegationTarget().getChildrenMap();
List<Fqn> fqnsToBeRemoved = new LinkedList<Fqn>();
fqnsToBeRemoved.add(fqn);
if (childMap == null || childMap.isEmpty()) return fqnsToBeRemoved;
- for (Object n : childMap.values())
+ for (InternalNode n : childMap.values())
{
- NodeSPI child = (NodeSPI) n;
- lockForWritingRecursive(child.getFqn(), ctx, fqnsToBeRemoved);
+ lockForWritingRecursive(n.getFqn(), ctx, fqnsToBeRemoved);
}
return fqnsToBeRemoved;
@@ -307,17 +306,25 @@
if (fqnList != null) fqnList.add(fqn);
// now wrap and add to the context
- ReadCommittedNode rcn = wrapNodeForWriting(ctx, fqn, true, false, true, false,
false);
+ NodeSPI rcn = wrapNodeForWriting(ctx, fqn, true, false, true, false, false);
if (rcn != null)
{
rcn.markForUpdate(ctx, dataContainer, nodeFactory, writeSkewCheck);
- ReadCommittedNode parent = (ReadCommittedNode) ctx.lookUpNode(fqn.getParent());
-
parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(rcn.getDelegationTarget(),
configuration.getIsolationLevel() == IsolationLevel.READ_COMMITTED));
- Map<Object, NodeSPI> children = rcn.getChildrenMapDirect();
+ // Why is this necessary again?!?? - Manik, 24Jul08
+
+// NodeSPI parent = ctx.lookUpNode(fqn.getParent());
+// parent.getDelegationTarget().addChild(rcn.getDelegationTarget());
+
+ // yukky logic.
+
+//
parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(rcn.getDelegationTarget(),
configuration.getIsolationLevel() == IsolationLevel.READ_COMMITTED));
+
+// Map<Object, NodeSPI> children = rcn.getChildrenMapDirect();
+ Map<Object, InternalNode<?, ?>> children =
rcn.getDelegationTarget().getChildrenMap();
if (children != null)
{
- for (NodeSPI child : children.values())
+ for (InternalNode child : children.values())
{
lockForWritingRecursive(child.getFqn(), ctx, fqnList);
}
@@ -341,15 +348,15 @@
}
}
- private boolean isParentLockNeeded(NodeSPI parent)
+ private boolean isParentLockNeeded(InternalNode parent)
{
return lockParentForChildInsertRemove || (parent != null &&
parent.isLockForChildInsertRemove());
}
private boolean isParentLockNeeded(Fqn parent, InvocationContext ctx)
{
- NodeSPI parentNode = ctx.lookUpNode(parent);
- if (parentNode == null) parentNode = dataContainer.peek(parent, true, true);
- return isParentLockNeeded(parentNode);
+ ReadCommittedNode parentNodeTmp = (ReadCommittedNode) ctx.lookUpNode(parent);
+ InternalNode in = parentNodeTmp == null ? dataContainer.peekInternalNode(parent,
true) : parentNodeTmp.getDelegationTarget();
+ return isParentLockNeeded(in);
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java 2008-07-28 10:29:41
UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java 2008-07-28 10:56:29
UTC (rev 6414)
@@ -6,12 +6,14 @@
import org.jboss.cache.InternalNode;
import org.jboss.cache.Node;
import org.jboss.cache.NodeSPI;
+import org.jboss.cache.invocation.InvocationContext;
import org.jboss.cache.lock.NodeLock;
import org.jboss.cache.optimistic.DataVersion;
import org.jboss.cache.transaction.GlobalTransaction;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
/**
* A node reference that delegates all calls to a different {@link
org.jboss.cache.InternalNode}. Simple indirection
@@ -40,7 +42,7 @@
/**
* @return the InternalNode being delegated to.
*/
- public InternalNode<K, V> getDelegate()
+ public final InternalNode<K, V> getDelegate()
{
return delegate;
}
@@ -50,259 +52,319 @@
*
* @param delegate node to delegate to.
*/
- public void setDelegate(InternalNode<K, V> delegate)
+ public final void setDelegate(InternalNode<K, V> delegate)
{
this.delegate = delegate;
}
- public NodeSPI<K, V> getParent()
+ public final NodeSPI<K, V> getParent()
{
return delegate.getParent();
}
- public CacheSPI<K, V> getCache()
+ public final CacheSPI<K, V> getCache()
{
return delegate.getCache();
}
- public boolean isChildrenLoaded()
+ public final boolean isChildrenLoaded()
{
return delegate.isChildrenLoaded();
}
- public void setChildrenLoaded(boolean flag)
+ public final void setChildrenLoaded(boolean flag)
{
delegate.setChildrenLoaded(flag);
}
- public V get(K key)
+ public final V get(K key)
{
return delegate.get(key);
}
- public Map<K, V> getData()
+ public final Map<K, V> getData()
{
return delegate.getData();
}
- public V put(K key, V value)
+ public final V put(K key, V value)
{
return delegate.put(key, value);
}
- public NodeSPI<K, V> getOrCreateChild(Object child_name, GlobalTransaction gtx)
+ public final NodeSPI<K, V> getOrCreateChild(Object child_name, GlobalTransaction
gtx)
{
return delegate.getOrCreateChild(child_name, gtx);
}
- public V remove(K key)
+ public final InternalNode<K, V> getChild(Fqn f)
{
- return delegate.remove(key);
+ return delegate.getChild(f);
}
- public void addChild(NodeSPI child)
+ public final InternalNode<K, V> getChild(Object childName)
{
+ return delegate.getChild(childName);
+ }
+
+ public final Set<InternalNode<K, V>> getChildren()
+ {
+ return delegate.getChildren();
+ }
+
+ public final Set<InternalNode<K, V>> getChildren(boolean
includeMarkedForRemoval)
+ {
+ return delegate.getChildren(includeMarkedForRemoval);
+ }
+
+ public final ConcurrentMap<Object, InternalNode<K, V>> getChildrenMap()
+ {
+ return delegate.getChildrenMap();
+ }
+
+ public final void setChildrenMap(ConcurrentMap<Object, InternalNode<K, V>>
children)
+ {
+ delegate.setChildrenMap(children);
+ }
+
+ public final void addChild(Object nodeName, InternalNode<K, V> nodeToAdd)
+ {
+ delegate.addChild(nodeName, nodeToAdd);
+ }
+
+ public final void addChild(InternalNode<K, V> child)
+ {
delegate.addChild(child);
}
- public NodeSPI<K, V> addChild(Fqn f)
+ public final InternalNode<K, V> addChild(Fqn f)
{
return delegate.addChild(f);
}
- public NodeSPI<K, V> addChild(Fqn f, boolean notify)
+ public final InternalNode<K, V> addChild(Fqn f, boolean notify)
{
return delegate.addChild(f, notify);
}
- public NodeSPI<K, V> addChild(Object o, boolean notify)
+ public final InternalNode<K, V> addChild(Object o, boolean notify)
{
return delegate.addChild(o, notify);
}
- public void clear()
+ public final InternalNode<K, V> getOrCreateChild(Object childName,
InvocationContext ctx)
{
+ return delegate.getOrCreateChild(childName, ctx);
+ }
+
+ public final V remove(K key)
+ {
+ return delegate.remove(key);
+ }
+
+ public final NodeSPI<K, V> addChildDirect(Fqn f)
+ {
+ return delegate.addChildDirect(f);
+ }
+
+ public final NodeSPI<K, V> addChildDirect(Fqn f, boolean notify)
+ {
+ return delegate.addChildDirect(f, notify);
+ }
+
+ public final NodeSPI<K, V> addChildDirect(Object o, boolean notify)
+ {
+ return delegate.addChildDirect(o, notify);
+ }
+
+ public final void clear()
+ {
delegate.clear();
}
- public NodeSPI<K, V> getChild(Fqn fqn)
+ public final NodeSPI<K, V> getChildDirect(Fqn fqn)
{
- return delegate.getChild(fqn);
+ return delegate.getChildDirect(fqn);
}
- public Set<Object> getChildrenNames()
+ public final Set<Object> getChildrenNames()
{
return delegate.getChildrenNames();
}
- public Set<K> getKeys()
+ public final Set<K> getKeys()
{
return delegate.getKeys();
}
- public boolean removeChild(Object childName)
+ public final void setInternalState(Map<K, V> state)
{
+ delegate.setInternalState(state);
+ }
+
+ public final boolean removeChild(Object childName)
+ {
return delegate.removeChild(childName);
}
- public boolean removeChild(Fqn f)
+ public final boolean removeChild(Fqn f)
{
return delegate.removeChild(f);
}
- public Map<Object, Node<K, V>> getChildrenMap()
+ public final Map<Object, Node<K, V>> getChildrenMapDirect()
{
- return delegate.getChildrenMap();
+ return delegate.getChildrenMapDirect();
}
- public void setChildrenMap(Map<Object, Node<K, V>> children)
+ public final void setChildrenMapDirect(Map<Object, Node<K, V>> children)
{
- delegate.setChildrenMap(children);
+ delegate.setChildrenMapDirect(children);
}
- public void putAll(Map<K, V> data)
+ public final void putAll(Map<K, V> data)
{
delegate.putAll(data);
}
- public void removeChildren()
+ public final void removeChildren()
{
delegate.removeChildren();
}
- public void setVersion(DataVersion version)
+ public final void setVersion(DataVersion version)
{
delegate.setVersion(version);
}
- public DataVersion getVersion()
+ public final DataVersion getVersion()
{
return delegate.getVersion();
}
- public Fqn getFqn()
+ public final Fqn getFqn()
{
return delegate.getFqn();
}
- public void setFqn(Fqn fqn)
+ public final void setFqn(Fqn fqn)
{
delegate.setFqn(fqn);
}
- public NodeSPI<K, V> getChild(Object childName)
+ public final NodeSPI<K, V> getChildDirect(Object childName)
{
- return delegate.getChild(childName);
+ return delegate.getChildDirect(childName);
}
- public Set<NodeSPI<K, V>> getChildren()
+ public final Set<NodeSPI<K, V>> getChildrenDirect()
{
- return delegate.getChildren();
+ return delegate.getChildrenDirect();
}
- public boolean hasChildren()
+ public final boolean hasChildren()
{
return delegate.hasChildren();
}
- public Set<NodeSPI<K, V>> getChildren(boolean includeMarkedForRemoval)
+ public final Set<NodeSPI<K, V>> getChildrenDirect(boolean
includeMarkedForRemoval)
{
- return delegate.getChildren(includeMarkedForRemoval);
+ return delegate.getChildrenDirect(includeMarkedForRemoval);
}
- public boolean isDataLoaded()
+ public final boolean isDataLoaded()
{
return delegate.isDataLoaded();
}
- public void setDataLoaded(boolean dataLoaded)
+ public final void setDataLoaded(boolean dataLoaded)
{
delegate.setDataLoaded(dataLoaded);
}
- public boolean isValid()
+ public final boolean isValid()
{
return delegate.isValid();
}
- public void setValid(boolean valid, boolean recursive)
+ public final void setValid(boolean valid, boolean recursive)
{
delegate.setValid(valid, recursive);
}
- public boolean isLockForChildInsertRemove()
+ public final boolean isLockForChildInsertRemove()
{
return delegate.isLockForChildInsertRemove();
}
- public void setLockForChildInsertRemove(boolean lockForChildInsertRemove)
+ public final void setLockForChildInsertRemove(boolean lockForChildInsertRemove)
{
delegate.setLockForChildInsertRemove(lockForChildInsertRemove);
}
- public void setInternalState(Map state)
+ public final Map getInternalState(boolean onlyInternalState)
{
- delegate.setInternalState(state);
- }
-
- public Map getInternalState(boolean onlyInternalState)
- {
return delegate.getInternalState(onlyInternalState);
}
- public void releaseObjectReferences(boolean recursive)
+ public final void releaseObjectReferences(boolean recursive)
{
delegate.releaseObjectReferences(recursive);
}
- public boolean isRemoved()
+ public final boolean isRemoved()
{
return delegate.isRemoved();
}
- public void setRemoved(boolean marker)
+ public final void setRemoved(boolean marker)
{
delegate.setRemoved(marker);
}
- public void markAsRemoved(boolean marker, boolean recursive)
+ public final void markAsRemoved(boolean marker, boolean recursive)
{
delegate.markAsRemoved(marker, recursive);
}
- public void setResident(boolean resident)
+ public final void setResident(boolean resident)
{
delegate.setResident(resident);
}
- public boolean isResident()
+ public final boolean isResident()
{
return delegate.isResident();
}
- public InternalNode<K, V> copy()
+ public final InternalNode<K, V> copy()
{
InternalNode<K, V> cloneDelegate = delegate.copy();
return new NodeReference<K, V>(cloneDelegate);
}
- public NodeLock getLock()
+ public final NodeLock getLock()
{
return delegate.getLock();
}
- public void addChild(Object nodeName, Node<K, V> nodeToAdd)
+ public final void addChildDirect(Object nodeName, Node<K, V> nodeToAdd)
{
- delegate.addChild(nodeName, nodeToAdd);
+ delegate.addChildDirect(nodeName, nodeToAdd);
}
- public void printDetails(StringBuilder sb, int indent)
+ public final void addChildDirect(NodeSPI<K, V> child)
{
+ delegate.addChildDirect(child);
+ }
+
+ public final void printDetails(StringBuilder sb, int indent)
+ {
delegate.printDetails(sb, indent);
}
@Override
- public String toString()
+ public final String toString()
{
return "NodeReference{" +
"delegate=" + delegate +
@@ -310,7 +372,7 @@
}
@Override
- public boolean equals(Object o)
+ public final boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@@ -323,7 +385,7 @@
}
@Override
- public int hashCode()
+ public final int hashCode()
{
return (delegate != null ? delegate.hashCode() : 0);
}
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -73,20 +73,13 @@
flags &= ~flag.mask;
}
+ @Override
public boolean isNullNode()
{
return false;
}
- /**
- * Marks a node for updating. Internally, this creates a copy of the delegate and
performs any checks necessary to
- * maintain isolation level.
- *
- * @param ctx invocation context
- * @param container data container
- * @param nodeFactory node factory for creating new nodes/copies.
- * @param writeSkewCheck if true, and the node supports write skew checking, nodes are
tested for write skews.
- */
+ @Override
public void markForUpdate(InvocationContext ctx, DataContainer container, NodeFactory
nodeFactory, boolean writeSkewCheck)
{
if (isFlagSet(CHANGED)) return; // already copied
@@ -100,13 +93,7 @@
}
}
- /**
- * Commits any updates made on this node to the underlying data structure, making it
visible to all other transactions.
- *
- * @param ctx invocation context
- * @param container data container
- * @param nodeFactory node factory
- */
+ @Override
public void commitUpdate(InvocationContext ctx, DataContainer container, NodeFactory
nodeFactory)
{
if (isFlagSet(CHANGED))
@@ -120,8 +107,8 @@
{
if (!fqn.isRoot())
{
- NodeSPI parent = lookupParent(fqn, ctx, container);
- parent.removeChildDirect(fqn.getLastElement());
+ InternalNode parent = lookupParent(fqn, ctx, container);
+ parent.removeChild(fqn.getLastElement());
setValid(false, false);
updateNode(ctx, container, nodeFactory);
}
@@ -133,8 +120,9 @@
else if (isFlagSet(CREATED))
{
// add newly created nodes to parents.
- NodeSPI parent = lookupParent(fqn, ctx, container);
- parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(node,
false));
+ InternalNode parent = lookupParent(fqn, ctx, container);
+// parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(node,
false));
+ parent.addChild(node);
}
else
{
@@ -161,15 +149,22 @@
* @return Parent node, never null.
* @throws NodeNotExistsException if the parent node cannot be found in any scope or
data container.
*/
- protected final NodeSPI lookupParent(Fqn fqn, InvocationContext ctx, DataContainer
container) throws NodeNotExistsException
+ protected final InternalNode lookupParent(Fqn fqn, InvocationContext ctx,
DataContainer container) throws NodeNotExistsException
{
+ InternalNode retval;
Fqn parentFqn = fqn.getParent();
NodeSPI parent = ctx.lookUpNode(parentFqn);
- if (parent != null) return parent;
- parent = container.peek(parentFqn);
- if (parent == null)
+ if (parent != null)
+ {
+ retval = parent.getDelegationTarget();
+ }
+ else
+ {
+ retval = container.peekInternalNode(parentFqn, false);
+ }
+ if (retval == null)
throw new NodeNotExistsException("Node " + parentFqn + " cannot
be found in any context or data container!");
- return parent;
+ return retval;
}
/**
@@ -186,28 +181,26 @@
node = backup;
}
+ @Override
public void rollbackUpdate()
{
node = backup;
reset();
}
- /**
- * @return true if this node has been marked for update, false otherwise.
- */
+ @Override
public boolean isChanged()
{
return isFlagSet(CHANGED);
}
- /**
- * @return true if this node has been newly created in the current scope.
- */
+ @Override
public boolean isCreated()
{
return isFlagSet(CREATED);
}
+ @Override
public void setCreated(boolean created)
{
if (created)
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -6,9 +6,7 @@
import org.jboss.cache.Fqn;
import org.jboss.cache.InternalNode;
import org.jboss.cache.NodeFactory;
-import org.jboss.cache.NodeSPI;
import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.invocation.NodeInvocationDelegate;
import static org.jboss.cache.mvcc.ReadCommittedNode.Flags.CHANGED;
import static org.jboss.cache.mvcc.ReadCommittedNode.Flags.DELETED;
import org.jboss.cache.optimistic.DataVersioningException;
@@ -41,9 +39,9 @@
if (writeSkewCheck)
{
// check for write skew.
- NodeInvocationDelegate underlyingNode = (NodeInvocationDelegate)
container.peek(fqn, false, true); // even check for invalid nodes. we should check
tombstones too.
+ InternalNode underlyingNode = container.peekInternalNode(fqn, true);
- if (underlyingNode != null && underlyingNode.getDelegationTarget() !=
node)
+ if (underlyingNode != null && underlyingNode != node)
{
String errormsg = new StringBuilder().append("Detected write skew on Fqn
[").append(fqn).append("]. Another process has changed the node since we last
read it!").toString();
if (log.isWarnEnabled()) log.warn(errormsg + ". Unable to copy node for
update.");
@@ -61,12 +59,12 @@
{
if (getFqn().isRoot())
{
- dataContainer.setRoot(nf.createNodeInvocationDelegate(node, false));
+ dataContainer.setRoot(node);
}
else if (!isFlagSet(DELETED))
{
- NodeSPI parent = lookupParent(getFqn(), ctx, dataContainer);
- parent.addChildDirect(nf.createNodeInvocationDelegate(node, false));
+ InternalNode parent = lookupParent(getFqn(), ctx, dataContainer);
+ parent.addChild(node);
}
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNode.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNode.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -25,8 +25,10 @@
* @author Steve Woodcock (<a
href="mailto:stevew@jofti.com">stevew@jofti.com</a>)
* @since 1.3.0
*/
-public interface WorkspaceNode<K, V> extends Node<K, V>
+public interface WorkspaceNode<K, V>// extends Node<K, V>
{
+ Fqn getFqn();
+
/**
* Returns 2 Sets - a set of children added (first set) and a set of children
removed.
*
@@ -129,7 +131,7 @@
* @param o node name
* @return a child node
*/
- NodeSPI<K, V> getChild(Object o);
+ NodeSPI<K, V> getChildDirect(Object o);
/**
* Overrides {@link Node#getChild(Fqn)} to return a {@link org.jboss.cache.NodeSPI}
rather than a {@link org.jboss.cache.Node}
@@ -137,7 +139,7 @@
* @param f node fqn
* @return a child node
*/
- NodeSPI<K, V> getChild(Fqn f);
+ NodeSPI<K, V> getChildDirect(Fqn f);
/**
* Adds a given WorkspaceNode to the current node's child map
@@ -173,4 +175,22 @@
void setRemoved(boolean marker);
void markAsRemoved(boolean marker, boolean recursive);
+
+ void clearData();
+
+ Map<K, V> getData();
+
+ V remove(K removeKey);
+
+ V get(K key);
+
+ Set<K> getKeys();
+
+ Set<Object> getChildrenNames();
+
+ boolean removeChild(Object nodeName);
+
+ void putAll(Map<K, V> data);
+
+ V put(K key, V value);
}
Modified: core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNodeImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNodeImpl.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNodeImpl.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -112,7 +112,19 @@
@Override
public void markAsRemoved(boolean marker, boolean recursive)
{
- super.markAsRemoved(marker, recursive);
+ setFlag(NodeFlags.REMOVED, marker);
+
+ if (recursive && children != null)
+ {
+ synchronized (this)
+ {
+ for (Object child : children.values())
+ {
+ ((NodeSPI) child).markAsDeleted(marker, true);
+ }
+ }
+ }
+
if (marker)
{
if (childrenAdded != null) childrenAdded.clear();
@@ -255,23 +267,18 @@
setFlag(VERSIONING_IMPLICIT, versioningImplicit);
}
- public NodeSPI<K, V> getChild(Object childName)
- {
- //see if in the the transaction map
-// return optimisticChildNodeMap.get(childName);
- throw new UnsupportedOperationException("This call should be intercepted by
the optimisticNodeInterceptor and the child node should be retrieved from the
workspace.");
- }
-
public NodeSPI<K, V> getNode()
{
return node;
}
+ @Override
public DataVersion getVersion()
{
return version;
}
+ @Override
public void setVersion(DataVersion version)
{
this.version = version;
@@ -339,10 +346,11 @@
return getClass().getSimpleName() + " [ fqn=" + getFqn() + " "
+ sb + "ver=" + version + " " + (isVersioningImplicit() ?
"implicit" : "explicit") + "]";
}
- public Node<K, V> addChild(Fqn f)
+ @Override
+ public NodeSPI<K, V> addChildDirect(Fqn f)
{
CacheSPI cache = getCache();
- Node<K, V> newNode = this;
+ NodeSPI<K, V> newNode = null;
GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
if (f.size() == 1)
@@ -352,7 +360,7 @@
else
{
// recursively create children
- Node<K, V> currentParent = this;
+ NodeSPI<K, V> currentParent = this.getNode();
for (Object o : f.peekElements())
{
if (currentParent instanceof WorkspaceNode)
@@ -367,7 +375,7 @@
}
else
{
- newNode = ((NodeSPI<K, V>) currentParent).getOrCreateChild(o,
gtx);
+ newNode = currentParent.getOrCreateChild(o, gtx);
}
}
currentParent = newNode;
@@ -422,16 +430,18 @@
throw new UnsupportedOperationException();
}
- public NodeSPI<K, V> getChild(Fqn f)
+ @Override
+ public NodeSPI<K, V> getChildDirect(Fqn f)
{
if (f.size() > 1)
{
throw new UnsupportedOperationException("Workspace node does not support
fetching indirect children");
}
- return getChild(f.getLastElement());
+ return getChildDirect(f.getLastElement());
}
- public Set<Node<K, V>> getChildren()
+ @Override
+ public Set getChildren()
{
throw new UnsupportedOperationException();
}
Modified:
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -10,9 +10,11 @@
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.Node;
-import org.jboss.cache.NodeSPI;
import org.jboss.cache.Version;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
import org.jboss.cache.loader.CacheLoader;
import org.jboss.cache.marshall.NodeData;
import org.jboss.cache.marshall.NodeDataExceptionMarker;
@@ -35,16 +37,22 @@
private Set<Fqn> internalFqns;
- protected DefaultStateTransferGenerator(CacheSPI cache)
+ @Inject
+ public void inject(CacheSPI cache)
{
this.cache = cache;
+ }
+
+ @Start(priority = 18)
+ private void start()
+ {
this.internalFqns = cache.getInternalFqns();
}
- public void generateState(ObjectOutputStream out, Node rootNode, boolean
generateTransient,
+ public void generateState(ObjectOutputStream out, Object rootNode, boolean
generateTransient,
boolean generatePersistent, boolean suppressErrors) throws
Exception
{
- Fqn fqn = rootNode.getFqn();
+ Fqn fqn = getFqn(rootNode);
try
{
cache.getMarshaller().objectToObjectStream(STATE_TRANSFER_VERSION, out);
@@ -55,8 +63,7 @@
{
log.trace("writing transient state for " + fqn);
}
- marshallTransientState((NodeSPI) rootNode, out);
- delimitStream(out);
+ marshallTransientState((InternalNode) rootNode, out);
if (log.isTraceEnabled())
{
@@ -69,7 +76,6 @@
log.trace("writing associated state");
}
- marshallAssociatedState(fqn, out);
delimitStream(out);
if (log.isTraceEnabled())
@@ -116,6 +122,13 @@
}
}
+ private Fqn getFqn(Object o)
+ {
+ if (o instanceof Node) return ((Node) o).getFqn();
+ if (o instanceof InternalNode) return ((InternalNode) o).getFqn();
+ throw new IllegalArgumentException();
+ }
+
/**
* Places a delimiter marker on the stream
*
@@ -133,14 +146,14 @@
* @param out
* @throws Exception
*/
- protected void marshallTransientState(NodeSPI node, ObjectOutputStream out) throws
Exception
+ protected void marshallTransientState(InternalNode node, ObjectOutputStream out)
throws Exception
{
List<NodeData> nodeData = new LinkedList<NodeData>();
generateNodeDataList(node, nodeData);
cache.getMarshaller().objectToObjectStream(nodeData, out, node.getFqn());
}
- protected void generateNodeDataList(NodeSPI<?, ?> node, List<NodeData>
list) throws Exception
+ protected void generateNodeDataList(InternalNode<?, ?> node,
List<NodeData> list) throws Exception
{
if (internalFqns.contains(node.getFqn()))
{
@@ -165,14 +178,6 @@
list.add(nd);
// then visit the children
- for (NodeSPI child : node.getChildrenDirect()) generateNodeDataList(child, list);
+ for (InternalNode child : node.getChildren()) generateNodeDataList(child, list);
}
-
- /**
- * Does nothing in this base class; can be overridden in a subclass.
- */
- protected void marshallAssociatedState(Fqn fqn, ObjectOutputStream baos) throws
Exception
- {
- // no-op in this base class
- }
}
Modified:
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -11,13 +11,14 @@
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
-import org.jboss.cache.Node;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.NodeFactory;
-import org.jboss.cache.NodeSPI;
import org.jboss.cache.Region;
import org.jboss.cache.buddyreplication.BuddyManager;
import org.jboss.cache.eviction.EvictedEventNode;
import org.jboss.cache.eviction.NodeEventType;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
import org.jboss.cache.invocation.InvocationContext;
import org.jboss.cache.loader.CacheLoader;
import org.jboss.cache.loader.CacheLoaderManager;
@@ -42,28 +43,34 @@
private CacheSPI cache;
- private Fqn targetFqn;
-
private NodeFactory factory;
private Set<Fqn> internalFqns;
- public DefaultStateTransferIntegrator(Fqn targetFqn, CacheSPI<?, ?> cache,
NodeFactory nodefactory)
+ @Inject
+ public void inject(CacheSPI<?, ?> cache, NodeFactory nodefactory)
{
- this.targetFqn = targetFqn;
this.cache = cache;
this.factory = nodefactory;
+ }
+
+ @Start(priority = 14)
+ public void start()
+ {
this.internalFqns = cache.getInternalFqns();
}
- public void integrateState(ObjectInputStream ois, Node target) throws Exception
+ public void integrateState(ObjectInputStream ois, Object target, Fqn targetRoot)
throws Exception
{
- integrateTransientState(ois, (NodeSPI) target);
+ // pop version from the stream first!
+ short version = (Short) cache.getMarshaller().objectFromObjectStream(ois);
+ log.info("Using version " + version);
+ integrateTransientState(ois, (InternalNode) target);
integrateAssociatedState(ois);
- integratePersistentState(ois);
+ integratePersistentState(ois, targetRoot);
}
- protected void integrateTransientState(ObjectInputStream in, NodeSPI target) throws
Exception
+ protected void integrateTransientState(ObjectInputStream in, InternalNode target)
throws Exception
{
boolean transientSet = false;
try
@@ -92,11 +99,9 @@
{
if (!transientSet)
{
- target.clearDataDirect();
- target.removeChildrenDirect();
+ target.clear();
+ target.removeChildren();
}
-
-// resetClassLoader(oldCL);
}
}
@@ -112,7 +117,7 @@
cache.getMarshaller().objectFromObjectStream(in);
}
- protected void integratePersistentState(ObjectInputStream in) throws Exception
+ protected void integratePersistentState(ObjectInputStream in, Fqn targetFqn) throws
Exception
{
CacheLoaderManager loaderManager = cache.getCacheLoaderManager();
@@ -169,66 +174,32 @@
}
}
- protected NodeFactory getFactory()
- {
- return factory;
- }
-
- protected Fqn getTargetFqn()
- {
- return targetFqn;
- }
-
/**
* Generates NodeAdded notifications for all nodes of the tree. This is
* called whenever the tree is initially retrieved (state transfer)
*/
- private void notifyAllNodesCreated(InvocationContext ctx, NodeSPI curr)
+ private void notifyAllNodesCreated(InvocationContext ctx, InternalNode curr)
{
if (curr == null) return;
ctx.setOriginLocal(false);
cache.getNotifier().notifyNodeCreated(curr.getFqn(), true, ctx);
cache.getNotifier().notifyNodeCreated(curr.getFqn(), false, ctx);
// AND notify that they have been modified!!
- if (!curr.getKeysDirect().isEmpty())
+ if (!curr.getKeys().isEmpty())
{
cache.getNotifier().notifyNodeModified(curr.getFqn(), true,
NodeModifiedEvent.ModificationType.PUT_MAP, Collections.emptyMap(), ctx);
- cache.getNotifier().notifyNodeModified(curr.getFqn(), false,
NodeModifiedEvent.ModificationType.PUT_MAP, curr.getDataDirect(), ctx);
+ cache.getNotifier().notifyNodeModified(curr.getFqn(), false,
NodeModifiedEvent.ModificationType.PUT_MAP, curr.getData(), ctx);
}
ctx.setOriginLocal(true);
- Set<NodeSPI> children = curr.getChildrenDirect();
- for (NodeSPI n : children)
- {
- notifyAllNodesCreated(ctx, n);
- }
+ Set<InternalNode> children = curr.getChildren();
+ for (InternalNode n : children) notifyAllNodesCreated(ctx, n);
}
- /*
- private ClassLoader setClassLoader(ClassLoader newLoader)
+ private void integrateTransientState(InternalNode target, ObjectInputStream in) throws
Exception
{
- ClassLoader oldClassLoader = null;
- if (newLoader != null)
- {
- oldClassLoader = Thread.currentThread().getContextClassLoader();
- Thread.currentThread().setContextClassLoader(newLoader);
- }
- return oldClassLoader;
- }
+ target.removeChildren();
- private void resetClassLoader(ClassLoader oldLoader)
- {
- if (oldLoader != null)
- {
- Thread.currentThread().setContextClassLoader(oldLoader);
- }
- }
- */
-
- private void integrateTransientState(NodeSPI target, ObjectInputStream in) throws
Exception
- {
- target.removeChildrenDirect();
-
List<NodeData> list = readNodesAsList(in);
if (list != null)
{
@@ -276,7 +247,7 @@
return (List<NodeData>) obj;
}
- private NodeData integrateStateTransferChildren(NodeSPI parent, int offset,
Iterator<NodeData> nodeDataIterator)
+ private NodeData integrateStateTransferChildren(InternalNode parent, int offset,
Iterator<NodeData> nodeDataIterator)
throws IOException, ClassNotFoundException
{
int parent_level = parent.getFqn().size();
@@ -305,10 +276,9 @@
Map attrs = nd.getAttributes();
- // We handle this NodeData. Create a TreeNode and
- // integrate its data
- NodeSPI target = factory.createNode(fqn, parent, attrs);
- parent.addChild(fqn.getLastElement(), target);
+ InternalNode internalTarget = factory.createInternalNode(fqn);
+ internalTarget.setInternalState(attrs);
+ parent.addChild(internalTarget);
// JBCACHE-913
Region region = cache.getRegion(fqn, false);
@@ -320,7 +290,7 @@
// Recursively call, which will walk down the tree
// and return the next NodeData that's a child of our parent
- nd = integrateStateTransferChildren(target, offset, nodeDataIterator);
+ nd = integrateStateTransferChildren(internalTarget, offset, nodeDataIterator);
}
if (nd != null && nd.isExceptionMarker())
{
@@ -331,15 +301,15 @@
return null;
}
- private Set<Node> retainInternalNodes(Node target)
+ private Set<InternalNode> retainInternalNodes(InternalNode target)
{
- Set<Node> result = new HashSet<Node>();
+ Set<InternalNode> result = new HashSet<InternalNode>();
Fqn targetFqn = target.getFqn();
for (Fqn internalFqn : internalFqns)
{
if (internalFqn.isChildOf(targetFqn))
{
- Node internalNode = getInternalNode(target, internalFqn);
+ InternalNode internalNode = getInternalNode(target, internalFqn);
if (internalNode != null)
{
result.add(internalNode);
@@ -350,11 +320,10 @@
return result;
}
- private Node getInternalNode(Node parent, Fqn internalFqn)
+ private InternalNode getInternalNode(InternalNode parent, Fqn internalFqn)
{
Object name = internalFqn.get(parent.getFqn().size());
- cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
- Node result = parent.getChild(name);
+ InternalNode result = parent.getChild(name);
if (result != null)
{
if (internalFqn.size() < result.getFqn().size())
@@ -366,11 +335,11 @@
return result;
}
- private void integrateRetainedNodes(NodeSPI target)
+ private void integrateRetainedNodes(InternalNode target)
{
- Set<Node> retainedNodes = retainInternalNodes(target);
+ Set<InternalNode> retainedNodes = retainInternalNodes(target);
Fqn rootFqn = target.getFqn();
- for (Node retained : retainedNodes)
+ for (InternalNode retained : retainedNodes)
{
if (retained.getFqn().isChildOf(rootFqn))
{
@@ -379,12 +348,12 @@
}
}
- private void integrateRetainedNode(NodeSPI ancestor, Node descendant)
+ private void integrateRetainedNode(InternalNode ancestor, InternalNode descendant)
{
Fqn descFqn = descendant.getFqn();
Fqn ancFqn = ancestor.getFqn();
Object name = descFqn.get(ancFqn.size());
- NodeSPI child = (NodeSPI) ancestor.getChild(name);
+ InternalNode child = ancestor.getChild(name);
if (ancFqn.size() == descFqn.size() + 1)
{
if (child == null)
@@ -403,8 +372,11 @@
// Missing level -- have to create empty node
// This shouldn't really happen -- internal fqns should
// be immediately under the root
- child = factory.createNode(name, ancestor);
- ancestor.addChild(name, child);
+// child = factory.createInternalNode(name, ancestor);
+// ancestor.addChild(name, child);
+
+ // since this shouldn't happen, deal with it. - Manik - Jul08
+ throw new NullPointerException("Child is null");
}
// Keep walking down the tree
Modified:
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferManager.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferManager.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferManager.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -11,6 +11,7 @@
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.NodeFactory;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.RegionEmptyException;
@@ -43,14 +44,16 @@
protected RegionManager regionManager;
protected Configuration configuration;
private CacheLoaderManager cacheLoaderManager;
- private boolean fetchTransientState;
- private boolean fetchPersistentState;
- private long stateRetrievalTimeout;
+ boolean fetchTransientState;
+ boolean fetchPersistentState;
+ protected long stateRetrievalTimeout;
private NodeFactory nodeFactory;
+ protected StateTransferIntegrator integrator;
+ protected StateTransferGenerator generator;
@Inject
- public void injectDependencies(CacheSPI cache, Marshaller marshaller, RegionManager
regionManager, Configuration configuration, CacheLoaderManager cacheLoaderManager,
NodeFactory nodeFactory)
+ public void injectDependencies(CacheSPI cache, Marshaller marshaller, RegionManager
regionManager, Configuration configuration, CacheLoaderManager cacheLoaderManager,
NodeFactory nodeFactory, StateTransferIntegrator integrator, StateTransferGenerator
generator)
{
this.cache = cache;
this.regionManager = regionManager;
@@ -58,6 +61,8 @@
this.configuration = configuration;
this.cacheLoaderManager = cacheLoaderManager;
this.nodeFactory = nodeFactory;
+ this.integrator = integrator;
+ this.generator = generator;
}
@Start(priority = 19)
@@ -76,27 +81,18 @@
if (canProvideState && (fetchPersistentState || fetchTransientState))
{
marshaller.objectToObjectStream(true, out);
- StateTransferGenerator generator = getStateTransferGenerator();
long startTime = System.currentTimeMillis();
- NodeSPI rootNode = cache.peek(fqn, false, false);
+ InternalNode rootNode = cache.getRoot().getDelegationTarget();
- try
- {
- if (log.isDebugEnabled())
- {
- log.debug("locking the " + fqn + " subtree to return the
in-memory (transient) state");
- }
- acquireLocksForStateTransfer(rootNode, timeout, force);
- generator.generateState(out, rootNode, fetchTransientState,
fetchPersistentState, suppressErrors);
- if (log.isDebugEnabled())
- {
- log.debug("Successfully generated state in " +
(System.currentTimeMillis() - startTime) + " msec");
- }
- }
- finally
- {
- releaseStateTransferLocks(rootNode);
- }
+ // we don't need READ locks for MVCC based state transfer!
+
+ if (log.isDebugEnabled())
+ log.debug("locking the " + fqn + " subtree to return the
in-memory (transient) state");
+
+ generator.generateState(out, rootNode, fetchTransientState,
fetchPersistentState, suppressErrors);
+
+ if (log.isDebugEnabled())
+ log.debug("Successfully generated state in " +
(System.currentTimeMillis() - startTime) + " msec");
}
else
{
@@ -128,7 +124,8 @@
public void setState(ObjectInputStream in, Fqn targetRoot) throws Exception
{
- NodeSPI target = cache.peek(targetRoot, false, false);
+ cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+ NodeSPI target = cache.getNode(targetRoot);
if (target == null)
{
// Create the integration root, but do not replicate
@@ -137,7 +134,8 @@
//needed for BR state transfers
cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
cache.put(targetRoot, null);
- target = cache.peek(targetRoot, false, false);
+
cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+ target = cache.getNode(targetRoot);
}
Object o = marshaller.objectFromObjectStream(in);
Boolean hasState = (Boolean) o;
@@ -166,69 +164,21 @@
* persistent state (or null)
* @param targetRoot node into which the state should be integrated
*/
- private void setState(ObjectInputStream state, NodeSPI targetRoot) throws Exception
+ protected void setState(ObjectInputStream state, NodeSPI targetRoot) throws Exception
{
long startTime = System.currentTimeMillis();
+ /*
+ * Vladimir/Manik/Brian (Dec 7,2006)
+ *
+ * integrator.integrateState(in,targetRoot, cl) will call cache.put for each
+ * node read from stream. Having option override below allows nodes read
+ * to be directly stored into a tree since we bypass interceptor chain.
+ *
+ */
+ if (log.isDebugEnabled()) log.debug("starting state integration at node "
+ targetRoot);
+ integrator.integrateState(state, targetRoot.getDelegationTarget(),
targetRoot.getFqn());
- try
- {
- // Acquire a lock on the root node
- acquireLocksForStateTransfer(targetRoot, stateRetrievalTimeout, true);
-
- /*
- * Vladimir/Manik/Brian (Dec 7,2006)
- *
- * integrator.integrateState(in,targetRoot, cl) will call cache.put for each
- * node read from stream. Having option override below allows nodes read
- * to be directly stored into a tree since we bypass interceptor chain.
- *
- */
-
-// Option option = new Option();
-// option.setBypassInterceptorChain(true);
-// cache.getInvocationContext().setOptionOverrides(option);
-//
- StateTransferIntegrator integrator = getStateTransferIntegrator(state,
targetRoot.getFqn());
- if (log.isDebugEnabled())
- {
- log.debug("starting state integration at node " + targetRoot);
- }
- integrator.integrateState(state, targetRoot);
- if (log.isDebugEnabled())
- {
- log.debug("successfully integrated state in " +
(System.currentTimeMillis() - startTime) + " msec");
- }
- }
- finally
- {
- releaseStateTransferLocks(targetRoot);
- }
+ if (log.isDebugEnabled())
+ log.debug("successfully integrated state in " +
(System.currentTimeMillis() - startTime) + " msec");
}
-
-
- /**
- * Acquires locks on a root node for an owner for state transfer.
- */
- protected void acquireLocksForStateTransfer(NodeSPI root, long timeout, boolean force)
throws InterruptedException
- {
- // no op
- }
-
- /**
- * Releases all state transfer locks acquired.
- */
- protected void releaseStateTransferLocks(NodeSPI root)
- {
- // no op
- }
-
- protected StateTransferGenerator getStateTransferGenerator()
- {
- return StateTransferFactory.getStateTransferGenerator(cache);
- }
-
- protected StateTransferIntegrator getStateTransferIntegrator(ObjectInputStream
istream, Fqn fqn) throws Exception
- {
- return StateTransferFactory.getStateTransferIntegrator(istream, fqn, cache,
nodeFactory);
- }
}
Copied:
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferGenerator.java
(from rev 6358,
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java)
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferGenerator.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferGenerator.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -0,0 +1,185 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at
gnu.org.
+ */
+package org.jboss.cache.statetransfer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
+import org.jboss.cache.Node;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.Version;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.marshall.NodeData;
+import org.jboss.cache.marshall.NodeDataExceptionMarker;
+
+import java.io.ObjectOutputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@Deprecated
+public class LegacyStateTransferGenerator implements StateTransferGenerator
+{
+
+ public static final short STATE_TRANSFER_VERSION =
Version.getVersionShort("2.0.0.GA");
+
+ private Log log = LogFactory.getLog(getClass().getName());
+
+ private CacheSPI cache;
+
+ private Set<Fqn> internalFqns;
+
+ @Inject
+ public void inject(CacheSPI cache)
+ {
+ this.cache = cache;
+ }
+
+ @Start(priority = 18)
+ private void start()
+ {
+ this.internalFqns = cache.getInternalFqns();
+ }
+
+ public void generateState(ObjectOutputStream out, Object rootNode, boolean
generateTransient,
+ boolean generatePersistent, boolean suppressErrors) throws
Exception
+ {
+ Fqn fqn = getFqn(rootNode);
+ try
+ {
+ cache.getMarshaller().objectToObjectStream(STATE_TRANSFER_VERSION, out);
+ if (generateTransient)
+ {
+ //transient + marker
+ if (log.isTraceEnabled())
+ {
+ log.trace("writing transient state for " + fqn);
+ }
+ marshallTransientState((NodeSPI) rootNode, out);
+ delimitStream(out);
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("transient state succesfully written");
+ }
+
+ //associated + marker
+ if (log.isTraceEnabled())
+ {
+ log.trace("writing associated state");
+ }
+
+ delimitStream(out);
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("associated state succesfully written");
+ }
+
+ }
+ else
+ {
+ //we have to write two markers for transient and associated
+ delimitStream(out);
+ delimitStream(out);
+ }
+
+ CacheLoader cacheLoader = cache.getCacheLoaderManager() == null ? null :
cache.getCacheLoaderManager().getCacheLoader();
+ if (cacheLoader != null && generatePersistent)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("writing persistent state for " + fqn + ",using
" + cache.getCacheLoaderManager().getCacheLoader().getClass());
+ }
+
+ if (fqn.isRoot())
+ {
+ cacheLoader.loadEntireState(out);
+ }
+ else
+ {
+ cacheLoader.loadState(fqn, out);
+ }
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("persistent state succesfully written");
+ }
+ }
+ delimitStream(out);
+ }
+ catch (Exception e)
+ {
+ cache.getMarshaller().objectToObjectStream(new NodeDataExceptionMarker(e,
cache.getLocalAddress()), out);
+ throw e;
+ }
+ }
+
+ private Fqn getFqn(Object o)
+ {
+ if (o instanceof Node) return ((Node) o).getFqn();
+ if (o instanceof InternalNode) return ((InternalNode) o).getFqn();
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * Places a delimiter marker on the stream
+ *
+ * @param out stream
+ * @throws java.io.IOException if there are errs
+ */
+ protected void delimitStream(ObjectOutputStream out) throws Exception
+ {
+
cache.getMarshaller().objectToObjectStream(DefaultStateTransferManager.STREAMING_DELIMITER_NODE,
out);
+ }
+
+ /**
+ * Do a preorder traversal: visit the node first, then the node's children
+ *
+ * @param out
+ * @throws Exception
+ */
+ protected void marshallTransientState(NodeSPI node, ObjectOutputStream out) throws
Exception
+ {
+ List<NodeData> nodeData = new LinkedList<NodeData>();
+ generateNodeDataList(node, nodeData);
+ cache.getMarshaller().objectToObjectStream(nodeData, out, node.getFqn());
+ }
+
+ protected void generateNodeDataList(NodeSPI<?, ?> node, List<NodeData>
list) throws Exception
+ {
+ if (internalFqns.contains(node.getFqn()))
+ {
+ return;
+ }
+
+ Map attrs;
+ NodeData nd;
+
+ // first handle the current node
+ attrs = node.getInternalState(false);
+
+ if (attrs.size() == 0)
+ {
+ nd = new NodeData(node.getFqn());
+ }
+ else
+ {
+ nd = new NodeData(node.getFqn(), attrs, true);
+ }
+
+ list.add(nd);
+
+ // then visit the children
+ for (NodeSPI child : node.getChildrenDirect()) generateNodeDataList(child, list);
+ }
+}
\ No newline at end of file
Copied:
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferIntegrator.java
(from rev 6358,
core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java)
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferIntegrator.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferIntegrator.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -0,0 +1,383 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at
gnu.org.
+ */
+package org.jboss.cache.statetransfer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+import org.jboss.cache.NodeFactory;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.Region;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.eviction.EvictedEventNode;
+import org.jboss.cache.eviction.NodeEventType;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.loader.CacheLoaderManager;
+import org.jboss.cache.marshall.NodeData;
+import org.jboss.cache.marshall.NodeDataExceptionMarker;
+import org.jboss.cache.marshall.NodeDataMarker;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@Deprecated
+public class LegacyStateTransferIntegrator implements StateTransferIntegrator
+{
+
+ private static final Log log =
LogFactory.getLog(LegacyStateTransferIntegrator.class);
+ private static final boolean trace = log.isTraceEnabled();
+
+ private CacheSPI cache;
+
+ private NodeFactory factory;
+
+ private Set<Fqn> internalFqns;
+
+ @Inject
+ public void inject(CacheSPI<?, ?> cache, NodeFactory nodefactory)
+ {
+ this.cache = cache;
+ this.factory = nodefactory;
+ }
+
+ @Start(priority = 14)
+ public void start()
+ {
+ this.internalFqns = cache.getInternalFqns();
+ }
+
+ public void integrateState(ObjectInputStream ois, Object target, Fqn targetFqn) throws
Exception
+ {
+ // pop version from the stream first!
+ short version = (Short) cache.getMarshaller().objectFromObjectStream(ois);
+ log.info("Using version " + version);
+ integrateTransientState(ois, (NodeSPI) target);
+ // read another marker for the dummy associated state
+ if (trace) log.trace("Reading marker for nonexistent associated state");
+ cache.getMarshaller().objectFromObjectStream(ois);
+ integratePersistentState(ois, targetFqn);
+ }
+
+ protected void integrateTransientState(ObjectInputStream in, NodeSPI target) throws
Exception
+ {
+ boolean transientSet = false;
+ try
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("integrating transient state for " + target);
+ }
+
+ integrateTransientState(target, in);
+
+ transientSet = true;
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("transient state successfully integrated");
+ }
+
+ notifyAllNodesCreated(cache.getInvocationContext(), target);
+ }
+ catch (Exception e)
+ {
+ throw new CacheException(e);
+ }
+ finally
+ {
+ if (!transientSet)
+ {
+ target.clearDataDirect();
+ target.removeChildrenDirect();
+ }
+ }
+ }
+
+ protected void integratePersistentState(ObjectInputStream in, Fqn targetFqn) throws
Exception
+ {
+ if (trace) log.trace("Reading persistent state from stream");
+ CacheLoaderManager loaderManager = cache.getCacheLoaderManager();
+ CacheLoader loader = loaderManager == null ? null :
loaderManager.getCacheLoader();
+ if (loader == null)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("cache loader is null, will not attempt to integrate
persistent state");
+ }
+ }
+ else
+ {
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("integrating persistent state using " +
loader.getClass().getName());
+ }
+
+ boolean persistentSet = false;
+ try
+ {
+ if (targetFqn.isRoot())
+ {
+ loader.storeEntireState(in);
+ }
+ else
+ {
+ loader.storeState(targetFqn, in);
+ }
+ persistentSet = true;
+ }
+ catch (ClassCastException cce)
+ {
+ log.error("Failed integrating persistent state. One of cacheloaders is
not"
+ + " adhering to state stream format. See JBCACHE-738.");
+ throw cce;
+ }
+ finally
+ {
+ if (!persistentSet)
+ {
+ log.warn("persistent state integration failed, removing all nodes
from loader");
+ loader.remove(targetFqn);
+ }
+ else
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("persistent state integrated successfully");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Generates NodeAdded notifications for all nodes of the tree. This is
+ * called whenever the tree is initially retrieved (state transfer)
+ */
+ private void notifyAllNodesCreated(InvocationContext ctx, NodeSPI curr)
+ {
+ if (curr == null) return;
+ ctx.setOriginLocal(false);
+ cache.getNotifier().notifyNodeCreated(curr.getFqn(), true, ctx);
+ cache.getNotifier().notifyNodeCreated(curr.getFqn(), false, ctx);
+ // AND notify that they have been modified!!
+ if (!curr.getKeysDirect().isEmpty())
+ {
+ cache.getNotifier().notifyNodeModified(curr.getFqn(), true,
NodeModifiedEvent.ModificationType.PUT_MAP, Collections.emptyMap(), ctx);
+ cache.getNotifier().notifyNodeModified(curr.getFqn(), false,
NodeModifiedEvent.ModificationType.PUT_MAP, curr.getDataDirect(), ctx);
+ }
+ ctx.setOriginLocal(true);
+
+ Set<NodeSPI> children = curr.getChildrenDirect();
+ for (NodeSPI n : children)
+ {
+ notifyAllNodesCreated(ctx, n);
+ }
+ }
+
+ private void integrateTransientState(NodeSPI target, ObjectInputStream in) throws
Exception
+ {
+ if (trace) log.trace("Reading transient state from stream");
+ target.removeChildrenDirect();
+
+ List<NodeData> list = readNodesAsList(in);
+ if (list != null)
+ {
+ // if the list was null we read an EOF marker!! So don't bother popping it
off the stack later.
+ Iterator<NodeData> nodeDataIterator = list.iterator();
+
+ // Read the first NodeData and integrate into our target
+ if (nodeDataIterator.hasNext())
+ {
+ NodeData nd = nodeDataIterator.next();
+
+ //are there any transient nodes at all?
+ if (nd != null && !nd.isMarker())
+ {
+ Map attributes = nd.getAttributes();
+
+ target.setInternalState(attributes);
+
+ // Check whether this is an integration into the buddy backup
+ // subtree
+ Fqn tferFqn = nd.getFqn();
+ Fqn tgtFqn = target.getFqn();
+ boolean move =
tgtFqn.isChildOrEquals(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN)
+ && !tferFqn.isChildOrEquals(tgtFqn);
+ // If it is an integration, calculate how many levels of offset
+ int offset = move ? tgtFqn.size() - tferFqn.size() : 0;
+
+ integrateStateTransferChildren(target, offset, nodeDataIterator);
+
+ integrateRetainedNodes(target);
+ }
+ }
+
+ // read marker off stack
+ if (trace) log.trace("Reading marker from stream");
+ cache.getMarshaller().objectFromObjectStream(in);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<NodeData> readNodesAsList(ObjectInputStream in) throws Exception
+ {
+ Object obj = cache.getMarshaller().objectFromObjectStream(in);
+ if (obj instanceof NodeDataMarker) return null;
+
+ return (List<NodeData>) obj;
+ }
+
+ private NodeData integrateStateTransferChildren(NodeSPI parent, int offset,
Iterator<NodeData> nodeDataIterator)
+ throws IOException, ClassNotFoundException
+ {
+ int parent_level = parent.getFqn().size();
+ int target_level = parent_level + 1;
+ Fqn fqn;
+ int size;
+ NodeData nd = nodeDataIterator.hasNext() ? nodeDataIterator.next() : null;
+ while (nd != null && !nd.isMarker())
+ {
+ fqn = nd.getFqn();
+ // If we need to integrate into the buddy backup subtree,
+ // change the Fqn to fit under it
+ if (offset > 0)
+ {
+ fqn = Fqn.fromRelativeFqn(parent.getFqn().getAncestor(offset), fqn);
+ }
+ size = fqn.size();
+ if (size <= parent_level)
+ {
+ return nd;
+ }
+ else if (size > target_level)
+ {
+ throw new IllegalStateException("NodeData " + fqn + " is not a
direct child of " + parent.getFqn());
+ }
+
+ Map attrs = nd.getAttributes();
+
+ // We handle this NodeData. Create a TreeNode and
+ // integrate its data
+ NodeSPI target = factory.createNode(fqn, parent, attrs);
+ parent.addChild(fqn.getLastElement(), target);
+
+ // JBCACHE-913
+ Region region = cache.getRegion(fqn, false);
+ if (region != null && region.getEvictionPolicy() != null)
+ {
+ region.putNodeEvent(new EvictedEventNode(fqn, NodeEventType.ADD_NODE_EVENT,
+ attrs == null ? 0 : attrs.size()));
+ }
+
+ // Recursively call, which will walk down the tree
+ // and return the next NodeData that's a child of our parent
+ nd = integrateStateTransferChildren(target, offset, nodeDataIterator);
+ }
+ if (nd != null && nd.isExceptionMarker())
+ {
+ NodeDataExceptionMarker ndem = (NodeDataExceptionMarker) nd;
+ throw new CacheException("State provider node " +
ndem.getCacheNodeIdentity()
+ + " threw exception during loadState", ndem.getCause());
+ }
+ return null;
+ }
+
+ private Set<Node> retainInternalNodes(Node target)
+ {
+ Set<Node> result = new HashSet<Node>();
+ Fqn targetFqn = target.getFqn();
+ for (Fqn internalFqn : internalFqns)
+ {
+ if (internalFqn.isChildOf(targetFqn))
+ {
+ Node internalNode = getInternalNode(target, internalFqn);
+ if (internalNode != null)
+ {
+ result.add(internalNode);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private Node getInternalNode(Node parent, Fqn internalFqn)
+ {
+ Object name = internalFqn.get(parent.getFqn().size());
+ cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+ Node result = parent.getChild(name);
+ if (result != null)
+ {
+ if (internalFqn.size() < result.getFqn().size())
+ {
+ // need to recursively walk down the tree
+ result = getInternalNode(result, internalFqn);
+ }
+ }
+ return result;
+ }
+
+ private void integrateRetainedNodes(NodeSPI target)
+ {
+ Set<Node> retainedNodes = retainInternalNodes(target);
+ Fqn rootFqn = target.getFqn();
+ for (Node retained : retainedNodes)
+ {
+ if (retained.getFqn().isChildOf(rootFqn))
+ {
+ integrateRetainedNode(target, retained);
+ }
+ }
+ }
+
+ private void integrateRetainedNode(NodeSPI ancestor, Node descendant)
+ {
+ Fqn descFqn = descendant.getFqn();
+ Fqn ancFqn = ancestor.getFqn();
+ Object name = descFqn.get(ancFqn.size());
+ NodeSPI child = (NodeSPI) ancestor.getChild(name);
+ if (ancFqn.size() == descFqn.size() + 1)
+ {
+ if (child == null)
+ {
+ ancestor.addChild(name, descendant);
+ }
+ else
+ {
+ log.warn("Received unexpected internal node " + descFqn + " in
transferred state");
+ }
+ }
+ else
+ {
+ if (child == null)
+ {
+ // Missing level -- have to create empty node
+ // This shouldn't really happen -- internal fqns should
+ // be immediately under the root
+ child = factory.createNode(name, ancestor);
+ ancestor.addChild(name, child);
+ }
+
+ // Keep walking down the tree
+ integrateRetainedNode(child, descendant);
+ }
+ }
+}
\ No newline at end of file
Modified:
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferManager.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferManager.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferManager.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -1,17 +1,25 @@
package org.jboss.cache.statetransfer;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.Fqn;
import org.jboss.cache.NodeSPI;
+import org.jboss.cache.RegionEmptyException;
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.lock.LockManager;
import static org.jboss.cache.lock.LockType.READ;
import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.marshall.InactiveRegionException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
/**
* This is to support legacy locking schemes such as Pessimistic and Optimistic locking.
*
* @author Manik Surtani (<a
href="mailto:manik@jboss.org">manik@jboss.org</a>)
* @since 3.0
*/
+@Deprecated
public class LegacyStateTransferManager extends DefaultStateTransferManager
{
protected LockManager lockManager;
@@ -23,6 +31,109 @@
}
@Override
+ public void getState(ObjectOutputStream out, Fqn fqn, long timeout, boolean force,
boolean suppressErrors) throws Exception
+ {
+ // can't give state for regions currently being activated/inactivated
+ boolean canProvideState = (!regionManager.isInactive(fqn) &&
cache.peek(fqn, false) != null);
+
+ if (canProvideState && (fetchPersistentState || fetchTransientState))
+ {
+ marshaller.objectToObjectStream(true, out);
+ long startTime = System.currentTimeMillis();
+ NodeSPI rootNode = cache.peek(fqn, false, false);
+
+ try
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("locking the " + fqn + " subtree to return the
in-memory (transient) state");
+ }
+ acquireLocksForStateTransfer(rootNode, timeout, force);
+ generator.generateState(out, rootNode, fetchTransientState,
fetchPersistentState, suppressErrors);
+ if (log.isDebugEnabled())
+ {
+ log.debug("Successfully generated state in " +
(System.currentTimeMillis() - startTime) + " msec");
+ }
+ }
+ finally
+ {
+ releaseStateTransferLocks(rootNode);
+ }
+ }
+ else
+ {
+ marshaller.objectToObjectStream(false, out);
+ Exception e = null;
+ if (!canProvideState)
+ {
+ String exceptionMessage = "Cache instance at " +
cache.getLocalAddress() + " cannot provide state for fqn " + fqn +
".";
+
+ if (regionManager.isInactive(fqn))
+ {
+ exceptionMessage += " Region for fqn " + fqn + " is
inactive.";
+ e = new InactiveRegionException(exceptionMessage);
+ }
+ // this is not really an exception. Just provide empty state. The exception
is just a signal. Yes, lousy. - JBCACHE-1349
+ if (cache.peek(fqn, false, false) == null)
+ {
+ e = new RegionEmptyException();
+ }
+ }
+ if (!fetchPersistentState && !fetchTransientState)
+ {
+ e = new CacheException("Cache instance at " +
cache.getLocalAddress() + " is not configured to provide state");
+ }
+ marshaller.objectToObjectStream(e, out);
+ if (e != null) throw e;
+ }
+ }
+
+ /**
+ * Set the portion of the cache rooted in <code>targetRoot</code>
+ * to match the given state. Updates the contents of
<code>targetRoot</code>
+ * to reflect those in <code>new_state</code>.
+ * <p/>
+ * <strong>NOTE:</strong> This method performs no locking of nodes; it
+ * is up to the caller to lock <code>targetRoot</code> before calling
+ * this method.
+ *
+ * @param state a serialized byte[][] array where element 0 is the
+ * transient state (or null) , and element 1 is the
+ * persistent state (or null)
+ * @param targetRoot node into which the state should be integrated
+ */
+ protected void setState(ObjectInputStream state, NodeSPI targetRoot) throws Exception
+ {
+ long startTime = System.currentTimeMillis();
+
+ acquireLocksForStateTransfer(targetRoot, stateRetrievalTimeout, true);
+ /*
+ * Vladimir/Manik/Brian (Dec 7,2006)
+ *
+ * integrator.integrateState(in,targetRoot, cl) will call cache.put for each
+ * node read from stream. Having option override below allows nodes read
+ * to be directly stored into a tree since we bypass interceptor chain.
+ *
+ */
+ try
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("starting state integration at node " + targetRoot);
+ }
+ integrator.integrateState(state, targetRoot, targetRoot.getFqn());
+ if (log.isDebugEnabled())
+ {
+ log.debug("successfully integrated state in " +
(System.currentTimeMillis() - startTime) + " msec");
+ }
+ }
+ finally
+ {
+ releaseStateTransferLocks(targetRoot);
+ }
+ }
+
+
protected void acquireLocksForStateTransfer(NodeSPI root, long timeout, boolean force)
throws InterruptedException
{
try
@@ -44,7 +155,6 @@
}
}
- @Override
protected void releaseStateTransferLocks(NodeSPI root)
{
try
Deleted: core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -1,75 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at
gnu.org.
- */
-package org.jboss.cache.statetransfer;
-
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeFactory;
-import org.jboss.cache.Version;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-
-/**
- * Factory class able to create {@link StateTransferGenerator} and
- * {@link StateTransferIntegrator} instances.
- *
- * @author <a href="brian.stansberry(a)jboss.com">Brian
Stansberry</a>
- * @version $Revision$
- */
-public abstract class StateTransferFactory
-{
- private static final short RV_200 = Version.getVersionShort("2.0.0");
-
- /**
- * Gets the StateTransferGenerator able to handle the given cache instance.
- *
- * @param cache the cache
- * @return the {@link StateTransferGenerator}
- * @throws IllegalStateException if the cache's ReplicationVersion is < 2.0.0
- */
- public static StateTransferGenerator getStateTransferGenerator(CacheSPI cache)
- {
- short version = cache.getConfiguration().getReplicationVersion();
-
- // Compiler won't let me use a switch
-
- if (version < RV_200 && version > 0) // <= 0 is actually a version
> 15.31.63
- throw new IllegalStateException("State transfer with cache replication
version < 2.0.0 not supported");
- else
- return new DefaultStateTransferGenerator(cache); // current default
- }
-
- public static StateTransferIntegrator getStateTransferIntegrator(ObjectInputStream in,
Fqn fqn, CacheSPI cache, NodeFactory nodeFactory)
- throws Exception
- {
- short version;
- try
- {
- version = (Short) cache.getMarshaller().objectFromObjectStream(in);
- }
- catch (IOException io)
- {
- // something is wrong with this stream, close it
- try
- {
- in.close();
- }
- catch (IOException ignored)
- {
- }
- throw new IllegalStateException("Stream corrupted ", io);
- }
-
- // Compiler won't let me use a switch
-
- if (version < RV_200 && version > 0) // <= 0 is actually a version
> 15.31.63
- throw new IllegalStateException("State transfer with cache replication
version < 2.0.0 not supported");
- else
- return new DefaultStateTransferIntegrator(fqn, cache, nodeFactory); // current
default
- }
-}
Modified:
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferGenerator.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferGenerator.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferGenerator.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -6,8 +6,6 @@
*/
package org.jboss.cache.statetransfer;
-import org.jboss.cache.Node;
-
import java.io.ObjectOutputStream;
/**
@@ -15,6 +13,6 @@
*/
public interface StateTransferGenerator
{
- void generateState(ObjectOutputStream stream, Node rootNode, boolean
generateTransient, boolean generatePersistent, boolean suppressErrors) throws Exception;
-
+ // TODO: rootNode is an Object to support both InternalNodes and NodeSPIs.
+ void generateState(ObjectOutputStream stream, Object rootNode, boolean
generateTransient, boolean generatePersistent, boolean suppressErrors) throws Exception;
}
\ No newline at end of file
Modified:
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferIntegrator.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferIntegrator.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferIntegrator.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -6,7 +6,7 @@
*/
package org.jboss.cache.statetransfer;
-import org.jboss.cache.Node;
+import org.jboss.cache.Fqn;
import java.io.ObjectInputStream;
@@ -15,7 +15,6 @@
*/
public interface StateTransferIntegrator
{
-
- void integrateState(ObjectInputStream ois, Node target) throws Exception;
-
+ // TODO: target is an Object to support both InternalNodes and NodeSPIs.
+ void integrateState(ObjectInputStream ois, Object target, Fqn targetFqn) throws
Exception;
}
\ No newline at end of file
Modified:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -1,5 +1,7 @@
package org.jboss.cache.util.concurrent;
+import org.jboss.cache.UnversionedNode;
+
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
@@ -16,6 +18,8 @@
*/
public class SelfInitializingConcurrentHashMap<K, V> implements ConcurrentMap<K,
V>
{
+ static boolean DEBUG = false; // TODO remove this
+
private volatile ConcurrentMap<K, V> delegate;
// private int initialCapacity = -1, concurrencyLevel = -1;
// private float loadFactor = -1;
@@ -82,6 +86,7 @@
public final V put(K key, V value)
{
+ if (DEBUG) if (value instanceof UnversionedNode) throw new RuntimeException();
return getDelegate().put(key, value);
}
@@ -97,16 +102,19 @@
public final V putIfAbsent(K key, V value)
{
+ if (DEBUG) if (value instanceof UnversionedNode) throw new RuntimeException();
return getDelegate().putIfAbsent(key, value);
}
public final boolean replace(K key, V oldValue, V newValue)
{
+ if (DEBUG) if (oldValue instanceof UnversionedNode) throw new RuntimeException();
return getDelegate().replace(key, oldValue, newValue);
}
public final V replace(K key, V value)
{
+ if (DEBUG) if (value instanceof UnversionedNode) throw new RuntimeException();
return getDelegate().replace(key, value);
}
Modified: core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -124,7 +124,7 @@
}
catch (Exception e)
{
- throw new CacheException("Unable to invoke method " + method + "
on object instance " + instance +
+ throw new CacheException("Unable to invoke method " + method + "
on object " + //instance +
(parameters != null ? " with parameters " +
Arrays.asList(parameters) : ""), e);
}
}
Modified:
core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java
===================================================================
---
core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -21,7 +21,7 @@
{
cache.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
cache.getConfiguration().setIsolationLevel(IsolationLevel.READ_COMMITTED);
- CacheLoaderConfig clc = getSingleCacheLoaderConfig("",
DummySharedInMemoryCacheLoader.class.getName(), "", false, true, false);
+ CacheLoaderConfig clc = getSingleCacheLoaderConfig("",
DummySharedInMemoryCacheLoader.class.getName(), "debug=true", false, true,
false);
clc.setPassivation(true);
cache.getConfiguration().setCacheLoaderConfig(clc);
}
Copied:
core/trunk/src/test/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommandTest.java
(from rev 6358,
core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java)
===================================================================
---
core/trunk/src/test/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommandTest.java
(rev 0)
+++
core/trunk/src/test/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommandTest.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -0,0 +1,138 @@
+package org.jboss.cache.commands.legacy.write;
+
+import static org.easymock.EasyMock.createStrictControl;
+import static org.easymock.EasyMock.expect;
+import org.easymock.IMocksControl;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.commands.read.AbstractDataCommandTest;
+import org.jboss.cache.mock.MockNodesFixture;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.optimistic.DataVersioningException;
+import org.jboss.cache.optimistic.DefaultDataVersion;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.Collections;
+
+/**
+ * tester class for {@link VersionedInvalidateCommand}.
+ *
+ * @author Mircea.Markus(a)jboss.com
+ * @since 2.2
+ */
+@Test(groups = "unit")
+public class VersionedInvalidateCommandTest extends AbstractDataCommandTest
+{
+ DataVersion dataVersion;
+ VersionedInvalidateCommand command;
+ IMocksControl control;
+
+ Notifier notifier;
+ TransactionManager tmMock;
+
+ MockNodesFixture nodes;
+ CacheSPI spiMock;
+
+ protected void moreSetup()
+ {
+ control = createStrictControl();
+ notifier = control.createMock(Notifier.class);
+ container = control.createMock(DataContainer.class);
+ tmMock = control.createMock(TransactionManager.class);
+ spiMock = control.createMock(CacheSPI.class);
+ nodes = new MockNodesFixture();
+
+ command = new VersionedInvalidateCommand(testFqn);
+ dataVersion = new DefaultDataVersion(10);
+ command.setDataVersion(dataVersion);
+ command.initialize(spiMock, container, notifier);
+ command.initialize(tmMock);
+ }
+
+ public void testWithExistingNode()
+ {
+ nodes.adfNode.put("key", "value");
+ nodes.adfNode.setVersion(dataVersion);
+ nodes.adfNode.setDataLoaded(true);
+ expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
+ notifier.notifyNodeEvicted(testFqn, true, ctx);
+ notifier.notifyNodeEvicted(testFqn, false, ctx);
+
+ control.replay();
+ assert null == command.perform(ctx);
+ assert nodes.adfNode.getData().isEmpty();
+ assert !nodes.adfNode.isDataLoaded();
+ assert !nodes.adfNode.isValid();
+ assert nodes.adfNode.getVersion().equals(dataVersion);
+
+ control.verify();
+ }
+
+ public void testWithExistingNodeInvalidVersion()
+ {
+ nodes.adfNode.put("key", "value");
+ nodes.adfNode.setDataLoaded(true);
+ nodes.adfNode.setVersion(new DefaultDataVersion(100));
+ expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
+ control.replay();
+
+ try
+ {
+ command.perform(ctx);
+ assert false : "exception expected";
+ }
+ catch (DataVersioningException e)
+ {
+ //expected as there is a version mismatch
+ }
+ assert !nodes.adfNode.getData().isEmpty();
+ assert nodes.adfNode.isDataLoaded();
+ assert nodes.adfNode.isValid();
+ assert !dataVersion.equals(nodes.adfNode.getVersion());
+
+ control.verify();
+ }
+
+ public void testExistingTombstone()
+ {
+ nodes.adfNode.setValid(false, true);
+ nodes.adfNode.setVersion(dataVersion);
+ expect(spiMock.getNode(testFqn)).andReturn(null);
+ expect(container.peek(testFqn, true, true)).andReturn(nodes.adfNode);
+ notifier.notifyNodeEvicted(testFqn, true, ctx);
+ notifier.notifyNodeEvicted(testFqn, false, ctx);
+
+ control.replay();
+ assert null == command.perform(ctx);
+ assert nodes.adfNode.getData().isEmpty();
+ assert !nodes.adfNode.isDataLoaded();
+ assert !nodes.adfNode.isValid();
+ assert nodes.adfNode.getVersion().equals(dataVersion);
+ control.verify();
+ }
+
+ public void testCreateTombstone() throws Exception
+ {
+ Transaction tx = control.createMock(Transaction.class);
+ expect(tmMock.suspend()).andReturn(tx);
+ spiMock.put(testFqn, Collections.emptyMap());
+ tmMock.resume(tx);
+
+ control.replay();
+ command.createTombstone(ctx);
+ control.verify();
+ }
+
+ public void testCreateTombstoneNoTx() throws Exception
+ {
+ expect(tmMock.suspend()).andReturn(null);
+ spiMock.put(testFqn, Collections.EMPTY_MAP);
+
+ control.replay();
+ command.createTombstone(ctx);
+ control.verify();
+ }
+}
Deleted:
core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java
===================================================================
---
core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -1,138 +0,0 @@
-package org.jboss.cache.commands.write;
-
-import static org.easymock.EasyMock.createStrictControl;
-import static org.easymock.EasyMock.expect;
-import org.easymock.IMocksControl;
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.commands.read.AbstractDataCommandTest;
-import org.jboss.cache.mock.MockNodesFixture;
-import org.jboss.cache.notifications.Notifier;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.optimistic.DataVersioningException;
-import org.jboss.cache.optimistic.DefaultDataVersion;
-import org.testng.annotations.Test;
-
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.util.Collections;
-
-/**
- * tester class for {@link VersionedInvalidateCommand}.
- *
- * @author Mircea.Markus(a)jboss.com
- * @since 2.2
- */
-@Test(groups = "unit")
-public class VersionedInvalidateCommandTest extends AbstractDataCommandTest
-{
- DataVersion dataVersion;
- VersionedInvalidateCommand command;
- IMocksControl control;
-
- Notifier notifier;
- TransactionManager tmMock;
-
- MockNodesFixture nodes;
- CacheSPI spiMock;
-
- protected void moreSetup()
- {
- control = createStrictControl();
- notifier = control.createMock(Notifier.class);
- container = control.createMock(DataContainer.class);
- tmMock = control.createMock(TransactionManager.class);
- spiMock = control.createMock(CacheSPI.class);
- nodes = new MockNodesFixture();
-
- command = new VersionedInvalidateCommand(testFqn);
- dataVersion = new DefaultDataVersion(10);
- command.setDataVersion(dataVersion);
- command.initialize(spiMock, container, notifier);
- command.initialize(tmMock);
- }
-
- public void testWithExistingNode()
- {
- nodes.adfNode.put("key", "value");
- nodes.adfNode.setVersion(dataVersion);
- nodes.adfNode.setDataLoaded(true);
- expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
- notifier.notifyNodeEvicted(testFqn, true, ctx);
- notifier.notifyNodeEvicted(testFqn, false, ctx);
-
- control.replay();
- assert null == command.perform(ctx);
- assert nodes.adfNode.getData().isEmpty();
- assert !nodes.adfNode.isDataLoaded();
- assert !nodes.adfNode.isValid();
- assert nodes.adfNode.getVersion().equals(dataVersion);
-
- control.verify();
- }
-
- public void testWithExistingNodeInvalidVersion()
- {
- nodes.adfNode.put("key", "value");
- nodes.adfNode.setDataLoaded(true);
- nodes.adfNode.setVersion(new DefaultDataVersion(100));
- expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
- control.replay();
-
- try
- {
- command.perform(ctx);
- assert false : "exception expected";
- }
- catch (DataVersioningException e)
- {
- //expected as there is a version mismatch
- }
- assert !nodes.adfNode.getData().isEmpty();
- assert nodes.adfNode.isDataLoaded();
- assert nodes.adfNode.isValid();
- assert !dataVersion.equals(nodes.adfNode.getVersion());
-
- control.verify();
- }
-
- public void testExistingTombstone()
- {
- nodes.adfNode.setValid(false, true);
- nodes.adfNode.setVersion(dataVersion);
- expect(spiMock.getNode(testFqn)).andReturn(null);
- expect(container.peek(testFqn, true, true)).andReturn(nodes.adfNode);
- notifier.notifyNodeEvicted(testFqn, true, ctx);
- notifier.notifyNodeEvicted(testFqn, false, ctx);
-
- control.replay();
- assert null == command.perform(ctx);
- assert nodes.adfNode.getData().isEmpty();
- assert !nodes.adfNode.isDataLoaded();
- assert !nodes.adfNode.isValid();
- assert nodes.adfNode.getVersion().equals(dataVersion);
- control.verify();
- }
-
- public void testCreateTumbstone() throws Exception
- {
- Transaction tx = control.createMock(Transaction.class);
- expect(tmMock.suspend()).andReturn(tx);
- spiMock.put(testFqn, Collections.emptyMap());
- tmMock.resume(tx);
-
- control.replay();
- command.createTombstone(ctx);
- control.verify();
- }
-
- public void testCreateTumbstoneNoTx() throws Exception
- {
- expect(tmMock.suspend()).andReturn(null);
- spiMock.put(testFqn, Collections.EMPTY_MAP);
-
- control.replay();
- command.createTombstone(ctx);
- control.verify();
- }
-}
Modified: core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java 2008-07-28 10:29:41 UTC
(rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java 2008-07-28 10:56:29 UTC
(rev 6414)
@@ -1,9 +1,13 @@
package org.jboss.cache.mock;
import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DataContainer;
import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
import org.jboss.cache.Node;
+import org.jboss.cache.NodeFactory;
import org.jboss.cache.NodeSPI;
+import org.jboss.cache.invocation.InvocationContext;
import org.jboss.cache.lock.NodeLock;
import org.jboss.cache.optimistic.DataVersion;
import org.jboss.cache.transaction.GlobalTransaction;
@@ -292,6 +296,46 @@
}
}
+ public boolean isNullNode()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void markForUpdate(InvocationContext ctx, DataContainer container, NodeFactory
nodeFactory, boolean writeSkewCheck)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void commitUpdate(InvocationContext ctx, DataContainer container, NodeFactory
nodeFactory)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isChanged()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isCreated()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public InternalNode getDelegationTarget()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setCreated(boolean created)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void rollbackUpdate()
+ {
+ throw new UnsupportedOperationException();
+ }
+
public Set getChildren()
{
return getChildrenDirect();
Modified:
core/trunk/src/test/java/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java
===================================================================
---
core/trunk/src/test/java/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/test/java/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -8,7 +8,6 @@
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
-import org.jboss.cache.Node;
import org.jboss.cache.commands.tx.CommitCommand;
import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
import org.jboss.cache.interceptors.CallInterceptor;
@@ -251,8 +250,8 @@
TransactionWorkspace workspace = entry.getTransactionWorkSpace();
- Node one = workspace.getNode(Fqn.fromString("/one"));
- Node two = workspace.getNode(Fqn.fromString("/one/two"));
+ WorkspaceNode one = workspace.getNode(Fqn.fromString("/one"));
+ WorkspaceNode two = workspace.getNode(Fqn.fromString("/one/two"));
cache.removeNode("/one");
@@ -311,8 +310,8 @@
TransactionWorkspace workspace = entry.getTransactionWorkSpace();
- Node one = workspace.getNode(Fqn.fromString("/one"));
- Node two = workspace.getNode(Fqn.fromString("/one/two"));
+ WorkspaceNode one = workspace.getNode(Fqn.fromString("/one"));
+ WorkspaceNode two = workspace.getNode(Fqn.fromString("/one/two"));
cache.removeNode("/one");
Modified: core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java
===================================================================
---
core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -68,6 +68,7 @@
@AfterMethod(alwaysRun = true)
public void tearDown() throws Exception
{
+ log.info("**** TEARING DOWN ****");
loader.remove(Fqn.ROOT);
TestingUtil.killCaches(cache);
}
@@ -342,19 +343,12 @@
public void testGetChildren4()
{
- try
+ if (!cache.exists("/a/b/c"))
{
- if (!cache.exists("/a/b/c"))
- {
- cache.put("/a/b/c", null);
- }
- Set children = cache.getChildrenNames((Fqn) null);// get "null* node
children names
- assertTrue(children.isEmpty());
+ cache.put("/a/b/c", null);
}
- catch (Exception e)
- {
- fail(e.toString());
- }
+ Set children = cache.getChildrenNames((Fqn) null);// get "null* node children
names
+ assertTrue(children.isEmpty());
}
@@ -417,6 +411,7 @@
cache.evict(Fqn.fromString("/a/2"));// passivate node
cache.evict(Fqn.fromString("/a/3"));// passivate node
cache.evict(Fqn.fromString("/a"));// passivate node
+ assert !exists("/a");
assertTrue(loader.exists(Fqn.fromString("/a")));
addDelay();
Object val = cache.get("/a", "test");// load node's
attributes but not children
Added: core/trunk/src/test/java/org/jboss/cache/profiling/MemoryFootprintTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/profiling/MemoryFootprintTest.java
(rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/profiling/MemoryFootprintTest.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -0,0 +1,40 @@
+package org.jboss.cache.profiling;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.lock.IsolationLevel;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+
+@Test(groups = "profiling")
+public class MemoryFootprintTest
+{
+ int numFqns = 100000;
+
+ public void testLocal() throws IOException
+ {
+ Cache<String, String> c = new DefaultCacheFactory<String,
String>().createCache(false);
+ c.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
+ c.getConfiguration().setIsolationLevel(IsolationLevel.READ_COMMITTED);
+// c.getConfiguration().setIsolationLevel(IsolationLevel.REPEATABLE_READ);
+ c.start();
+
+ for (int i = 100000; i < 100000 + numFqns; i++)
+ {
+ String key = "keyX" + i;
+ String value = "valX" + i;
+ Fqn fqn = Fqn.fromElements(i);
+ c.put(fqn, key, value);
+ }
+
+ System.out.println("Hit enter when done");
+ System.in.read();
+
+ c.stop();
+ }
+
+
+}
Modified:
core/trunk/src/test/java/org/jboss/cache/statetransfer/StateTransferTestBase.java
===================================================================
---
core/trunk/src/test/java/org/jboss/cache/statetransfer/StateTransferTestBase.java 2008-07-28
10:29:41 UTC (rev 6413)
+++
core/trunk/src/test/java/org/jboss/cache/statetransfer/StateTransferTestBase.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -345,7 +345,7 @@
try
{
stopCache(caches.get(cacheID));
- TestingUtil.sleepThread(1500);
+// TestingUtil.sleepThread(1500);
File file = new File(getTempLocation(cacheID));
cleanFile(file);
}
@@ -354,6 +354,13 @@
// errors in teardown should not fail test
}
}
+
+ // repeat. Make sure everything is properly STOPPED!!!
+
+ for (Cache c : caches.values())
+ {
+ TestingUtil.killCaches(c);
+ }
}
protected void stopCache(Cache cache)
Modified: core/trunk/src/test/java/org/jboss/cache/util/ImmutableListCopyTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/util/ImmutableListCopyTest.java 2008-07-28
10:29:41 UTC (rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/util/ImmutableListCopyTest.java 2008-07-28
10:56:29 UTC (rev 6414)
@@ -141,4 +141,14 @@
while (li.hasPrevious()) assert li.previous() == number--;
assert number == 0;
}
+
+ public void testSubLists()
+ {
+ List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+ List<Integer> list = new ImmutableListCopy<Integer>(ints);
+
+ assert ints.subList(2, 5).equals(list.subList(2, 5));
+ assert ints.subList(1, 9).equals(list.subList(1, 9));
+ assert ints.subList(0, 1).equals(list.subList(0, 1));
+ }
}
Modified: core/trunk/src/test/java/org/jboss/cache/util/TestingUtil.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/util/TestingUtil.java 2008-07-28 10:29:41 UTC
(rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/util/TestingUtil.java 2008-07-28 10:56:29 UTC
(rev 6414)
@@ -421,37 +421,44 @@
{
for (Cache c : caches)
{
- if (c != null && c.getCacheStatus() == CacheStatus.STARTED)
+ try
{
- CacheSPI spi = (CacheSPI) c;
- if (spi.getTransactionManager() != null)
+ if (c != null && c.getCacheStatus() == CacheStatus.STARTED)
{
- try
+ CacheSPI spi = (CacheSPI) c;
+ if (spi.getTransactionManager() != null)
{
- spi.getTransactionManager().rollback();
+ try
+ {
+ spi.getTransactionManager().rollback();
+ }
+ catch (Exception e)
+ {
+ // don't care
+ }
}
- catch (Exception e)
+
+ CacheLoaderManager clm = spi.getCacheLoaderManager();
+ CacheLoader cl = clm == null ? null : clm.getCacheLoader();
+ if (cl != null)
{
- // don't care
+ try
+ {
+ cl.remove(Fqn.ROOT);
+ }
+ catch (Exception e)
+ {
+ // don't care
+ }
}
- }
- CacheLoaderManager clm = spi.getCacheLoaderManager();
- CacheLoader cl = clm == null ? null : clm.getCacheLoader();
- if (cl != null)
- {
- try
- {
- cl.remove(Fqn.ROOT);
- }
- catch (Exception e)
- {
- // don't care
- }
+ spi.stop();
+ spi.destroy();
}
+ }
+ catch (Throwable t)
+ {
- spi.stop();
- spi.destroy();
}
}
}