Skip to content

Commit

Permalink
concurrency: add basic deadlock tests involving shared locks
Browse files Browse the repository at this point in the history
Informs cockroachdb#109634

Release note: None
  • Loading branch information
arulajmani committed Jan 30, 2024
1 parent 61efb1e commit 9985973
Showing 1 changed file with 387 additions and 0 deletions.
387 changes: 387 additions & 0 deletions pkg/kv/kvserver/concurrency/testdata/concurrency_manager/shared_locks
Original file line number Diff line number Diff line change
Expand Up @@ -951,3 +951,390 @@ finish req=req26
finish req=req27
----
[-] finish req27: finishing request

reset
----

# -----------------------------------------------------------------------------
# Ensure deadlocks involving shared locks are detected. Basic test with lock
# inversion, where shared locks are held and exclusive locking requests are
# waiting.
# -----------------------------------------------------------------------------

new-request name=req28 txn=txn1 ts=10,1
get key=a str=shared
----

sequence req=req28
----
[1] sequence req28: sequencing request
[1] sequence req28: acquiring latches
[1] sequence req28: scanning lock table for conflicting locks
[1] sequence req28: sequencing complete, returned guard

on-lock-acquired req=req28 key=a dur=u str=shared
----
[-] acquire lock: txn 00000001 @ ‹a›

finish req=req28
----
[-] finish req28: finishing request

new-request name=req29 txn=txn2 ts=10,1
get key=b str=shared
----

sequence req=req29
----
[2] sequence req29: sequencing request
[2] sequence req29: acquiring latches
[2] sequence req29: scanning lock table for conflicting locks
[2] sequence req29: sequencing complete, returned guard

on-lock-acquired req=req29 key=b dur=u str=shared
----
[-] acquire lock: txn 00000002 @ ‹b›

finish req=req29
----
[-] finish req29: finishing request

new-request name=req30 txn=txn1 ts=10,1
get key=b str=exclusive
----

sequence req=req30
----
[3] sequence req30: sequencing request
[3] sequence req30: acquiring latches
[3] sequence req30: scanning lock table for conflicting locks
[3] sequence req30: waiting in lock wait-queues
[3] sequence req30: lock wait-queue event: wait for (distinguished) txn 00000002 holding lock @ key ‹"b"› (queuedLockingRequests: 1, queuedReaders: 0)
[3] sequence req30: pushing after 0s for: liveness detection = true, deadlock detection = true, timeout enforcement = false, priority enforcement = false, wait policy error = false
[3] sequence req30: pushing txn 00000002 to abort
[3] sequence req30: blocked on select in concurrency_test.(*cluster).PushTransaction

new-request name=req31 txn=txn2 ts=10,1
get key=a str=exclusive
----

sequence req=req31
----
[3] sequence req30: dependency cycle detected 00000001->00000002->00000001
[4] sequence req31: sequencing request
[4] sequence req31: acquiring latches
[4] sequence req31: scanning lock table for conflicting locks
[4] sequence req31: waiting in lock wait-queues
[4] sequence req31: lock wait-queue event: wait for (distinguished) txn 00000001 holding lock @ key ‹"a"› (queuedLockingRequests: 1, queuedReaders: 0)
[4] sequence req31: pushing after 0s for: liveness detection = true, deadlock detection = true, timeout enforcement = false, priority enforcement = false, wait policy error = false
[4] sequence req31: pushing txn 00000001 to abort
[4] sequence req31: blocked on select in concurrency_test.(*cluster).PushTransaction
[4] sequence req31: dependency cycle detected 00000002->00000001->00000002

debug-lock-table
----
num=2
lock: "a"
holder: txn: 00000001-0000-0000-0000-000000000000 epoch: 0, iso: Serializable, info: unrepl [(str: Shared seq: 0)]
queued locking requests:
active: true req: 31, strength: Exclusive, txn: 00000002-0000-0000-0000-000000000000
distinguished req: 31
lock: "b"
holder: txn: 00000002-0000-0000-0000-000000000000 epoch: 0, iso: Serializable, info: unrepl [(str: Shared seq: 0)]
queued locking requests:
active: true req: 30, strength: Exclusive, txn: 00000001-0000-0000-0000-000000000000
distinguished req: 30

# Break the deadlock by aborting txn1.
on-txn-updated txn=txn1 status=aborted
----
[-] update txn: aborting txn1
[3] sequence req30: detected pusher aborted
[3] sequence req30: conflicted with ‹00000002-0000-0000-0000-000000000000› on ‹"b"› for 0.000s
[3] sequence req30: sequencing complete, returned error: TransactionAbortedError(ABORT_REASON_PUSHER_ABORTED)
[4] sequence req31: resolving intent ‹"a"› for txn 00000001 with ABORTED status
[4] sequence req31: lock wait-queue event: done waiting
[4] sequence req31: conflicted with ‹00000001-0000-0000-0000-000000000000› on ‹"a"› for 0.000s
[4] sequence req31: acquiring latches
[4] sequence req31: scanning lock table for conflicting locks
[4] sequence req31: sequencing complete, returned guard

finish req=req31
----
[-] finish req31: finishing request

reset namespace
----

# -----------------------------------------------------------------------------
# Another lock inversion test, but this time exclusive locks are held and shared
# locking requests are waiting.
# -----------------------------------------------------------------------------

new-txn name=txn1 ts=10,1 epoch=0
----

new-txn name=txn2 ts=10,1 epoch=0
----

new-request name=req1 txn=txn1 ts=10,1
get key=a str=exclusive
----

sequence req=req1
----
[1] sequence req1: sequencing request
[1] sequence req1: acquiring latches
[1] sequence req1: scanning lock table for conflicting locks
[1] sequence req1: sequencing complete, returned guard

on-lock-acquired req=req1 key=a dur=u str=exclusive
----
[-] acquire lock: txn 00000001 @ ‹a›

finish req=req1
----
[-] finish req1: finishing request

new-request name=req2 txn=txn2 ts=10,1
get key=b str=exclusive
----

sequence req=req2
----
[2] sequence req2: sequencing request
[2] sequence req2: acquiring latches
[2] sequence req2: scanning lock table for conflicting locks
[2] sequence req2: sequencing complete, returned guard

on-lock-acquired req=req2 key=b dur=u str=exclusive
----
[-] acquire lock: txn 00000002 @ ‹b›

finish req=req2
----
[-] finish req2: finishing request

new-request name=req3 txn=txn1 ts=10,1
get key=b str=shared
----

sequence req=req3
----
[3] sequence req3: sequencing request
[3] sequence req3: acquiring latches
[3] sequence req3: scanning lock table for conflicting locks
[3] sequence req3: waiting in lock wait-queues
[3] sequence req3: lock wait-queue event: wait for (distinguished) txn 00000002 holding lock @ key ‹"b"› (queuedLockingRequests: 1, queuedReaders: 0)
[3] sequence req3: pushing after 0s for: liveness detection = true, deadlock detection = true, timeout enforcement = false, priority enforcement = false, wait policy error = false
[3] sequence req3: pushing txn 00000002 to abort
[3] sequence req3: blocked on select in concurrency_test.(*cluster).PushTransaction

new-request name=req4 txn=txn2 ts=10,1
get key=a str=shared
----

sequence req=req4
----
[3] sequence req3: dependency cycle detected 00000001->00000002->00000001
[4] sequence req4: sequencing request
[4] sequence req4: acquiring latches
[4] sequence req4: scanning lock table for conflicting locks
[4] sequence req4: waiting in lock wait-queues
[4] sequence req4: lock wait-queue event: wait for (distinguished) txn 00000001 holding lock @ key ‹"a"› (queuedLockingRequests: 1, queuedReaders: 0)
[4] sequence req4: pushing after 0s for: liveness detection = true, deadlock detection = true, timeout enforcement = false, priority enforcement = false, wait policy error = false
[4] sequence req4: pushing txn 00000001 to abort
[4] sequence req4: blocked on select in concurrency_test.(*cluster).PushTransaction
[4] sequence req4: dependency cycle detected 00000002->00000001->00000002

debug-lock-table
----
num=2
lock: "a"
holder: txn: 00000001-0000-0000-0000-000000000000 epoch: 0, iso: Serializable, ts: 10.000000000,1, info: unrepl [(str: Exclusive seq: 0)]
queued locking requests:
active: true req: 35, strength: Shared, txn: 00000002-0000-0000-0000-000000000000
distinguished req: 35
lock: "b"
holder: txn: 00000002-0000-0000-0000-000000000000 epoch: 0, iso: Serializable, ts: 10.000000000,1, info: unrepl [(str: Exclusive seq: 0)]
queued locking requests:
active: true req: 34, strength: Shared, txn: 00000001-0000-0000-0000-000000000000
distinguished req: 34

# Break the deadlock by aborting txn1.
on-txn-updated txn=txn1 status=aborted
----
[-] update txn: aborting txn1
[3] sequence req3: detected pusher aborted
[3] sequence req3: conflicted with ‹00000002-0000-0000-0000-000000000000› on ‹"b"› for 0.000s
[3] sequence req3: sequencing complete, returned error: TransactionAbortedError(ABORT_REASON_PUSHER_ABORTED)
[4] sequence req4: resolving intent ‹"a"› for txn 00000001 with ABORTED status
[4] sequence req4: lock wait-queue event: done waiting
[4] sequence req4: conflicted with ‹00000001-0000-0000-0000-000000000000› on ‹"a"› for 0.000s
[4] sequence req4: acquiring latches
[4] sequence req4: scanning lock table for conflicting locks
[4] sequence req4: sequencing complete, returned guard

finish req=req4
----
[-] finish req4: finishing request

reset namespace
----

# -----------------------------------------------------------------------------
# Another deadlock test, but this time there are multiple shared locks held
# on a key.
#
# Setup: txn1, txn2 hold shared locks on a.
# txn3 holds exclusive lock on b.
# txn2 tries to acquire a shared lock on b.
#
# Test: txn3 tries to acquire an exclusive lock on a; nothing happens yet.
# txn1 proceeds to commit. txn2 now starts pushing txn2 and detects the
# deadlock.
# -----------------------------------------------------------------------------

new-txn name=txn1 ts=10,1 epoch=0
----

new-txn name=txn2 ts=10,1 epoch=0
----

new-txn name=txn3 ts=10,1 epoch=0
----


new-request name=req1 txn=txn1 ts=10,1
get key=a str=shared
----

sequence req=req1
----
[1] sequence req1: sequencing request
[1] sequence req1: acquiring latches
[1] sequence req1: scanning lock table for conflicting locks
[1] sequence req1: sequencing complete, returned guard

on-lock-acquired req=req1 key=a dur=u str=shared
----
[-] acquire lock: txn 00000001 @ ‹a›

finish req=req1
----
[-] finish req1: finishing request

new-request name=req2 txn=txn2 ts=10,1
get key=a str=shared
----

sequence req=req2
----
[2] sequence req2: sequencing request
[2] sequence req2: acquiring latches
[2] sequence req2: scanning lock table for conflicting locks
[2] sequence req2: sequencing complete, returned guard

on-lock-acquired req=req2 key=a dur=u str=shared
----
[-] acquire lock: txn 00000002 @ ‹a›

finish req=req2
----
[-] finish req2: finishing request

new-request name=req3 txn=txn3 ts=10,1
get key=b str=exclusive
----

sequence req=req3
----
[3] sequence req3: sequencing request
[3] sequence req3: acquiring latches
[3] sequence req3: scanning lock table for conflicting locks
[3] sequence req3: sequencing complete, returned guard

on-lock-acquired req=req3 key=b dur=u str=exclusive
----
[-] acquire lock: txn 00000003 @ ‹b›

finish req=req3
----
[-] finish req3: finishing request

new-request name=req4 txn=txn2 ts=10,1
get key=b str=shared
----

sequence req=req4
----
[4] sequence req4: sequencing request
[4] sequence req4: acquiring latches
[4] sequence req4: scanning lock table for conflicting locks
[4] sequence req4: waiting in lock wait-queues
[4] sequence req4: lock wait-queue event: wait for (distinguished) txn 00000003 holding lock @ key ‹"b"› (queuedLockingRequests: 1, queuedReaders: 0)
[4] sequence req4: pushing after 0s for: liveness detection = true, deadlock detection = true, timeout enforcement = false, priority enforcement = false, wait policy error = false
[4] sequence req4: pushing txn 00000003 to abort
[4] sequence req4: blocked on select in concurrency_test.(*cluster).PushTransaction

debug-lock-table
----
num=2
lock: "a"
holders: txn: 00000001-0000-0000-0000-000000000000 epoch: 0, iso: Serializable, info: unrepl [(str: Shared seq: 0)]
txn: 00000002-0000-0000-0000-000000000000 epoch: 0, iso: Serializable, info: unrepl [(str: Shared seq: 0)]
lock: "b"
holder: txn: 00000003-0000-0000-0000-000000000000 epoch: 0, iso: Serializable, ts: 10.000000000,1, info: unrepl [(str: Exclusive seq: 0)]
queued locking requests:
active: true req: 39, strength: Shared, txn: 00000002-0000-0000-0000-000000000000
distinguished req: 39

# Setup complete.

new-request name=req5 txn=txn3 ts=10,1
get key=a str=exclusive
----

sequence req=req5
----
[5] sequence req5: sequencing request
[5] sequence req5: acquiring latches
[5] sequence req5: scanning lock table for conflicting locks
[5] sequence req5: waiting in lock wait-queues
[5] sequence req5: lock wait-queue event: wait for (distinguished) txn 00000001 holding lock @ key ‹"a"› (queuedLockingRequests: 1, queuedReaders: 0)
[5] sequence req5: pushing after 0s for: liveness detection = true, deadlock detection = true, timeout enforcement = false, priority enforcement = false, wait policy error = false
[5] sequence req5: pushing txn 00000001 to abort
[5] sequence req5: blocked on select in concurrency_test.(*cluster).PushTransaction

on-txn-updated txn=txn1 status=committed
----
[-] update txn: committing txn1
[4] sequence req4: dependency cycle detected 00000002->00000003->00000002
[5] sequence req5: resolving intent ‹"a"› for txn 00000001 with COMMITTED status
[5] sequence req5: lock wait-queue event: wait for (distinguished) txn 00000002 holding lock @ key ‹"a"› (queuedLockingRequests: 1, queuedReaders: 0)
[5] sequence req5: conflicted with ‹00000001-0000-0000-0000-000000000000› on ‹"a"› for 0.000s
[5] sequence req5: pushing after 0s for: liveness detection = true, deadlock detection = true, timeout enforcement = false, priority enforcement = false, wait policy error = false
[5] sequence req5: pushing txn 00000002 to abort
[5] sequence req5: blocked on select in concurrency_test.(*cluster).PushTransaction
[5] sequence req5: dependency cycle detected 00000003->00000002->00000003

# Break the deadlock by aborting txn2.
on-txn-updated txn=txn2 status=aborted
----
[-] update txn: aborting txn2
[4] sequence req4: detected pusher aborted
[4] sequence req4: conflicted with ‹00000003-0000-0000-0000-000000000000› on ‹"b"› for 0.000s
[4] sequence req4: sequencing complete, returned error: TransactionAbortedError(ABORT_REASON_PUSHER_ABORTED)
[5] sequence req5: resolving intent ‹"a"› for txn 00000002 with ABORTED status
[5] sequence req5: lock wait-queue event: done waiting
[5] sequence req5: conflicted with ‹00000002-0000-0000-0000-000000000000› on ‹"a"› for 0.000s
[5] sequence req5: acquiring latches
[5] sequence req5: scanning lock table for conflicting locks
[5] sequence req5: sequencing complete, returned guard

finish req=req5
----
[-] finish req5: finishing request

reset namespace
----

0 comments on commit 9985973

Please sign in to comment.