active_record_mutex 3.1.0 → 3.2.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34e4fb422fbe0336eee934df7fdeb49843c4b0335fe4222db9d8df1728b7d477
|
4
|
+
data.tar.gz: c3dc8c6fe86409160ded37ed5941cef3033d03b82e60c630c950ade50fc1d901
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd1437072b603f1dd5641d70970fe3bd2a24e77862a88d035222b4b1c0c360eb99ce14a573be87fc2e331e85955283262380be09c709e3bad936944a36b6615a
|
7
|
+
data.tar.gz: 2f4528e9a7d63ce3e2f9584f0b0099c783b07bf518174fd50c107237e0ad994fed77519f408ef27daa3aa752d3df1452fdc7a0139a312c21fe6d708d77cc5f0c
|
data/active_record_mutex.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: active_record_mutex 3.
|
2
|
+
# stub: active_record_mutex 3.2.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "active_record_mutex".freeze
|
6
|
-
s.version = "3.
|
6
|
+
s.version = "3.2.0".freeze
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
9
9
|
s.require_paths = ["lib".freeze]
|
@@ -20,7 +20,8 @@ module ActiveRecord
|
|
20
20
|
#
|
21
21
|
# @raise [ ArgumentError ] if no **name** option is provided in the options hash.
|
22
22
|
def initialize(opts = {})
|
23
|
-
@name = opts[:name]
|
23
|
+
@name = opts[:name].to_s
|
24
|
+
@name.size != 0 or raise ArgumentError, "mutex requires a nonempty :name argument"
|
24
25
|
internal_name # create/check internal_name
|
25
26
|
end
|
26
27
|
|
@@ -43,38 +44,48 @@ module ActiveRecord
|
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
47
|
+
# The lock_name method generates the name for the mutex's internal lock
|
48
|
+
# variable based on its class and {name} attributes, prefixing it with a
|
49
|
+
# truncated version of the name that only includes printable characters.
|
50
|
+
#
|
51
|
+
# @return [ String ] the generated lock name
|
52
|
+
def lock_name
|
53
|
+
prefix_name = name.gsub(/[^[:print:]]/, '')[0, 32]
|
54
|
+
prefix_name + ?= + internal_name
|
55
|
+
end
|
56
|
+
|
57
|
+
# The synchronize method attempts to acquire a mutex lock for the given name
|
58
|
+
# and executes the block passed to it. If the lock is already held by another
|
59
|
+
# database connection, this method will return nil instead of raising an
|
60
|
+
# exception and not execute the block. #
|
61
|
+
#
|
62
|
+
# This method provides a convenient way to ensure that critical sections of code
|
63
|
+
# are executed while holding the mutex lock. It attempts to acquire the lock using
|
64
|
+
# the underlying locking mechanisms (such as {lock} and {unlock}) and executes
|
65
|
+
# the block passed to it.
|
66
|
+
#
|
67
|
+
# The **block** and **timeout** options are passed to the {lock} method
|
68
|
+
# and configure the way the lock is acquired.
|
69
|
+
#
|
70
|
+
# The **force** option is passed to the {unlock} method, which will force the
|
71
|
+
# lock to open if true.
|
72
|
+
#
|
73
|
+
# @example
|
74
|
+
# foo.mutex.synchronize { do_something_with foo } # wait forever and never give up
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# foo.mutex.synchronize(timeout: 5) { do_something_with foo } # wait 5s and give up
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# unless foo.mutex.synchronize(block: false) { do_something_with foo }
|
81
|
+
# # try again later
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# @param opts [ Hash ] Options hash containing the **block**, **timeout**, or **force** keys
|
85
|
+
#
|
86
|
+
# @yield [ Result ] The block to be executed while holding the mutex lock
|
87
|
+
#
|
88
|
+
# @return [ Nil or result of yielded block ] depending on whether the lock was acquired
|
78
89
|
def synchronize(opts = {})
|
79
90
|
locked = lock(opts.slice(:block, :timeout)) or return
|
80
91
|
yield
|
@@ -147,7 +158,7 @@ module ActiveRecord
|
|
147
158
|
decrement_counter
|
148
159
|
end
|
149
160
|
if counter_zero?
|
150
|
-
case query("SELECT RELEASE_LOCK(#{quote(
|
161
|
+
case query("SELECT RELEASE_LOCK(#{quote(lock_name)})")
|
151
162
|
when 1
|
152
163
|
true
|
153
164
|
when 0, nil
|
@@ -181,7 +192,7 @@ module ActiveRecord
|
|
181
192
|
#
|
182
193
|
# @return [ true, false ] true if the mutex is unlocked, false otherwise
|
183
194
|
def unlocked?
|
184
|
-
query("SELECT IS_FREE_LOCK(#{quote(
|
195
|
+
query("SELECT IS_FREE_LOCK(#{quote(lock_name)})") == 1
|
185
196
|
end
|
186
197
|
|
187
198
|
# The locked? method returns true if this mutex is currently locked by
|
@@ -194,7 +205,7 @@ module ActiveRecord
|
|
194
205
|
|
195
206
|
# Returns true if the mutex is was acquired on this database connection.
|
196
207
|
def owned?
|
197
|
-
query("SELECT CONNECTION_ID() = IS_USED_LOCK(#{quote(
|
208
|
+
query("SELECT CONNECTION_ID() = IS_USED_LOCK(#{quote(lock_name)})") == 1
|
198
209
|
end
|
199
210
|
|
200
211
|
# Returns true if this mutex was not acquired on this database connection,
|
@@ -225,13 +236,15 @@ module ActiveRecord
|
|
225
236
|
ActiveRecord::Base.connection.quote(value)
|
226
237
|
end
|
227
238
|
|
239
|
+
alias counter_name internal_name
|
240
|
+
|
228
241
|
# The counter method generates a unique name for the mutex's internal
|
229
242
|
# counter variable. This name is used as part of the SQL query to set and
|
230
243
|
# retrieve the counter value.
|
231
244
|
#
|
232
245
|
# @return [String] the unique name for the mutex's internal counter variable.
|
233
246
|
def counter
|
234
|
-
"@#{
|
247
|
+
"@#{counter_name}"
|
235
248
|
end
|
236
249
|
|
237
250
|
# The increment_counter method increments the internal counter value for
|
@@ -290,7 +303,7 @@ module ActiveRecord
|
|
290
303
|
increment_counter
|
291
304
|
true
|
292
305
|
else
|
293
|
-
case query("SELECT GET_LOCK(#{quote(
|
306
|
+
case query("SELECT GET_LOCK(#{quote(lock_name)}, #{timeout})")
|
294
307
|
when 1
|
295
308
|
increment_counter
|
296
309
|
true
|
data/test/database_mutex_test.rb
CHANGED
@@ -55,6 +55,22 @@ class DatabaseMutexTest < Test::Unit::TestCase
|
|
55
55
|
assert_kind_of ActiveRecord::DatabaseMutex::Implementation, mutex
|
56
56
|
end
|
57
57
|
|
58
|
+
private def lock_exists?(string)
|
59
|
+
ActiveRecord::Base.all_mutexes.map(&:OBJECT_NAME).any? {
|
60
|
+
_1.include?(string)
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_all_mutexes
|
65
|
+
string = SecureRandom.hex(16)
|
66
|
+
mutex = ActiveRecord::DatabaseMutex.for(string)
|
67
|
+
assert_false lock_exists?(string)
|
68
|
+
mutex.lock
|
69
|
+
assert lock_exists?(string)
|
70
|
+
ensure
|
71
|
+
mutex.unlock force: true
|
72
|
+
end
|
73
|
+
|
58
74
|
def test_create
|
59
75
|
mutex = Implementation.new(:name => 'Create')
|
60
76
|
assert_equal 'Create', mutex.name
|