redis_queued_locks 1.20.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/project-overview.md +249 -36
- data/.claude/rules/acquirer.md +16 -14
- data/.claude/rules/arguments.md +2 -2
- data/.claude/rules/changelog.md +27 -0
- data/.claude/rules/git.md +1 -1
- data/.claude/rules/logic.md +34 -13
- data/.claude/rules/swarm.md +4 -5
- data/.claude/rules/tests.md +9 -6
- data/.claude/rules/type-checking.md +13 -14
- data/.claude/rules/visitors.md +13 -14
- data/.claude/skills/rql-code-review/SKILL.md +134 -43
- data/CHANGELOG.md +105 -125
- data/CLAUDE.md +11 -9
- data/README.md +501 -136
- data/Rakefile +11 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +1 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +68 -10
- data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +82 -15
- data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +92 -14
- data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rb +441 -63
- data/lib/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rb +2 -2
- data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rb +1 -0
- data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire.rb +5 -5
- data/lib/redis_queued_locks/acquirer/acquire_lock.rb +176 -39
- data/lib/redis_queued_locks/acquirer/clear_dead_requests.rb +322 -49
- data/lib/redis_queued_locks/acquirer/extend_lock_ttl.rb +125 -13
- data/lib/redis_queued_locks/acquirer/is_locked.rb +0 -1
- data/lib/redis_queued_locks/acquirer/is_queued.rb +0 -1
- data/lib/redis_queued_locks/acquirer/keys.rb +16 -3
- data/lib/redis_queued_locks/acquirer/lock_info.rb +31 -39
- data/lib/redis_queued_locks/acquirer/lock_series_poc/instr_visitor.rb +11 -5
- data/lib/redis_queued_locks/acquirer/lock_series_poc/log_visitor.rb +20 -10
- data/lib/redis_queued_locks/acquirer/lock_series_poc.rb +105 -36
- data/lib/redis_queued_locks/acquirer/locks.rb +32 -11
- data/lib/redis_queued_locks/acquirer/queue_info.rb +30 -8
- data/lib/redis_queued_locks/acquirer/queues.rb +26 -6
- data/lib/redis_queued_locks/acquirer/reindex_locks.rb +117 -4
- data/lib/redis_queued_locks/acquirer/release_all_locks.rb +37 -6
- data/lib/redis_queued_locks/acquirer/release_lock.rb +33 -7
- data/lib/redis_queued_locks/acquirer/release_locks_of.rb +45 -6
- data/lib/redis_queued_locks/acquirer/release_read_lock.rb +22 -3
- data/lib/redis_queued_locks/client.rb +140 -56
- data/lib/redis_queued_locks/config.rb +105 -14
- data/lib/redis_queued_locks/errors.rb +34 -4
- data/lib/redis_queued_locks/instrument/sampler.rb +4 -7
- data/lib/redis_queued_locks/logging/sampler.rb +4 -8
- data/lib/redis_queued_locks/resource.rb +137 -12
- data/lib/redis_queued_locks/swarm/flush_zombies.rb +1 -0
- data/lib/redis_queued_locks/swarm/redis_client_builder.rb +8 -4
- data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +8 -6
- data/lib/redis_queued_locks/swarm/zombie_info.rb +6 -2
- data/lib/redis_queued_locks/swarm.rb +86 -5
- data/lib/redis_queued_locks/utilities.rb +1 -1
- data/lib/redis_queued_locks/version.rb +2 -2
- data/rbs_collection.lock.yaml +4 -0
- data/rbs_collection.yaml +2 -1
- data/sig/manifest.yml +1 -0
- data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +2 -2
- data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +2 -2
- data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +25 -5
- data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +32 -12
- data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +61 -40
- data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +59 -11
- data/sig/redis_queued_locks/acquirer/acquire_lock/{yield_with_expire → yield_expire}/log_visitor.rbs +4 -4
- data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +4 -4
- data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +6 -4
- data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +23 -1
- data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +16 -3
- data/sig/redis_queued_locks/acquirer/queues.rbs +1 -1
- data/sig/redis_queued_locks/acquirer/reindex_locks.rbs +22 -1
- data/sig/redis_queued_locks/acquirer/release_lock.rbs +3 -2
- data/sig/redis_queued_locks/acquirer/release_read_lock.rbs +1 -1
- data/sig/redis_queued_locks/client.rbs +24 -10
- data/sig/redis_queued_locks/config.rbs +54 -1
- data/sig/redis_queued_locks/errors.rbs +5 -2
- data/sig/redis_queued_locks/instrument/sampler.rbs +3 -3
- data/sig/redis_queued_locks/instrument/void_notifier.rbs +3 -1
- data/sig/redis_queued_locks/logging/sampler.rbs +3 -3
- data/sig/redis_queued_locks/resource.rbs +23 -13
- data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +1 -1
- data/sig/redis_queued_locks/utilities.rbs +2 -1
- data/sig/redis_queued_locks.rbs +7 -0
- data/sig/vendor/redis_client.rbs +1 -0
- metadata +4 -3
- /data/sig/redis_queued_locks/{acquier.rbs → acquirer.rbs} +0 -0
|
@@ -6,7 +6,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock::WithAcqTimeout
|
|
|
6
6
|
# @param redis [RedisClient]
|
|
7
7
|
# Redis connection manager required for additional data extraction for error message.
|
|
8
8
|
# @param timeout [NilClass,Integer]
|
|
9
|
-
# Time period after which the logic will fail with timeout error.
|
|
9
|
+
# Time period after which the logic will fail with timeout error (`nil` and `0`: no timeout).
|
|
10
10
|
# @param lock_key [String]
|
|
11
11
|
# Lock name in RQL notation (rql:lock:some-lock-name).
|
|
12
12
|
# @param lock_name [String]
|
|
@@ -26,7 +26,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock::WithAcqTimeout
|
|
|
26
26
|
#
|
|
27
27
|
# @api private
|
|
28
28
|
# @since 1.0.0
|
|
29
|
-
# @version 1.
|
|
29
|
+
# @version 1.21.0
|
|
30
30
|
def with_acq_timeout(
|
|
31
31
|
redis,
|
|
32
32
|
timeout,
|
|
@@ -30,7 +30,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock::YieldExpire
|
|
|
30
30
|
# @param access_strategy [Symbol] Lock obtaining strategy.
|
|
31
31
|
# @param timed [Boolean] Should the lock be wrapped by Timeout with with lock's ttl
|
|
32
32
|
# @param ttl_shift [Numeric] Lock's TTL shifting. Should affect block's ttl. In millisecodns.
|
|
33
|
-
# @param ttl [Integer
|
|
33
|
+
# @param ttl [Integer] Lock's time to live (in ms). A positive Integer.
|
|
34
34
|
# @param queue_ttl [Integer] Lock request lifetime.
|
|
35
35
|
# @param meta [NilClass,Hash<String|Symbol,Any>] Custom metadata wich is passed to the lock data;
|
|
36
36
|
# @param log_sampled [Boolean] Should the logic be logged or not.
|
|
@@ -45,7 +45,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock::YieldExpire
|
|
|
45
45
|
#
|
|
46
46
|
# @api private
|
|
47
47
|
# @since 1.3.0
|
|
48
|
-
# @version 1.
|
|
48
|
+
# @version 1.21.0
|
|
49
49
|
# rubocop:disable Metrics/MethodLength
|
|
50
50
|
def yield_expire(
|
|
51
51
|
redis,
|
|
@@ -71,7 +71,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock::YieldExpire
|
|
|
71
71
|
initial_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :millisecond)
|
|
72
72
|
|
|
73
73
|
if block_given?
|
|
74
|
-
if timed
|
|
74
|
+
if timed
|
|
75
75
|
# NOTE:
|
|
76
76
|
# - steep is ignored cuz steep can not recognize `::Integer - ::Integer|::Float`
|
|
77
77
|
# operation here for some mystical reason (it tryes to find overloadd `-` method for
|
|
@@ -150,7 +150,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock::YieldExpire
|
|
|
150
150
|
|
|
151
151
|
# @param timeout [Float]
|
|
152
152
|
# @param lock_key [String]
|
|
153
|
-
# @param lock_ttl [Integer
|
|
153
|
+
# @param lock_ttl [Integer]
|
|
154
154
|
# @param acquirer_id [String]
|
|
155
155
|
# @param host_id [String]
|
|
156
156
|
# @param meta [NilClass,Hash<Symbol|String,Any>]
|
|
@@ -161,7 +161,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock::YieldExpire
|
|
|
161
161
|
#
|
|
162
162
|
# @api private
|
|
163
163
|
# @since 1.3.0
|
|
164
|
-
# @version 1.
|
|
164
|
+
# @version 1.21.0
|
|
165
165
|
def yield_with_timeout(timeout, lock_key, lock_ttl, acquirer_id, host_id, meta, &block)
|
|
166
166
|
::Timeout.timeout(timeout, RedisQueuedLocks::TimedLockIntermediateTimeoutError, &block)
|
|
167
167
|
rescue RedisQueuedLocks::TimedLockIntermediateTimeoutError
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# @api private
|
|
4
4
|
# @since 1.0.0
|
|
5
|
-
# @version 1.
|
|
5
|
+
# @version 1.22.0
|
|
6
6
|
# rubocop:disable Metrics/ModuleLength
|
|
7
7
|
# rubocop:disable Metrics/MethodLength
|
|
8
8
|
# rubocop:disable Metrics/ClassLength
|
|
@@ -42,8 +42,8 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
42
42
|
# A current fiber that want to acquire a lock.
|
|
43
43
|
# @option ractor_id [Integer,String]
|
|
44
44
|
# The current ractor that want to acquire a lock.
|
|
45
|
-
# @option ttl [Integer
|
|
46
|
-
# Lock's time to live (in milliseconds).
|
|
45
|
+
# @option ttl [Integer]
|
|
46
|
+
# Lock's time to live (in milliseconds). A positive Integer (both modes).
|
|
47
47
|
# @option queue_ttl [Integer]
|
|
48
48
|
# Lifetime of the acuier's lock request. In seconds.
|
|
49
49
|
# @option lock_index_enabled [Boolean]
|
|
@@ -57,7 +57,8 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
57
57
|
# - pre-configured in `config['lock_index_grace_period']`;
|
|
58
58
|
# - used only with the enabled lock index (`lock_index_enabled`);
|
|
59
59
|
# @option timeout [Integer,NilClass]
|
|
60
|
-
# Time period whe should try to acquire the lock (in seconds).
|
|
60
|
+
# Time period whe should try to acquire the lock (in seconds). Nil means "without timeout"
|
|
61
|
+
# (`0` is the same as `nil`: `Timeout.timeout(0)` sets no timeout).
|
|
61
62
|
# @option timed [Boolean]
|
|
62
63
|
# Limit the invocation time period of the passed block of code by the lock's TTL.
|
|
63
64
|
# @option retry_count [Integer,NilClass]
|
|
@@ -125,13 +126,29 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
125
126
|
# (but with checking the limist, retries, timeouts and so on). if lock is
|
|
126
127
|
# free to obtain - it will be obtained;
|
|
127
128
|
# - pre-configured in `config['default_access_strategy']`;
|
|
129
|
+
# @option priority [Integer,Symbol]
|
|
130
|
+
# - The lock request priority: from `RedisQueuedLocks::Resource::MIN_LOCK_PRIORITY` (`-100`)
|
|
131
|
+
# to `RedisQueuedLocks::Resource::MAX_LOCK_PRIORITY` (`100`), `0` by default, or a priority
|
|
132
|
+
# name of `lock_priorities` (resolved to its Integer priority: the lock request queues,
|
|
133
|
+
# the logs and the instrumentation use the Integer priority);
|
|
134
|
+
# - `:queued` access strategy: the lock request is placed in the lock request queue after all
|
|
135
|
+
# requests of the same or higher priority and before all requests of the lower priority
|
|
136
|
+
# (strict priority, FIFO inside the same priority; between modes too: the read and write
|
|
137
|
+
# lock request queues use the same positions);
|
|
138
|
+
# - `:random` access strategy: the lock request does not wait for its turn (it ignores the
|
|
139
|
+
# order of the lock request queues and the priorities of other requests), but it is queued
|
|
140
|
+
# at the position of its priority like a `:queued` one: `:queued` lock requests wait for it;
|
|
141
|
+
# - the obtained lock is never taken away: the priority orders the waiting lock requests only;
|
|
142
|
+
# - pre-configured in `config['default_lock_priority']`;
|
|
143
|
+
# @option lock_priorities [Hash<Symbol,Integer>]
|
|
144
|
+
# - The priority names (`config['lock_priorities']`): a priority name => its Integer priority;
|
|
128
145
|
# @option log_sampling_enabled [Boolean]
|
|
129
146
|
# - enables <log sampling>: only the configured percent of RQL cases will be logged;
|
|
130
147
|
# - disabled by default;
|
|
131
148
|
# - works in tandem with <config['log_sampling_percent'] and <config['log_sampler']>;
|
|
132
149
|
# @option log_sampling_percent [Integer]
|
|
133
150
|
# - the percent of cases that should be logged;
|
|
134
|
-
# - take an effect when <config['
|
|
151
|
+
# - take an effect when <config['log_sampling_enabled']> is true;
|
|
135
152
|
# - works in tandem with <config['log_sampling_enabled']> and <config['log_sampler']> configs;
|
|
136
153
|
# @option log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
|
|
137
154
|
# - percent-based log sampler that decides should be RQL case logged or not;
|
|
@@ -152,7 +169,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
152
169
|
# - works in tandem with <config['instr_sampling_percent']> and <config['instr_sampler']>;
|
|
153
170
|
# @option instr_sampling_percent [Integer]
|
|
154
171
|
# - the percent of cases that should be instrumented;
|
|
155
|
-
# - take an effect when <config['
|
|
172
|
+
# - take an effect when <config['instr_sampling_enabled']> is true;
|
|
156
173
|
# - works in tandem with <config['instr_sampling_enabled']>
|
|
157
174
|
# and <config['instr_sampler']> configs;
|
|
158
175
|
# @option instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
|
|
@@ -176,7 +193,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
176
193
|
#
|
|
177
194
|
# @api private
|
|
178
195
|
# @since 1.0.0
|
|
179
|
-
# @version 1.
|
|
196
|
+
# @version 1.22.0
|
|
180
197
|
def acquire_lock(
|
|
181
198
|
redis,
|
|
182
199
|
lock_name,
|
|
@@ -205,6 +222,8 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
205
222
|
conflict_strategy:,
|
|
206
223
|
read_write_mode:,
|
|
207
224
|
access_strategy:,
|
|
225
|
+
priority:,
|
|
226
|
+
lock_priorities:,
|
|
208
227
|
log_sampling_enabled:,
|
|
209
228
|
log_sampling_percent:,
|
|
210
229
|
log_sampler:,
|
|
@@ -227,7 +246,9 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
227
246
|
end
|
|
228
247
|
|
|
229
248
|
# Step 0.1 (RW): prevent :read_write_mode incompatabilities
|
|
230
|
-
|
|
249
|
+
case read_write_mode # NOTE: (steep) case/when narrows `Symbol` to `RQL::readWriteMode` below
|
|
250
|
+
when :read, :write then nil
|
|
251
|
+
else
|
|
231
252
|
raise(
|
|
232
253
|
RedisQueuedLocks::ArgumentError,
|
|
233
254
|
"`:read_write_mode` argument should be `:read` or `:write`, " \
|
|
@@ -235,29 +256,100 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
235
256
|
)
|
|
236
257
|
end
|
|
237
258
|
|
|
238
|
-
# Step 0.1
|
|
239
|
-
# -
|
|
240
|
-
|
|
259
|
+
# Step 0.1: prevent :ttl incompatibilities (both modes)
|
|
260
|
+
# - write lock: `PEXPIRE` with a non-positive ttl deletes the just obtained lock key in the
|
|
261
|
+
# obtaining transaction (the lock is "obtained" without the mutual exclusion);
|
|
262
|
+
# - read lock: the read lock expiration time is calculated from the lock ttl;
|
|
263
|
+
if !ttl.is_a?(::Integer) || ttl <= 0
|
|
241
264
|
raise(
|
|
242
265
|
RedisQueuedLocks::ArgumentError,
|
|
243
|
-
"`:ttl` argument should be a positive Integer
|
|
266
|
+
"`:ttl` argument should be a positive Integer, got #{ttl.inspect}."
|
|
267
|
+
)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Step 0.1: prevent :queue_ttl, :timeout, :retry_* and :lock_index_grace_period
|
|
271
|
+
# incompatibilities (the same ranges as their config keys):
|
|
272
|
+
# - a non-positive queue ttl drops the own lock request in the queueing pipeline (the lock
|
|
273
|
+
# request is always dead);
|
|
274
|
+
# - a negative timeout/retry delay/retry jitter fails `Timeout.timeout`/`sleep` in the
|
|
275
|
+
# middle of the acquirement (`0` timeout is the same as `nil`: no timeout);
|
|
276
|
+
if !queue_ttl.is_a?(::Integer) || queue_ttl <= 0
|
|
277
|
+
raise(
|
|
278
|
+
RedisQueuedLocks::ArgumentError,
|
|
279
|
+
"`:queue_ttl` argument should be a positive Integer, got #{queue_ttl.inspect}."
|
|
280
|
+
)
|
|
281
|
+
end
|
|
282
|
+
if timeout != nil && (!timeout.is_a?(::Integer) || timeout < 0)
|
|
283
|
+
raise(
|
|
284
|
+
RedisQueuedLocks::ArgumentError,
|
|
285
|
+
"`:timeout` argument should be nil or a non-negative Integer, got #{timeout.inspect}."
|
|
286
|
+
)
|
|
287
|
+
end
|
|
288
|
+
if retry_count != nil && (!retry_count.is_a?(::Integer) || retry_count < 0)
|
|
289
|
+
raise(
|
|
290
|
+
RedisQueuedLocks::ArgumentError,
|
|
291
|
+
"`:retry_count` argument should be nil or a non-negative Integer, " \
|
|
292
|
+
"got #{retry_count.inspect}."
|
|
293
|
+
)
|
|
294
|
+
end
|
|
295
|
+
if !retry_delay.is_a?(::Integer) || retry_delay < 0
|
|
296
|
+
raise(
|
|
297
|
+
RedisQueuedLocks::ArgumentError,
|
|
298
|
+
"`:retry_delay` argument should be a non-negative Integer, got #{retry_delay.inspect}."
|
|
299
|
+
)
|
|
300
|
+
end
|
|
301
|
+
if !retry_jitter.is_a?(::Integer) || retry_jitter < 0
|
|
302
|
+
raise(
|
|
303
|
+
RedisQueuedLocks::ArgumentError,
|
|
304
|
+
"`:retry_jitter` argument should be a non-negative Integer, got #{retry_jitter.inspect}."
|
|
305
|
+
)
|
|
306
|
+
end
|
|
307
|
+
if !lock_index_grace_period.is_a?(::Integer) || lock_index_grace_period < 0
|
|
308
|
+
raise(
|
|
309
|
+
RedisQueuedLocks::ArgumentError,
|
|
310
|
+
"`:lock_index_grace_period` argument should be a non-negative Integer, " \
|
|
311
|
+
"got #{lock_index_grace_period.inspect}."
|
|
312
|
+
)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# Step 0.1: prevent :priority incompatibilities (the same range as its config key)
|
|
316
|
+
# - a Symbol is a priority name of `config['lock_priorities']`: it is resolved to its
|
|
317
|
+
# Integer priority (the lock request queues, the logs and the instrumentation use the
|
|
318
|
+
# Integer priority; an unknown name stays a Symbol and fails the check);
|
|
319
|
+
# - each priority has its own band of positions in the lock request queues: the range
|
|
320
|
+
# bounds the shift of the positions (float scores lose precision with the shift: the FIFO
|
|
321
|
+
# order inside a priority keeps ~61 µs for -100..100, see `LOCK_PRIORITY_BAND`);
|
|
322
|
+
priority = lock_priorities.fetch(priority, priority) if priority.is_a?(::Symbol)
|
|
323
|
+
if !priority.is_a?(::Integer) ||
|
|
324
|
+
priority < RedisQueuedLocks::Resource::MIN_LOCK_PRIORITY ||
|
|
325
|
+
priority > RedisQueuedLocks::Resource::MAX_LOCK_PRIORITY
|
|
326
|
+
raise(
|
|
327
|
+
RedisQueuedLocks::ArgumentError,
|
|
328
|
+
"`:priority` argument should be an Integer from " \
|
|
329
|
+
"#{RedisQueuedLocks::Resource::MIN_LOCK_PRIORITY} to " \
|
|
330
|
+
"#{RedisQueuedLocks::Resource::MAX_LOCK_PRIORITY} or a priority name of " \
|
|
331
|
+
"`config['lock_priorities']` (#{lock_priorities.keys.map(&:inspect).join(', ')}), " \
|
|
332
|
+
"got #{priority.inspect}."
|
|
244
333
|
)
|
|
245
334
|
end
|
|
246
335
|
|
|
247
336
|
# Step 0.2: prevent :meta incompatabiltiies (structure)
|
|
337
|
+
# - Symbol keys are written to the lock data as Strings (`Symbol#name`, as redis-client
|
|
338
|
+
# does it) and would overwrite the reserved lock data fields too;
|
|
248
339
|
if meta.is_a?(::Hash) && (meta.any? do |key, _value|
|
|
249
|
-
key
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
340
|
+
meta_key = key.is_a?(::Symbol) ? key.name : key
|
|
341
|
+
meta_key == 'acq_id' ||
|
|
342
|
+
meta_key == 'hst_id' ||
|
|
343
|
+
meta_key == 'ts' ||
|
|
344
|
+
meta_key == 'ini_ttl' ||
|
|
345
|
+
meta_key == 'lock_key' ||
|
|
346
|
+
meta_key == 'rem_ttl' ||
|
|
347
|
+
meta_key == 'spc_ext_ttl' ||
|
|
348
|
+
meta_key == 'spc_cnt' ||
|
|
349
|
+
meta_key == 'l_spc_ext_ini_ttl' ||
|
|
350
|
+
meta_key == 'l_spc_ext_ts' ||
|
|
351
|
+
meta_key == 'l_spc_ts' ||
|
|
352
|
+
meta_key == 'rw_mode'
|
|
261
353
|
end)
|
|
262
354
|
raise(
|
|
263
355
|
RedisQueuedLocks::ArgumentError,
|
|
@@ -295,7 +387,9 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
295
387
|
RedisQueuedLocks::Resource.prepare_read_lock_key(lock_name, acquirer_id)
|
|
296
388
|
end
|
|
297
389
|
|
|
298
|
-
|
|
390
|
+
# NOTE: the position in the lock request queue: the enqueue time shifted by the priority band
|
|
391
|
+
# (see `RedisQueuedLocks::Resource::LOCK_PRIORITY_BAND`);
|
|
392
|
+
acquirer_position = RedisQueuedLocks::Resource.calc_initial_acquirer_position(priority)
|
|
299
393
|
|
|
300
394
|
log_sampled = RedisQueuedLocks::Logging.should_log?(
|
|
301
395
|
log_sampling_enabled,
|
|
@@ -342,10 +436,13 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
342
436
|
|
|
343
437
|
LogVisitor.start_lock_obtaining(
|
|
344
438
|
logger, log_sampled, lock_key,
|
|
345
|
-
queue_ttl, acquirer_id, host_id, access_strategy, read_write_mode
|
|
439
|
+
queue_ttl, acquirer_id, host_id, access_strategy, read_write_mode, priority
|
|
346
440
|
)
|
|
347
441
|
|
|
348
442
|
# Step 2: try to lock with timeout
|
|
443
|
+
# NOTE: the acquirement start time is defined out of the timeout block: the failed
|
|
444
|
+
# acquirement reports the acquirement time too (Steps 3.b and 3.c);
|
|
445
|
+
acq_start_time = clock_gettime
|
|
349
446
|
with_acq_timeout(
|
|
350
447
|
redis,
|
|
351
448
|
timeout,
|
|
@@ -355,24 +452,23 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
355
452
|
detailed_acq_timeout_error,
|
|
356
453
|
on_timeout: acq_dequeue
|
|
357
454
|
) do
|
|
358
|
-
acq_start_time = clock_gettime
|
|
359
|
-
|
|
360
455
|
# Step 2.1: cyclically try to obtain the lock
|
|
361
456
|
while acq_process[:should_try]
|
|
362
457
|
|
|
363
458
|
LogVisitor.start_try_to_lock_cycle(
|
|
364
459
|
logger, log_sampled, lock_key,
|
|
365
|
-
queue_ttl, acquirer_id, host_id, access_strategy, read_write_mode
|
|
460
|
+
queue_ttl, acquirer_id, host_id, access_strategy, read_write_mode, priority
|
|
366
461
|
)
|
|
367
462
|
|
|
368
463
|
# Step 2.X: check the actual score: is it in queue ttl limit or not?
|
|
369
|
-
if RedisQueuedLocks::Resource.dead_score_reached?(acquirer_position, queue_ttl)
|
|
370
|
-
# Step 2.X.X: dead score reached => re-queue the lock request with the new score
|
|
371
|
-
|
|
464
|
+
if RedisQueuedLocks::Resource.dead_score_reached?(acquirer_position, priority, queue_ttl)
|
|
465
|
+
# Step 2.X.X: dead score reached => re-queue the lock request with the new score
|
|
466
|
+
# (the end of the requests of the same priority);
|
|
467
|
+
acquirer_position = RedisQueuedLocks::Resource.calc_initial_acquirer_position(priority)
|
|
372
468
|
|
|
373
469
|
LogVisitor.dead_score_reached__reset_acquirer_position(
|
|
374
470
|
logger, log_sampled, lock_key,
|
|
375
|
-
queue_ttl, acquirer_id, host_id, access_strategy, read_write_mode
|
|
471
|
+
queue_ttl, acquirer_id, host_id, access_strategy, read_write_mode, priority
|
|
376
472
|
)
|
|
377
473
|
end
|
|
378
474
|
|
|
@@ -392,6 +488,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
392
488
|
acquirer_id,
|
|
393
489
|
host_id,
|
|
394
490
|
acquirer_position,
|
|
491
|
+
priority,
|
|
395
492
|
lock_ttl,
|
|
396
493
|
queue_ttl,
|
|
397
494
|
lock_index_enabled,
|
|
@@ -425,10 +522,11 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
425
522
|
# instrumetnation: (reentrant lock with ttl extension)
|
|
426
523
|
LogVisitor.extendable_reentrant_lock_obtained(
|
|
427
524
|
logger, log_sampled, result[:lock_key],
|
|
428
|
-
queue_ttl, acquirer_id, host_id, acq_time, access_strategy, read_write_mode
|
|
525
|
+
queue_ttl, acquirer_id, host_id, acq_time, access_strategy, read_write_mode,
|
|
526
|
+
priority
|
|
429
527
|
)
|
|
430
528
|
InstrVisitor.extendable_reentrant_lock_obtained(
|
|
431
|
-
instrumenter, instr_sampled, result[:lock_key], read_write_mode,
|
|
529
|
+
instrumenter, instr_sampled, result[:lock_key], read_write_mode, priority,
|
|
432
530
|
result[:ttl], result[:acq_id], result[:hst_id], result[:ts], acq_time,
|
|
433
531
|
instrument
|
|
434
532
|
)
|
|
@@ -436,10 +534,11 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
436
534
|
# instrumetnation: (reentrant lock without ttl extension)
|
|
437
535
|
LogVisitor.reentrant_lock_obtained(
|
|
438
536
|
logger, log_sampled, result[:lock_key],
|
|
439
|
-
queue_ttl, acquirer_id, host_id, acq_time, access_strategy, read_write_mode
|
|
537
|
+
queue_ttl, acquirer_id, host_id, acq_time, access_strategy, read_write_mode,
|
|
538
|
+
priority
|
|
440
539
|
)
|
|
441
540
|
InstrVisitor.reentrant_lock_obtained(
|
|
442
|
-
instrumenter, instr_sampled, result[:lock_key], read_write_mode,
|
|
541
|
+
instrumenter, instr_sampled, result[:lock_key], read_write_mode, priority,
|
|
443
542
|
result[:ttl], result[:acq_id], result[:hst_id], result[:ts], acq_time,
|
|
444
543
|
instrument
|
|
445
544
|
)
|
|
@@ -448,10 +547,11 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
448
547
|
# NOTE: classic is: acq_process[:result][:process] == :lock_obtaining
|
|
449
548
|
LogVisitor.lock_obtained(
|
|
450
549
|
logger, log_sampled, result[:lock_key],
|
|
451
|
-
queue_ttl, acquirer_id, host_id, acq_time, access_strategy, read_write_mode
|
|
550
|
+
queue_ttl, acquirer_id, host_id, acq_time, access_strategy, read_write_mode,
|
|
551
|
+
priority
|
|
452
552
|
)
|
|
453
553
|
InstrVisitor.lock_obtained(
|
|
454
|
-
instrumenter, instr_sampled, result[:lock_key], read_write_mode,
|
|
554
|
+
instrumenter, instr_sampled, result[:lock_key], read_write_mode, priority,
|
|
455
555
|
result[:ttl], result[:acq_id], result[:hst_id], result[:ts], acq_time,
|
|
456
556
|
instrument
|
|
457
557
|
)
|
|
@@ -609,6 +709,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
609
709
|
instr_sampled,
|
|
610
710
|
acq_process[:lock_info][:lock_key],
|
|
611
711
|
read_write_mode,
|
|
712
|
+
priority,
|
|
612
713
|
acq_process[:lock_info][:ttl],
|
|
613
714
|
acq_process[:lock_info][:acq_id],
|
|
614
715
|
acq_process[:lock_info][:hst_id],
|
|
@@ -624,6 +725,7 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
624
725
|
instr_sampled,
|
|
625
726
|
acq_process[:lock_info][:lock_key],
|
|
626
727
|
read_write_mode,
|
|
728
|
+
priority,
|
|
627
729
|
acq_process[:lock_info][:ttl],
|
|
628
730
|
acq_process[:lock_info][:acq_id],
|
|
629
731
|
acq_process[:lock_info][:hst_id],
|
|
@@ -650,8 +752,43 @@ module RedisQueuedLocks::Acquirer::AcquireLock
|
|
|
650
752
|
acq_process[:result] = :timeout_reached
|
|
651
753
|
end
|
|
652
754
|
# Step 3.b: lock is not acquired (acquirer is dequeued by timeout callback)
|
|
755
|
+
acq_time = ((clock_gettime - acq_start_time) / 1_000.0).ceil(2)
|
|
756
|
+
LogVisitor.lock_obtaining_failed(
|
|
757
|
+
logger, log_sampled, lock_key, queue_ttl, acquirer_id, host_id,
|
|
758
|
+
acq_time, access_strategy, read_write_mode, priority, acq_process[:result]
|
|
759
|
+
)
|
|
760
|
+
InstrVisitor.lock_obtaining_failed(
|
|
761
|
+
instrumenter, instr_sampled, lock_key, read_write_mode, priority, lock_ttl, acquirer_id,
|
|
762
|
+
host_id, Time.now.to_f, acq_time, acq_process[:result], instrument
|
|
763
|
+
)
|
|
653
764
|
{ ok: false, result: acq_process[:result] } #: { ok: bool, result: Symbol }
|
|
654
765
|
end
|
|
766
|
+
rescue RedisQueuedLocks::LockAlreadyObtainedError,
|
|
767
|
+
RedisQueuedLocks::ConflictLockObtainError,
|
|
768
|
+
RedisQueuedLocks::LockAcquirementRetryLimitError,
|
|
769
|
+
RedisQueuedLocks::LockAcquirementTimeoutError => error
|
|
770
|
+
# Step 3.c: (raise_errors) the failed acquirement is reported before the error is raised
|
|
771
|
+
# (like Step 3.b); errors of the block of code under the obtained lock are not reported;
|
|
772
|
+
# NOTE: (steep) the locals of the method body are nilable in the method-level `rescue` for
|
|
773
|
+
# Steep, but these errors are raised by the acquirement only (after Step 1: the locals
|
|
774
|
+
# are assigned);
|
|
775
|
+
# steep:ignore:start
|
|
776
|
+
unless acq_process[:acquired]
|
|
777
|
+
if error.is_a?(RedisQueuedLocks::LockAcquirementTimeoutError)
|
|
778
|
+
acq_process[:result] = :timeout_reached
|
|
779
|
+
end
|
|
780
|
+
acq_time = ((clock_gettime - acq_start_time) / 1_000.0).ceil(2)
|
|
781
|
+
LogVisitor.lock_obtaining_failed(
|
|
782
|
+
logger, log_sampled, lock_key, queue_ttl, acquirer_id, host_id,
|
|
783
|
+
acq_time, access_strategy, read_write_mode, priority, acq_process[:result]
|
|
784
|
+
)
|
|
785
|
+
InstrVisitor.lock_obtaining_failed(
|
|
786
|
+
instrumenter, instr_sampled, lock_key, read_write_mode, priority, lock_ttl, acquirer_id,
|
|
787
|
+
host_id, Time.now.to_f, acq_time, acq_process[:result], instrument
|
|
788
|
+
)
|
|
789
|
+
end
|
|
790
|
+
# steep:ignore:end
|
|
791
|
+
raise
|
|
655
792
|
end
|
|
656
793
|
end
|
|
657
794
|
end
|