redis_queued_locks 1.12.1 → 1.13.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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +32 -5
  5. data/LICENSE.txt +1 -1
  6. data/README.md +222 -203
  7. data/Rakefile +12 -4
  8. data/Steepfile +16 -0
  9. data/github_ci/ruby3.3.gemfile +17 -0
  10. data/github_ci/ruby3.3.gemfile.lock +217 -0
  11. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/delay_execution.rb +4 -4
  12. data/lib/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +40 -0
  13. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/dequeue_from_lock_queue.rb +17 -8
  14. data/lib/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rb +166 -0
  15. data/lib/redis_queued_locks/acquirer/acquire_lock/log_visitor.rb +218 -0
  16. data/lib/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rb +543 -0
  17. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/try_to_lock.rb +126 -92
  18. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/with_acq_timeout.rb +14 -9
  19. data/lib/redis_queued_locks/acquirer/acquire_lock/yield_expire/log_visitor.rb +76 -0
  20. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock/yield_expire.rb +42 -19
  21. data/lib/redis_queued_locks/{acquier → acquirer}/acquire_lock.rb +68 -41
  22. data/lib/redis_queued_locks/{acquier → acquirer}/clear_dead_requests.rb +5 -3
  23. data/lib/redis_queued_locks/{acquier → acquirer}/extend_lock_ttl.rb +4 -3
  24. data/lib/redis_queued_locks/{acquier → acquirer}/is_locked.rb +1 -1
  25. data/lib/redis_queued_locks/{acquier → acquirer}/is_queued.rb +1 -1
  26. data/lib/redis_queued_locks/{acquier → acquirer}/keys.rb +5 -5
  27. data/lib/redis_queued_locks/{acquier → acquirer}/lock_info.rb +9 -5
  28. data/lib/redis_queued_locks/{acquier → acquirer}/locks.rb +16 -3
  29. data/lib/redis_queued_locks/{acquier → acquirer}/queue_info.rb +8 -6
  30. data/lib/redis_queued_locks/{acquier → acquirer}/queues.rb +9 -2
  31. data/lib/redis_queued_locks/{acquier → acquirer}/release_all_locks.rb +23 -18
  32. data/lib/redis_queued_locks/{acquier → acquirer}/release_lock.rb +25 -19
  33. data/lib/redis_queued_locks/acquirer.rb +18 -0
  34. data/lib/redis_queued_locks/client.rb +164 -254
  35. data/lib/redis_queued_locks/config/dsl.rb +94 -0
  36. data/lib/redis_queued_locks/config.rb +231 -0
  37. data/lib/redis_queued_locks/data.rb +2 -0
  38. data/lib/redis_queued_locks/errors.rb +27 -11
  39. data/lib/redis_queued_locks/instrument.rb +11 -4
  40. data/lib/redis_queued_locks/logging/void_logger.rb +38 -1
  41. data/lib/redis_queued_locks/logging.rb +20 -5
  42. data/lib/redis_queued_locks/resource.rb +49 -11
  43. data/lib/redis_queued_locks/swarm/acquirers.rb +17 -16
  44. data/lib/redis_queued_locks/swarm/flush_zombies.rb +26 -25
  45. data/lib/redis_queued_locks/swarm/probe_hosts.rb +20 -19
  46. data/lib/redis_queued_locks/swarm/redis_client_builder.rb +3 -3
  47. data/lib/redis_queued_locks/swarm/supervisor.rb +19 -6
  48. data/lib/redis_queued_locks/swarm/swarm_element/isolated.rb +20 -18
  49. data/lib/redis_queued_locks/swarm/swarm_element/threaded.rb +35 -27
  50. data/lib/redis_queued_locks/swarm/zombie_info.rb +9 -9
  51. data/lib/redis_queued_locks/swarm.rb +20 -41
  52. data/lib/redis_queued_locks/utilities.rb +2 -2
  53. data/lib/redis_queued_locks/version.rb +2 -2
  54. data/lib/redis_queued_locks.rb +2 -2
  55. data/rbs_collection.lock.yaml +40 -0
  56. data/rbs_collection.yaml +16 -0
  57. data/redis_queued_locks.gemspec +22 -23
  58. data/sig/manifest.yml +7 -0
  59. data/sig/redis_queued_locks/acquier.rbs +4 -0
  60. data/sig/redis_queued_locks/acquirer/acquire_lock/delay_execution.rbs +9 -0
  61. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue/log_visitor.rbs +21 -0
  62. data/sig/redis_queued_locks/acquirer/acquire_lock/dequeue_from_lock_queue.rbs +26 -0
  63. data/sig/redis_queued_locks/acquirer/acquire_lock/instr_visitor.rbs +71 -0
  64. data/sig/redis_queued_locks/acquirer/acquire_lock/log_visitor.rbs +72 -0
  65. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock/log_visitor.rbs +179 -0
  66. data/sig/redis_queued_locks/acquirer/acquire_lock/try_to_lock.rbs +48 -0
  67. data/sig/redis_queued_locks/acquirer/acquire_lock/with_acq_timeout.rbs +19 -0
  68. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_expire.rbs +41 -0
  69. data/sig/redis_queued_locks/acquirer/acquire_lock/yield_with_expire/log_visitor.rbs +32 -0
  70. data/sig/redis_queued_locks/acquirer/acquire_lock.rbs +51 -0
  71. data/sig/redis_queued_locks/acquirer/clear_dead_requests.rbs +28 -0
  72. data/sig/redis_queued_locks/acquirer/extend_lock_ttl.rbs +28 -0
  73. data/sig/redis_queued_locks/acquirer/is_locked.rbs +9 -0
  74. data/sig/redis_queued_locks/acquirer/is_queued.rbs +9 -0
  75. data/sig/redis_queued_locks/acquirer/keys.rbs +10 -0
  76. data/sig/redis_queued_locks/acquirer/lock_info.rbs +10 -0
  77. data/sig/redis_queued_locks/acquirer/locks.rbs +16 -0
  78. data/sig/redis_queued_locks/acquirer/queue_info.rbs +13 -0
  79. data/sig/redis_queued_locks/acquirer/queues.rbs +16 -0
  80. data/sig/redis_queued_locks/acquirer/release_all_locks.rbs +30 -0
  81. data/sig/redis_queued_locks/acquirer/release_lock.rbs +38 -0
  82. data/sig/redis_queued_locks/client.rbs +195 -0
  83. data/sig/redis_queued_locks/config/dsl.rbs +26 -0
  84. data/sig/redis_queued_locks/config.rbs +23 -0
  85. data/sig/redis_queued_locks/data.rbs +4 -0
  86. data/sig/redis_queued_locks/debugger/interface.rbs +9 -0
  87. data/sig/redis_queued_locks/debugger.rbs +13 -0
  88. data/sig/redis_queued_locks/errors.rbs +43 -0
  89. data/sig/redis_queued_locks/instrument/active_support.rbs +7 -0
  90. data/sig/redis_queued_locks/instrument/sampler.rbs +9 -0
  91. data/sig/redis_queued_locks/instrument/void_notifier.rbs +7 -0
  92. data/sig/redis_queued_locks/instrument.rbs +15 -0
  93. data/sig/redis_queued_locks/logging/sampler.rbs +9 -0
  94. data/sig/redis_queued_locks/logging/void_logger.rbs +15 -0
  95. data/sig/redis_queued_locks/logging.rbs +15 -0
  96. data/sig/redis_queued_locks/resource.rbs +42 -0
  97. data/sig/redis_queued_locks/swarm/acquirers.rbs +10 -0
  98. data/sig/redis_queued_locks/swarm/flush_zombies.rbs +13 -0
  99. data/sig/redis_queued_locks/swarm/probe_hosts.rbs +13 -0
  100. data/sig/redis_queued_locks/swarm/redis_client_builder.rbs +19 -0
  101. data/sig/redis_queued_locks/swarm/supervisor.rbs +26 -0
  102. data/sig/redis_queued_locks/swarm/swarm_element/isolated.rbs +52 -0
  103. data/sig/redis_queued_locks/swarm/swarm_element/threaded.rbs +61 -0
  104. data/sig/redis_queued_locks/swarm/swarm_element.rbs +8 -0
  105. data/sig/redis_queued_locks/swarm/zombie_info.rbs +24 -0
  106. data/sig/redis_queued_locks/swarm.rbs +41 -0
  107. data/sig/redis_queued_locks/utilities/lock.rbs +10 -0
  108. data/sig/redis_queued_locks/utilities.rbs +11 -0
  109. data/sig/redis_queued_locks/version.rbs +3 -0
  110. data/sig/redis_queued_locks.rbs +14 -0
  111. data/sig/vendor/active_support.rbs +9 -0
  112. data/sig/vendor/redis_client.rbs +39 -0
  113. data/sig/vendor/semantic_logger.rbs +4 -0
  114. metadata +96 -54
  115. data/lib/redis_queued_locks/acquier/acquire_lock/dequeue_from_lock_queue/log_visitor.rb +0 -40
  116. data/lib/redis_queued_locks/acquier/acquire_lock/instr_visitor.rb +0 -166
  117. data/lib/redis_queued_locks/acquier/acquire_lock/log_visitor.rb +0 -216
  118. data/lib/redis_queued_locks/acquier/acquire_lock/try_to_lock/log_visitor.rb +0 -541
  119. data/lib/redis_queued_locks/acquier/acquire_lock/yield_expire/log_visitor.rb +0 -76
  120. data/lib/redis_queued_locks/acquier.rb +0 -18
@@ -3,8 +3,8 @@
3
3
  # @api private
4
4
  # @since 1.0.0
5
5
  # @version 1.7.0
6
- # rubocop:disable Metrics/ModuleLength, Metrics/BlockNesting
7
- module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
6
+ # rubocop:disable Metrics/ModuleLength
7
+ module RedisQueuedLocks::Acquirer::AcquireLock::TryToLock
8
8
  require_relative 'try_to_lock/log_visitor'
9
9
 
10
10
  # @return [String]
@@ -20,10 +20,13 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
20
20
  # @param logger [::Logger,#debug]
21
21
  # @param log_lock_try [Boolean]
22
22
  # @param lock_key [String]
23
+ # @param read_write_mode [Symbol]
23
24
  # @param lock_key_queue [String]
24
- # @param acquier_id [String]
25
+ # @param read_lock_key_queue [String]
26
+ # @param write_lock_key_queue [String]
27
+ # @param acquirer_id [String]
25
28
  # @param host_id [String]
26
- # @param acquier_position [Numeric]
29
+ # @param acquirer_position [Numeric]
27
30
  # @param ttl [Integer]
28
31
  # @param queue_ttl [Integer]
29
32
  # @param fail_fast [Boolean]
@@ -36,17 +39,20 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
36
39
  #
37
40
  # @api private
38
41
  # @since 1.0.0
39
- # @version 1.9.0
42
+ # @version 1.13.0
40
43
  # rubocop:disable Metrics/MethodLength
41
44
  def try_to_lock(
42
45
  redis,
43
46
  logger,
44
47
  log_lock_try,
45
48
  lock_key,
49
+ read_write_mode,
46
50
  lock_key_queue,
47
- acquier_id,
51
+ read_lock_key_queue,
52
+ write_lock_key_queue,
53
+ acquirer_id,
48
54
  host_id,
49
- acquier_position,
55
+ acquirer_position,
50
56
  ttl,
51
57
  queue_ttl,
52
58
  fail_fast,
@@ -57,25 +63,28 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
57
63
  instr_sampled
58
64
  )
59
65
  # Step X: intermediate invocation results
66
+ # @type var inter_result: Symbol?
60
67
  inter_result = nil
68
+ # @type var timestamp: Float?
61
69
  timestamp = nil
70
+ # @type var spc_processed_timestamp: Float?
62
71
  spc_processed_timestamp = nil
63
72
 
64
73
  LogVisitor.start(
65
74
  logger, log_sampled, log_lock_try, lock_key,
66
- queue_ttl, acquier_id, host_id, access_strategy
75
+ queue_ttl, acquirer_id, host_id, access_strategy
67
76
  )
68
77
 
69
78
  # Step X: start to work with lock acquiring
70
79
  result = redis.with do |rconn|
71
80
  LogVisitor.rconn_fetched(
72
81
  logger, log_sampled, log_lock_try, lock_key,
73
- queue_ttl, acquier_id, host_id, access_strategy
82
+ queue_ttl, acquirer_id, host_id, access_strategy
74
83
  )
75
84
 
76
85
  # Step 0:
77
86
  # watch the lock key changes (and discard acquirement if lock is already
78
- # obtained by another acquier during the current lock acquiremntt)
87
+ # obtained by another acquirer during the current lock acquiremntt)
79
88
  rconn.multi(watch: [lock_key]) do |transact|
80
89
  # SP-Conflict status PREPARING: get the current lock obtainer
81
90
  current_lock_obtainer = rconn.call('HGET', lock_key, 'acq_id')
@@ -83,15 +92,14 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
83
92
  sp_conflict_status = nil
84
93
 
85
94
  # SP-Conflict Step X1: calculate the current deadlock status
86
- if current_lock_obtainer != nil && acquier_id == current_lock_obtainer
95
+ if current_lock_obtainer != nil && acquirer_id == current_lock_obtainer
87
96
  LogVisitor.same_process_conflict_detected(
88
97
  logger, log_sampled, log_lock_try, lock_key,
89
- queue_ttl, acquier_id, host_id, access_strategy
98
+ queue_ttl, acquirer_id, host_id, access_strategy
90
99
  )
91
100
 
92
101
  # SP-Conflict Step X2: self-process dead lock moment started.
93
102
  # SP-Conflict CHECK (Step CHECK): check chosen strategy and flag the current status
94
- # rubocop:disable Lint/DuplicateBranch
95
103
  case conflict_strategy
96
104
  when :work_through
97
105
  # <SP-Conflict Moment>: work through => exit
@@ -112,11 +120,9 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
112
120
  # but is forgotten to be added here;
113
121
  sp_conflict_status = :conflict_wait_for_lock
114
122
  end
115
- # rubocop:enable Lint/DuplicateBranch
116
-
117
123
  LogVisitor.same_process_conflict_analyzed(
118
124
  logger, log_sampled, log_lock_try, lock_key,
119
- queue_ttl, acquier_id, host_id, access_strategy, sp_conflict_status
125
+ queue_ttl, acquirer_id, host_id, access_strategy, sp_conflict_status
120
126
  )
121
127
  end
122
128
 
@@ -150,14 +156,16 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
150
156
  transact.call(
151
157
  'HSET',
152
158
  lock_key,
153
- 'l_spc_ext_ts', (spc_processed_timestamp = Time.now.to_f),
159
+ 'l_spc_ext_ts', spc_processed_timestamp = Time.now.to_f,
154
160
  'l_spc_ext_ini_ttl', ttl
155
161
  )
156
162
  inter_result = :extendable_conflict_work_through
157
163
 
164
+ # @type var sp_conflict_status: Symbol
165
+ # @type var spc_processed_timestamp: Float
158
166
  LogVisitor.reentrant_lock__extend_and_work_through(
159
167
  logger, log_sampled, log_lock_try, lock_key,
160
- queue_ttl, acquier_id, host_id, access_strategy,
168
+ queue_ttl, acquirer_id, host_id, access_strategy,
161
169
  sp_conflict_status, ttl, spc_processed_timestamp
162
170
  )
163
171
  # SP-Conflict-Step X2: switch to dead lock logic or not
@@ -177,12 +185,14 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
177
185
  transact.call(
178
186
  'HSET',
179
187
  lock_key,
180
- 'l_spc_ts', (spc_processed_timestamp = Time.now.to_f)
188
+ 'l_spc_ts', spc_processed_timestamp = Time.now.to_f
181
189
  )
182
190
 
191
+ # @type var sp_conflict_status: Symbol
192
+ # @type var spc_processed_timestamp: Float
183
193
  LogVisitor.reentrant_lock__work_through(
184
194
  logger, log_sampled, log_lock_try, lock_key,
185
- queue_ttl, acquier_id, host_id, access_strategy,
195
+ queue_ttl, acquirer_id, host_id, access_strategy,
186
196
  sp_conflict_status, spc_processed_timestamp
187
197
  )
188
198
  # SP-Conflict-Step X2: switch to dead lock logic or not
@@ -190,9 +200,11 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
190
200
  inter_result = :conflict_dead_lock
191
201
  spc_processed_timestamp = Time.now.to_f
192
202
 
203
+ # @type var sp_conflict_status: Symbol
204
+ # @type var spc_processed_timestamp: Float
193
205
  LogVisitor.single_process_lock_conflict__dead_lock(
194
206
  logger, log_sampled, log_lock_try, lock_key,
195
- queue_ttl, acquier_id, host_id, access_strategy,
207
+ queue_ttl, acquirer_id, host_id, access_strategy,
196
208
  sp_conflict_status, spc_processed_timestamp
197
209
  )
198
210
  # Reached the SP-Non-Conflict Mode (NOTE):
@@ -202,87 +214,94 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
202
214
  # Fast-Step X1: lock is already obtained. fail fast leads to "no try".
203
215
  inter_result = :fail_fast_no_try
204
216
  else
205
- # Step 1: add an acquier to the lock acquirement queue
206
- rconn.call('ZADD', lock_key_queue, 'NX', acquier_position, acquier_id)
217
+ # Step 1: add an acquirer to the lock acquirement queue
218
+ # NOTE:
219
+ # 'NX' means "Only add new elements. Don't update already existing elements."
220
+ # that works as:
221
+ # 1. (enqueue) <<if you are already in the queue - do nothing and wait your time>>
222
+ # 2. (requeue) or <<add to the right pre-calculated position if you are
223
+ # not in the queue now>>;
224
+ rconn.call('ZADD', lock_key_queue, 'NX', acquirer_position, acquirer_id)
207
225
 
208
226
  LogVisitor.acq_added_to_queue(
209
227
  logger, log_sampled, log_lock_try, lock_key,
210
- queue_ttl, acquier_id, host_id, access_strategy
228
+ queue_ttl, acquirer_id, host_id, access_strategy
211
229
  )
212
230
 
213
- # Step 2.1: drop expired acquiers from the lock queue
231
+ # Step 2.1: drop expired acquirers from the lock queue
214
232
  rconn.call(
215
233
  'ZREMRANGEBYSCORE',
216
234
  lock_key_queue,
217
235
  '-inf',
218
- RedisQueuedLocks::Resource.acquier_dead_score(queue_ttl)
236
+ RedisQueuedLocks::Resource.acquirer_dead_score(queue_ttl)
219
237
  )
220
238
 
221
239
  LogVisitor.remove_expired_acqs(
222
240
  logger, log_sampled, log_lock_try, lock_key,
223
- queue_ttl, acquier_id, host_id, access_strategy
241
+ queue_ttl, acquirer_id, host_id, access_strategy
224
242
  )
225
243
 
226
- # Step 3: get the actual acquier waiting in the queue
227
- waiting_acquier = Array(rconn.call('ZRANGE', lock_key_queue, '0', '0')).first
244
+ # Step 3: get the actual acquirer waiting in the queue
245
+ waiting_acquirer = Array(rconn.call('ZRANGE', lock_key_queue, '0', '0')).first
228
246
 
229
247
  LogVisitor.get_first_from_queue(
230
248
  logger, log_sampled, log_lock_try, lock_key,
231
- queue_ttl, acquier_id, host_id, access_strategy, waiting_acquier
249
+ queue_ttl, acquirer_id, host_id, access_strategy, waiting_acquirer
232
250
  )
233
251
 
234
252
  # Step PRE-4.x: check if the request time limit is reached
235
253
  # (when the current try self-removes itself from queue (queue ttl has come))
236
- if waiting_acquier == nil
254
+ if waiting_acquirer == nil
237
255
  LogVisitor.exit__queue_ttl_reached(
238
256
  logger, log_sampled, log_lock_try, lock_key,
239
- queue_ttl, acquier_id, host_id, access_strategy
257
+ queue_ttl, acquirer_id, host_id, access_strategy
240
258
  )
241
259
 
242
260
  inter_result = :dead_score_reached
243
261
  # Step STRATEGY: check the stragegy and corresponding preventing factor
244
- # Step STRATEGY (queued): check the actual acquier: is it ours? are we aready to lock?
245
- elsif access_strategy == :queued && waiting_acquier != acquier_id
262
+ # Step STRATEGY (queued): check the actual acquirer: is it ours? are we aready to lock?
263
+ elsif access_strategy == :queued && waiting_acquirer != acquirer_id
246
264
  # Step ROLLBACK 1.1: our time hasn't come yet. retry!
265
+
247
266
  LogVisitor.exit__no_first(
248
267
  logger, log_sampled, log_lock_try, lock_key,
249
- queue_ttl, acquier_id, host_id, access_strategy, waiting_acquier,
268
+ queue_ttl, acquirer_id, host_id, access_strategy, waiting_acquirer,
250
269
  rconn.call('HGETALL', lock_key).to_h
251
270
  )
252
- inter_result = :acquier_is_not_first_in_queue
271
+ inter_result = :acquirer_is_not_first_in_queue
253
272
  # Step STRAGEY: successfull (:queued OR :random)
254
- elsif (access_strategy == :queued && waiting_acquier == acquier_id) ||
273
+ elsif (access_strategy == :queued && waiting_acquirer == acquirer_id) ||
255
274
  (access_strategy == :random)
256
275
  # NOTE: our time has come! let's try to acquire the lock!
257
276
 
258
277
  # Step 5: find the lock -> check if the our lock is already acquired
259
- locked_by_acquier = rconn.call('HGET', lock_key, 'acq_id')
278
+ locked_by_acquirer = rconn.call('HGET', lock_key, 'acq_id')
260
279
 
261
- if locked_by_acquier
280
+ if locked_by_acquirer
262
281
  # Step ROLLBACK 2: required lock is stil acquired. retry!
263
282
 
264
283
  LogVisitor.exit__lock_still_obtained(
265
284
  logger, log_sampled, log_lock_try, lock_key,
266
- queue_ttl, acquier_id, host_id, access_strategy,
267
- waiting_acquier, locked_by_acquier,
285
+ queue_ttl, acquirer_id, host_id, access_strategy,
286
+ waiting_acquirer, locked_by_acquirer,
268
287
  rconn.call('HGETALL', lock_key).to_h
269
288
  )
270
289
  inter_result = :lock_is_still_acquired
271
290
  else
272
291
  # NOTE: required lock is free and ready to be acquired! acquire!
273
292
 
274
- # Step 6.1: remove our acquier from waiting queue
275
- transact.call('ZREM', lock_key_queue, acquier_id)
293
+ # Step 6.1: remove our acquirer from waiting queue
294
+ transact.call('ZREM', lock_key_queue, acquirer_id)
276
295
 
277
- # Step 6.2: acquire a lock and store an info about the acquier and host
296
+ # Step 6.2: acquire a lock and store an info about the acquirer and host
278
297
  transact.call(
279
298
  'HSET',
280
299
  lock_key,
281
- 'acq_id', acquier_id,
300
+ 'acq_id', acquirer_id,
282
301
  'hst_id', host_id,
283
- 'ts', (timestamp = Time.now.to_f),
302
+ 'ts', timestamp = Time.now.to_f,
284
303
  'ini_ttl', ttl,
285
- *(meta.to_a if meta != nil)
304
+ *(meta.to_a if meta != nil) # steep:ignore
286
305
  )
287
306
 
288
307
  # Step 6.3: set the lock expiration time in order to prevent "infinite locks"
@@ -290,7 +309,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
290
309
 
291
310
  LogVisitor.obtain__free_to_acquire(
292
311
  logger, log_sampled, log_lock_try, lock_key,
293
- queue_ttl, acquier_id, host_id, access_strategy
312
+ queue_ttl, acquirer_id, host_id, access_strategy
294
313
  )
295
314
  end
296
315
  end
@@ -316,62 +335,74 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
316
335
  # 3. HINCRBY (increased spc count) (OK for != nil)
317
336
  # 4. HSET (store the last spc time and ttl data) (OK for == 2 or != nil)
318
337
  if result[0] != nil && result[1] != nil && result[2] != nil && result[3] != nil
319
- RedisQueuedLocks::Data[ok: true, result: {
320
- process: :extendable_conflict_work_through,
321
- lock_key: lock_key,
322
- acq_id: acquier_id,
323
- hst_id: host_id,
324
- ts: spc_processed_timestamp,
325
- ttl: ttl
326
- }]
338
+ {
339
+ ok: true,
340
+ result: {
341
+ process: :extendable_conflict_work_through,
342
+ lock_key: lock_key,
343
+ acq_id: acquirer_id,
344
+ hst_id: host_id,
345
+ ts: spc_processed_timestamp,
346
+ ttl: ttl
347
+ }
348
+ }
327
349
  elsif result[0] != nil
328
350
  # NOTE: that is enough to the fact that the lock is extended but <TODO>
329
351
  # TODO: add detalized overview (log? some in-line code clarifications?) of the result
330
- RedisQueuedLocks::Data[ok: true, result: {
331
- process: :extendable_conflict_work_through,
332
- lock_key: lock_key,
333
- acq_id: acquier_id,
334
- hst_id: host_id,
335
- ts: spc_processed_timestamp,
336
- ttl: ttl
337
- }]
352
+ {
353
+ ok: true,
354
+ result: {
355
+ process: :extendable_conflict_work_through,
356
+ lock_key: lock_key,
357
+ acq_id: acquirer_id,
358
+ hst_id: host_id,
359
+ ts: spc_processed_timestamp,
360
+ ttl: ttl
361
+ }
362
+ }
338
363
  else
339
364
  # NOTE: unknown behaviour :thinking:
340
- RedisQueuedLocks::Data[ok: false, result: :unknown]
365
+ { ok: false, result: :unknown }
341
366
  end
342
367
  elsif result == nil || (result.is_a?(::Array) && result.empty?)
343
368
  # NOTE: the lock key was changed durign an SPC logic execution
344
- RedisQueuedLocks::Data[ok: false, result: :lock_is_acquired_during_acquire_race]
369
+ { ok: false, result: :lock_is_acquired_during_acquire_race }
345
370
  else
346
371
  # NOTE: unknown behaviour :thinking:. this part is not reachable at the moment.
347
- RedisQueuedLocks::Data[ok: false, result: :unknown]
372
+ { ok: false, result: :unknown }
348
373
  end
349
374
  when inter_result == :conflict_work_through
350
375
  # Step 7.same_process_conflict.B:
351
376
  # - conflict_work_through case => yield <block> without lock realesing/extending
352
- RedisQueuedLocks::Data[ok: true, result: {
353
- process: :conflict_work_through,
354
- lock_key: lock_key,
355
- acq_id: acquier_id,
356
- hst_id: host_id,
357
- ts: spc_processed_timestamp,
358
- ttl: ttl
359
- }]
377
+ {
378
+ ok: true,
379
+ result: {
380
+ process: :conflict_work_through,
381
+ lock_key: lock_key,
382
+ acq_id: acquirer_id,
383
+ hst_id: host_id,
384
+ ts: spc_processed_timestamp,
385
+ ttl: ttl
386
+ }
387
+ }
360
388
  when inter_result == :conflict_dead_lock
361
389
  # Step 7.same_process_conflict.C:
362
390
  # - deadlock. should fail in acquirement logic;
363
- RedisQueuedLocks::Data[ok: false, result: inter_result]
391
+ { ok: false, result: :conflict_dead_lock }
364
392
  when fail_fast && inter_result == :fail_fast_no_try
365
393
  # Step 7.a: lock is still acquired and we should exit from the logic as soon as possible
366
- RedisQueuedLocks::Data[ok: false, result: inter_result]
394
+ { ok: false, result: :fail_fast_no_try }
367
395
  when inter_result == :dead_score_reached
368
- RedisQueuedLocks::Data[ok: false, result: inter_result]
369
- when inter_result == :lock_is_still_acquired || inter_result == :acquier_is_not_first_in_queue
396
+ { ok: false, result: :dead_score_reached }
397
+ when inter_result == :lock_is_still_acquired
370
398
  # Step 7.b: lock is still acquired by another process => failed to acquire
371
- RedisQueuedLocks::Data[ok: false, result: inter_result]
399
+ { ok: false, result: :lock_is_still_acquired }
400
+ when inter_result == :acquirer_is_not_first_in_queue
401
+ # Step 7.c: lock is still acquired by another process => failed to acquire
402
+ { ok: false, result: :acquirer_is_not_first_in_queue }
372
403
  when result == nil || (result.is_a?(::Array) && result.empty?)
373
- # Step 7.c: lock is already acquired durign the acquire race => failed to acquire
374
- RedisQueuedLocks::Data[ok: false, result: :lock_is_acquired_during_acquire_race]
404
+ # Step 7.d: lock is already acquired durign the acquire race => failed to acquire
405
+ { ok: false, result: :lock_is_acquired_during_acquire_race }
375
406
  when result.is_a?(::Array) && result.size == 3 # NOTE: 3 is a count of redis lock commands
376
407
  # TODO:
377
408
  # => (!) analyze the command result and do actions with the depending on it;
@@ -383,20 +414,23 @@ module RedisQueuedLocks::Acquier::AcquireLock::TryToLock
383
414
  # 3. pexpire should return 1 (expiration time is successfully applied)
384
415
 
385
416
  # Step 7.d: locked! :) let's go! => successfully acquired
386
- RedisQueuedLocks::Data[ok: true, result: {
387
- process: :lock_obtaining,
388
- lock_key: lock_key,
389
- acq_id: acquier_id,
390
- hst_id: host_id,
391
- ts: timestamp,
392
- ttl: ttl
393
- }]
417
+ {
418
+ ok: true,
419
+ result: {
420
+ process: :lock_obtaining,
421
+ lock_key: lock_key,
422
+ acq_id: acquirer_id,
423
+ hst_id: host_id,
424
+ ts: timestamp,
425
+ ttl: ttl
426
+ }
427
+ }
394
428
  else
395
429
  # Ste 7.3: unknown behaviour :thinking:
396
- RedisQueuedLocks::Data[ok: false, result: :unknown]
430
+ { ok: false, result: :unknown }
397
431
  end
398
432
  # rubocop:enable Lint/DuplicateBranch
399
433
  end
400
434
  # rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
401
435
  end
402
- # rubocop:enable Metrics/ModuleLength, Metrics/BlockNesting
436
+ # rubocop:enable Metrics/ModuleLength
@@ -2,7 +2,7 @@
2
2
 
3
3
  # @api private
4
4
  # @since 1.0.0
5
- module RedisQueuedLocks::Acquier::AcquireLock::WithAcqTimeout
5
+ 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]
@@ -17,9 +17,11 @@ module RedisQueuedLocks::Acquier::AcquireLock::WithAcqTimeout
17
17
  # Add additional error data about lock queue and required lock to the timeout error or not.
18
18
  # @option on_timeout [Proc,NilClass]
19
19
  # Callback invoked on Timeout::Error.
20
+ # @param block [Block] Custom logic that should be invoked under the obtained lock.
20
21
  # @return [Any]
21
22
  #
22
- # @raise [RedisQueuedLocks::LockAcquiermentIntermediateTimeoutError]
23
+ # @raise [RedisQueuedLocks::LockAcquirementIntermediateTimeoutError]
24
+ # @raise [RedisQueuedLocks::LockAcquirementTimeoutError]
23
25
  #
24
26
  # @api private
25
27
  # @since 1.0.0
@@ -34,21 +36,24 @@ module RedisQueuedLocks::Acquier::AcquireLock::WithAcqTimeout
34
36
  on_timeout: nil,
35
37
  &block
36
38
  )
37
- ::Timeout.timeout(timeout, RedisQueuedLocks::LockAcquiermentIntermediateTimeoutError, &block)
38
- rescue RedisQueuedLocks::LockAcquiermentIntermediateTimeoutError
39
- on_timeout.call unless on_timeout == nil
39
+ ::Timeout.timeout(timeout, RedisQueuedLocks::LockAcquirementIntermediateTimeoutError, &block)
40
+ rescue RedisQueuedLocks::LockAcquirementIntermediateTimeoutError
41
+ if on_timeout != nil
42
+ # @type var on_timeout: Proc
43
+ on_timeout.call
44
+ end
40
45
 
41
46
  if raise_errors
42
47
  if detailed_acq_timeout_error
43
48
  # TODO: rewrite these invocations to separated inner-AcquireLock-related modules
44
49
  # in order to remove any dependencies from the other public RQL commands cuz
45
50
  # all AcquireLock logic elements should be fully independent from others as a core;
46
- lock_info = RedisQueuedLocks::Acquier::LockInfo.lock_info(redis, lock_name)
47
- queue_info = RedisQueuedLocks::Acquier::QueueInfo.queue_info(redis, lock_name)
51
+ lock_info = RedisQueuedLocks::Acquirer::LockInfo.lock_info(redis, lock_name)
52
+ queue_info = RedisQueuedLocks::Acquirer::QueueInfo.queue_info(redis, lock_name)
48
53
 
49
54
  # rubocop:disable Metrics/BlockNesting
50
55
  raise(
51
- RedisQueuedLocks::LockAcquiermentTimeoutError,
56
+ RedisQueuedLocks::LockAcquirementTimeoutError,
52
57
  "Failed to acquire the lock \"#{lock_key}\" " \
53
58
  "for the given <#{timeout} seconds> timeout. Details: " \
54
59
  "<Lock Data> => #{lock_info ? lock_info.inspect : '<no_data>'}; " \
@@ -57,7 +62,7 @@ module RedisQueuedLocks::Acquier::AcquireLock::WithAcqTimeout
57
62
  # rubocop:enable Metrics/BlockNesting
58
63
  else
59
64
  raise(
60
- RedisQueuedLocks::LockAcquiermentTimeoutError,
65
+ RedisQueuedLocks::LockAcquirementTimeoutError,
61
66
  "Failed to acquire the lock \"#{lock_key}\" " \
62
67
  "for the given <#{timeout} seconds> timeout."
63
68
  )
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 1.7.0
5
+ module RedisQueuedLocks::Acquirer::AcquireLock::YieldExpire::LogVisitor
6
+ class << self
7
+ # @param logger [::Logger,#debug]
8
+ # @param log_sampled [Boolean]
9
+ # @param lock_key [String]
10
+ # @param queue_ttl [Integer]
11
+ # @param acquirer_id [String]
12
+ # @param host_id [String]
13
+ # @param access_strategy [Symbol]
14
+ # @return [void]
15
+ #
16
+ # @api private
17
+ # @since 1.7.0
18
+ # @version 1.9.0
19
+ def expire_lock(
20
+ logger,
21
+ log_sampled,
22
+ lock_key,
23
+ queue_ttl,
24
+ acquirer_id,
25
+ host_id,
26
+ access_strategy
27
+ )
28
+ return unless log_sampled
29
+
30
+ logger.debug do
31
+ "[redis_queued_locks.expire_lock] " \
32
+ "lock_key => '#{lock_key}' " \
33
+ "queue_ttl => #{queue_ttl} " \
34
+ "acq_id => '#{acquirer_id}' " \
35
+ "hst_id => '#{host_id}' " \
36
+ "acs_strat => '#{access_strategy}'"
37
+ end rescue nil
38
+ end
39
+
40
+ # @param logger [::Logger,#debug]
41
+ # @param log_sampled [Boolean]
42
+ # @param lock_key [String]
43
+ # @param decreased_ttl [Integer]
44
+ # @param queue_ttl [Integer]
45
+ # @param acquirer_id [String]
46
+ # @param host_id [String]
47
+ # @param access_strategy [Symbol]
48
+ # @return [void]
49
+ #
50
+ # @api private
51
+ # @since 1.7.0
52
+ # @version 1.9.0
53
+ def decrease_lock(
54
+ logger,
55
+ log_sampled,
56
+ lock_key,
57
+ decreased_ttl,
58
+ queue_ttl,
59
+ acquirer_id,
60
+ host_id,
61
+ access_strategy
62
+ )
63
+ return unless log_sampled
64
+
65
+ logger.debug do
66
+ "[redis_queued_locks.decrease_lock] " \
67
+ "lock_key => '#{lock_key}' " \
68
+ "decreased_ttl => #{decreased_ttl} " \
69
+ "queue_ttl => #{queue_ttl} " \
70
+ "acq_id => '#{acquirer_id}' " \
71
+ "hst_id => '#{host_id}' " \
72
+ "acs_strat => '#{access_strategy}'"
73
+ end rescue nil
74
+ end
75
+ end
76
+ end