active_record_mutex 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
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
|