zookeeper 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,89 @@
1
+ module ZookeeperCallbacks
2
+ class Callback
3
+ attr_reader :proc, :completed, :context
4
+
5
+ def initialize
6
+ @completed = false
7
+ @proc = Proc.new do |hash|
8
+ initialize_context(hash)
9
+ yield if block_given?
10
+ @completed = true
11
+ end
12
+ end
13
+
14
+ def call(*args)
15
+ puts "call passed #{args.inspect}"
16
+ @proc.call(*args)
17
+ end
18
+
19
+ def completed?
20
+ @completed
21
+ end
22
+
23
+ def initialize_context(hash)
24
+ @context = nil
25
+ end
26
+ end
27
+
28
+ class WatcherCallback < Callback
29
+ ## wexists, awexists, wget, awget, wget_children, awget_children
30
+ attr_reader :type, :state, :path
31
+
32
+ def initialize_context(hash)
33
+ @type, @state, @path, @context = hash[:type], hash[:state], hash[:path], hash[:context]
34
+ end
35
+ end
36
+
37
+ class DataCallback < Callback
38
+ ## aget, awget
39
+ attr_reader :return_code, :data, :stat
40
+
41
+ def initialize_context(hash)
42
+ @return_code, @data, @stat, @context = hash[:rc], hash[:data], hash[:stat], hash[:context]
43
+ end
44
+ end
45
+
46
+ class StringCallback < Callback
47
+ ## acreate, async
48
+ attr_reader :return_code, :path
49
+
50
+ def initialize_context(hash)
51
+ @return_code, @path, @context = hash[:rc], hash[:path], hash[:context]
52
+ end
53
+ end
54
+
55
+ class StringsCallback < Callback
56
+ ## aget_children, awget_children
57
+ attr_reader :return_code, :children, :stat
58
+
59
+ def initialize_context(hash)
60
+ @return_code, @children, @stat, @context = hash[:rc], hash[:children], hash[:stat], hash[:context]
61
+ end
62
+ end
63
+
64
+ class StatCallback < Callback
65
+ ## aset, aexists, awexists
66
+ attr_reader :return_code, :stat
67
+
68
+ def initialize_context(hash)
69
+ @return_code, @stat, @context = hash[:rc], hash[:stat], hash[:context]
70
+ end
71
+ end
72
+
73
+ class VoidCallback < Callback
74
+ ## adelete, aset_acl, add_auth
75
+ attr_reader :return_code
76
+
77
+ def initialize_context(hash)
78
+ @return_code, @context = hash[:rc], hash[:context]
79
+ end
80
+ end
81
+
82
+ class ACLCallback < Callback
83
+ ## aget_acl
84
+ attr_reader :return_code, :acl, :stat
85
+ def initialize_context(hash)
86
+ @return_code, @acl, @stat, @context = hash[:rc], hash[:acl], hash[:stat], hash[:context]
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,54 @@
1
+ module ZookeeperConstants
2
+ # file type masks
3
+ ZOO_EPHEMERAL = 1
4
+ ZOO_SEQUENCE = 2
5
+
6
+ # session state
7
+ ZOO_EXPIRED_SESSION_STATE = -112
8
+ ZOO_AUTH_FAILED_STATE = -113
9
+ ZOO_CONNECTING_STATE = 1
10
+ ZOO_ASSOCIATING_STATE = 2
11
+ ZOO_CONNECTED_STATE = 3
12
+
13
+ # watch types
14
+ ZOO_CREATED_EVENT = 1
15
+ ZOO_DELETED_EVENT = 2
16
+ ZOO_CHANGED_EVENT = 3
17
+ ZOO_CHILD_EVENT = 4
18
+ ZOO_SESSION_EVENT = -1
19
+ ZOO_NOTWATCHING_EVENT = -2
20
+
21
+ def print_events
22
+ puts "ZK events:"
23
+ ZookeeperConstants::constants.each do |c|
24
+ puts "\t #{c}" if c =~ /^ZOO..*EVENT$/
25
+ end
26
+ end
27
+
28
+ def print_states
29
+ puts "ZK states:"
30
+ ZookeeperConstants::constants.each do |c|
31
+ puts "\t #{c}" if c =~ /^ZOO..*STATE$/
32
+ end
33
+ end
34
+
35
+ def event_by_value(v)
36
+ return unless v
37
+ ZookeeperConstants::constants.each do |c|
38
+ next unless c =~ /^ZOO..*EVENT$/
39
+ if eval("ZookeeperConstants::#{c}") == v
40
+ return c
41
+ end
42
+ end
43
+ end
44
+
45
+ def state_by_value(v)
46
+ return unless v
47
+ ZookeeperConstants::constants.each do |c|
48
+ next unless c =~ /^ZOO..*STATE$/
49
+ if eval("ZookeeperConstants::#{c}") == v
50
+ return c
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,91 @@
1
+ module ZookeeperExceptions
2
+ # exceptions/errors
3
+ ZOK = 0
4
+ ZSYSTEMERROR = -1
5
+ ZRUNTIMEINCONSISTENCY = -2
6
+ ZDATAINCONSISTENCY = -3
7
+ ZCONNECTIONLOSS = -4
8
+ ZMARSHALLINGERROR = -5
9
+ ZUNIMPLEMENTED = -6
10
+ ZOPERATIONTIMEOUT = -7
11
+ ZBADARGUMENTS = -8
12
+ ZINVALIDSTATE = -9
13
+
14
+ # api errors
15
+ ZAPIERROR = -100
16
+ ZNONODE = -101
17
+ ZNOAUTH = -102
18
+ ZBADVERSION = -103
19
+ ZNOCHILDRENFOREPHEMERALS = -108
20
+ ZNODEEXISTS = -110
21
+ ZNOTEMPTY = -111
22
+ ZSESSIONEXPIRED = -112
23
+ ZINVALIDCALLBACK = -113
24
+ ZINVALIDACL = -114
25
+ ZAUTHFAILED = -115
26
+ ZCLOSING = -116
27
+ ZNOTHING = -117
28
+ ZSESSIONMOVED = -118
29
+
30
+ class ZookeeperException < Exception
31
+ class EverythingOk < ZookeeperException; end
32
+ class SystemError < ZookeeperException; end
33
+ class RunTimeInconsistency < ZookeeperException; end
34
+ class DataInconsistency < ZookeeperException; end
35
+ class ConnectionLoss < ZookeeperException; end
36
+ class MarshallingError < ZookeeperException; end
37
+ class Unimplemented < ZookeeperException; end
38
+ class OperationTimeOut < ZookeeperException; end
39
+ class BadArguments < ZookeeperException; end
40
+ class InvalidState < ZookeeperException; end
41
+ class ApiError < ZookeeperException; end
42
+ class NoNode < ZookeeperException; end
43
+ class NoAuth < ZookeeperException; end
44
+ class BadVersion < ZookeeperException; end
45
+ class NoChildrenForEphemerals < ZookeeperException; end
46
+ class NodeExists < ZookeeperException; end
47
+ class NotEmpty < ZookeeperException; end
48
+ class SessionExpired < ZookeeperException; end
49
+ class InvalidCallback < ZookeeperException; end
50
+ class InvalidACL < ZookeeperException; end
51
+ class AuthFailed < ZookeeperException; end
52
+ class Closing < ZookeeperException; end
53
+ class Nothing < ZookeeperException; end
54
+ class SessionMoved < ZookeeperException; end
55
+
56
+ def self.by_code(code)
57
+ case code
58
+ when ZOK then EverythingOk
59
+ when ZSYSTEMERROR then SystemError
60
+ when ZRUNTIMEINCONSISTENCY then RunTimeInconsistency
61
+ when ZDATAINCONSISTENCY then DataInconsistency
62
+ when ZCONNECTIONLOSS then ConnectionLoss
63
+ when ZMARSHALLINGERROR then MarshallingError
64
+ when ZUNIMPLEMENTED then Unimplemented
65
+ when ZOPERATIONTIMEOUT then OperationTimeOut
66
+ when ZBADARGUMENTS then BadArguments
67
+ when ZINVALIDSTATE then InvalidState
68
+ when ZAPIERROR then ApiError
69
+ when ZNONODE then NoNode
70
+ when ZNOAUTH then NoAuth
71
+ when ZBADVERSION then BadVersion
72
+ when ZNOCHILDRENFOREPHEMERALS then NoChildrenForEphemerals
73
+ when ZNODEEXISTS then NodeExists
74
+ when ZNOTEMPTY then NotEmpty
75
+ when ZSESSIONEXPIRED then SessionExpired
76
+ when ZINVALIDCALLBACK then InvalidCallback
77
+ when ZINVALIDACL then InvalidACL
78
+ when ZAUTHFAILED then AuthFailed
79
+ when ZCLOSING then Closing
80
+ when ZNOTHING then Nothing
81
+ when ZSESSIONMOVED then SessionMoved
82
+ else Exception.new("no exception defined for code #{code}")
83
+ end
84
+ end
85
+
86
+ def self.raise_on_error(code)
87
+ exc = self.by_code(code)
88
+ raise exc unless exc == EverythingOk
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,12 @@
1
+ module ZookeeperStat
2
+ class Stat
3
+ attr_reader :version, :exists
4
+ def initialize(val)
5
+ @exists = !!val
6
+ @czxid, @mzxid, @ctime, @mtime, @version, @cversion, @aversion,
7
+ @ephemeralOwner, @dataLength, @numChildren, @pzxid = val if val.is_a?(Array)
8
+ val.each { |k,v| instance_variable_set "@#{k}", v } if val.is_a?(Hash)
9
+ raise ArgumentError unless (val.is_a?(Hash) or val.is_a?(Array) or val == nil)
10
+ end
11
+ end
12
+ end
data/lib/zookeeper.rb CHANGED
@@ -1,78 +1,234 @@
1
1
  # Ruby wrapper for the Zookeeper C API
2
- # Phillip Pearson <pp@myelin.co.nz>
3
2
 
4
3
  require 'zookeeper_c'
5
-
6
- class ZkStat
7
- attr_reader :version
8
- def initialize(ary)
9
- @czxid, @mzxid, @ctime, @mtime, @version, @cversion, @aversion, @ephemeralOwner = ary
10
- end
11
- end
4
+ require 'thread'
5
+ require 'zookeeper/callbacks'
6
+ require 'zookeeper/constants'
7
+ require 'zookeeper/exceptions'
8
+ require 'zookeeper/stat'
9
+ require 'zookeeper/acls'
12
10
 
13
11
  class Zookeeper < CZookeeper
14
- def initialize(host)
12
+ include ZookeeperCallbacks
13
+ include ZookeeperConstants
14
+ include ZookeeperExceptions
15
+ include ZookeeperACLs
16
+ include ZookeeperStat
17
+
18
+ ZKRB_GLOBAL_CB_REQ = -1
19
+
20
+ # debug levels
21
+ ZOO_LOG_LEVEL_ERROR = 1
22
+ ZOO_LOG_LEVEL_WARN = 2
23
+ ZOO_LOG_LEVEL_INFO = 3
24
+ ZOO_LOG_LEVEL_DEBUG = 4
25
+
26
+ def initialize(host, timeout = 10)
27
+ @watcher_reqs = { ZKRB_GLOBAL_CB_REQ => { :watcher => get_default_global_watcher } }
28
+ @completion_reqs = {}
29
+ @req_mutex = Mutex.new
30
+ @current_req_id = 1
15
31
  super(host)
16
- @watchers = {} # path => [ block, block, ... ]
32
+
33
+ if timeout > 0
34
+ time_to_stop = Time.now + timeout
35
+ until state == Zookeeper::ZOO_CONNECTED_STATE
36
+ break if Time.now > time_to_stop
37
+ sleep 0.1
38
+ end
39
+
40
+ return nil if state != Zookeeper::ZOO_CONNECTED_STATE
41
+ end
42
+
43
+ setup_dispatch_thread!
17
44
  end
45
+
46
+ public
47
+ def get(options = {})
48
+ assert_supported_keys(options, [:path, :watcher, :watcher_context, :callback, :callback_context])
49
+ assert_required_keys(options, [:path])
50
+
51
+ req_id = setup_call(options)
52
+ rc, value, stat = super(req_id, options[:path], options[:callback], options[:watcher])
18
53
 
19
- def exists(path, &blk)
20
- (@watchers[path] ||= []) << blk if blk
21
- ZkStat.new(super(path, !!blk))
54
+ rv = { :req_id => req_id, :rc => rc }
55
+ options[:callback] ? rv : rv.merge(:data => value, :stat => Stat.new(stat))
22
56
  end
57
+
58
+ def set(options = {})
59
+ assert_supported_keys(options, [:path, :data, :version, :callback, :callback_context])
60
+ assert_required_keys(options, [:path])
61
+ options[:version] ||= -1
23
62
 
24
- def stat(path, &blk)
25
- exists(path, &blk)
26
- rescue Zookeeper::NoNodeError
27
- nil
63
+ req_id = setup_call(options)
64
+ rc, stat = super(req_id, options[:path], options[:data], options[:callback], options[:version])
65
+
66
+ rv = { :req_id => req_id, :rc => rc }
67
+ options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
28
68
  end
69
+
70
+ def get_children(options = {})
71
+ assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
72
+ assert_required_keys(options, [:path])
73
+
74
+ req_id = setup_call(options)
75
+ rc, children, stat = super(req_id, options[:path], options[:callback], options[:watcher])
29
76
 
30
- def get(path)
31
- value, stat = super
32
- [value, ZkStat.new(stat)]
77
+ rv = { :req_id => req_id, :rc => rc }
78
+ options[:callback] ? rv : rv.merge(:children => children, :stat => Stat.new(stat))
33
79
  end
34
80
 
35
- def try_acquire(path, value)
36
- # create the parent node if it doesn't exist already
37
- create(path, "lock node", 0) unless stat(path)
81
+ def stat(options = {})
82
+ assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
83
+ assert_required_keys(options, [:path])
84
+
85
+ req_id = setup_call(options)
86
+ rc, stat = exists(req_id, options[:path], options[:callback], options[:watcher])
87
+
88
+ rv = { :req_id => req_id, :rc => rc }
89
+ options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
90
+ end
91
+
92
+ def create(options = {})
93
+ assert_supported_keys(options, [:path, :data, :acl, :ephemeral, :sequence, :callback, :callback_context])
94
+ assert_required_keys(options, [:path])
95
+
96
+ flags = 0
97
+ flags |= ZOO_EPHEMERAL if options[:ephemeral]
98
+ flags |= ZOO_SEQUENCE if options[:sequence]
38
99
 
39
- # attempt to obtain the lock
40
- realpath = create("#{path}/lock-", value, Zookeeper::ZOO_EPHEMERAL | Zookeeper::ZOO_SEQUENCE)
41
- #puts "created lock node #{realpath}"
100
+ options[:acl] ||= ZOO_OPEN_ACL_UNSAFE
101
+
102
+ req_id = setup_call(options)
103
+ rc, newpath = super(req_id, options[:path], options[:data], options[:callback], options[:acl], flags)
104
+
105
+ rv = { :req_id => req_id, :rc => rc }
106
+ options[:callback] ? rv : rv.merge(:path => newpath)
107
+ end
108
+
109
+ def delete(options = {})
110
+ assert_supported_keys(options, [:path, :version, :callback, :callback_context])
111
+ assert_required_keys(options, [:path])
112
+ options[:version] ||= -1
113
+
114
+ req_id = setup_call(options)
115
+ rc = super(req_id, options[:path], options[:version], options[:callback])
116
+
117
+ { :req_id => req_id, :rc => rc }
118
+ end
42
119
 
43
- # see if we got it
44
- serial = /lock-(\d+)$/.match(realpath).captures[0].to_i
45
- have_lock = true
46
- ls(path).each do |child|
47
- if m = /lock-(\d+)$/.match(child)
48
- if m.captures[0].to_i < serial
49
- have_lock = false
50
- break
51
- end
120
+ def set_acl(options = {})
121
+ assert_supported_keys(options, [:path, :acl, :version, :callback, :callback_context])
122
+ assert_required_keys(options, [:path, :acl])
123
+ options[:version] ||= -1
124
+
125
+ req_id = setup_call(options)
126
+ rc = super(req_id, options[:path], options[:acl], options[:callback], options[:version])
127
+
128
+ { :req_id => req_id, :rc => rc }
129
+ end
130
+
131
+ def get_acl(options = {})
132
+ assert_supported_keys(options, [:path, :callback, :callback_context])
133
+ assert_required_keys(options, [:path])
134
+
135
+ req_id = setup_call(options)
136
+ rc, acls, stat = super(req_id, options[:path], options[:callback])
137
+
138
+ rv = { :req_id => req_id, :rc => rc }
139
+ options[:callback] ? rv : rv.merge(:acl => acls, :stat => Stat.new(stat))
140
+ end
141
+
142
+ private
143
+ def setup_dispatch_thread!
144
+ @dispatcher = Thread.new {
145
+ while true do
146
+ dispatch_next_callback
147
+ sleep 0.1
52
148
  end
53
- end
149
+ }
150
+ end
54
151
 
55
- # call block
56
- yield(have_lock)
152
+ def dispatch_next_callback
153
+ hash = get_next_event
154
+ return nil unless hash
155
+
156
+ is_completion = hash.has_key?(:rc)
157
+
158
+ hash[:stat] = Stat.new(hash[:stat]) if hash.has_key?(:stat)
159
+ hash[:acl] = hash[:acl].map { |acl| ACL.new(acl) } if hash[:acl]
160
+
161
+ callback_context = is_completion ? get_completion(hash[:req_id]) : get_watcher(hash[:req_id])
162
+ callback = is_completion ? callback_context[:callback] : callback_context[:watcher]
163
+ hash[:context] = callback_context[:context]
164
+
165
+ # TODO: Eventually enforce derivation from Zookeeper::Callback
166
+ if callback.respond_to?(:call)
167
+ callback.call(hash)
168
+ else
169
+ puts "dispatch_next_callback found non-callback => #{callback.inspect}"
170
+ end
171
+ end
172
+
173
+ def setup_call(opts)
174
+ req_id = nil
175
+ @req_mutex.synchronize {
176
+ req_id = @current_req_id
177
+ @current_req_id += 1
178
+ setup_completion(req_id, opts) if opts[:callback]
179
+ setup_watcher(req_id, opts) if opts[:watcher]
180
+ }
181
+ req_id
182
+ end
183
+
184
+ def setup_watcher(req_id, call_opts)
185
+ @watcher_reqs[req_id] = { :watcher => call_opts[:watcher],
186
+ :context => call_opts[:watcher_context] }
187
+ end
57
188
 
58
- # release the lock
59
- #puts "deleting #{realpath}"
60
- delete(realpath, stat(realpath).version)
189
+ def setup_completion(req_id, call_opts)
190
+ @completion_reqs[req_id] = { :callback => call_opts[:callback],
191
+ :context => call_opts[:callback_context] }
192
+ end
193
+
194
+ def get_watcher(req_id)
195
+ @req_mutex.synchronize {
196
+ req_id != ZKRB_GLOBAL_CB_REQ ? @watcher_reqs.delete(req_id) : @watcher_reqs[req_id]
197
+ }
198
+ end
199
+
200
+ def get_completion(req_id)
201
+ @req_mutex.synchronize { @completion_reqs.delete(req_id) }
61
202
  end
62
203
 
63
- def watcher(type, state, path)
64
- raise Exception("watchers don't work in ruby yet") # ... until I figure out how to synchronize access to the Ruby interpreter
204
+ public
205
+ # TODO: Sanitize user mistakes by unregistering watchers from ops that
206
+ # don't return ZOK (except wexists)? Make users clean up after themselves for now.
207
+ def unregister_watcher(req_id)
208
+ @req_mutex.synchronize {
209
+ @watcher_reqs.delete(req_id)
210
+ }
211
+ end
65
212
 
66
- return unless type == ZOO_SESSION_EVENT
213
+ private
214
+ def get_default_global_watcher
215
+ Proc.new { |args|
216
+ puts "Ruby ZK Global CB called type=#{event_by_value(args[:type])} state=#{state_by_value(args[:state])}"
217
+ }
218
+ end
67
219
 
68
- case state
69
- when ZOO_CONNECTED_STATE
70
- puts "ruby watcher; got an event for #{path}"
220
+ def assert_supported_keys(args, supported)
221
+ unless (args.keys - supported).empty?
222
+ raise ZookeeperException::BadArguments,
223
+ "Supported arguments are: #{supported.inspect}, but arguments #{args.keys.inspect} were supplied instead"
224
+ end
225
+ end
71
226
 
72
- when ZOO_AUTH_FAILED_STATE
73
- raise Exception, "auth failure"
74
- when ZOO_EXPIRED_SESSION_STATE
75
- raise Exception, "session expired"
227
+ def assert_required_keys(args, required)
228
+ unless (required - args.keys).empty?
229
+ raise ZookeeperException::BadArguments,
230
+ "Required arguments are: #{required.inspect}, but only the arguments #{args.keys.inspect} were supplied."
76
231
  end
77
232
  end
78
233
  end
234
+
data/test/test_basic.rb CHANGED
@@ -1,63 +1,40 @@
1
+ require 'rubygems'
2
+
1
3
  HERE = File.expand_path(File.dirname(__FILE__))
2
4
 
3
5
  require "#{HERE}/../lib/zookeeper"
4
6
 
5
7
  z = Zookeeper.new("localhost:2181")
6
8
 
7
- puts "root: #{z.get_children("/").inspect}"
9
+ puts "root: #{z.get_children(:path => "/").inspect}"
8
10
 
9
11
  path = "/testing_node"
10
12
 
11
13
  puts "working with path #{path}"
12
14
 
13
- stat = z.stat(path)
15
+ h = z.stat(:path => path)
16
+ stat = h[:stat]
14
17
  puts "exists? #{stat.inspect}"
15
18
 
16
- unless stat.nil?
17
- z.get_children(path).each do |o|
19
+ if stat.exists
20
+ z.get_children(:path => path)[:children].each do |o|
18
21
  puts " child object: #{o}"
19
22
  end
20
- puts "delete: #{z.delete(path, stat.version).inspect}"
23
+ puts "delete: #{z.delete(:path => path, :version => stat.version).inspect}"
21
24
  end
22
25
 
23
- puts "create: #{z.create(path, "initial value", 0).inspect}"
26
+ puts "create: #{z.create(:path => path, :data => 'initial value').inspect}"
24
27
 
25
- value, stat = z.get(path)
28
+ v = z.get(:path => path)
29
+ value, stat = v[:data], v[:stat]
26
30
  puts "current value #{value}, stat #{stat.inspect}"
27
31
 
28
- puts "set: #{z.set(path, "this is a test", stat.version).inspect}"
32
+ puts "set: #{z.set(:path => path, :data => 'this is a test', :version => stat.version).inspect}"
29
33
 
30
- value, stat = z.get(path)
34
+ v = z.get(:path => path)
35
+ value, stat = v[:data], v[:stat]
31
36
  puts "new value: #{value.inspect} #{stat.inspect}"
32
37
 
33
- puts "delete: #{z.delete(path, stat.version).inspect}"
34
-
35
- begin
36
- puts "exists? #{z.exists(path)}"
37
- raise Exception, "it shouldn't exist"
38
- rescue Zookeeper::NoNodeError
39
- puts "doesn't exist - good, because we just deleted it!"
40
- end
41
-
42
- puts "trying a watcher"
43
- puts z
44
- if s = z.stat("/test"); z.delete("/test", s.version); end
45
- z.create("/test", "foo", 0)
46
- z.exists("/test") do
47
- puts "callback!!!"
48
- end
49
- puts "now changing it"
50
- z.set("/test", "bar", 0)
51
- sleep 1
52
- puts "did the watcher say something?"
53
-
54
- puts "let's try using a lock"
55
- z.try_acquire("/test_lock", "this is the content of the lock file") do |have_lock|
56
- puts have_lock ? "we have the lock!" : "failed to obtain lock :("
57
- if have_lock
58
- puts "sleeping"
59
- sleep 5
60
- end
61
- end
62
- puts "done with locking..."
38
+ puts "delete: #{z.delete(:path => path, :version => stat.version).inspect}"
63
39
 
40
+ puts "exists? #{z.stat(:path => path)[:stat].exists}"
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'zookeeper'
3
+
4
+ def wait_until(timeout=10, &block)
5
+ time_to_stop = Time.now + timeout
6
+ until yield do
7
+ break if Time.now > time_to_stop
8
+ sleep 0.1
9
+ end
10
+ end
11
+
12
+ puts 'Initializing Zookeeper'
13
+
14
+ zk = Zookeeper.new('localhost:2181')
15
+
16
+ if zk.state != Zookeeper::ZOO_CONNECTED_STATE
17
+ puts 'Unable to connect to Zookeeper!'
18
+ Kernel.exit
19
+ end
20
+
21
+ def callback(args)
22
+ puts "CALLBACK EXECUTED, args = #{args.inspect}"
23
+ puts args.return_code == Zookeeper::ZOK ? "TEST PASSED IN CALLBACK" : "TEST FAILED IN CALLBACK"
24
+ end
25
+
26
+ ccb = Zookeeper::VoidCallback.new do
27
+ callback(ccb)
28
+ end
29
+
30
+ resp = zk.create(:path => '/test', :data => "new data", :sequence => true, :callback => ccb)
31
+ puts "#{resp.inspect}"
32
+ puts "TEST FAILED [create]" unless resp[:rc] == Zookeeper::ZOK
33
+
34
+ wait_until { ccb.completed? }
35
+
36
+ puts ccb.completed? ? "TEST PASSED" : "TEST FAILED"
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'zookeeper'
3
+ zk = Zookeeper.new('localhost:2181')
4
+
5
+ puts "get acl #{zk.get_acl(:path => '/').inspect}"
6
+ puts "zerror #{zk.zerror(Zookeeper::ZBADVERSION)}"
7
+