zk 1.5.1 → 1.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/Guardfile +9 -5
- data/README.markdown +1 -1
- data/RELEASES.markdown +8 -0
- data/lib/zk/client/threaded.rb +12 -5
- data/lib/zk/fork_hook.rb +3 -0
- data/lib/zk/locker/locker_base.rb +58 -14
- data/lib/zk/version.rb +1 -1
- data/spec/message_queue_spec.rb +3 -2
- data/spec/shared/client_contexts.rb +1 -1
- data/spec/shared/locker_contexts.rb +53 -0
- data/spec/shared/locker_examples.rb +55 -0
- data/spec/support/logging.rb +37 -23
- data/spec/zk/locker/exclusive_locker_spec.rb +122 -0
- data/spec/zk/locker/locker_basic_spec.rb +79 -0
- data/spec/zk/locker/shared_exclusive_integration_spec.rb +157 -0
- data/spec/zk/locker/shared_locker_spec.rb +137 -0
- data/spec/zk/pool_spec.rb +6 -3
- data/spec/zk/watch_spec.rb +0 -1
- data/spec/zk/zookeeper_spec.rb +2 -1
- data/zk.gemspec +1 -1
- metadata +19 -9
- data/spec/zk/locker_spec.rb +0 -552
data/spec/zk/pool_spec.rb
CHANGED
@@ -2,11 +2,12 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe ZK::Pool do
|
4
4
|
describe :Simple do
|
5
|
+
include_context 'connection opts'
|
5
6
|
|
6
7
|
before do
|
7
8
|
report_realtime('opening pool') do
|
8
9
|
@pool_size = 2
|
9
|
-
@connection_pool = ZK::Pool::Simple.new(
|
10
|
+
@connection_pool = ZK::Pool::Simple.new(connection_host, @pool_size, :watcher => :default)
|
10
11
|
@connection_pool.should be_open
|
11
12
|
end
|
12
13
|
end
|
@@ -27,7 +28,7 @@ describe ZK::Pool do
|
|
27
28
|
end
|
28
29
|
|
29
30
|
report_realtime("closing") do
|
30
|
-
ZK.open(
|
31
|
+
ZK.open(connection_host) do |zk|
|
31
32
|
begin
|
32
33
|
zk.delete('/test_pool')
|
33
34
|
rescue ZK::Exceptions::NoNode
|
@@ -213,10 +214,12 @@ describe ZK::Pool do
|
|
213
214
|
end # Simple
|
214
215
|
|
215
216
|
describe :Bounded do
|
217
|
+
include_context 'connection opts'
|
218
|
+
|
216
219
|
before do
|
217
220
|
@min_clients = 1
|
218
221
|
@max_clients = 2
|
219
|
-
@connection_pool = ZK::Pool::Bounded.new(
|
222
|
+
@connection_pool = ZK::Pool::Bounded.new(connection_host, :min_clients => @min_clients, :max_clients => @max_clients, :timeout => @timeout)
|
220
223
|
@connection_pool.should be_open
|
221
224
|
wait_until(2) { @connection_pool.available_size > 0 }
|
222
225
|
end
|
data/spec/zk/watch_spec.rb
CHANGED
data/spec/zk/zookeeper_spec.rb
CHANGED
@@ -2,6 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
shared_examples_for 'ZK basic' do
|
4
4
|
before do
|
5
|
+
logger.debug { "connection_args: #{connection_args.inspect}" }
|
5
6
|
begin
|
6
7
|
@zk.create(@base_path)
|
7
8
|
rescue ZK::Exceptions::NodeExists
|
@@ -120,7 +121,7 @@ shared_examples_for 'ZK basic' do
|
|
120
121
|
end
|
121
122
|
end
|
122
123
|
|
123
|
-
describe
|
124
|
+
describe :threaded => true do
|
124
125
|
include_context 'threaded client connection'
|
125
126
|
it_should_behave_like 'ZK basic'
|
126
127
|
end
|
data/zk.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = %q{A high-level wrapper around the zookeeper driver}
|
13
13
|
s.description = s.summary + "\n"
|
14
14
|
|
15
|
-
s.add_runtime_dependency 'zookeeper', '~> 1.2.
|
15
|
+
s.add_runtime_dependency 'zookeeper', '~> 1.2.4'
|
16
16
|
s.add_runtime_dependency 'backports', '~> 2.5.1'
|
17
17
|
s.add_runtime_dependency 'logging', '~> 1.7.2'
|
18
18
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 1.5.
|
9
|
+
- 2
|
10
|
+
version: 1.5.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jonathan D. Simms
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2012-05-
|
19
|
+
date: 2012-05-24 00:00:00 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: zookeeper
|
@@ -26,12 +26,12 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 23
|
30
30
|
segments:
|
31
31
|
- 1
|
32
32
|
- 2
|
33
|
-
-
|
34
|
-
version: 1.2.
|
33
|
+
- 4
|
34
|
+
version: 1.2.4
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: *id001
|
37
37
|
- !ruby/object:Gem::Dependency
|
@@ -139,6 +139,8 @@ files:
|
|
139
139
|
- spec/message_queue_spec.rb
|
140
140
|
- spec/shared/client_contexts.rb
|
141
141
|
- spec/shared/client_examples.rb
|
142
|
+
- spec/shared/locker_contexts.rb
|
143
|
+
- spec/shared/locker_examples.rb
|
142
144
|
- spec/spec_helper.rb
|
143
145
|
- spec/support/00_test_port_attr.rb
|
144
146
|
- spec/support/bogus_mongoid.rb
|
@@ -157,7 +159,10 @@ files:
|
|
157
159
|
- spec/zk/client_spec.rb
|
158
160
|
- spec/zk/election_spec.rb
|
159
161
|
- spec/zk/extensions_spec.rb
|
160
|
-
- spec/zk/
|
162
|
+
- spec/zk/locker/exclusive_locker_spec.rb
|
163
|
+
- spec/zk/locker/locker_basic_spec.rb
|
164
|
+
- spec/zk/locker/shared_exclusive_integration_spec.rb
|
165
|
+
- spec/zk/locker/shared_locker_spec.rb
|
161
166
|
- spec/zk/module_spec.rb
|
162
167
|
- spec/zk/mongoid_spec.rb
|
163
168
|
- spec/zk/node_deletion_watcher_spec.rb
|
@@ -210,6 +215,8 @@ test_files:
|
|
210
215
|
- spec/message_queue_spec.rb
|
211
216
|
- spec/shared/client_contexts.rb
|
212
217
|
- spec/shared/client_examples.rb
|
218
|
+
- spec/shared/locker_contexts.rb
|
219
|
+
- spec/shared/locker_examples.rb
|
213
220
|
- spec/spec_helper.rb
|
214
221
|
- spec/support/00_test_port_attr.rb
|
215
222
|
- spec/support/bogus_mongoid.rb
|
@@ -228,7 +235,10 @@ test_files:
|
|
228
235
|
- spec/zk/client_spec.rb
|
229
236
|
- spec/zk/election_spec.rb
|
230
237
|
- spec/zk/extensions_spec.rb
|
231
|
-
- spec/zk/
|
238
|
+
- spec/zk/locker/exclusive_locker_spec.rb
|
239
|
+
- spec/zk/locker/locker_basic_spec.rb
|
240
|
+
- spec/zk/locker/shared_exclusive_integration_spec.rb
|
241
|
+
- spec/zk/locker/shared_locker_spec.rb
|
232
242
|
- spec/zk/module_spec.rb
|
233
243
|
- spec/zk/mongoid_spec.rb
|
234
244
|
- spec/zk/node_deletion_watcher_spec.rb
|
data/spec/zk/locker_spec.rb
DELETED
@@ -1,552 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
# this is a remnant of the old Locker class, but a good test of what's expected
|
4
|
-
# from ZK::Client#locker
|
5
|
-
#
|
6
|
-
describe 'ZK::Client#locker' do
|
7
|
-
include_context 'connection opts'
|
8
|
-
|
9
|
-
before(:each) do
|
10
|
-
@zk = ZK.new("localhost:#{ZK.test_port}", connection_opts)
|
11
|
-
@zk2 = ZK.new("localhost:#{ZK.test_port}", connection_opts)
|
12
|
-
@zk3 = ZK.new("localhost:#{ZK.test_port}", connection_opts)
|
13
|
-
@connections = [@zk, @zk2, @zk3]
|
14
|
-
wait_until { @connections.all? { |c| c.connected? } }
|
15
|
-
logger.debug { "all connections connected" }
|
16
|
-
@path_to_lock = "/lock_tester"
|
17
|
-
end
|
18
|
-
|
19
|
-
after(:each) do
|
20
|
-
@zk.close!
|
21
|
-
@zk2.close!
|
22
|
-
@zk3.close!
|
23
|
-
wait_until { @connections.all? { |c| c.closed? } }
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should be able to acquire the lock if no one else is locking it" do
|
27
|
-
@zk.locker(@path_to_lock).lock.should be_true
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should not be able to acquire the lock if someone else is locking it" do
|
31
|
-
@zk.locker(@path_to_lock).lock.should be_true
|
32
|
-
@zk2.locker(@path_to_lock).lock.should be_false
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should be able to acquire the lock after the first one releases it" do
|
36
|
-
lock1 = @zk.locker(@path_to_lock)
|
37
|
-
lock2 = @zk2.locker(@path_to_lock)
|
38
|
-
|
39
|
-
lock1.lock.should be_true
|
40
|
-
lock2.lock.should be_false
|
41
|
-
lock1.unlock
|
42
|
-
lock2.lock.should be_true
|
43
|
-
end
|
44
|
-
|
45
|
-
it "should be able to acquire the lock if the first locker goes away" do
|
46
|
-
lock1 = @zk.locker(@path_to_lock)
|
47
|
-
lock2 = @zk2.locker(@path_to_lock)
|
48
|
-
|
49
|
-
lock1.lock.should be_true
|
50
|
-
lock2.lock.should be_false
|
51
|
-
@zk.close!
|
52
|
-
lock2.lock.should be_true
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should be able to handle multi part path locks" do
|
56
|
-
@zk.locker("my/multi/part/path").lock.should be_true
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should blocking lock" do
|
60
|
-
array = []
|
61
|
-
first_lock = @zk.locker("mylock")
|
62
|
-
first_lock.lock.should be_true
|
63
|
-
array << :first_lock
|
64
|
-
|
65
|
-
thread = Thread.new do
|
66
|
-
@zk.locker("mylock").with_lock do
|
67
|
-
array << :second_lock
|
68
|
-
end
|
69
|
-
array.length.should == 2
|
70
|
-
end
|
71
|
-
|
72
|
-
array.length.should == 1
|
73
|
-
first_lock.unlock
|
74
|
-
thread.join(10)
|
75
|
-
array.length.should == 2
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
shared_examples_for 'SharedLocker' do
|
81
|
-
let(:shared_locker) { ZK::Locker.shared_locker(zk, path) }
|
82
|
-
let(:shared_locker2) { ZK::Locker.shared_locker(zk2, path) }
|
83
|
-
|
84
|
-
describe :assert! do
|
85
|
-
it %[should raise LockAssertionFailedError if its connection is no longer connected?] do
|
86
|
-
zk.close!
|
87
|
-
lambda { shared_locker.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
|
88
|
-
end
|
89
|
-
|
90
|
-
it %[should raise LockAssertionFailedError if locked? is false] do
|
91
|
-
shared_locker.should_not be_locked
|
92
|
-
lambda { shared_locker.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
|
93
|
-
end
|
94
|
-
|
95
|
-
it %[should raise LockAssertionFailedError lock_path does not exist] do
|
96
|
-
shared_locker.lock
|
97
|
-
lambda { shared_locker.assert! }.should_not raise_error
|
98
|
-
|
99
|
-
zk.delete(shared_locker.lock_path)
|
100
|
-
lambda { shared_locker.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
|
101
|
-
end
|
102
|
-
|
103
|
-
it %[should raise LockAssertionFailedError if there is an exclusive lock with a number lower than ours] do
|
104
|
-
# this should *really* never happen
|
105
|
-
shared_locker.lock.should be_true
|
106
|
-
shl_path = shared_locker.lock_path
|
107
|
-
|
108
|
-
shared_locker2.lock.should be_true
|
109
|
-
|
110
|
-
shared_locker.unlock.should be_true
|
111
|
-
shared_locker.should_not be_locked
|
112
|
-
|
113
|
-
zk.exists?(shl_path).should be_false
|
114
|
-
|
115
|
-
shared_locker2.lock_path.should_not == shl_path
|
116
|
-
|
117
|
-
# convert the first shared lock path into a exclusive one
|
118
|
-
|
119
|
-
exl_path = shl_path.sub(%r%/sh(\d+)\Z%, '/ex\1')
|
120
|
-
|
121
|
-
zk.create(exl_path, :ephemeral => true)
|
122
|
-
|
123
|
-
lambda { shared_locker2.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
describe :acquirable? do
|
128
|
-
describe %[with default options] do
|
129
|
-
it %[should work if the lock root doesn't exist] do
|
130
|
-
zk.rm_rf(ZK::Locker.default_root_lock_node)
|
131
|
-
shared_locker.should be_acquirable
|
132
|
-
end
|
133
|
-
|
134
|
-
it %[should check local state of lockedness] do
|
135
|
-
shared_locker.lock.should be_true
|
136
|
-
shared_locker.should be_acquirable
|
137
|
-
end
|
138
|
-
|
139
|
-
it %[should check if any participants would prevent us from acquiring the lock] do
|
140
|
-
ex_lock = ZK::Locker.exclusive_locker(zk, path)
|
141
|
-
ex_lock.lock.should be_true
|
142
|
-
shared_locker.should_not be_acquirable
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
describe :lock do
|
148
|
-
describe 'non-blocking success' do
|
149
|
-
before do
|
150
|
-
@rval = shared_locker.lock
|
151
|
-
@rval2 = shared_locker2.lock
|
152
|
-
end
|
153
|
-
|
154
|
-
it %[should acquire the first lock] do
|
155
|
-
@rval.should be_true
|
156
|
-
shared_locker.should be_locked
|
157
|
-
end
|
158
|
-
|
159
|
-
it %[should acquire the second lock] do
|
160
|
-
@rval2.should be_true
|
161
|
-
shared_locker2.should be_locked
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
describe 'non-blocking failure' do
|
166
|
-
before do
|
167
|
-
zk.mkdir_p(root_lock_path)
|
168
|
-
@write_lock_path = zk.create("#{root_lock_path}/#{ZK::Locker::EXCLUSIVE_LOCK_PREFIX}", '', :mode => :ephemeral_sequential)
|
169
|
-
@rval = shared_locker.lock
|
170
|
-
end
|
171
|
-
|
172
|
-
it %[should return false] do
|
173
|
-
@rval.should be_false
|
174
|
-
end
|
175
|
-
|
176
|
-
it %[should not be locked] do
|
177
|
-
shared_locker.should_not be_locked
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
describe 'blocking success' do
|
182
|
-
before do
|
183
|
-
zk.mkdir_p(root_lock_path)
|
184
|
-
@write_lock_path = zk.create("#{root_lock_path}/#{ZK::Locker::EXCLUSIVE_LOCK_PREFIX}", '', :mode => :ephemeral_sequential)
|
185
|
-
$stderr.sync = true
|
186
|
-
end
|
187
|
-
|
188
|
-
it %[should acquire the lock after the write lock is released] do
|
189
|
-
ary = []
|
190
|
-
|
191
|
-
shared_locker.lock.should be_false
|
192
|
-
|
193
|
-
th = Thread.new do
|
194
|
-
shared_locker.lock(true)
|
195
|
-
ary << :locked
|
196
|
-
end
|
197
|
-
|
198
|
-
shared_locker.wait_until_blocked(5)
|
199
|
-
shared_locker.should be_waiting
|
200
|
-
shared_locker.should_not be_locked
|
201
|
-
ary.should be_empty
|
202
|
-
|
203
|
-
zk.delete(@write_lock_path)
|
204
|
-
|
205
|
-
th.join(2).should == th
|
206
|
-
|
207
|
-
ary.should_not be_empty
|
208
|
-
ary.length.should == 1
|
209
|
-
|
210
|
-
shared_locker.should be_locked
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end # SharedLocker
|
215
|
-
|
216
|
-
shared_examples_for 'ExclusiveLocker' do
|
217
|
-
let(:ex_locker) { ZK::Locker.exclusive_locker(zk, path) }
|
218
|
-
let(:ex_locker2) { ZK::Locker.exclusive_locker(zk2, path) }
|
219
|
-
|
220
|
-
describe :assert! do
|
221
|
-
it %[should raise LockAssertionFailedError if its connection is no longer connected?] do
|
222
|
-
zk.close!
|
223
|
-
lambda { ex_locker.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
|
224
|
-
end
|
225
|
-
|
226
|
-
it %[should raise LockAssertionFailedError if locked? is false] do
|
227
|
-
ex_locker.should_not be_locked
|
228
|
-
lambda { ex_locker.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
|
229
|
-
end
|
230
|
-
|
231
|
-
it %[should raise LockAssertionFailedError lock_path does not exist] do
|
232
|
-
ex_locker.lock
|
233
|
-
lambda { ex_locker.assert! }.should_not raise_error
|
234
|
-
|
235
|
-
zk.delete(ex_locker.lock_path)
|
236
|
-
lambda { ex_locker.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
|
237
|
-
end
|
238
|
-
|
239
|
-
it %[should raise LockAssertionFailedError if there is an exclusive lock with a number lower than ours] do
|
240
|
-
# this should *really* never happen
|
241
|
-
|
242
|
-
rlp = ex_locker.root_lock_path
|
243
|
-
|
244
|
-
zk.mkdir_p(rlp)
|
245
|
-
|
246
|
-
bogus_path = zk.create("#{rlp}/#{ZK::Locker::EXCLUSIVE_LOCK_PREFIX}", :sequential => true, :ephemeral => true)
|
247
|
-
|
248
|
-
th = Thread.new do
|
249
|
-
ex_locker2.lock(true)
|
250
|
-
end
|
251
|
-
|
252
|
-
logger.debug { "calling wait_until_blocked" }
|
253
|
-
ex_locker2.wait_until_blocked(2)
|
254
|
-
ex_locker2.should be_waiting
|
255
|
-
|
256
|
-
wait_until { zk.exists?(ex_locker2.lock_path) }
|
257
|
-
|
258
|
-
zk.exists?(ex_locker2.lock_path).should be_true
|
259
|
-
|
260
|
-
zk.delete(bogus_path)
|
261
|
-
|
262
|
-
th.join(5).should == th
|
263
|
-
|
264
|
-
ex_locker2.lock_path.should_not == bogus_path
|
265
|
-
|
266
|
-
zk.create(bogus_path, :ephemeral => true)
|
267
|
-
|
268
|
-
lambda { ex_locker2.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
describe :acquirable? do
|
273
|
-
it %[should work if the lock root doesn't exist] do
|
274
|
-
zk.rm_rf(ZK::Locker.default_root_lock_node)
|
275
|
-
ex_locker.should be_acquirable
|
276
|
-
end
|
277
|
-
|
278
|
-
it %[should check local state of lockedness] do
|
279
|
-
ex_locker.lock.should be_true
|
280
|
-
ex_locker.should be_acquirable
|
281
|
-
end
|
282
|
-
|
283
|
-
it %[should check if any participants would prevent us from acquiring the lock] do
|
284
|
-
ex_locker.lock.should be_true
|
285
|
-
ex_locker2.should_not be_acquirable
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
describe :lock do
|
290
|
-
describe 'non-blocking' do
|
291
|
-
before do
|
292
|
-
@rval = ex_locker.lock
|
293
|
-
@rval2 = ex_locker2.lock
|
294
|
-
end
|
295
|
-
|
296
|
-
it %[should acquire the first lock] do
|
297
|
-
@rval.should be_true
|
298
|
-
end
|
299
|
-
|
300
|
-
it %[should not acquire the second lock] do
|
301
|
-
@rval2.should be_false
|
302
|
-
end
|
303
|
-
|
304
|
-
it %[should acquire the second lock after the first lock is released] do
|
305
|
-
ex_locker.unlock.should be_true
|
306
|
-
ex_locker2.lock.should be_true
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
describe 'blocking' do
|
311
|
-
before do
|
312
|
-
zk.mkdir_p(root_lock_path)
|
313
|
-
end
|
314
|
-
|
315
|
-
it %[should block waiting for the lock] do
|
316
|
-
ary = []
|
317
|
-
read_lock_path = zk.create('/_zklocking/shlock/read', '', :mode => :ephemeral_sequential)
|
318
|
-
|
319
|
-
ex_locker.lock.should be_false
|
320
|
-
|
321
|
-
th = Thread.new do
|
322
|
-
ex_locker.lock(true)
|
323
|
-
ary << :locked
|
324
|
-
end
|
325
|
-
|
326
|
-
ex_locker.wait_until_blocked(5)
|
327
|
-
|
328
|
-
ary.should be_empty
|
329
|
-
ex_locker.should_not be_locked
|
330
|
-
|
331
|
-
zk.delete(read_lock_path)
|
332
|
-
|
333
|
-
th.join(2).should == th
|
334
|
-
|
335
|
-
ary.length.should == 1
|
336
|
-
ex_locker.should be_locked
|
337
|
-
end
|
338
|
-
end # blocking
|
339
|
-
end # lock
|
340
|
-
end # ExclusiveLocker
|
341
|
-
|
342
|
-
shared_examples_for 'shared-exclusive interaction' do
|
343
|
-
before do
|
344
|
-
@sh_lock = ZK::Locker.shared_locker(zk, path)
|
345
|
-
@ex_lock = ZK::Locker.exclusive_locker(zk2, path)
|
346
|
-
end
|
347
|
-
|
348
|
-
describe 'shared lock acquired first' do
|
349
|
-
it %[should block exclusive locks from acquiring until released] do
|
350
|
-
@sh_lock.lock.should be_true
|
351
|
-
@ex_lock.lock.should be_false
|
352
|
-
|
353
|
-
mutex = Monitor.new
|
354
|
-
cond = mutex.new_cond
|
355
|
-
|
356
|
-
th = Thread.new do
|
357
|
-
logger.debug { "@ex_lock trying to acquire acquire lock" }
|
358
|
-
@ex_lock.with_lock do
|
359
|
-
th[:got_lock] = @ex_lock.locked?
|
360
|
-
logger.debug { "@ex_lock.locked? #{@ex_lock.locked?}" }
|
361
|
-
|
362
|
-
mutex.synchronize do
|
363
|
-
cond.broadcast
|
364
|
-
end
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
|
-
mutex.synchronize do
|
369
|
-
logger.debug { "unlocking the shared lock" }
|
370
|
-
@sh_lock.unlock.should be_true
|
371
|
-
cond.wait_until { th[:got_lock] } # make sure they actually received the lock (avoid race)
|
372
|
-
th[:got_lock].should be_true
|
373
|
-
logger.debug { "ok, they got the lock" }
|
374
|
-
end
|
375
|
-
|
376
|
-
th.join(5).should == th
|
377
|
-
|
378
|
-
logger.debug { "thread joined, exclusive lock should be releasd" }
|
379
|
-
|
380
|
-
@ex_lock.should_not be_locked
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
describe 'exclusive lock acquired first' do
|
385
|
-
it %[should block shared lock from acquiring until released] do
|
386
|
-
@ex_lock.lock.should be_true
|
387
|
-
@sh_lock.lock.should be_false
|
388
|
-
|
389
|
-
mutex = Monitor.new
|
390
|
-
cond = mutex.new_cond
|
391
|
-
|
392
|
-
th = Thread.new do
|
393
|
-
logger.debug { "@ex_lock trying to acquire acquire lock" }
|
394
|
-
@sh_lock.with_lock do
|
395
|
-
th[:got_lock] = @sh_lock.locked?
|
396
|
-
logger.debug { "@sh_lock.locked? #{@sh_lock.locked?}" }
|
397
|
-
|
398
|
-
mutex.synchronize do
|
399
|
-
cond.broadcast
|
400
|
-
end
|
401
|
-
end
|
402
|
-
end
|
403
|
-
|
404
|
-
mutex.synchronize do
|
405
|
-
logger.debug { "unlocking the shared lock" }
|
406
|
-
@ex_lock.unlock.should be_true
|
407
|
-
cond.wait_until { th[:got_lock] } # make sure they actually received the lock (avoid race)
|
408
|
-
th[:got_lock].should be_true
|
409
|
-
logger.debug { "ok, they got the lock" }
|
410
|
-
end
|
411
|
-
|
412
|
-
th.join(5).should == th
|
413
|
-
|
414
|
-
logger.debug { "thread joined, exclusive lock should be releasd" }
|
415
|
-
|
416
|
-
@sh_lock.should_not be_locked
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
describe 'shared-exclusive-shared' do
|
421
|
-
before do
|
422
|
-
zk3.should_not be_nil
|
423
|
-
@sh_lock2 = ZK::Locker.shared_locker(zk3, path)
|
424
|
-
end
|
425
|
-
|
426
|
-
it %[should act something like a queue] do
|
427
|
-
@array = []
|
428
|
-
|
429
|
-
@sh_lock.lock.should be_true
|
430
|
-
@sh_lock.should be_locked
|
431
|
-
|
432
|
-
ex_th = Thread.new do
|
433
|
-
begin
|
434
|
-
@ex_lock.lock(true) # blocking lock
|
435
|
-
@ex_lock.assert!
|
436
|
-
@array << :ex_lock
|
437
|
-
ensure
|
438
|
-
@ex_lock.unlock
|
439
|
-
end
|
440
|
-
end
|
441
|
-
|
442
|
-
logger.debug { "about to wait for @ex_lock to be blocked" }
|
443
|
-
|
444
|
-
@ex_lock.wait_until_blocked(5)
|
445
|
-
@ex_lock.should be_waiting
|
446
|
-
|
447
|
-
logger.debug { "@ex_lock is waiting" }
|
448
|
-
|
449
|
-
@ex_lock.should_not be_locked
|
450
|
-
|
451
|
-
# this is the important one, does the second shared lock get blocked by
|
452
|
-
# the exclusive lock
|
453
|
-
@sh_lock2.lock.should_not be_true
|
454
|
-
|
455
|
-
sh2_th = Thread.new do
|
456
|
-
begin
|
457
|
-
@sh_lock2.lock(true)
|
458
|
-
@sh_lock2.assert!
|
459
|
-
@array << :sh_lock2
|
460
|
-
ensure
|
461
|
-
@sh_lock2.unlock
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
logger.debug { "about to wait for @sh_lock2 to be blocked" }
|
466
|
-
|
467
|
-
@sh_lock2.wait_until_blocked(5)
|
468
|
-
@sh_lock2.should be_waiting
|
469
|
-
|
470
|
-
logger.debug { "@sh_lock2 is waiting" }
|
471
|
-
|
472
|
-
# ok, now unlock the first in the chain
|
473
|
-
@sh_lock.assert!
|
474
|
-
@sh_lock.unlock.should be_true
|
475
|
-
|
476
|
-
ex_th.join(5).should == ex_th
|
477
|
-
sh2_th.join(5).should == sh2_th
|
478
|
-
|
479
|
-
@array.length.should == 2
|
480
|
-
@array.should == [:ex_lock, :sh_lock2]
|
481
|
-
end
|
482
|
-
end
|
483
|
-
end # shared-exclusive interaction
|
484
|
-
|
485
|
-
describe ZK::Locker do
|
486
|
-
include_context 'connection opts'
|
487
|
-
|
488
|
-
let(:zk) { ZK.new("localhost:#{ZK.test_port}", connection_opts) }
|
489
|
-
let(:zk2) { ZK.new("localhost:#{ZK.test_port}", connection_opts) }
|
490
|
-
let(:zk3) { ZK.new("localhost:#{ZK.test_port}", connection_opts) }
|
491
|
-
|
492
|
-
let(:connections) { [zk, zk2, zk3] }
|
493
|
-
|
494
|
-
let(:path) { "shlock" }
|
495
|
-
let(:root_lock_path) { "#{ZK::Locker.default_root_lock_node}/#{path}" }
|
496
|
-
|
497
|
-
before do
|
498
|
-
wait_until{ connections.all?(&:connected?) }
|
499
|
-
zk.rm_rf(ZK::Locker.default_root_lock_node)
|
500
|
-
end
|
501
|
-
|
502
|
-
after do
|
503
|
-
connections.each { |c| c.close! }
|
504
|
-
wait_until { !connections.any?(&:connected?) }
|
505
|
-
ZK.open("localhost:#{ZK.test_port}") { |z| z.rm_rf(ZK::Locker.default_root_lock_node) }
|
506
|
-
end
|
507
|
-
|
508
|
-
it_should_behave_like 'SharedLocker'
|
509
|
-
it_should_behave_like 'ExclusiveLocker'
|
510
|
-
it_should_behave_like 'shared-exclusive interaction'
|
511
|
-
end # ZK::Locker
|
512
|
-
|
513
|
-
describe ZK::Locker, :chrooted => true do
|
514
|
-
include_context 'connection opts'
|
515
|
-
|
516
|
-
let(:chroot_path) { '/_zk_chroot_' }
|
517
|
-
|
518
|
-
let(:zk) { ZK.new("localhost:#{ZK.test_port}#{chroot_path}", connection_opts) }
|
519
|
-
|
520
|
-
describe 'when the chroot exists' do
|
521
|
-
let(:zk2) { ZK.new("localhost:#{ZK.test_port}#{chroot_path}", connection_opts) }
|
522
|
-
let(:zk3) { ZK.new("localhost:#{ZK.test_port}#{chroot_path}", connection_opts) }
|
523
|
-
|
524
|
-
let(:connections) { [zk, zk2, zk3] }
|
525
|
-
|
526
|
-
let(:path) { "shlock" }
|
527
|
-
let(:root_lock_path) { "#{ZK::Locker.default_root_lock_node}/#{path}" }
|
528
|
-
|
529
|
-
before do
|
530
|
-
ZK.open("localhost:#{ZK.test_port}") do |zk|
|
531
|
-
zk.mkdir_p(chroot_path)
|
532
|
-
end
|
533
|
-
|
534
|
-
wait_until{ connections.all?(&:connected?) }
|
535
|
-
end
|
536
|
-
|
537
|
-
after do
|
538
|
-
connections.each { |c| c.close! }
|
539
|
-
wait_until { !connections.any?(&:connected?) }
|
540
|
-
|
541
|
-
ZK.open("localhost:#{ZK.test_port}") do |zk|
|
542
|
-
zk.rm_rf(chroot_path)
|
543
|
-
end
|
544
|
-
end
|
545
|
-
|
546
|
-
it_should_behave_like 'SharedLocker'
|
547
|
-
it_should_behave_like 'ExclusiveLocker'
|
548
|
-
it_should_behave_like 'shared-exclusive interaction'
|
549
|
-
end
|
550
|
-
end
|
551
|
-
|
552
|
-
|