[exo-jcr-commits] exo-jcr SVN: r1532 - jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache.
do-not-reply at jboss.org
do-not-reply at jboss.org
Thu Jan 21 11:13:00 EST 2010
Author: nzamosenchuk
Date: 2010-01-21 11:13:00 -0500 (Thu, 21 Jan 2010)
New Revision: 1532
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManager.java
Log:
EXOJCR-424: added sorting in onSaveItems() in cacheable Lock manager to avoid deadlocks.
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManager.java 2010-01-21 14:48:20 UTC (rev 1531)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/jbosscache/CacheableLockManager.java 2010-01-21 16:13:00 UTC (rev 1532)
@@ -44,7 +44,6 @@
import org.exoplatform.services.jcr.impl.core.lock.SessionLockManager;
import org.exoplatform.services.jcr.impl.dataflow.TransientItemData;
import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData;
-import org.exoplatform.services.jcr.impl.dataflow.persistent.TxIsolatedOperation;
import org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspacePersistentDataManager;
import org.exoplatform.services.jcr.impl.storage.JCRInvalidItemStateException;
import org.exoplatform.services.jcr.observation.ExtendedEvent;
@@ -64,7 +63,6 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -164,7 +162,7 @@
private final Fqn<String> lockRoot;
private Map<String, CacheableSessionLockManager> sessionLockManagers;
-
+
/**
* Constructor.
*
@@ -176,12 +174,11 @@
* @throws RepositoryConfigurationException
*/
public CacheableLockManager(WorkspacePersistentDataManager dataManager, WorkspaceEntry config,
- InitialContextInitializer context, TransactionService transactionService)
- throws RepositoryConfigurationException
+ InitialContextInitializer context, TransactionService transactionService) throws RepositoryConfigurationException
{
this(dataManager, config, context, transactionService.getTransactionManager());
}
-
+
/**
* Constructor.
*
@@ -191,12 +188,11 @@
* @throws RepositoryConfigurationException
*/
public CacheableLockManager(WorkspacePersistentDataManager dataManager, WorkspaceEntry config,
- InitialContextInitializer context)
- throws RepositoryConfigurationException
+ InitialContextInitializer context) throws RepositoryConfigurationException
{
this(dataManager, config, context, (TransactionManager)null);
}
-
+
/**
* Constructor.
*
@@ -211,7 +207,7 @@
InitialContextInitializer context, TransactionManager transactionManager) throws RepositoryConfigurationException
{
lockRoot = Fqn.fromElements(LOCKS);
-
+
List<SimpleParameterEntry> paramenerts = config.getLockManager().getParameters();
this.dataManager = dataManager;
@@ -252,15 +248,15 @@
CacheFactory<Serializable, Object> factory = new DefaultCacheFactory<Serializable, Object>();
cache = factory.createCache(pathToConfig, false);
-
+
if (transactionManager != null)
{
cache.getConfiguration().getRuntimeConfig().setTransactionManager(transactionManager);
}
-
+
cache.create();
cache.start();
-
+
createStructuredNode(lockRoot);
// Context recall is a workaround of JDBCCacheLoader starting.
@@ -338,7 +334,7 @@
*/
public boolean isLockLive(String nodeId)
{
- if (pendingLocks.containsKey(nodeId) || cache.getRoot().hasChild(makeLockFqn(nodeId)))
+ if (pendingLocks.containsKey(nodeId) || cache.getRoot().hasChild(makeLockFqn(nodeId)))
{
return true;
}
@@ -382,7 +378,9 @@
chengesLogList.add(iter.nextLog());
}
}
-
+
+ List<LockOperationContainer> containers = new ArrayList<LockOperationContainer>();
+
for (PlainChangesLog currChangesLog : chengesLogList)
{
String nodeIdentifier;
@@ -394,30 +392,31 @@
if (currChangesLog.getSize() < 2)
{
log.error("Incorrect changes log of type ExtendedEvent.LOCK size=" + currChangesLog.getSize()
- + "<2 \n" + currChangesLog.dump());
+ + "<2 \n" + currChangesLog.dump());
break;
}
nodeIdentifier = currChangesLog.getAllStates().get(0).getData().getParentIdentifier();
if (pendingLocks.containsKey(nodeIdentifier))
{
- internalLock(nodeIdentifier);
+ containers.add(new LockOperationContainer(nodeIdentifier, currChangesLog.getSessionId(),
+ ExtendedEvent.LOCK));
}
else
{
- throw new LockException("Lock must exist in pending locks.");
+ log.error("Lock must exist in pending locks.");
}
break;
case ExtendedEvent.UNLOCK :
if (currChangesLog.getSize() < 2)
{
log.error("Incorrect changes log of type ExtendedEvent.UNLOCK size=" + currChangesLog.getSize()
- + "<2 \n" + currChangesLog.dump());
+ + "<2 \n" + currChangesLog.dump());
break;
}
- internalUnLock(currChangesLog.getSessionId(), currChangesLog.getAllStates().get(0).getData()
- .getParentIdentifier());
+ containers.add(new LockOperationContainer(currChangesLog.getAllStates().get(0).getData()
+ .getParentIdentifier(), currChangesLog.getSessionId(), ExtendedEvent.UNLOCK));
break;
default :
HashSet<String> removedLock = new HashSet<String>();
@@ -439,23 +438,90 @@
}
for (String identifier : removedLock)
{
- internalUnLock(currChangesLog.getSessionId(), identifier);
+ containers.add(new LockOperationContainer(identifier, currChangesLog.getSessionId(),
+ ExtendedEvent.UNLOCK));
}
break;
}
}
- catch (LockException e)
+ catch (IllegalStateException e)
{
log.error(e.getLocalizedMessage(), e);
}
- catch (IllegalStateException e)
+ }
+
+ // sort locking and unlocking operations to avoid deadlocks in JBossCache
+ Collections.sort(containers);
+ for (LockOperationContainer container : containers)
+ {
+ try
{
- log.error(e.getLocalizedMessage(), e);
+ container.apply();
}
+ catch (LockException e)
+ {
+ log.error(e.getMessage(), e);
+ }
}
}
/**
+ * Class containing operation type (LOCK or UNLOCK) and all the needed information like node uuid and session id
+ */
+ private class LockOperationContainer implements Comparable<LockOperationContainer>
+ {
+
+ private String identifier;
+
+ private String sessionId;
+
+ private int type;
+
+ /**
+ * @param identifier node identifier
+ * @param sessionId id of session
+ * @param type ExtendedEvent type specifying the operation (LOCK or UNLOCK)
+ */
+ public LockOperationContainer(String identifier, String sessionId, int type)
+ {
+ super();
+ this.identifier = identifier;
+ this.sessionId = sessionId;
+ this.type = type;
+ }
+
+ /**
+ * @return node identifier
+ */
+ public String getIdentifier()
+ {
+ return identifier;
+ }
+
+ public void apply() throws LockException
+ {
+ // invoke internalLock in LOCK operation
+ if (type == ExtendedEvent.LOCK)
+ {
+ internalLock(identifier);
+ }
+ // invoke internalUnLock in UNLOCK operation
+ else if (type == ExtendedEvent.UNLOCK)
+ {
+ internalUnLock(sessionId, identifier);
+ }
+ }
+
+ /**
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(LockOperationContainer o)
+ {
+ return identifier.compareTo(o.getIdentifier());
+ }
+ }
+
+ /**
* Refreshed lock data in cache
*
* @param newLockData
@@ -498,7 +564,7 @@
}
Collections.sort(removeLockList);
-
+
for (String rLock : removeLockList)
{
removeLock(rLock);
@@ -699,7 +765,7 @@
protected LockData getLockDataById(String nodeId)
{
- return (LockData) cache.get(makeLockFqn(nodeId), LOCK_DATA);
+ return (LockData)cache.get(makeLockFqn(nodeId), LOCK_DATA);
}
protected synchronized List<LockData> getLockList()
@@ -709,7 +775,7 @@
List<LockData> locksData = new ArrayList<LockData>();
for (Object nodeId : nodesId)
{
- LockData lockData = (LockData) cache.get(makeLockFqn((String) nodeId), LOCK_DATA);;
+ LockData lockData = (LockData)cache.get(makeLockFqn((String)nodeId), LOCK_DATA);;
if (lockData != null)
{
locksData.add(lockData);
@@ -728,14 +794,14 @@
try
{
NodeData nData = (NodeData)dataManager.getItemData(nodeIdentifier);
-
+
//TODO EXOJCR-412, should be refactored in future.
//Skip removing, because that node was removed in other node of cluster.
if (nData == null)
{
return;
}
-
+
PlainChangesLog changesLog =
new PlainChangesLogImpl(new ArrayList<ItemState>(), SystemIdentity.SYSTEM, ExtendedEvent.UNLOCK);
@@ -794,7 +860,7 @@
{
sessionLockManagers.remove(sessionID);
}
-
+
/**
* Make lock absolute Fqn, i.e. /$LOCKS/nodeID.
*
@@ -805,17 +871,18 @@
{
return Fqn.fromRelativeElements(lockRoot, nodeId);
}
-
+
/**
* Will be created structured node in cache, like /$LOCKS
*/
- private void createStructuredNode(Fqn fqn) {
- Node<Serializable, Object> node = cache.getRoot().getChild(fqn);
- if (node == null)
- {
- cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
- node = cache.getRoot().addChild(fqn);
- }
+ private void createStructuredNode(Fqn fqn)
+ {
+ Node<Serializable, Object> node = cache.getRoot().getChild(fqn);
+ if (node == null)
+ {
+ cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
+ node = cache.getRoot().addChild(fqn);
+ }
node.setResident(true);
}
}
More information about the exo-jcr-commits
mailing list