Author: sergiykarpenko
Date: 2010-11-05 12:29:16 -0400 (Fri, 05 Nov 2010)
New Revision: 3403
Modified:
jcr/branches/1.14-ISPN/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
Log:
EXOJCR-1006: allow to keep missing values into the JCR cache based on JBossCache
Modified:
jcr/branches/1.14-ISPN/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
===================================================================
---
jcr/branches/1.14-ISPN/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java 2010-11-05
15:33:42 UTC (rev 3402)
+++
jcr/branches/1.14-ISPN/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java 2010-11-05
16:29:16 UTC (rev 3403)
@@ -31,6 +31,7 @@
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.datamodel.NullItemData;
+import org.exoplatform.services.jcr.datamodel.NullNodeData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPath;
import org.exoplatform.services.jcr.datamodel.QPathEntry;
@@ -58,6 +59,7 @@
import java.util.Set;
import javax.jcr.RepositoryException;
+import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
/**
@@ -187,7 +189,7 @@
do
{
String itemId = (String)cache.get(makeChildFqn(root, parentId,
(String)childs.next()), ITEM_ID);
- if (itemId != null)
+ if (itemId != null && !itemId.equals(NullItemData.NULL_ID))
{
n = (T)cache.get(makeItemFqn(itemId), ITEM_DATA);
}
@@ -387,10 +389,10 @@
*/
public void put(ItemData item)
{
- // TODO its temporary
+ // There is different commit processing for NullNodeData and ordinary ItemData
if (item instanceof NullItemData)
{
- // skip null values
+ putNullItem((NullItemData)item);
return;
}
@@ -583,17 +585,6 @@
public void addChildPropertiesList(NodeData parent, List<PropertyData>
childProperties)
{
// TODO not implemented, will force read from DB
- // try
- // {
- // cache.beginTransaction();
- // cache.setLocal(true);
- //
- // }
- // finally
- // {
- // cache.setLocal(false);
- // cache.commitTransaction();
- // }
}
/**
@@ -610,24 +601,46 @@
public ItemData get(String parentId, QPathEntry name, ItemType itemType)
{
String itemId = null;
- if (itemType == ItemType.NODE || itemType == ItemType.UNKNOWN)
+
+ if (itemType == ItemType.UNKNOWN)
{
- // try as node first
+ // Try as node first.
itemId = (String)cache.get(makeChildFqn(childNodes, parentId, name), ITEM_ID);
+
+ if (itemId == null || itemId.equals(NullItemData.NULL_ID))
+ {
+ // node with such a name is not found or marked as not-exist, so check the
properties
+ String propId = (String)cache.get(makeChildFqn(childProps, parentId, name),
ITEM_ID);
+ if (propId != null)
+ {
+ itemId = propId;
+ }
+ }
}
-
- if (itemType == ItemType.PROPERTY || itemType == ItemType.UNKNOWN && itemId
== null)
+ else if (itemType == ItemType.NODE)
{
- // try as property
+ itemId = (String)cache.get(makeChildFqn(childNodes, parentId, name), ITEM_ID);
+ }
+ else
+ {
itemId = (String)cache.get(makeChildFqn(childProps, parentId, name), ITEM_ID);
}
if (itemId != null)
{
- return get(itemId);
+ if (itemId.equals(NullItemData.NULL_ID))
+ {
+ // this NullNodeData object will not be placed at cache, so we can use unsafe
constructor
+ return new NullNodeData(parentId, name);
+ }
+ else
+ {
+ return get(itemId);
+ }
}
return null;
+
}
/**
@@ -653,7 +666,7 @@
for (Object child : set)
{
NodeData node = (NodeData)cache.get(makeItemFqn((String)child), ITEM_DATA);
- if (node == null)
+ if (node == null || node instanceof NullItemData)
{
return null;
}
@@ -718,7 +731,7 @@
for (Object child : set)
{
PropertyData prop = (PropertyData)cache.get(makeItemFqn((String)child),
ITEM_DATA);
- if (prop == null)
+ if (prop == null || prop instanceof NullItemData)
{
return null;
}
@@ -861,9 +874,60 @@
}
// add in ITEMS
- return (ItemData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
+ // NullNodeData must never be returned inside internal cache operations.
+ ItemData returnedData =
(ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
+ return (returnedData instanceof NullItemData) ? null : returnedData;
+
}
+ /**
+ * Internal put NullNode.
+ *
+ * @param node, NodeData, new data to put in the cache
+ */
+ protected void putNullItem(NullItemData node)
+ {
+ boolean inTransaction = cache.isTransactionActive();
+ try
+ {
+ if (!inTransaction)
+ {
+ cache.beginTransaction();
+ }
+ cache.setLocal(true);
+
+ if (node.getQPath() == null)
+ {
+ //put in $ITEMS
+ cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
+ }
+ else
+ {
+ if (node.isNode())
+ {
+ // put in $CHILD_NODES
+ cache.put(makeChildFqn(childNodes, node.getParentIdentifier(),
node.getQPath().getEntries()[node
+ .getQPath().getEntries().length - 1]), ITEM_ID, node.getIdentifier());
+ }
+ else
+ {
+ // put in $CHILD_PROPERTIES
+ cache.put(makeChildFqn(childProps, node.getParentIdentifier(),
node.getQPath().getEntries()[node
+ .getQPath().getEntries().length - 1]), ITEM_ID, node.getIdentifier());
+ }
+ }
+ }
+ finally
+ {
+ cache.setLocal(false);
+ if (!inTransaction)
+ {
+ dedicatedTxCommit();
+ }
+ }
+
+ }
+
protected ItemData putNodeInBufferedCache(NodeData node, ModifyChildOption
modifyListsOfChild)
{
// if not a root node
@@ -882,7 +946,9 @@
}
}
// add in ITEMS
- return (ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA,
node);
+ // NullNodeData must never be returned inside internal cache operations.
+ ItemData returnedData =
(ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
+ return (returnedData instanceof NullItemData) ? null : returnedData;
}
/**
@@ -904,7 +970,9 @@
cache.addToList(makeChildListFqn(childPropsList, prop.getParentIdentifier()),
ITEM_LIST, prop.getIdentifier());
}
// add in ITEMS
- return (PropertyData)cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA,
prop);
+ // NullItemData must never be returned inside internal cache operations.
+ ItemData returnedData = (ItemData)cache.put(makeItemFqn(prop.getIdentifier()),
ITEM_DATA, prop);
+ return (returnedData instanceof NullItemData) ? null : (PropertyData)returnedData;
}
protected void removeItem(ItemData item)
@@ -958,18 +1026,22 @@
protected void updateMixin(NodeData node)
{
NodeData prevData = (NodeData)cache.put(makeItemFqn(node.getIdentifier()),
ITEM_DATA, node);
- if (prevData != null)
+ // prevent update NullNodeData
+ if (!(prevData instanceof NullItemData))
{
- // do update ACL if needed
- if (prevData.getACL() == null || !prevData.getACL().equals(node.getACL()))
+ if (prevData != null)
{
- updateChildsACL(node.getIdentifier(), node.getACL());
+ // do update ACL if needed
+ if (prevData.getACL() == null || !prevData.getACL().equals(node.getACL()))
+ {
+ updateChildsACL(node.getIdentifier(), node.getACL());
+ }
}
+ else if (LOG.isDebugEnabled())
+ {
+ LOG.debug("Previous NodeData not found for mixin update " +
node.getQPath().getAsString());
+ }
}
- else if (LOG.isDebugEnabled())
- {
- LOG.debug("Previous NodeData not found for mixin update " +
node.getQPath().getAsString());
- }
}
/**
@@ -1058,7 +1130,8 @@
// check is this descendant of prevRootPath
QPath nodeQPath = data.getQPath();
- if (nodeQPath.isDescendantOf(prevRootPath))
+ // NullNodeData's qPath==null;
+ if (nodeQPath != null && nodeQPath.isDescendantOf(prevRootPath))
{
//make relative path
@@ -1224,4 +1297,44 @@
NOT_MODIFY, MODIFY, FORCE_MODIFY
}
+ /**
+ * Allows to commit the cache changes in a dedicated XA Tx in order to avoid
potential
+ * deadlocks
+ */
+ private void dedicatedTxCommit()
+ {
+ // Ensure that the commit is done in a dedicated tx to avoid deadlock due
+ // to global XA Tx
+ TransactionManager tm = getTransactionManager();
+ Transaction tx = null;
+ try
+ {
+ if (tm != null)
+ {
+ try
+ {
+ tx = tm.suspend();
+ }
+ catch (Exception e)
+ {
+ LOG.warn("Cannot suspend the current transaction", e);
+ }
+ }
+ cache.commitTransaction();
+ }
+ finally
+ {
+ if (tx != null)
+ {
+ try
+ {
+ tm.resume(tx);
+ }
+ catch (Exception e)
+ {
+ LOG.warn("Cannot resume the current transaction", e);
+ }
+ }
+ }
+ }
}