Reputation: 357
Consider a social network graph with users and news items.
There are multiple methods that modify the graph and they can be called concurrently.
I implemented a locking manager to avoid any dead locks. It locks users ordered from lowest to highest user id, that is stored as a property in user nodes.
Locks are released in reverse order.
Nevertheless I get the following DeadLockDetectedException
when executing a specific method concurrently:
org.neo4j.kernel.TopLevelTransaction@41aaf8e9:
locking manager locked [NODE(0) [#1], NODE(5) [#3]]
org.neo4j.kernel.TopLevelTransaction@41aaf8e9:
locking manager released [NODE(5) [#3], NODE(0) [#1]]
org.neo4j.kernel.TopLevelTransaction@41aaf8e9:
locking manager locked [NODE(1) [#2]
Exception in thread "Thread-3" org.neo4j.kernel.TopLevelTransaction@6242de17:
org...DeadlockDetectedException:
LockClient[18] can't wait on resource RWLock[NODE(1)] since =>
LockClient[18] <-[:HELD_BY]- RWLock[NODE(5)] <-[:WAITING_FOR]- LockClient[20] <-[:HELD_BY]- RWLock[NODE(1)]
org.neo4j.kernel.TopLevelTransaction@7007944f:
locking manager locked [NODE(1) [#2], NODE(5) [#3]]
As you can see, a transaction locks two user nodes (id 1 and 3).
A bit later it tries to lock another user node (id 2), but this lock can't be acquired: There is a second transaction that has locked the user with id 2 and is waiting to lock the user with id 3.
Plausible, this would be a dead lock.
However, the code and the previous log message tells another story: Before the transaction tries to lock the user with id 2, it released the two locks it has acquired previously. Here is the corresponding code:
Transaction tx = graph.beginTransaction();
// locks NODE(0) and NODE(5)
Lock[] locks = LockManager.lock(tx, following, followed);
boolean result = removeFollowship(following, followed);
// releases NODE(5) and NODE(0)
LockManager.releaseLocks(locks);
...
// tries to lock NODE(1)
List<Lock> locks = LockManager.lock(tx, replicaLayer);
try {
return addStatusUpdate(author, statusUpdate);
} finally {
LockManager.releaseLocks(locks);
}
...
tx.success();
The lock manager locks nodes via tx.acquireWriteLock(node)
and releases locks via lock.release()
.
Is there anything I'm not aware of? For example, is there a delay between the call of lock.release
and new locking of the corresponding node?
Upvotes: 0
Views: 426
Reputation: 41676
Locks are really just released when the transaction finishes.
That's why until your tx.close()
is called it still holds the locks.
Upvotes: 1