zk 1.9.6 → 1.10.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 (40) hide show
  1. checksums.yaml +5 -13
  2. data/.github/workflows/build.yml +55 -0
  3. data/Gemfile +15 -6
  4. data/README.markdown +9 -9
  5. data/RELEASES.markdown +10 -1
  6. data/lib/zk/client.rb +1 -1
  7. data/lib/zk/event_handler.rb +15 -7
  8. data/lib/zk/fork_hook.rb +2 -2
  9. data/lib/zk/locker/locker_base.rb +13 -0
  10. data/lib/zk/locker/semaphore.rb +1 -3
  11. data/lib/zk/node_deletion_watcher.rb +3 -4
  12. data/lib/zk/pool.rb +11 -11
  13. data/lib/zk/version.rb +1 -1
  14. data/spec/event_catcher_spec.rb +1 -1
  15. data/spec/message_queue_spec.rb +6 -6
  16. data/spec/shared/client_examples.rb +81 -81
  17. data/spec/shared/locker_examples.rb +13 -13
  18. data/spec/spec_helper.rb +10 -11
  19. data/spec/zk/00_forked_client_integration_spec.rb +3 -3
  20. data/spec/zk/client/locking_and_session_death_spec.rb +2 -2
  21. data/spec/zk/client_spec.rb +19 -19
  22. data/spec/zk/election_spec.rb +44 -44
  23. data/spec/zk/extensions_spec.rb +2 -2
  24. data/spec/zk/locker/exclusive_locker_spec.rb +41 -41
  25. data/spec/zk/locker/locker_basic_spec.rb +55 -33
  26. data/spec/zk/locker/semaphore_spec.rb +39 -32
  27. data/spec/zk/locker/shared_exclusive_integration_spec.rb +37 -37
  28. data/spec/zk/locker/shared_locker_spec.rb +43 -43
  29. data/spec/zk/locker_spec.rb +2 -2
  30. data/spec/zk/module_spec.rb +25 -25
  31. data/spec/zk/mongoid_spec.rb +47 -47
  32. data/spec/zk/node_deletion_watcher_spec.rb +39 -31
  33. data/spec/zk/pool_spec.rb +56 -65
  34. data/spec/zk/threaded_callback_spec.rb +10 -10
  35. data/spec/zk/threadpool_spec.rb +25 -25
  36. data/spec/zk/watch_spec.rb +67 -79
  37. data/spec/zk/zookeeper_spec.rb +31 -31
  38. data/zk.gemspec +1 -1
  39. metadata +23 -24
  40. data/.travis.yml +0 -30
@@ -20,47 +20,47 @@ describe 'ZK::Client#locker' do
20
20
  @zk.close!
21
21
  @zk2.close!
22
22
  @zk3.close!
23
- wait_until { @connections.all? { |c| c.closed? } }
23
+ wait_until { @connections.all? { |c| c.closed? } }
24
24
  end
25
25
 
26
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
27
+ expect(@zk.locker(@path_to_lock).lock).to be(true)
28
28
  end
29
29
 
30
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
31
+ expect(@zk.locker(@path_to_lock).lock).to be(true)
32
+ expect(@zk2.locker(@path_to_lock).lock).to be(false)
33
33
  end
34
34
 
35
35
  it "should assert properly if lock is acquired" do
36
- @zk.locker(@path_to_lock).assert.should be_false
36
+ expect(@zk.locker(@path_to_lock).assert).to be(false)
37
37
  l = @zk2.locker(@path_to_lock)
38
- l.lock.should be_true
39
- l.assert.should be_true
38
+ expect(l.lock).to be(true)
39
+ expect(l.assert).to be(true)
40
40
  end
41
41
 
42
42
  it "should be able to acquire the lock after the first one releases it" do
43
43
  lock1 = @zk.locker(@path_to_lock)
44
44
  lock2 = @zk2.locker(@path_to_lock)
45
-
46
- lock1.lock.should be_true
47
- lock2.lock.should be_false
45
+
46
+ expect(lock1.lock).to be(true)
47
+ expect(lock2.lock).to be(false)
48
48
  lock1.unlock
49
- lock2.lock.should be_true
49
+ expect(lock2.lock).to be(true)
50
50
  end
51
51
 
52
52
  it "should be able to acquire the lock if the first locker goes away" do
53
53
  lock1 = @zk.locker(@path_to_lock)
54
54
  lock2 = @zk2.locker(@path_to_lock)
55
55
 
56
- lock1.lock.should be_true
57
- lock2.lock.should be_false
56
+ expect(lock1.lock).to be(true)
57
+ expect(lock2.lock).to be(false)
58
58
  @zk.close!
59
- lock2.lock.should be_true
59
+ expect(lock2.lock).to be(true)
60
60
  end
61
61
 
62
62
  it "should be able to handle multi part path locks" do
63
- @zk.locker("my/multi/part/path").lock.should be_true
63
+ expect(@zk.locker("my/multi/part/path").lock).to be(true)
64
64
  end
65
65
 
66
66
  describe :with_lock do
@@ -70,23 +70,23 @@ describe 'ZK::Client#locker' do
70
70
  describe 'Client::Conveniences' do
71
71
  it %[should yield the lock instance to the block] do
72
72
  @zk.with_lock(@path_to_lock) do |lock|
73
- lock.should_not be_nil
74
- lock.should be_kind_of(ZK::Locker::LockerBase)
75
- lambda { lock.assert! }.should_not raise_error
73
+ expect(lock).not_to be_nil
74
+ expect(lock).to be_kind_of(ZK::Locker::LockerBase)
75
+ expect { lock.assert! }.not_to raise_error
76
76
  end
77
77
  end
78
78
 
79
79
  it %[should yield a shared lock when :mode => shared given] do
80
80
  @zk.with_lock(@path_to_lock, :mode => :shared) do |lock|
81
- lock.should_not be_nil
82
- lock.should be_kind_of(ZK::Locker::SharedLocker)
83
- lambda { lock.assert! }.should_not raise_error
81
+ expect(lock).not_to be_nil
82
+ expect(lock).to be_kind_of(ZK::Locker::SharedLocker)
83
+ expect { lock.assert! }.not_to raise_error
84
84
  end
85
85
  end
86
86
 
87
87
  it %[should take a timeout] do
88
88
  first_lock = @zk.locker(@path_to_lock)
89
- first_lock.lock.should be_true
89
+ expect(first_lock.lock).to be(true)
90
90
 
91
91
  thread = Thread.new do
92
92
  begin
@@ -98,8 +98,8 @@ describe 'ZK::Client#locker' do
98
98
  end
99
99
  end
100
100
 
101
- thread.join(2).should == thread
102
- @exc.should be_kind_of(ZK::Exceptions::LockWaitTimeoutError)
101
+ expect(thread.join(2)).to eq(thread)
102
+ expect(@exc).to be_kind_of(ZK::Exceptions::LockWaitTimeoutError)
103
103
  end
104
104
  end
105
105
 
@@ -107,26 +107,26 @@ describe 'ZK::Client#locker' do
107
107
  it "should blocking lock" do
108
108
  array = []
109
109
  first_lock = @zk.locker("mylock")
110
- first_lock.lock.should be_true
110
+ expect(first_lock.lock).to be(true)
111
111
  array << :first_lock
112
112
 
113
113
  thread = Thread.new do
114
114
  @zk.locker("mylock").with_lock do
115
115
  array << :second_lock
116
116
  end
117
- array.length.should == 2
117
+ expect(array.length).to eq(2)
118
118
  end
119
119
 
120
- array.length.should == 1
120
+ expect(array.length).to eq(1)
121
121
  first_lock.unlock
122
122
  thread.join(10)
123
- array.length.should == 2
123
+ expect(array.length).to eq(2)
124
124
  end
125
125
 
126
126
  it %[should accept a :wait option] do
127
127
  array = []
128
128
  first_lock = @zk.locker("mylock")
129
- first_lock.lock.should be_true
129
+ expect(first_lock.lock).to be(true)
130
130
 
131
131
  second_lock = @zk.locker("mylock")
132
132
 
@@ -140,10 +140,32 @@ describe 'ZK::Client#locker' do
140
140
  end
141
141
  end
142
142
 
143
- array.should be_empty
144
- thread.join(2).should == thread
145
- @exc.should_not be_nil
146
- @exc.should be_kind_of(ZK::Exceptions::LockWaitTimeoutError)
143
+ expect(array).to be_empty
144
+ expect(thread.join(2)).to eq(thread)
145
+ expect(@exc).not_to be_nil
146
+ expect(@exc).to be_kind_of(ZK::Exceptions::LockWaitTimeoutError)
147
+ end
148
+
149
+ it "should interrupt a blocked lock" do
150
+ first_lock = @zk.locker("mylock")
151
+ expect(first_lock.lock).to be(true)
152
+
153
+ second_lock = @zk.locker("mylock")
154
+ thread = Thread.new do
155
+ begin
156
+ second_lock.with_lock do
157
+ raise "NO NO NO!! should not have called the block!!"
158
+ end
159
+ rescue Exception => e
160
+ @exc = e
161
+ end
162
+ end
163
+
164
+ Thread.pass until second_lock.waiting?
165
+
166
+ second_lock.interrupt!
167
+ thread.join(2)
168
+ expect(@exc).to be_kind_of(ZK::Exceptions::WakeUpException)
147
169
  end
148
170
  end
149
171
  end # with_lock
@@ -10,25 +10,32 @@ shared_examples_for 'ZK::Locker::Semaphore' do
10
10
  it_should_behave_like 'LockerBase#assert!'
11
11
  end
12
12
 
13
+ context %[invalid semaphore_size] do
14
+ let(:semaphore_size) { :boom }
15
+ it 'should raise' do
16
+ expect{ locker }.to raise_error(ZK::Exceptions::BadArguments)
17
+ end
18
+ end
19
+
13
20
  describe :acquirable? do
14
21
  describe %[with default options] do
15
22
  it %[should work if the lock root doesn't exist] do
16
23
  zk.rm_rf(ZK::Locker::Semaphore.default_root_node)
17
- locker.should be_acquirable
24
+ expect(locker).to be_acquirable
18
25
  end
19
26
 
20
27
  it %[should check local state of lockedness] do
21
- locker.lock.should be_true
22
- locker.should be_acquirable
28
+ expect(locker.lock).to be(true)
29
+ expect(locker).to be_acquirable
23
30
  end
24
31
 
25
32
  it %[should check if any participants would prevent us from acquiring the lock] do
26
- locker3.lock.should be_true
27
- locker.should be_acquirable # total locks given less than semaphore_size
28
- locker2.lock.should be_true
29
- locker.should_not be_acquirable # total locks given equal to semaphore size
33
+ expect(locker3.lock).to be(true)
34
+ expect(locker).to be_acquirable # total locks given less than semaphore_size
35
+ expect(locker2.lock).to be(true)
36
+ expect(locker).not_to be_acquirable # total locks given equal to semaphore size
30
37
  locker3.unlock
31
- locker.should be_acquirable # total locks given less than semaphore_size
38
+ expect(locker).to be_acquirable # total locks given less than semaphore_size
32
39
  end
33
40
  end
34
41
  end
@@ -41,13 +48,13 @@ shared_examples_for 'ZK::Locker::Semaphore' do
41
48
  end
42
49
 
43
50
  it %[should acquire the first lock] do
44
- @rval.should be_true
45
- locker.should be_locked
51
+ expect(@rval).to be(true)
52
+ expect(locker).to be_locked
46
53
  end
47
54
 
48
55
  it %[should acquire the second lock] do
49
- @rval2.should be_true
50
- locker2.should be_locked
56
+ expect(@rval2).to be(true)
57
+ expect(locker2).to be_locked
51
58
  end
52
59
  end
53
60
 
@@ -61,15 +68,15 @@ shared_examples_for 'ZK::Locker::Semaphore' do
61
68
  end
62
69
 
63
70
  it %[should return false] do
64
- @rval.should be_false
71
+ expect(@rval).to be(false)
65
72
  end
66
73
 
67
74
  it %[should not be locked] do
68
- locker.should_not be_locked
75
+ expect(locker).not_to be_locked
69
76
  end
70
77
 
71
78
  it %[should not have a lock_path] do
72
- locker.lock_path.should be_nil
79
+ expect(locker.lock_path).to be_nil
73
80
  end
74
81
  end
75
82
 
@@ -87,7 +94,7 @@ shared_examples_for 'ZK::Locker::Semaphore' do
87
94
  it %[should acquire the lock after the write lock is released] do
88
95
  ary = []
89
96
 
90
- locker.lock.should be_false
97
+ expect(locker.lock).to be(false)
91
98
 
92
99
  th = Thread.new do
93
100
  locker.lock(:wait => true)
@@ -95,18 +102,18 @@ shared_examples_for 'ZK::Locker::Semaphore' do
95
102
  end
96
103
 
97
104
  locker.wait_until_blocked(5)
98
- locker.should be_waiting
99
- locker.should_not be_locked
100
- ary.should be_empty
105
+ expect(locker).to be_waiting
106
+ expect(locker).not_to be_locked
107
+ expect(ary).to be_empty
101
108
 
102
109
  zk.delete(@existing_locks.shuffle.first)
103
110
 
104
- th.join(2).should == th
111
+ expect(th.join(2)).to eq(th)
105
112
 
106
- ary.should_not be_empty
107
- ary.length.should == 1
113
+ expect(ary).not_to be_empty
114
+ expect(ary.length).to eq(1)
108
115
 
109
- locker.should be_locked
116
+ expect(locker).to be_locked
110
117
  end
111
118
  end
112
119
 
@@ -116,9 +123,9 @@ shared_examples_for 'ZK::Locker::Semaphore' do
116
123
 
117
124
  write_lock_dir = File.dirname(@existing_locks.first)
118
125
 
119
- zk.children(write_lock_dir).length.should == semaphore_size
126
+ expect(zk.children(write_lock_dir).length).to eq(semaphore_size)
120
127
 
121
- locker.lock.should be_false
128
+ expect(locker.lock).to be(false)
122
129
 
123
130
  th = Thread.new do
124
131
  begin
@@ -130,16 +137,16 @@ shared_examples_for 'ZK::Locker::Semaphore' do
130
137
  end
131
138
 
132
139
  locker.wait_until_blocked(5)
133
- locker.should be_waiting
134
- locker.should_not be_locked
135
- ary.should be_empty
140
+ expect(locker).to be_waiting
141
+ expect(locker).not_to be_locked
142
+ expect(ary).to be_empty
136
143
 
137
- th.join(2).should == th
144
+ expect(th.join(2)).to eq(th)
138
145
 
139
- zk.children(write_lock_dir).length.should == semaphore_size
146
+ expect(zk.children(write_lock_dir).length).to eq(semaphore_size)
140
147
 
141
- ary.should be_empty
142
- @exc.should be_kind_of(ZK::Exceptions::LockWaitTimeoutError)
148
+ expect(ary).to be_empty
149
+ expect(@exc).to be_kind_of(ZK::Exceptions::LockWaitTimeoutError)
143
150
  end
144
151
 
145
152
  end
@@ -8,12 +8,12 @@ shared_examples_for :shared_exclusive_integration do
8
8
 
9
9
  describe 'shared lock acquired first' do
10
10
  it %[should block exclusive locks from acquiring until released] do
11
- @sh_lock.lock.should be_true
12
- @ex_lock.lock.should be_false
11
+ expect(@sh_lock.lock).to be(true)
12
+ expect(@ex_lock.lock).to be(false)
13
13
 
14
14
  mutex = Monitor.new
15
15
  cond = mutex.new_cond
16
-
16
+
17
17
  th = Thread.new do
18
18
  logger.debug { "@ex_lock trying to acquire acquire lock" }
19
19
  @ex_lock.with_lock do
@@ -28,29 +28,29 @@ shared_examples_for :shared_exclusive_integration do
28
28
 
29
29
  mutex.synchronize do
30
30
  logger.debug { "unlocking the shared lock" }
31
- @sh_lock.unlock.should be_true
31
+ expect(@sh_lock.unlock).to be(true)
32
32
  cond.wait_until { th[:got_lock] } # make sure they actually received the lock (avoid race)
33
- th[:got_lock].should be_true
33
+ expect(th[:got_lock]).to be(true)
34
34
  logger.debug { "ok, they got the lock" }
35
35
  end
36
36
 
37
- th.join(5).should == th
37
+ expect(th.join(5)).to eq(th)
38
38
 
39
39
  logger.debug { "thread joined, exclusive lock should be releasd" }
40
40
 
41
- @ex_lock.should_not be_locked
41
+ expect(@ex_lock).not_to be_locked
42
42
  end
43
43
  end
44
44
 
45
45
  describe 'multiple shared locks acquired first' do
46
46
  before do
47
- zk3.should_not be_nil
48
- @sh_lock2 = ZK::Locker.shared_locker(zk3, path)
47
+ expect(zk3).not_to be_nil
48
+ @sh_lock2 = ZK::Locker.shared_locker(zk3, path)
49
49
  end
50
50
  it %[should not aquire a lock when highest-numbered released but others remain] do
51
- @sh_lock.lock.should be_true
52
- @sh_lock2.lock.should be_true
53
- @ex_lock.lock.should be_false
51
+ expect(@sh_lock.lock).to be(true)
52
+ expect(@sh_lock2.lock).to be(true)
53
+ expect(@ex_lock.lock).to be(false)
54
54
 
55
55
  mutex = Monitor.new
56
56
  cond = mutex.new_cond
@@ -75,28 +75,28 @@ shared_examples_for :shared_exclusive_integration do
75
75
  mutex.synchronize do
76
76
  @ex_lock.wait_until_blocked(1)
77
77
  logger.debug { "unlocking the highest shared lock" }
78
- @sh_lock2.unlock.should be_true
78
+ expect(@sh_lock2.unlock).to be(true)
79
79
  cond.wait_until { (!th[:got_lock].nil?) } # make sure they actually received the lock (avoid race)
80
- th[:got_lock].should be_false
80
+ expect(th[:got_lock]).to be(false)
81
81
  logger.debug { "they didn't get the lock." }
82
82
  end
83
83
 
84
- th.join(5).should == th
84
+ expect(th.join(5)).to eq(th)
85
85
 
86
86
  logger.debug { "thread joined, exclusive lock should be releasd" }
87
- @sh_lock.unlock.should be_true
88
- @ex_lock.should_not be_locked
87
+ expect(@sh_lock.unlock).to be(true)
88
+ expect(@ex_lock).not_to be_locked
89
89
  end
90
90
  end
91
91
 
92
92
  describe 'exclusive lock acquired first' do
93
93
  it %[should block shared lock from acquiring until released] do
94
- @ex_lock.lock.should be_true
95
- @sh_lock.lock.should be_false
94
+ expect(@ex_lock.lock).to be(true)
95
+ expect(@sh_lock.lock).to be(false)
96
96
 
97
97
  mutex = Monitor.new
98
98
  cond = mutex.new_cond
99
-
99
+
100
100
  th = Thread.new do
101
101
  logger.debug { "@ex_lock trying to acquire acquire lock" }
102
102
  @sh_lock.with_lock do
@@ -111,31 +111,31 @@ shared_examples_for :shared_exclusive_integration do
111
111
 
112
112
  mutex.synchronize do
113
113
  logger.debug { "unlocking the shared lock" }
114
- @ex_lock.unlock.should be_true
114
+ expect(@ex_lock.unlock).to be(true)
115
115
  cond.wait_until { th[:got_lock] } # make sure they actually received the lock (avoid race)
116
- th[:got_lock].should be_true
116
+ expect(th[:got_lock]).to be(true)
117
117
  logger.debug { "ok, they got the lock" }
118
118
  end
119
119
 
120
- th.join(5).should == th
120
+ expect(th.join(5)).to eq(th)
121
121
 
122
122
  logger.debug { "thread joined, exclusive lock should be releasd" }
123
123
 
124
- @sh_lock.should_not be_locked
124
+ expect(@sh_lock).not_to be_locked
125
125
  end
126
126
  end
127
127
 
128
128
  describe 'shared-exclusive-shared' do
129
129
  before do
130
- zk3.should_not be_nil
131
- @sh_lock2 = ZK::Locker.shared_locker(zk3, path)
130
+ expect(zk3).not_to be_nil
131
+ @sh_lock2 = ZK::Locker.shared_locker(zk3, path)
132
132
  end
133
133
 
134
134
  it %[should act something like a queue] do
135
135
  @array = []
136
136
 
137
- @sh_lock.lock.should be_true
138
- @sh_lock.should be_locked
137
+ expect(@sh_lock.lock).to be(true)
138
+ expect(@sh_lock).to be_locked
139
139
 
140
140
  ex_th = Thread.new do
141
141
  begin
@@ -150,15 +150,15 @@ shared_examples_for :shared_exclusive_integration do
150
150
  logger.debug { "about to wait for @ex_lock to be blocked" }
151
151
 
152
152
  @ex_lock.wait_until_blocked(5)
153
- @ex_lock.should be_waiting
153
+ expect(@ex_lock).to be_waiting
154
154
 
155
155
  logger.debug { "@ex_lock is waiting" }
156
156
 
157
- @ex_lock.should_not be_locked
157
+ expect(@ex_lock).not_to be_locked
158
158
 
159
159
  # this is the important one, does the second shared lock get blocked by
160
160
  # the exclusive lock
161
- @sh_lock2.lock.should_not be_true
161
+ expect(@sh_lock2.lock).not_to be(true)
162
162
 
163
163
  sh2_th = Thread.new do
164
164
  begin
@@ -173,19 +173,19 @@ shared_examples_for :shared_exclusive_integration do
173
173
  logger.debug { "about to wait for @sh_lock2 to be blocked" }
174
174
 
175
175
  @sh_lock2.wait_until_blocked(5)
176
- @sh_lock2.should be_waiting
176
+ expect(@sh_lock2).to be_waiting
177
177
 
178
178
  logger.debug { "@sh_lock2 is waiting" }
179
179
 
180
180
  # ok, now unlock the first in the chain
181
181
  @sh_lock.assert!
182
- @sh_lock.unlock.should be_true
182
+ expect(@sh_lock.unlock).to be(true)
183
183
 
184
- ex_th.join(5).should == ex_th
185
- sh2_th.join(5).should == sh2_th
184
+ expect(ex_th.join(5)).to eq(ex_th)
185
+ expect(sh2_th.join(5)).to eq(sh2_th)
186
186
 
187
- @array.length.should == 2
188
- @array.should == [:ex_lock, :sh_lock2]
187
+ expect(@array.length).to eq(2)
188
+ expect(@array).to eq([:ex_lock, :sh_lock2])
189
189
  end
190
190
  end
191
191
  end # shared_exclusive_integration