zookeeper 0.2.2 → 0.3.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.
- 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"
|