21
21
from redis import Redis
22
22
23
23
24
+ # RwLock implementation
25
+ # =====================
26
+ #
27
+ # The lock owns three keys:
28
+ # - `<prefix>:write`: If this exists, holds the token of the user that
29
+ # owns the exclusive write lock.
30
+ # - `<prefix>:write_semaphore`: Semaphore tracking writers that are
31
+ # waiting to acquire the lock. If any writers are waiting, readers
32
+ # block.
33
+ # - `<prefix>:read`: Another semaphore, tracks readers.
34
+ #
35
+ # Semaphores are implemented as ordered sets, where score is the
36
+ # expiration time of the semaphore lease (Redis instance time). Expired
37
+ # leases are pruned before attempting to acquire the lock.
38
+ #
39
+ # We can't use built-in key expiration because individual set members
40
+ # cannot have an expiration. We can't create keys dynamically because
41
+ # this may break multi-node compatibility.
42
+ #
43
+ # The write-acquire script is careful to ensure that the writer waiting
44
+ # semaphore is only held if the caller is actually blocking; otherwise
45
+ # the caller adds contention for no reason.
46
+
47
+
24
48
class RwLock :
25
49
"""A shared reader-writer lock.
26
50
@@ -30,14 +54,17 @@ class RwLock:
30
54
priority when waiting on the lock so that readers do not starve
31
55
waiting writers. Writers are allowed to starve readers, however.
32
56
33
- This type of lock is effective for scenarios where reads are
57
+ This type of unfair lock is effective for scenarios where reads are
34
58
frequent and writes are infrequent. Because this lock relies on busy
35
59
waiting, it can be wasteful to use if your critical sections are
36
60
long and frequent.
37
61
38
62
This lock is not fault-tolerant in a multi-node Redis setup. When a
39
63
master fails and data is lost, writer exclusivity may be violated.
40
64
In a single-node setup, the lock is sound.
65
+
66
+ This lock is not re-entrant; attempting to acquire it twice in the
67
+ same thread may cause a deadlock until the blocking timeout ends.
41
68
"""
42
69
43
70
lua_acquire_reader = None
@@ -78,7 +105,7 @@ class RwLock:
78
105
# KEYS[3] - reader lock name
79
106
# ARGV[1] - token
80
107
# ARGV[2] - expiration
81
- # ARGV[3] - sempahore expiration
108
+ # ARGV[3] - sempahore expiration (or 0 to release the sempahore)
82
109
# ARGV[4] - max writers
83
110
#
84
111
# NOTE: return codes:
0 commit comments