zookeeper 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/Manifest +13 -1
- data/README +30 -0
- data/Rakefile +1 -1
- data/examples/cloud_config.rb +125 -0
- data/ext/zkc-3.3.1.tar.gz +0 -0
- data/ext/zookeeper_c.c +338 -393
- data/ext/zookeeper_lib.c +527 -0
- data/ext/zookeeper_lib.h +151 -0
- data/lib/zookeeper/acls.rb +31 -0
- data/lib/zookeeper/callbacks.rb +89 -0
- data/lib/zookeeper/constants.rb +54 -0
- data/lib/zookeeper/exceptions.rb +91 -0
- data/lib/zookeeper/stat.rb +12 -0
- data/lib/zookeeper.rb +207 -51
- data/test/test_basic.rb +16 -39
- data/test/test_callback1.rb +36 -0
- data/test/test_esoteric.rb +7 -0
- data/test/test_watcher1.rb +56 -0
- data/test/test_watcher2.rb +52 -0
- data/zookeeper.gemspec +6 -6
- data.tar.gz.sig +0 -0
- metadata +31 -7
- metadata.gz.sig +0 -0
- data/ext/zkc-3.2.2.tar.gz +0 -0
@@ -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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
20
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
31
|
-
|
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
|
36
|
-
|
37
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
149
|
+
}
|
150
|
+
end
|
54
151
|
|
55
|
-
|
56
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
64
|
-
|
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
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
15
|
+
h = z.stat(:path => path)
|
16
|
+
stat = h[:stat]
|
14
17
|
puts "exists? #{stat.inspect}"
|
15
18
|
|
16
|
-
|
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,
|
26
|
+
puts "create: #{z.create(:path => path, :data => 'initial value').inspect}"
|
24
27
|
|
25
|
-
|
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,
|
32
|
+
puts "set: #{z.set(:path => path, :data => 'this is a test', :version => stat.version).inspect}"
|
29
33
|
|
30
|
-
|
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"
|