redis_queued_locks 1.7.0 → 1.9.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +60 -1
  4. data/README.md +485 -46
  5. data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +4 -0
  6. data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue.rb +4 -1
  7. data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +20 -5
  8. data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +24 -0
  9. data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +56 -0
  10. data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock.rb +37 -30
  11. data/lib/redis_queued_locks/acquier/acquire_lock/with_acq_timeout.rb +41 -7
  12. data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +8 -0
  13. data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire.rb +21 -9
  14. data/lib/redis_queued_locks/acquier/acquire_lock.rb +61 -22
  15. data/lib/redis_queued_locks/acquier/clear_dead_requests.rb +5 -1
  16. data/lib/redis_queued_locks/acquier/extend_lock_ttl.rb +5 -1
  17. data/lib/redis_queued_locks/acquier/lock_info.rb +4 -3
  18. data/lib/redis_queued_locks/acquier/locks.rb +2 -2
  19. data/lib/redis_queued_locks/acquier/queue_info.rb +2 -2
  20. data/lib/redis_queued_locks/acquier/release_all_locks.rb +12 -2
  21. data/lib/redis_queued_locks/acquier/release_lock.rb +12 -2
  22. data/lib/redis_queued_locks/client.rb +320 -10
  23. data/lib/redis_queued_locks/errors.rb +8 -0
  24. data/lib/redis_queued_locks/instrument.rb +8 -1
  25. data/lib/redis_queued_locks/logging.rb +8 -1
  26. data/lib/redis_queued_locks/resource.rb +59 -1
  27. data/lib/redis_queued_locks/swarm/acquirers.rb +44 -0
  28. data/lib/redis_queued_locks/swarm/flush_zombies.rb +133 -0
  29. data/lib/redis_queued_locks/swarm/probe_hosts.rb +69 -0
  30. data/lib/redis_queued_locks/swarm/redis_client_builder.rb +67 -0
  31. data/lib/redis_queued_locks/swarm/supervisor.rb +83 -0
  32. data/lib/redis_queued_locks/swarm/swarm_element/isolated.rb +287 -0
  33. data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +351 -0
  34. data/lib/redis_queued_locks/swarm/swarm_element.rb +8 -0
  35. data/lib/redis_queued_locks/swarm/zombie_info.rb +145 -0
  36. data/lib/redis_queued_locks/swarm.rb +241 -0
  37. data/lib/redis_queued_locks/utilities/lock.rb +22 -0
  38. data/lib/redis_queued_locks/utilities.rb +75 -0
  39. data/lib/redis_queued_locks/version.rb +2 -2
  40. data/lib/redis_queued_locks.rb +2 -0
  41. data/redis_queued_locks.gemspec +6 -10
  42. metadata +24 -6
  43. data/lib/redis_queued_locks/watcher.rb +0 -1
@@ -3,29 +3,63 @@
3
3
  # @api private
4
4
  # @since 1.0.0
5
5
  module RedisQueuedLocks::Acquier::AcquireLock::WithAcqTimeout
6
+ # @param redis [RedisClient]
7
+ # Redis connection manager required for additional data extraction for error message.
6
8
  # @param timeout [NilClass,Integer]
7
9
  # Time period after which the logic will fail with timeout error.
8
10
  # @param lock_key [String]
9
- # Lock name.
11
+ # Lock name in RQL notation (rql:lock:some-lock-name).
12
+ # @param lock_name [String]
13
+ # Original lock name passed by the businessl logic (without RQL notaiton parts).
10
14
  # @param raise_errors [Boolean]
11
15
  # Raise erros on exceptional cases.
16
+ # @param detailed_acq_timeout_error [Boolean]
17
+ # Add additional error data about lock queue and required lock to the timeout error or not.
12
18
  # @option on_timeout [Proc,NilClass]
13
19
  # Callback invoked on Timeout::Error.
14
20
  # @return [Any]
15
21
  #
16
22
  # @api private
17
23
  # @since 1.0.0
18
- def with_acq_timeout(timeout, lock_key, raise_errors, on_timeout: nil, &block)
24
+ # @version 1.8.0
25
+ def with_acq_timeout(
26
+ redis,
27
+ timeout,
28
+ lock_key,
29
+ lock_name,
30
+ raise_errors,
31
+ detailed_acq_timeout_error,
32
+ on_timeout: nil,
33
+ &block
34
+ )
19
35
  ::Timeout.timeout(timeout, &block)
20
36
  rescue ::Timeout::Error
21
37
  on_timeout.call unless on_timeout == nil
22
38
 
23
39
  if raise_errors
24
- raise(
25
- RedisQueuedLocks::LockAcquiermentTimeoutError,
26
- "Failed to acquire the lock \"#{lock_key}\" " \
27
- "for the given timeout (#{timeout} seconds)."
28
- )
40
+ if detailed_acq_timeout_error
41
+ # TODO: rewrite these invocations to separated inner-AcquireLock-related modules
42
+ # in order to remove any dependencies from the other public RQL commands cuz
43
+ # all AcquireLock logic elements should be fully independent from others as a core;
44
+ lock_info = RedisQueuedLocks::Acquier::LockInfo.lock_info(redis, lock_name)
45
+ queue_info = RedisQueuedLocks::Acquier::QueueInfo.queue_info(redis, lock_name)
46
+
47
+ # rubocop:disable Metrics/BlockNesting
48
+ raise(
49
+ RedisQueuedLocks::LockAcquiermentTimeoutError,
50
+ "Failed to acquire the lock \"#{lock_key}\" " \
51
+ "for the given <#{timeout} seconds> timeout. Details: " \
52
+ "<Lock Data> => #{lock_info ? lock_info.inspect : '<no_data>'}; " \
53
+ "<Queue Data> => #{queue_info ? queue_info.inspect : '<no_data>'};"
54
+ )
55
+ # rubocop:enable Metrics/BlockNesting
56
+ else
57
+ raise(
58
+ RedisQueuedLocks::LockAcquiermentTimeoutError,
59
+ "Failed to acquire the lock \"#{lock_key}\" " \
60
+ "for the given <#{timeout} seconds> timeout."
61
+ )
62
+ end
29
63
  end
30
64
  end
31
65
  end
@@ -10,17 +10,20 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire::LogVisitor
10
10
  # @param lock_key [String]
11
11
  # @param queue_ttl [Integer]
12
12
  # @param acquier_id [String]
13
+ # @param host_id [String]
13
14
  # @param access_strategy [Symbol]
14
15
  # @return [void]
15
16
  #
16
17
  # @api private
17
18
  # @since 1.7.0
19
+ # @version 1.9.0
18
20
  def expire_lock(
19
21
  logger,
20
22
  log_sampled,
21
23
  lock_key,
22
24
  queue_ttl,
23
25
  acquier_id,
26
+ host_id,
24
27
  access_strategy
25
28
  )
26
29
  return unless log_sampled
@@ -30,6 +33,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire::LogVisitor
30
33
  "lock_key => '#{lock_key}' " \
31
34
  "queue_ttl => #{queue_ttl} " \
32
35
  "acq_id => '#{acquier_id}' " \
36
+ "hst_id => '#{host_id}' " \
33
37
  "acs_strat => '#{access_strategy}'"
34
38
  end rescue nil
35
39
  end
@@ -40,11 +44,13 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire::LogVisitor
40
44
  # @param decreased_ttl [Integer]
41
45
  # @param queue_ttl [Integer]
42
46
  # @param acquier_id [String]
47
+ # @param host_id [String]
43
48
  # @param access_strategy [Symbol]
44
49
  # @return [void]
45
50
  #
46
51
  # @api private
47
52
  # @since 1.7.0
53
+ # @version 1.9.0
48
54
  def decrease_lock(
49
55
  logger,
50
56
  log_sampled,
@@ -52,6 +58,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire::LogVisitor
52
58
  decreased_ttl,
53
59
  queue_ttl,
54
60
  acquier_id,
61
+ host_id,
55
62
  access_strategy
56
63
  )
57
64
  return unless log_sampled
@@ -62,6 +69,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire::LogVisitor
62
69
  "decreased_ttl => #{decreased_ttl} " \
63
70
  "queue_ttl => #{queue_ttl} " \
64
71
  "acq_id => '#{acquier_id}' " \
72
+ "hst_id => '#{host_id}' " \
65
73
  "acs_strat => '#{access_strategy}'"
66
74
  end rescue nil
67
75
  end
@@ -19,12 +19,14 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
19
19
  # @param logger [::Logger,#debug] Logger object.
20
20
  # @param lock_key [String] Obtained lock key that should be expired.
21
21
  # @param acquier_id [String] Acquier identifier.
22
+ # @param host_id [String] Host identifier.
22
23
  # @param access_strategy [Symbol] Lock obtaining strategy.
23
24
  # @param timed [Boolean] Should the lock be wrapped by Timeout with with lock's ttl
24
25
  # @param ttl_shift [Float] Lock's TTL shifting. Should affect block's ttl. In millisecodns.
25
26
  # @param ttl [Integer,NilClass] Lock's time to live (in ms). Nil means "without timeout".
26
27
  # @param queue_ttl [Integer] Lock request lifetime.
27
28
  # @param block [Block] Custom logic that should be invoked unter the obtained lock.
29
+ # @param meta [NilClass,Hash<String|Symbol,Any>] Custom metadata wich is passed to the lock data;
28
30
  # @param log_sampled [Boolean] Should the logic be logged or not.
29
31
  # @param instr_sampled [Boolean] Should the logic be instrumented or not.
30
32
  # @param should_expire [Boolean] Should the lock be expired after the block invocation.
@@ -35,18 +37,20 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
35
37
  #
36
38
  # @api private
37
39
  # @since 1.3.0
38
- # @version 1.7.0
40
+ # @version 1.9.0
39
41
  # rubocop:disable Metrics/MethodLength
40
42
  def yield_expire(
41
43
  redis,
42
44
  logger,
43
45
  lock_key,
44
46
  acquier_id,
47
+ host_id,
45
48
  access_strategy,
46
49
  timed,
47
50
  ttl_shift,
48
51
  ttl,
49
52
  queue_ttl,
53
+ meta,
50
54
  log_sampled,
51
55
  instr_sampled,
52
56
  should_expire,
@@ -62,7 +66,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
62
66
  end
63
67
 
64
68
  if timed && ttl != nil
65
- yield_with_timeout(timeout, lock_key, ttl, &block)
69
+ yield_with_timeout(timeout, lock_key, ttl, acquier_id, host_id, meta, &block)
66
70
  else
67
71
  yield
68
72
  end
@@ -70,8 +74,8 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
70
74
  ensure
71
75
  if should_expire
72
76
  LogVisitor.expire_lock(
73
- logger, log_sampled,
74
- lock_key, queue_ttl, acquier_id, access_strategy
77
+ logger, log_sampled, lock_key,
78
+ queue_ttl, acquier_id, host_id, access_strategy
75
79
  )
76
80
  redis.call('EXPIRE', lock_key, '0')
77
81
  elsif should_decrease
@@ -81,8 +85,8 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
81
85
 
82
86
  if decreased_ttl > 0
83
87
  LogVisitor.decrease_lock(
84
- logger, log_sampled,
85
- lock_key, decreased_ttl, queue_ttl, acquier_id, access_strategy
88
+ logger, log_sampled, lock_key,
89
+ decreased_ttl, queue_ttl, acquier_id, host_id, access_strategy
86
90
  )
87
91
  # NOTE:# NOTE: EVAL signature -> <lua script>, (number of keys), *(keys), *(arguments)
88
92
  redis.call('EVAL', DECREASE_LOCK_PTTL, 1, lock_key, decreased_ttl)
@@ -97,18 +101,26 @@ module RedisQueuedLocks::Acquier::AcquireLock::YieldExpire
97
101
  # @param timeout [Float]
98
102
  # @parma lock_key [String]
99
103
  # @param lock_ttl [Integer,NilClass]
104
+ # @param acquier_id [String]
105
+ # @param host_id [String]
106
+ # @param meta [NilClass,Hash<Symbol|String,Any>]
100
107
  # @param block [Blcok]
101
108
  # @return [Any]
102
109
  #
103
110
  # @api private
104
111
  # @since 1.3.0
105
- def yield_with_timeout(timeout, lock_key, lock_ttl, &block)
112
+ # @version 1.9.0
113
+ def yield_with_timeout(timeout, lock_key, lock_ttl, acquier_id, host_id, meta, &block)
106
114
  ::Timeout.timeout(timeout, &block)
107
115
  rescue ::Timeout::Error
108
116
  raise(
109
117
  RedisQueuedLocks::TimedLockTimeoutError,
110
- "Passed <timed> block of code exceeded " \
111
- "the lock TTL (lock: \"#{lock_key}\", ttl: #{lock_ttl})"
118
+ "Passed <timed> block of code exceeded the lock TTL " \
119
+ "(lock: \"#{lock_key}\", " \
120
+ "ttl: #{lock_ttl}, " \
121
+ "meta: #{meta ? meta.inspect : '<no-meta>'}, " \
122
+ "acq_id: \"#{acquier_id}\", " \
123
+ "hst_id: \"#{host_id}\")"
112
124
  )
113
125
  end
114
126
  end
@@ -69,6 +69,10 @@ module RedisQueuedLocks::Acquier::AcquireLock
69
69
  # @option meta [NilClass,Hash<String|Symbol,Any>]
70
70
  # - A custom metadata wich will be passed to the lock data in addition to the existing data;
71
71
  # - Metadata can not contain reserved lock data keys;
72
+ # @option detailed_acq_timeout_error [Boolean]
73
+ # - Add additional data to the acquirement timeout error such as the current lock queue state
74
+ # and the required lock state;
75
+ # - See `config[:detailed_acq_timeout_error]` for details;
72
76
  # @option logger [::Logger,#debug]
73
77
  # - Logger object used from the configuration layer (see config[:logger]);
74
78
  # - See `RedisQueuedLocks::Logging::VoidLogger` for example;
@@ -117,6 +121,9 @@ module RedisQueuedLocks::Acquier::AcquireLock
117
121
  # - you can provide your own log sampler with bettter algorithm that should realize
118
122
  # `sampling_happened?(percent) => boolean` interface
119
123
  # (see `RedisQueuedLocks::Logging::Sampler` for example);
124
+ # @option log_sample_this [Boolean]
125
+ # - marks the method that everything should be logged despite the enabled log sampling;
126
+ # - makes sense when log sampling is enabled;
120
127
  # @option instr_sampling_enabled [Boolean]
121
128
  # - enables <instrumentaion sampling>: only the configured percent
122
129
  # of RQL cases will be instrumented;
@@ -135,6 +142,10 @@ module RedisQueuedLocks::Acquier::AcquireLock
135
142
  # - you can provide your own log sampler with bettter algorithm that should realize
136
143
  # `sampling_happened?(percent) => boolean` interface
137
144
  # (see `RedisQueuedLocks::Instrument::Sampler` for example);
145
+ # @option instr_sample_this [Boolean]
146
+ # - marks the method that everything should be instrumneted
147
+ # despite the enabled instrumentation sampling;
148
+ # - makes sense when instrumentation sampling is enabled;
138
149
  # @param [Block]
139
150
  # A block of code that should be executed after the successfully acquired lock.
140
151
  # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>,yield]
@@ -143,7 +154,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
143
154
  #
144
155
  # @api private
145
156
  # @since 1.0.0
146
- # @version 1.7.0
157
+ # @version 1.9.0
147
158
  def acquire_lock(
148
159
  redis,
149
160
  lock_name,
@@ -163,6 +174,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
163
174
  identity:,
164
175
  fail_fast:,
165
176
  meta:,
177
+ detailed_acq_timeout_error:,
166
178
  instrument:,
167
179
  logger:,
168
180
  log_lock_try:,
@@ -171,9 +183,11 @@ module RedisQueuedLocks::Acquier::AcquireLock
171
183
  log_sampling_enabled:,
172
184
  log_sampling_percent:,
173
185
  log_sampler:,
186
+ log_sample_this:,
174
187
  instr_sampling_enabled:,
175
188
  instr_sampling_percent:,
176
189
  instr_sampler:,
190
+ instr_sample_this:,
177
191
  &block
178
192
  )
179
193
  # Step 0: Prevent argument type incompatabilities
@@ -190,6 +204,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
190
204
  # Step 0.2: prevent :meta incompatabiltiies (structure)
191
205
  if meta.is_a?(::Hash) && (meta.any? do |key, _value|
192
206
  key == 'acq_id' ||
207
+ key == 'hst_id' ||
193
208
  key == 'ts' ||
194
209
  key == 'ini_ttl' ||
195
210
  key == 'lock_key' ||
@@ -203,7 +218,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
203
218
  raise(
204
219
  RedisQueuedLocks::ArgumentError,
205
220
  '`:meta` keys can not overlap reserved lock data keys ' \
206
- '"acq_id", "ts", "ini_ttl", "lock_key", "rem_ttl", "spc_cnt", ' \
221
+ '"acq_id", "hst_id", "ts", "ini_ttl", "lock_key", "rem_ttl", "spc_cnt", ' \
207
222
  '"spc_ext_ttl", "l_spc_ext_ini_ttl", "l_spc_ext_ts", "l_spc_ts"'
208
223
  )
209
224
  end
@@ -216,6 +231,12 @@ module RedisQueuedLocks::Acquier::AcquireLock
216
231
  ractor_id,
217
232
  identity
218
233
  )
234
+ host_id = RedisQueuedLocks::Resource.host_identifier(
235
+ process_id,
236
+ thread_id,
237
+ ractor_id,
238
+ identity
239
+ )
219
240
  lock_ttl = ttl
220
241
  lock_key = RedisQueuedLocks::Resource.prepare_lock_key(lock_name)
221
242
  lock_key_queue = RedisQueuedLocks::Resource.prepare_lock_queue(lock_name)
@@ -223,11 +244,13 @@ module RedisQueuedLocks::Acquier::AcquireLock
223
244
 
224
245
  log_sampled = RedisQueuedLocks::Logging.should_log?(
225
246
  log_sampling_enabled,
247
+ log_sample_this,
226
248
  log_sampling_percent,
227
249
  log_sampler
228
250
  )
229
251
  instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
230
252
  instr_sampling_enabled,
253
+ instr_sample_this,
231
254
  instr_sampling_percent,
232
255
  instr_sampler
233
256
  )
@@ -246,11 +269,13 @@ module RedisQueuedLocks::Acquier::AcquireLock
246
269
 
247
270
  acq_dequeue = proc do
248
271
  dequeue_from_lock_queue(
249
- redis, logger,
272
+ redis,
273
+ logger,
250
274
  lock_key,
251
275
  lock_key_queue,
252
276
  queue_ttl,
253
277
  acquier_id,
278
+ host_id,
254
279
  access_strategy,
255
280
  log_sampled,
256
281
  instr_sampled
@@ -258,20 +283,28 @@ module RedisQueuedLocks::Acquier::AcquireLock
258
283
  end
259
284
 
260
285
  LogVisitor.start_lock_obtaining(
261
- logger, log_sampled,
262
- lock_key, queue_ttl, acquier_id, access_strategy
286
+ logger, log_sampled, lock_key,
287
+ queue_ttl, acquier_id, host_id, access_strategy
263
288
  )
264
289
 
265
290
  # Step 2: try to lock with timeout
266
- with_acq_timeout(timeout, lock_key, raise_errors, on_timeout: acq_dequeue) do
291
+ with_acq_timeout(
292
+ redis,
293
+ timeout,
294
+ lock_key,
295
+ lock_name,
296
+ raise_errors,
297
+ detailed_acq_timeout_error,
298
+ on_timeout: acq_dequeue
299
+ ) do
267
300
  acq_start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
268
301
 
269
302
  # Step 2.1: cyclically try to obtain the lock
270
303
  while acq_process[:should_try]
271
304
 
272
305
  LogVisitor.start_try_to_lock_cycle(
273
- logger, log_sampled,
274
- lock_key, queue_ttl, acquier_id, access_strategy
306
+ logger, log_sampled, lock_key,
307
+ queue_ttl, acquier_id, host_id, access_strategy
275
308
  )
276
309
 
277
310
  # Step 2.X: check the actual score: is it in queue ttl limit or not?
@@ -280,8 +313,8 @@ module RedisQueuedLocks::Acquier::AcquireLock
280
313
  acquier_position = RedisQueuedLocks::Resource.calc_initial_acquier_position
281
314
 
282
315
  LogVisitor.dead_score_reached__reset_acquier_position(
283
- logger, log_sampled,
284
- lock_key, queue_ttl, acquier_id, access_strategy
316
+ logger, log_sampled, lock_key,
317
+ queue_ttl, acquier_id, host_id, access_strategy
285
318
  )
286
319
  end
287
320
 
@@ -292,6 +325,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
292
325
  lock_key,
293
326
  lock_key_queue,
294
327
  acquier_id,
328
+ host_id,
295
329
  acquier_position,
296
330
  lock_ttl,
297
331
  queue_ttl,
@@ -316,35 +350,35 @@ module RedisQueuedLocks::Acquier::AcquireLock
316
350
  if acq_process[:result][:process] == :extendable_conflict_work_through
317
351
  # instrumetnation: (reentrant lock with ttl extension)
318
352
  LogVisitor.extendable_reentrant_lock_obtained(
319
- logger, log_sampled,
320
- result[:lock_key], queue_ttl, acquier_id, acq_time, access_strategy
353
+ logger, log_sampled, result[:lock_key],
354
+ queue_ttl, acquier_id, host_id, acq_time, access_strategy
321
355
  )
322
356
  InstrVisitor.extendable_reentrant_lock_obtained(
323
- instrumenter, instr_sampled,
324
- result[:lock_key], result[:ttl], result[:acq_id], result[:ts], acq_time,
357
+ instrumenter, instr_sampled, result[:lock_key],
358
+ result[:ttl], result[:acq_id], result[:hst_id], result[:ts], acq_time,
325
359
  instrument
326
360
  )
327
361
  elsif acq_process[:result][:process] == :conflict_work_through
328
362
  # instrumetnation: (reentrant lock without ttl extension)
329
363
  LogVisitor.reentrant_lock_obtained(
330
- logger, log_sampled,
331
- result[:lock_key], queue_ttl, acquier_id, acq_time, access_strategy
364
+ logger, log_sampled, result[:lock_key],
365
+ queue_ttl, acquier_id, host_id, acq_time, access_strategy
332
366
  )
333
367
  InstrVisitor.reentrant_lock_obtained(
334
- instrumenter, instr_sampled,
335
- result[:lock_key], result[:ttl], result[:acq_id], result[:ts], acq_time,
368
+ instrumenter, instr_sampled, result[:lock_key],
369
+ result[:ttl], result[:acq_id], result[:hst_id], result[:ts], acq_time,
336
370
  instrument
337
371
  )
338
372
  else
339
373
  # instrumentation: (classic lock obtain)
340
374
  # NOTE: classic is: acq_process[:result][:process] == :lock_obtaining
341
375
  LogVisitor.lock_obtained(
342
- logger, log_sampled,
343
- result[:lock_key], queue_ttl, acquier_id, acq_time, access_strategy
376
+ logger, log_sampled, result[:lock_key],
377
+ queue_ttl, acquier_id, host_id, acq_time, access_strategy
344
378
  )
345
379
  InstrVisitor.lock_obtained(
346
- instrumenter, instr_sampled,
347
- result[:lock_key], result[:ttl], result[:acq_id], result[:ts], acq_time,
380
+ instrumenter, instr_sampled, result[:lock_key],
381
+ result[:ttl], result[:acq_id], result[:hst_id], result[:ts], acq_time,
348
382
  instrument
349
383
  )
350
384
  end
@@ -353,6 +387,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
353
387
  acq_process[:lock_info] = {
354
388
  lock_key: result[:lock_key],
355
389
  acq_id: result[:acq_id],
390
+ hst_id: result[:hst_id],
356
391
  ts: result[:ts],
357
392
  ttl: result[:ttl],
358
393
  process: result[:process]
@@ -450,11 +485,13 @@ module RedisQueuedLocks::Acquier::AcquireLock
450
485
  logger,
451
486
  lock_key,
452
487
  acquier_id,
488
+ host_id,
453
489
  access_strategy,
454
490
  timed,
455
491
  ttl_shift,
456
492
  ttl,
457
493
  queue_ttl,
494
+ meta,
458
495
  log_sampled,
459
496
  instr_sampled,
460
497
  should_expire, # NOTE: should expire the lock after the block execution
@@ -478,6 +515,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
478
515
  acq_process[:lock_info][:lock_key],
479
516
  acq_process[:lock_info][:ttl],
480
517
  acq_process[:lock_info][:acq_id],
518
+ acq_process[:lock_info][:hst_id],
481
519
  acq_process[:lock_info][:ts],
482
520
  acq_process[:acq_time],
483
521
  acq_process[:hold_time],
@@ -491,6 +529,7 @@ module RedisQueuedLocks::Acquier::AcquireLock
491
529
  acq_process[:lock_info][:lock_key],
492
530
  acq_process[:lock_info][:ttl],
493
531
  acq_process[:lock_info][:acq_id],
532
+ acq_process[:lock_info][:hst_id],
494
533
  acq_process[:lock_info][:ts],
495
534
  acq_process[:lock_info][:lock_key],
496
535
  acq_process[:acq_time],
@@ -13,9 +13,11 @@ module RedisQueuedLocks::Acquier::ClearDeadRequests
13
13
  # @param log_sampling_enabled [Boolean]
14
14
  # @param log_sampling_percent [Integer]
15
15
  # @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
16
+ # @param log_sample_this [Boolean]
16
17
  # @param instr_sampling_enabled [Boolean]
17
18
  # @param instr_sampling_percent [Integer]
18
19
  # @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
20
+ # @param instr_sample_this [Boolean]
19
21
  # @return [Hash<Symbol,Boolean|Hash<Symbol,Set<String>>>]
20
22
  #
21
23
  # @api private
@@ -31,9 +33,11 @@ module RedisQueuedLocks::Acquier::ClearDeadRequests
31
33
  log_sampling_enabled,
32
34
  log_sampling_percent,
33
35
  log_sampler,
36
+ log_sample_this,
34
37
  instr_sampling_enabled,
35
38
  instr_sampling_percent,
36
- instr_sampler
39
+ instr_sampler,
40
+ instr_sample_this
37
41
  )
38
42
  dead_score = RedisQueuedLocks::Resource.acquier_dead_score(dead_ttl / 1_000.0)
39
43
 
@@ -22,9 +22,11 @@ module RedisQueuedLocks::Acquier::ExtendLockTTL
22
22
  # @param log_sampling_enabled [Boolean]
23
23
  # @param log_sampling_percent [Integer]
24
24
  # @param log_sampler [#sampling_happened?,Module<RedisQueuedLocks::Logging::Sampler>]
25
+ # @param log_sample_this [Boolean]
25
26
  # @param instr_sampling_enabled [Boolean]
26
27
  # @param instr_sampling_percent [Integer]
27
28
  # @param instr_sampler [#sampling_happened?,Module<RedisQueuedLocks::Instrument::Sampler>]
29
+ # @param instr_sample_this [Boolean]
28
30
  # @return [Hash<Symbol,Boolean|Symbol>]
29
31
  #
30
32
  # @api private
@@ -40,9 +42,11 @@ module RedisQueuedLocks::Acquier::ExtendLockTTL
40
42
  log_sampling_enabled,
41
43
  log_sampling_percent,
42
44
  log_sampler,
45
+ log_sample_this,
43
46
  instr_sampling_enabled,
44
47
  instr_sampling_percent,
45
- instr_sampler
48
+ instr_sampler,
49
+ instr_sample_this
46
50
  )
47
51
  lock_key = RedisQueuedLocks::Resource.prepare_lock_key(lock_name)
48
52
 
@@ -10,7 +10,8 @@ module RedisQueuedLocks::Acquier::LockInfo
10
10
  # - `nil` is returned when lock key does not exist or expired;
11
11
  # - result format: {
12
12
  # 'lock_key' => "rql:lock:your_lockname", # acquired lock key
13
- # 'acq_id' => "rql:acq:process_id/thread_id", # lock acquier identifier
13
+ # 'acq_id' => "rql:acq:123/456/789/987/uniqstring", # lock acquier identifier
14
+ # 'hst_id' => "rql:hst:123/456/987/uniqstring", # lock host identifier
14
15
  # 'ts' => 123456789.2649841, # <locked at> time stamp (epoch, seconds.microseconds)
15
16
  # 'ini_ttl' => 123456789, # initial lock key ttl (milliseconds)
16
17
  # 'rem_ttl' => 123456789, # remaining lock key ttl (milliseconds)
@@ -24,7 +25,7 @@ module RedisQueuedLocks::Acquier::LockInfo
24
25
  #
25
26
  # @api private
26
27
  # @since 1.0.0
27
- # @version 1.3.0
28
+ # @version 1.9.0
28
29
  # rubocop:disable Metrics/MethodLength
29
30
  def lock_info(redis_client, lock_name)
30
31
  lock_key = RedisQueuedLocks::Resource.prepare_lock_key(lock_name)
@@ -55,7 +56,7 @@ module RedisQueuedLocks::Acquier::LockInfo
55
56
  lock_data['lock_key'] = lock_key
56
57
  lock_data['ts'] = Float(lock_data['ts'])
57
58
  lock_data['ini_ttl'] = Integer(lock_data['ini_ttl'])
58
- lock_data['rem_ttl'] = ((pttl_cmd_res == -1) ? Infinity : pttl_cmd_res)
59
+ lock_data['rem_ttl'] = ((pttl_cmd_res == -1) ? Float::INFINITY : pttl_cmd_res)
59
60
  lock_data['spc_cnt'] = Integer(lock_data['spc_cnt']) if lock_data['spc_cnt']
60
61
  lock_data['l_spc_ts'] = Float(lock_data['l_spc_ts']) if lock_data['l_spc_ts']
61
62
  lock_data['spc_ext_ttl'] = Integer(lock_data['spc_ext_ttl']) if lock_data['spc_ext_ttl']
@@ -45,7 +45,7 @@ module RedisQueuedLocks::Acquier::Locks
45
45
  #
46
46
  # @api private
47
47
  # @since 1.0.0
48
- # @version 1.3.0
48
+ # @version 1.9.0
49
49
  # rubocop:disable Metrics/MethodLength
50
50
  def extract_locks_info(redis_client, lock_keys)
51
51
  # TODO: refactor with RedisQueuedLocks::Acquier::LockInfo
@@ -72,7 +72,7 @@ module RedisQueuedLocks::Acquier::Locks
72
72
  hget_cmd_res.tap do |lock_data|
73
73
  lock_data['ts'] = Float(lock_data['ts'])
74
74
  lock_data['ini_ttl'] = Integer(lock_data['ini_ttl'])
75
- lock_data['rem_ttl'] = ((pttl_cmd_res == -1) ? Infinity : pttl_cmd_res)
75
+ lock_data['rem_ttl'] = ((pttl_cmd_res == -1) ? Float::INFINITY : pttl_cmd_res)
76
76
  lock_data['spc_cnt'] = Integer(lock_data['spc_cnt']) if lock_data['spc_cnt']
77
77
  lock_data['l_spc_ts'] = Float(lock_data['l_spc_ts']) if lock_data['l_spc_ts']
78
78
  lock_data['spc_ext_ttl'] =
@@ -17,8 +17,8 @@ module RedisQueuedLocks::Acquier::QueueInfo
17
17
  # - result format: {
18
18
  # "lock_queue" => "rql:lock_queue:your_lock_name", # lock queue key in redis,
19
19
  # queue: [
20
- # { "acq_id" => "rql:acq:process_id/thread_id", "score" => 123 },
21
- # { "acq_id" => "rql:acq:process_id/thread_id", "score" => 456 },
20
+ # { "acq_id" => "rql:acq:123/456/789/987/identity", "score" => 123 },
21
+ # { "acq_id" => "rql:acq:123/686/789/987/identity", "score" => 456 },
22
22
  # ] # ordered set (by score) with information about an acquier and their position in queue
23
23
  # }
24
24
  #
@@ -40,6 +40,9 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
40
40
  # - you can provide your own log sampler with bettter algorithm that should realize
41
41
  # `sampling_happened?(percent) => boolean` interface
42
42
  # (see `RedisQueuedLocks::Logging::Sampler` for example);
43
+ # @param log_sample_this [Boolean]
44
+ # - marks the method that everything should be logged despite the enabled log sampling;
45
+ # - makes sense when log sampling is enabled;
43
46
  # @param instr_sampling_enabled [Boolean]
44
47
  # - enables <instrumentaion sampling>: only the configured percent
45
48
  # of RQL cases will be instrumented;
@@ -58,6 +61,10 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
58
61
  # - you can provide your own log sampler with bettter algorithm that should realize
59
62
  # `sampling_happened?(percent) => boolean` interface
60
63
  # (see `RedisQueuedLocks::Instrument::Sampler` for example);
64
+ # @param instr_sample_this [Boolean]
65
+ # - marks the method that everything should be instrumneted
66
+ # despite the enabled instrumentation sampling;
67
+ # - makes sense when instrumentation sampling is enabled;
61
68
  # @return [RedisQueuedLocks::Data,Hash<Symbol,Any>]
62
69
  # Format: { ok: true, result: Hash<Symbol,Numeric> }
63
70
  #
@@ -73,18 +80,21 @@ module RedisQueuedLocks::Acquier::ReleaseAllLocks
73
80
  log_sampling_enabled,
74
81
  log_sampling_percent,
75
82
  log_sampler,
83
+ log_sample_this,
76
84
  instr_sampling_enabled,
77
85
  instr_sampling_percent,
78
- instr_sampler
86
+ instr_sampler,
87
+ instr_sample_this
79
88
  )
80
89
  rel_start_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
81
90
  fully_release_all_locks(redis, batch_size) => { ok:, result: }
82
91
  time_at = Time.now.to_f
83
92
  rel_end_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
84
- rel_time = ((rel_end_time - rel_start_time) / 1_000).ceil(2)
93
+ rel_time = ((rel_end_time - rel_start_time) / 1_000.0).ceil(2)
85
94
 
86
95
  instr_sampled = RedisQueuedLocks::Instrument.should_instrument?(
87
96
  instr_sampling_enabled,
97
+ instr_sample_this,
88
98
  instr_sampling_percent,
89
99
  instr_sampler
90
100
  )