active_record_mutex 2.5.1 → 3.1.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 +5 -5
- data/.envrc +1 -0
- data/CHANGES.md +151 -0
- data/Gemfile +0 -2
- data/README.md +105 -15
- data/Rakefile +8 -5
- data/active_record_mutex.gemspec +14 -33
- data/docker-compose.yml +13 -0
- data/examples/process1.rb +31 -0
- data/examples/process2.rb +28 -0
- data/lib/active_record/database_mutex/implementation.rb +210 -81
- data/lib/active_record/database_mutex/version.rb +1 -1
- data/lib/active_record/database_mutex.rb +56 -12
- data/test/database_mutex_test.rb +133 -9
- data/test/test_helper.rb +8 -9
- metadata +33 -24
- data/.gitignore +0 -6
- data/.travis.yml +0 -20
- data/VERSION +0 -1
data/test/database_mutex_test.rb
CHANGED
@@ -6,6 +6,10 @@ class DatabaseMutexTest < Test::Unit::TestCase
|
|
6
6
|
class Foo < ActiveRecord::Base; end
|
7
7
|
|
8
8
|
def setup
|
9
|
+
Foo.instance_eval do
|
10
|
+
@mutex_name = nil
|
11
|
+
@mutex = nil
|
12
|
+
end
|
9
13
|
ActiveRecord::Schema.define(:version => 1) do
|
10
14
|
create_table(:foos, :force => true) { |t| t.string :bar }
|
11
15
|
end
|
@@ -19,9 +23,6 @@ class DatabaseMutexTest < Test::Unit::TestCase
|
|
19
23
|
|
20
24
|
def test_class_method_mutex
|
21
25
|
old, ENV['RAILS_ENV'] = ENV['RAILS_ENV'], nil
|
22
|
-
Foo.instance_eval do
|
23
|
-
@mutex = nil
|
24
|
-
end
|
25
26
|
mutex = Foo.mutex
|
26
27
|
assert_kind_of ActiveRecord::DatabaseMutex::Implementation, mutex
|
27
28
|
assert_equal Foo.name, mutex.name
|
@@ -31,9 +32,6 @@ class DatabaseMutexTest < Test::Unit::TestCase
|
|
31
32
|
|
32
33
|
def test_class_method_mutex_within_env
|
33
34
|
old, ENV['RAILS_ENV'] = ENV['RAILS_ENV'], 'test'
|
34
|
-
Foo.instance_eval do
|
35
|
-
@mutex = nil
|
36
|
-
end
|
37
35
|
mutex = Foo.mutex
|
38
36
|
assert_kind_of ActiveRecord::DatabaseMutex::Implementation, mutex
|
39
37
|
assert_equal "#{Foo.name}@test", mutex.name
|
@@ -65,29 +63,126 @@ class DatabaseMutexTest < Test::Unit::TestCase
|
|
65
63
|
def test_lock
|
66
64
|
mutex = Implementation.new(:name => 'Lock')
|
67
65
|
assert mutex.unlocked?
|
66
|
+
assert mutex.not_owned?
|
68
67
|
assert_equal 0, mutex.send(:counter_value)
|
69
68
|
assert mutex.lock
|
70
69
|
assert mutex.locked?
|
71
|
-
assert mutex.
|
70
|
+
assert mutex.owned?
|
72
71
|
assert_equal 1, mutex.send(:counter_value)
|
73
72
|
assert mutex.lock
|
74
73
|
assert_equal 2, mutex.send(:counter_value)
|
75
74
|
end
|
76
75
|
|
76
|
+
def test_lock_with_timeout_multiple_threads
|
77
|
+
done = false
|
78
|
+
thread = Thread.new do
|
79
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
80
|
+
Implementation.new(:name => 'LockTimeout').synchronize {
|
81
|
+
done = true
|
82
|
+
sleep 2
|
83
|
+
}
|
84
|
+
end
|
85
|
+
ensure
|
86
|
+
done = true
|
87
|
+
end
|
88
|
+
mutex = Implementation.new(:name => 'LockTimeout')
|
89
|
+
until done
|
90
|
+
sleep 0.1
|
91
|
+
end
|
92
|
+
assert_false mutex.lock(timeout: 0.1, raise: false)
|
93
|
+
assert_raises(ActiveRecord::DatabaseMutex::MutexLocked) { mutex.lock(timeout: 0.1) }
|
94
|
+
thread.join
|
95
|
+
assert mutex.unlocked?
|
96
|
+
assert_false mutex.owned?
|
97
|
+
assert_equal 0, mutex.send(:counter_value)
|
98
|
+
assert mutex.lock(timeout: 1)
|
99
|
+
assert mutex.locked?
|
100
|
+
assert mutex.owned?
|
101
|
+
assert_equal 1, mutex.send(:counter_value)
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_lock_without_timeout_multiple_threads
|
105
|
+
done = false
|
106
|
+
thread = Thread.new do
|
107
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
108
|
+
Implementation.new(:name => 'SpinTimeout').synchronize {
|
109
|
+
done = true
|
110
|
+
sleep 2
|
111
|
+
}
|
112
|
+
end
|
113
|
+
ensure
|
114
|
+
done = true
|
115
|
+
end
|
116
|
+
mutex = Implementation.new(:name => 'SpinTimeout')
|
117
|
+
until done
|
118
|
+
sleep 0.1
|
119
|
+
end
|
120
|
+
thread.join
|
121
|
+
assert mutex.lock
|
122
|
+
assert mutex.locked?
|
123
|
+
assert mutex.owned?
|
124
|
+
assert_equal 1, mutex.send(:counter_value)
|
125
|
+
end
|
126
|
+
|
77
127
|
def test_unlock
|
78
128
|
mutex = Implementation.new(:name => 'Unlock')
|
79
129
|
assert_raises(ActiveRecord::DatabaseMutex::MutexUnlockFailed) { mutex.unlock }
|
80
130
|
assert_equal 0, mutex.send(:counter_value)
|
81
131
|
assert mutex.lock
|
82
132
|
assert mutex.locked?
|
83
|
-
assert mutex.
|
133
|
+
assert mutex.owned?
|
134
|
+
assert_equal 1, mutex.send(:counter_value)
|
135
|
+
assert mutex.lock
|
136
|
+
assert mutex.locked?
|
137
|
+
assert mutex.owned?
|
138
|
+
assert_equal 2, mutex.send(:counter_value)
|
139
|
+
assert_false mutex.unlock
|
140
|
+
assert_false mutex.unlocked?
|
141
|
+
assert_false mutex.not_owned?
|
84
142
|
assert_equal 1, mutex.send(:counter_value)
|
85
143
|
assert mutex.unlock
|
86
144
|
assert mutex.unlocked?
|
145
|
+
assert mutex.not_owned?
|
87
146
|
assert_equal 0, mutex.send(:counter_value)
|
88
147
|
assert_raises(ActiveRecord::DatabaseMutex::MutexUnlockFailed) { mutex.unlock }
|
89
148
|
end
|
90
149
|
|
150
|
+
def test_unlock_with_force
|
151
|
+
mutex = Implementation.new(:name => 'Unlock')
|
152
|
+
assert_false mutex.unlock raise: false
|
153
|
+
assert_raises(ActiveRecord::DatabaseMutex::MutexUnlockFailed) { mutex.unlock }
|
154
|
+
assert_equal 0, mutex.send(:counter_value)
|
155
|
+
assert mutex.lock
|
156
|
+
assert mutex.locked?
|
157
|
+
assert mutex.owned?
|
158
|
+
assert_equal 1, mutex.send(:counter_value)
|
159
|
+
assert mutex.lock
|
160
|
+
assert mutex.locked?
|
161
|
+
assert mutex.owned?
|
162
|
+
assert_equal 2, mutex.send(:counter_value)
|
163
|
+
assert mutex.unlock force: true
|
164
|
+
assert mutex.unlocked?
|
165
|
+
assert mutex.not_owned?
|
166
|
+
assert_equal 0, mutex.send(:counter_value)
|
167
|
+
assert_false mutex.unlock force: true, raise: false
|
168
|
+
assert_raises(ActiveRecord::DatabaseMutex::MutexUnlockFailed) { mutex.unlock force: true }
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_unlock?
|
172
|
+
mutex = Implementation.new(:name => 'Unlock')
|
173
|
+
assert_nil mutex.unlock?
|
174
|
+
assert_equal 0, mutex.send(:counter_value)
|
175
|
+
assert mutex.lock
|
176
|
+
assert mutex.locked?
|
177
|
+
assert mutex.owned?
|
178
|
+
assert_equal 1, mutex.send(:counter_value)
|
179
|
+
assert mutex.unlock?
|
180
|
+
assert mutex.unlocked?
|
181
|
+
assert mutex.not_owned?
|
182
|
+
assert_equal 0, mutex.send(:counter_value)
|
183
|
+
assert_nil mutex.unlock?
|
184
|
+
end
|
185
|
+
|
91
186
|
def test_synchronize
|
92
187
|
mutex = Implementation.new(:name => 'Sync1')
|
93
188
|
assert mutex.unlocked?
|
@@ -100,6 +195,30 @@ class DatabaseMutexTest < Test::Unit::TestCase
|
|
100
195
|
assert_equal 0, mutex.send(:counter_value)
|
101
196
|
end
|
102
197
|
|
198
|
+
def test_synchronize_two_threads
|
199
|
+
done = false
|
200
|
+
thread = Thread.new do
|
201
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
202
|
+
Implementation.new(:name => 'Sync1').synchronize {
|
203
|
+
done = true
|
204
|
+
sleep 2
|
205
|
+
}
|
206
|
+
end
|
207
|
+
ensure
|
208
|
+
done = true
|
209
|
+
end
|
210
|
+
mutex = Implementation.new(:name => 'Sync1')
|
211
|
+
yielded = false
|
212
|
+
until done
|
213
|
+
sleep 0.1
|
214
|
+
end
|
215
|
+
mutex.synchronize(block: false) { yielded = true }
|
216
|
+
assert_false yielded
|
217
|
+
thread.join
|
218
|
+
mutex.synchronize(block: false) { yielded = true }
|
219
|
+
assert yielded
|
220
|
+
end
|
221
|
+
|
103
222
|
def test_synchronize_exception
|
104
223
|
mutex = Implementation.new(:name => 'Sync2')
|
105
224
|
exception = Class.new StandardError
|
@@ -147,8 +266,13 @@ class DatabaseMutexTest < Test::Unit::TestCase
|
|
147
266
|
assert_nil mutex.synchronize {}
|
148
267
|
end
|
149
268
|
|
269
|
+
def test_internal_name
|
270
|
+
mutex = Implementation.new(:name => (250..255).map(&:chr) * '')
|
271
|
+
assert_equal '$3i3xQvUrNPGyH6kaIOkiPw', mutex.send(:internal_name)
|
272
|
+
end
|
273
|
+
|
150
274
|
def test_counter_name
|
151
275
|
mutex = Implementation.new(:name => (250..255).map(&:chr) * '')
|
152
|
-
assert_equal '@$
|
276
|
+
assert_equal '@$3i3xQvUrNPGyH6kaIOkiPw', mutex.send(:counter)
|
153
277
|
end
|
154
278
|
end
|
data/test/test_helper.rb
CHANGED
@@ -6,15 +6,14 @@ if ENV['START_SIMPLECOV'].to_i == 1
|
|
6
6
|
end
|
7
7
|
|
8
8
|
require 'active_record'
|
9
|
-
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
10
9
|
require 'active_record/database_mutex'
|
10
|
+
require 'debug'
|
11
|
+
|
12
|
+
database_url = URI.parse(ENV.fetch('DATABASE_URL'))
|
13
|
+
database = File.basename(database_url.path)
|
14
|
+
database_url_without_db = database_url.dup.tap { _1.path = '' }
|
15
|
+
ch = ActiveRecord::Base.establish_connection(database_url_without_db.to_s)
|
16
|
+
ch.with_connection { _1.execute %{ CREATE DATABASE IF NOT EXISTS #{database} } }
|
17
|
+
ActiveRecord::Base.establish_connection(database_url.to_s)
|
11
18
|
|
12
|
-
ActiveRecord::Base.establish_connection(
|
13
|
-
:adapter => "mysql2",
|
14
|
-
:database => ENV['DATABASE'] || "test",
|
15
|
-
:username => ENV['USER'],
|
16
|
-
:password => ENV['PASSWORD'],
|
17
|
-
:host => ENV['HOST'] || 'localhost'
|
18
|
-
)
|
19
19
|
require 'test/unit'
|
20
|
-
require 'byebug'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_mutex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Frank
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gem_hadar
|
@@ -16,14 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: '1.19'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: '1.19'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: all_images
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.6'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: test-unit
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,7 +53,7 @@ dependencies:
|
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '3.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: debug
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - ">="
|
@@ -72,14 +86,14 @@ dependencies:
|
|
72
86
|
requirements:
|
73
87
|
- - "~>"
|
74
88
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.3
|
89
|
+
version: '0.3'
|
76
90
|
type: :runtime
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
94
|
- - "~>"
|
81
95
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.3
|
96
|
+
version: '0.3'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: activerecord
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -87,9 +101,6 @@ dependencies:
|
|
87
101
|
- - ">="
|
88
102
|
- !ruby/object:Gem::Version
|
89
103
|
version: '4.0'
|
90
|
-
- - "<"
|
91
|
-
- !ruby/object:Gem::Version
|
92
|
-
version: '6'
|
93
104
|
type: :runtime
|
94
105
|
prerelease: false
|
95
106
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -97,23 +108,20 @@ dependencies:
|
|
97
108
|
- - ">="
|
98
109
|
- !ruby/object:Gem::Version
|
99
110
|
version: '4.0'
|
100
|
-
- - "<"
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
version: '6'
|
103
111
|
- !ruby/object:Gem::Dependency
|
104
|
-
name:
|
112
|
+
name: ostruct
|
105
113
|
requirement: !ruby/object:Gem::Requirement
|
106
114
|
requirements:
|
107
115
|
- - "~>"
|
108
116
|
- !ruby/object:Gem::Version
|
109
|
-
version: '
|
117
|
+
version: '0.6'
|
110
118
|
type: :runtime
|
111
119
|
prerelease: false
|
112
120
|
version_requirements: !ruby/object:Gem::Requirement
|
113
121
|
requirements:
|
114
122
|
- - "~>"
|
115
123
|
- !ruby/object:Gem::Version
|
116
|
-
version: '
|
124
|
+
version: '0.6'
|
117
125
|
description: Mutex that can be used to synchronise ruby processes via an ActiveRecord
|
118
126
|
datababase connection. (Only Mysql is supported at the moment.)
|
119
127
|
email: flori@ping.de
|
@@ -127,14 +135,16 @@ extra_rdoc_files:
|
|
127
135
|
- lib/active_record/mutex.rb
|
128
136
|
- lib/active_record_mutex.rb
|
129
137
|
files:
|
130
|
-
- ".
|
131
|
-
-
|
138
|
+
- ".envrc"
|
139
|
+
- CHANGES.md
|
132
140
|
- COPYING
|
133
141
|
- Gemfile
|
134
142
|
- README.md
|
135
143
|
- Rakefile
|
136
|
-
- VERSION
|
137
144
|
- active_record_mutex.gemspec
|
145
|
+
- docker-compose.yml
|
146
|
+
- examples/process1.rb
|
147
|
+
- examples/process2.rb
|
138
148
|
- lib/active_record/database_mutex.rb
|
139
149
|
- lib/active_record/database_mutex/implementation.rb
|
140
150
|
- lib/active_record/database_mutex/version.rb
|
@@ -146,7 +156,7 @@ homepage: http://github.com/flori/active_record_mutex
|
|
146
156
|
licenses:
|
147
157
|
- GPL-2
|
148
158
|
metadata: {}
|
149
|
-
post_install_message:
|
159
|
+
post_install_message:
|
150
160
|
rdoc_options:
|
151
161
|
- "--title"
|
152
162
|
- ActiveRecordMutex - Implementation of a Mutex for Active Record
|
@@ -165,9 +175,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
175
|
- !ruby/object:Gem::Version
|
166
176
|
version: '0'
|
167
177
|
requirements: []
|
168
|
-
|
169
|
-
|
170
|
-
signing_key:
|
178
|
+
rubygems_version: 3.5.18
|
179
|
+
signing_key:
|
171
180
|
specification_version: 4
|
172
181
|
summary: Implementation of a Mutex for Active Record
|
173
182
|
test_files:
|
data/.gitignore
DELETED
data/.travis.yml
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
rvm:
|
2
|
-
- 2.0
|
3
|
-
- 2.1
|
4
|
-
- 2.2
|
5
|
-
- 2.3.3
|
6
|
-
- jruby-head
|
7
|
-
matrix:
|
8
|
-
allow_failures:
|
9
|
-
- rvm: ruby-head
|
10
|
-
- rvm: jruby-head
|
11
|
-
before_script:
|
12
|
-
- mysql -e 'create database test;'
|
13
|
-
script:
|
14
|
-
- rake && codeclimate-test-reporter --file coverage
|
15
|
-
sudo: false
|
16
|
-
addons:
|
17
|
-
code_climate:
|
18
|
-
repo_token: 316615e61480039c3444f59bf124cf810d31110326e51f133e9cc9852de14892
|
19
|
-
env:
|
20
|
-
- START_SIMPLECOV=1
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.5.1
|