Neo4j deadlock for creating relationships between nodes locked in one transaction

My Neo4j server is throwing DeadlockDetectedExceptions when doing parallel requests and I can't figure out why.

The following code is called by a server plugin called by client REST requests and happens in a single transaction.

  Node nFollowing = loadUser(idFollowing);
  Node nFollowed = loadUser(idFollowed);

  // locking order to avoid deadlocks
  if (Long.valueOf(idFollowing) < Long.valueOf(idFollowed)) {
    tx.acquireWriteLock(nFollowing);
    tx.acquireWriteLock(nFollowed);
  } else {
    tx.acquireWriteLock(nFollowed);
    tx.acquireWriteLock(nFollowing);
  }

  // create relationship if not present
  for (Relationship followship : nFollowing.getRelationships(
    EdgeType.FOLLOWS, Direction.OUTGOING)) {
    if (followship.getEndNode().equals(nFollowed)) {
      return;
    }
  }
  nFollowing.createRelationshipTo(nFollowed, EdgeType.FOLLOWS);

      

While I was thinking about deadlocks, the following exception is thrown, indicating the deadlock that occurs when the relationship is created.

Exception (slightly reduced):

"ForsetiClient[78] can't acquire ExclusiveLock{owner=ForsetiClient[73]} on  
  RELATIONSHIP(49), because holders of that lock are waiting for ForsetiClient[78].\n
  Wait list:ExclusiveLock[ForsetiClient[73] waits for [73, 78, ]]",
"exception" : "DeadlockDetectedException",
"fullname" : "org.neo4j.kernel.DeadlockDetectedException",
"stacktrace" : [
  "org.neo4j.kernel.ha.lock.forseti.ForsetiClient.markAsWaitingFor(ForsetiClient.java:611)",
  "org.neo4j.kernel.ha.lock.forseti.ForsetiClient.acquireExclusive(ForsetiClient.java:190)",
  "org.neo4j.kernel.impl.nioneo.xa.TransactionalRelationshipLocker.getWriteLock(TransactionalRelationshipLocker.java:33)",
  "org.neo4j.kernel.impl.core.NodeProxy.createRelationshipTo(NodeProxy.java:455)",
  "de.uniko.sebschlicht.neo4j.graphity.WriteOptimizedGraphity.addFollowship(WriteOptimizedGraphity.java:40)",
  "de.uniko.sebschlicht.neo4j.graphity.Graphity.addFollowship(Graphity.java:115)",
  "de.uniko.sebschlicht.neo4j.GraphityBaselinePlugin.follow(GraphityBaselinePlugin.java:38)",
  "org.neo4j.server.rest.web.ExtensionService.invokeGraphDatabaseExtension(ExtensionService.java:134)",
  "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:139)"
]

      

I can't figure out why: I already have a lock for nFolloing

and nFollowed

. Indeed, deadlock is not meant to lock node, but relationship lock. Since relationships are only created when they are not already present, the lock holder must be current.

If that's right, the lock holder is waiting for himself. How can I avoid this or what else is the exception trying to say?

Just in case: I don't want to use the synchronized

blocks that are suggested and also marked how Neo4j should be avoided as it will slow down my work significantly and I don't expect these parallel queries to happen very often.

+3


source to share


1 answer


The deadlock was caused by a block snychronized

along with a manual transaction lock. I missed removing the statement synchronized

from the test I ran earlier. Although the statement synchronized

did not target the blocked node, an exception was raised. It seems that the two locking mechanisms are incompatible.



This resulted in a strange error message that didn't help me much.

+1


source







All Articles