zk 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'ZK::Locker::ExclusiveLocker' do
4
+ let(:locker) { ZK::Locker.exclusive_locker(zk, path) }
5
+ let(:locker2) { ZK::Locker.exclusive_locker(zk2, path) }
6
+
7
+ describe :assert! do
8
+ it_should_behave_like 'LockerBase#assert!'
9
+
10
+ it %[should raise LockAssertionFailedError if there is an exclusive lock with a number lower than ours] do
11
+ # this should *really* never happen
12
+
13
+ rlp = locker.root_lock_path
14
+
15
+ zk.mkdir_p(rlp)
16
+
17
+ bogus_path = zk.create("#{rlp}/#{ZK::Locker::EXCLUSIVE_LOCK_PREFIX}", :sequential => true, :ephemeral => true)
18
+
19
+ th = Thread.new do
20
+ locker2.lock(true)
21
+ end
22
+
23
+ logger.debug { "calling wait_until_blocked" }
24
+ locker2.wait_until_blocked(2)
25
+ locker2.should be_waiting
26
+
27
+ wait_until { zk.exists?(locker2.lock_path) }
28
+
29
+ zk.exists?(locker2.lock_path).should be_true
30
+
31
+ zk.delete(bogus_path)
32
+
33
+ th.join(5).should == th
34
+
35
+ locker2.lock_path.should_not == bogus_path
36
+
37
+ zk.create(bogus_path, :ephemeral => true)
38
+
39
+ lambda { locker2.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
40
+ end
41
+ end
42
+
43
+ describe :acquirable? do
44
+ it %[should work if the lock root doesn't exist] do
45
+ zk.rm_rf(ZK::Locker.default_root_lock_node)
46
+ locker.should be_acquirable
47
+ end
48
+
49
+ it %[should check local state of lockedness] do
50
+ locker.lock.should be_true
51
+ locker.should be_acquirable
52
+ end
53
+
54
+ it %[should check if any participants would prevent us from acquiring the lock] do
55
+ locker.lock.should be_true
56
+ locker2.should_not be_acquirable
57
+ end
58
+ end
59
+
60
+ describe :lock do
61
+ describe 'non-blocking' do
62
+ before do
63
+ @rval = locker.lock
64
+ @rval2 = locker2.lock
65
+ end
66
+
67
+ it %[should acquire the first lock] do
68
+ @rval.should be_true
69
+ end
70
+
71
+ it %[should not acquire the second lock] do
72
+ @rval2.should be_false
73
+ end
74
+
75
+ it %[should acquire the second lock after the first lock is released] do
76
+ locker.unlock.should be_true
77
+ locker2.lock.should be_true
78
+ end
79
+ end
80
+
81
+ describe 'blocking' do
82
+ before do
83
+ zk.mkdir_p(root_lock_path)
84
+ end
85
+
86
+ it %[should block waiting for the lock] do
87
+ ary = []
88
+ read_lock_path = zk.create("/_zklocking/#{path}/read", '', :mode => :ephemeral_sequential)
89
+
90
+ locker.lock.should be_false
91
+
92
+ th = Thread.new do
93
+ locker.lock(true)
94
+ ary << :locked
95
+ end
96
+
97
+ locker.wait_until_blocked(5)
98
+
99
+ ary.should be_empty
100
+ locker.should_not be_locked
101
+
102
+ zk.delete(read_lock_path)
103
+
104
+ th.join(2).should == th
105
+
106
+ ary.length.should == 1
107
+ locker.should be_locked
108
+ end
109
+ end # blocking
110
+ end # lock
111
+ end # ExclusiveLocker
112
+
113
+ describe do
114
+ include_context 'locker non-chrooted'
115
+ it_should_behave_like 'ZK::Locker::ExclusiveLocker'
116
+ end
117
+
118
+ describe :chrooted => true do
119
+ include_context 'locker chrooted'
120
+ it_should_behave_like 'ZK::Locker::ExclusiveLocker'
121
+ end
122
+
@@ -0,0 +1,79 @@
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(*connection_args)
11
+ @zk2 = ZK.new(*connection_args)
12
+ @zk3 = ZK.new(*connection_args)
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
+ end
78
+
79
+
@@ -0,0 +1,157 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for :shared_exclusive_integration do
4
+ before do
5
+ @sh_lock = ZK::Locker.shared_locker(zk, path)
6
+ @ex_lock = ZK::Locker.exclusive_locker(zk2, path)
7
+ end
8
+
9
+ describe 'shared lock acquired first' do
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
13
+
14
+ mutex = Monitor.new
15
+ cond = mutex.new_cond
16
+
17
+ th = Thread.new do
18
+ logger.debug { "@ex_lock trying to acquire acquire lock" }
19
+ @ex_lock.with_lock do
20
+ th[:got_lock] = @ex_lock.locked?
21
+ logger.debug { "@ex_lock.locked? #{@ex_lock.locked?}" }
22
+
23
+ mutex.synchronize do
24
+ cond.broadcast
25
+ end
26
+ end
27
+ end
28
+
29
+ mutex.synchronize do
30
+ logger.debug { "unlocking the shared lock" }
31
+ @sh_lock.unlock.should be_true
32
+ cond.wait_until { th[:got_lock] } # make sure they actually received the lock (avoid race)
33
+ th[:got_lock].should be_true
34
+ logger.debug { "ok, they got the lock" }
35
+ end
36
+
37
+ th.join(5).should == th
38
+
39
+ logger.debug { "thread joined, exclusive lock should be releasd" }
40
+
41
+ @ex_lock.should_not be_locked
42
+ end
43
+ end
44
+
45
+ describe 'exclusive lock acquired first' do
46
+ it %[should block shared lock from acquiring until released] do
47
+ @ex_lock.lock.should be_true
48
+ @sh_lock.lock.should be_false
49
+
50
+ mutex = Monitor.new
51
+ cond = mutex.new_cond
52
+
53
+ th = Thread.new do
54
+ logger.debug { "@ex_lock trying to acquire acquire lock" }
55
+ @sh_lock.with_lock do
56
+ th[:got_lock] = @sh_lock.locked?
57
+ logger.debug { "@sh_lock.locked? #{@sh_lock.locked?}" }
58
+
59
+ mutex.synchronize do
60
+ cond.broadcast
61
+ end
62
+ end
63
+ end
64
+
65
+ mutex.synchronize do
66
+ logger.debug { "unlocking the shared lock" }
67
+ @ex_lock.unlock.should be_true
68
+ cond.wait_until { th[:got_lock] } # make sure they actually received the lock (avoid race)
69
+ th[:got_lock].should be_true
70
+ logger.debug { "ok, they got the lock" }
71
+ end
72
+
73
+ th.join(5).should == th
74
+
75
+ logger.debug { "thread joined, exclusive lock should be releasd" }
76
+
77
+ @sh_lock.should_not be_locked
78
+ end
79
+ end
80
+
81
+ describe 'shared-exclusive-shared' do
82
+ before do
83
+ zk3.should_not be_nil
84
+ @sh_lock2 = ZK::Locker.shared_locker(zk3, path)
85
+ end
86
+
87
+ it %[should act something like a queue] do
88
+ @array = []
89
+
90
+ @sh_lock.lock.should be_true
91
+ @sh_lock.should be_locked
92
+
93
+ ex_th = Thread.new do
94
+ begin
95
+ @ex_lock.lock(true) # blocking lock
96
+ @ex_lock.assert!
97
+ @array << :ex_lock
98
+ ensure
99
+ @ex_lock.unlock
100
+ end
101
+ end
102
+
103
+ logger.debug { "about to wait for @ex_lock to be blocked" }
104
+
105
+ @ex_lock.wait_until_blocked(5)
106
+ @ex_lock.should be_waiting
107
+
108
+ logger.debug { "@ex_lock is waiting" }
109
+
110
+ @ex_lock.should_not be_locked
111
+
112
+ # this is the important one, does the second shared lock get blocked by
113
+ # the exclusive lock
114
+ @sh_lock2.lock.should_not be_true
115
+
116
+ sh2_th = Thread.new do
117
+ begin
118
+ @sh_lock2.lock(true)
119
+ @sh_lock2.assert!
120
+ @array << :sh_lock2
121
+ ensure
122
+ @sh_lock2.unlock
123
+ end
124
+ end
125
+
126
+ logger.debug { "about to wait for @sh_lock2 to be blocked" }
127
+
128
+ @sh_lock2.wait_until_blocked(5)
129
+ @sh_lock2.should be_waiting
130
+
131
+ logger.debug { "@sh_lock2 is waiting" }
132
+
133
+ # ok, now unlock the first in the chain
134
+ @sh_lock.assert!
135
+ @sh_lock.unlock.should be_true
136
+
137
+ ex_th.join(5).should == ex_th
138
+ sh2_th.join(5).should == sh2_th
139
+
140
+ @array.length.should == 2
141
+ @array.should == [:ex_lock, :sh_lock2]
142
+ end
143
+ end
144
+ end # shared_exclusive_integration
145
+
146
+ describe do
147
+ include_context 'locker non-chrooted'
148
+
149
+ it_should_behave_like :shared_exclusive_integration
150
+ end
151
+
152
+ describe :chrooted => true do
153
+ include_context 'locker chrooted'
154
+
155
+ it_should_behave_like :shared_exclusive_integration
156
+ end
157
+
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'ZK::Locker::SharedLocker' do
4
+ let(:locker) { ZK::Locker::SharedLocker.new(zk, path) }
5
+ let(:locker2) { ZK::Locker::SharedLocker.new(zk2, path) }
6
+
7
+ describe :assert! do
8
+ it_should_behave_like 'LockerBase#assert!'
9
+
10
+ it %[should raise LockAssertionFailedError if there is an exclusive lock with a number lower than ours] do
11
+ # this should *really* never happen
12
+ locker.lock.should be_true
13
+ shl_path = locker.lock_path
14
+
15
+ locker2.lock.should be_true
16
+
17
+ locker.unlock.should be_true
18
+ locker.should_not be_locked
19
+
20
+ zk.exists?(shl_path).should be_false
21
+
22
+ locker2.lock_path.should_not == shl_path
23
+
24
+ # convert the first shared lock path into a exclusive one
25
+
26
+ exl_path = shl_path.sub(%r%/sh(\d+)\Z%, '/ex\1')
27
+
28
+ zk.create(exl_path, :ephemeral => true)
29
+
30
+ lambda { locker2.assert! }.should raise_error(ZK::Exceptions::LockAssertionFailedError)
31
+ end
32
+ end
33
+
34
+ describe :acquirable? do
35
+ describe %[with default options] do
36
+ it %[should work if the lock root doesn't exist] do
37
+ zk.rm_rf(ZK::Locker.default_root_lock_node)
38
+ locker.should be_acquirable
39
+ end
40
+
41
+ it %[should check local state of lockedness] do
42
+ locker.lock.should be_true
43
+ locker.should be_acquirable
44
+ end
45
+
46
+ it %[should check if any participants would prevent us from acquiring the lock] do
47
+ ex_lock = ZK::Locker.exclusive_locker(zk, path)
48
+ ex_lock.lock.should be_true
49
+ locker.should_not be_acquirable
50
+ end
51
+ end
52
+ end
53
+
54
+ describe :lock do
55
+ describe 'non-blocking success' do
56
+ before do
57
+ @rval = locker.lock
58
+ @rval2 = locker2.lock
59
+ end
60
+
61
+ it %[should acquire the first lock] do
62
+ @rval.should be_true
63
+ locker.should be_locked
64
+ end
65
+
66
+ it %[should acquire the second lock] do
67
+ @rval2.should be_true
68
+ locker2.should be_locked
69
+ end
70
+ end
71
+
72
+ describe 'non-blocking failure' do
73
+ before do
74
+ zk.mkdir_p(root_lock_path)
75
+ @write_lock_path = zk.create("#{root_lock_path}/#{ZK::Locker::EXCLUSIVE_LOCK_PREFIX}", '', :mode => :ephemeral_sequential)
76
+ @rval = locker.lock
77
+ end
78
+
79
+ it %[should return false] do
80
+ @rval.should be_false
81
+ end
82
+
83
+ it %[should not be locked] do
84
+ locker.should_not be_locked
85
+ end
86
+ end
87
+
88
+ describe 'blocking success' do
89
+ before do
90
+ zk.mkdir_p(root_lock_path)
91
+ @write_lock_path = zk.create("#{root_lock_path}/#{ZK::Locker::EXCLUSIVE_LOCK_PREFIX}", '', :mode => :ephemeral_sequential)
92
+ $stderr.sync = true
93
+ end
94
+
95
+ it %[should acquire the lock after the write lock is released] do
96
+ ary = []
97
+
98
+ locker.lock.should be_false
99
+
100
+ th = Thread.new do
101
+ locker.lock(true)
102
+ ary << :locked
103
+ end
104
+
105
+ locker.wait_until_blocked(5)
106
+ locker.should be_waiting
107
+ locker.should_not be_locked
108
+ ary.should be_empty
109
+
110
+ zk.delete(@write_lock_path)
111
+
112
+ th.join(2).should == th
113
+
114
+ ary.should_not be_empty
115
+ ary.length.should == 1
116
+
117
+ locker.should be_locked
118
+ end
119
+ end
120
+ end # lock
121
+
122
+ it_should_behave_like 'LockerBase#unlock'
123
+ end # SharedLocker
124
+
125
+
126
+ describe do
127
+ include_context 'locker non-chrooted'
128
+
129
+ it_should_behave_like 'ZK::Locker::SharedLocker'
130
+ end
131
+
132
+ describe :chrooted => true do
133
+ include_context 'locker chrooted'
134
+
135
+ it_should_behave_like 'ZK::Locker::SharedLocker'
136
+ end
137
+