Рассмотрите график социальной сети с пользователями и новостями. Существует несколько методов, которые изменяют график, и их можно вызывать одновременно.
Я реализовал менеджер блокировки, чтобы избежать любых мертвых замков. Он блокирует пользователей, заказанных с самого низкого идентификатора пользователя, который хранится как свойство в пользовательских узлах. Замки выпускаются в обратном порядке.Блокировка освобождает причины мертвой блокировки в Neo4j
Тем не менее я получаю следующее DeadLockDetectedException
при выполнении определенного метода одновременно:
[email protected]:
locking manager locked [NODE(0) [#1], NODE(5) [#3]]
[email protected]:
locking manager released [NODE(5) [#3], NODE(0) [#1]]
[email protected]:
locking manager locked [NODE(1) [#2]
Exception in thread "Thread-3" [email protected]:
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)]
[email protected]:
locking manager locked [NODE(1) [#2], NODE(5) [#3]]
Как вы можете видеть, транзакция блокирует два узла пользователя (ID 1 и 3). Чуть позже он пытается заблокировать другой пользовательский узел (id 2), но эта блокировка не может быть получена: есть вторая транзакция, которая заблокировала пользователя с идентификатором 2 и ждет, чтобы заблокировать пользователя с идентификатором 3.
Правдоподобно, это был бы мертвый замок.
Однако код и предыдущее сообщение в журнале сообщают другую историю: Прежде чем транзакция попытается заблокировать пользователя с идентификатором 2, он освободил два блокировки, которые он приобрел ранее. Вот соответствующий код:
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();
Менеджер блокировки замков узлов через tx.acquireWriteLock(node)
и высвобождает замков через lock.release()
.
Есть ли что-нибудь, о чем я не знаю? Например, существует ли задержка между вызовом lock.release
и новой блокировкой соответствующего узла?
http://neo4j.com/docs/stable/javadocs/org/neo4j/graphdb/Lock.html: "' release() 'Освобождает эту блокировку до завершения транзакции. Это необязательная операция, и если ее не вызывать , этот замок будет освобожден, когда сделка с владельцем закончится ». Я понимаю что-то другое, и если вы правы, каким будет использование этого метода? –