slyphon-zookeeper 0.1.0-java
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/.gitignore +8 -0
- data/CHANGELOG +23 -0
- data/LICENSE +23 -0
- data/Manifest +33 -0
- data/README +42 -0
- data/Rakefile +19 -0
- data/examples/cloud_config.rb +125 -0
- data/ext/.gitignore +5 -0
- data/ext/extconf.rb +56 -0
- data/ext/zkc-3.3.2.tar.gz +0 -0
- data/ext/zookeeper_base.rb +117 -0
- data/ext/zookeeper_c.c +571 -0
- data/ext/zookeeper_lib.c +604 -0
- data/ext/zookeeper_lib.h +165 -0
- data/java/zookeeper_base.rb +426 -0
- data/lib/zookeeper.rb +180 -0
- data/lib/zookeeper/acls.rb +40 -0
- data/lib/zookeeper/callbacks.rb +89 -0
- data/lib/zookeeper/common.rb +97 -0
- data/lib/zookeeper/constants.rb +54 -0
- data/lib/zookeeper/exceptions.rb +92 -0
- data/lib/zookeeper/stat.rb +17 -0
- data/notes.txt +14 -0
- data/slyphon-zookeeper.gemspec +31 -0
- data/spec/default_watcher_spec.rb +41 -0
- data/spec/log4j.properties +17 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/zookeeper_spec.rb +924 -0
- data/test/test_basic.rb +37 -0
- data/test/test_callback1.rb +36 -0
- data/test/test_close.rb +16 -0
- data/test/test_esoteric.rb +7 -0
- data/test/test_watcher1.rb +56 -0
- data/test/test_watcher2.rb +52 -0
- metadata +178 -0
data/lib/zookeeper.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# Ruby wrapper for the Zookeeper C API
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'zookeeper/common'
|
5
|
+
require 'zookeeper/constants'
|
6
|
+
require 'zookeeper/callbacks'
|
7
|
+
require 'zookeeper/exceptions'
|
8
|
+
require 'zookeeper/stat'
|
9
|
+
require 'zookeeper/acls'
|
10
|
+
require 'logger'
|
11
|
+
|
12
|
+
if defined?(::JRUBY_VERSION)
|
13
|
+
$LOAD_PATH.unshift(File.expand_path('../java', File.dirname(__FILE__))).uniq!
|
14
|
+
else
|
15
|
+
$LOAD_PATH.unshift(File.expand_path('../ext', File.dirname(__FILE__))).uniq!
|
16
|
+
require 'zookeeper_c'
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'zookeeper_base'
|
20
|
+
|
21
|
+
class Zookeeper < ZookeeperBase
|
22
|
+
def reopen(timeout=10, watcher=nil)
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(host, timeout=10, watcher=nil)
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def get(options = {})
|
31
|
+
assert_open
|
32
|
+
assert_supported_keys(options, [:path, :watcher, :watcher_context, :callback, :callback_context])
|
33
|
+
assert_required_keys(options, [:path])
|
34
|
+
|
35
|
+
req_id = setup_call(options)
|
36
|
+
rc, value, stat = super(req_id, options[:path], options[:callback], options[:watcher])
|
37
|
+
|
38
|
+
rv = { :req_id => req_id, :rc => rc }
|
39
|
+
options[:callback] ? rv : rv.merge(:data => value, :stat => Stat.new(stat))
|
40
|
+
end
|
41
|
+
|
42
|
+
def set(options = {})
|
43
|
+
assert_open
|
44
|
+
assert_supported_keys(options, [:path, :data, :version, :callback, :callback_context])
|
45
|
+
assert_required_keys(options, [:path])
|
46
|
+
options[:version] ||= -1
|
47
|
+
|
48
|
+
req_id = setup_call(options)
|
49
|
+
rc, stat = super(req_id, options[:path], options[:data], options[:callback], options[:version])
|
50
|
+
|
51
|
+
rv = { :req_id => req_id, :rc => rc }
|
52
|
+
options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_children(options = {})
|
56
|
+
assert_open
|
57
|
+
assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
|
58
|
+
assert_required_keys(options, [:path])
|
59
|
+
|
60
|
+
req_id = setup_call(options)
|
61
|
+
rc, children, stat = super(req_id, options[:path], options[:callback], options[:watcher])
|
62
|
+
|
63
|
+
rv = { :req_id => req_id, :rc => rc }
|
64
|
+
options[:callback] ? rv : rv.merge(:children => children, :stat => Stat.new(stat))
|
65
|
+
end
|
66
|
+
|
67
|
+
def stat(options = {})
|
68
|
+
assert_open
|
69
|
+
assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
|
70
|
+
assert_required_keys(options, [:path])
|
71
|
+
|
72
|
+
req_id = setup_call(options)
|
73
|
+
rc, stat = exists(req_id, options[:path], options[:callback], options[:watcher])
|
74
|
+
|
75
|
+
rv = { :req_id => req_id, :rc => rc }
|
76
|
+
options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
|
77
|
+
end
|
78
|
+
|
79
|
+
def create(options = {})
|
80
|
+
assert_open
|
81
|
+
assert_supported_keys(options, [:path, :data, :acl, :ephemeral, :sequence, :callback, :callback_context])
|
82
|
+
assert_required_keys(options, [:path])
|
83
|
+
|
84
|
+
flags = 0
|
85
|
+
flags |= ZOO_EPHEMERAL if options[:ephemeral]
|
86
|
+
flags |= ZOO_SEQUENCE if options[:sequence]
|
87
|
+
|
88
|
+
options[:acl] ||= ZOO_OPEN_ACL_UNSAFE
|
89
|
+
|
90
|
+
req_id = setup_call(options)
|
91
|
+
rc, newpath = super(req_id, options[:path], options[:data], options[:callback], options[:acl], flags)
|
92
|
+
|
93
|
+
rv = { :req_id => req_id, :rc => rc }
|
94
|
+
options[:callback] ? rv : rv.merge(:path => newpath)
|
95
|
+
end
|
96
|
+
|
97
|
+
def delete(options = {})
|
98
|
+
assert_open
|
99
|
+
assert_supported_keys(options, [:path, :version, :callback, :callback_context])
|
100
|
+
assert_required_keys(options, [:path])
|
101
|
+
options[:version] ||= -1
|
102
|
+
|
103
|
+
req_id = setup_call(options)
|
104
|
+
rc = super(req_id, options[:path], options[:version], options[:callback])
|
105
|
+
|
106
|
+
{ :req_id => req_id, :rc => rc }
|
107
|
+
end
|
108
|
+
|
109
|
+
def set_acl(options = {})
|
110
|
+
assert_open
|
111
|
+
assert_supported_keys(options, [:path, :acl, :version, :callback, :callback_context])
|
112
|
+
assert_required_keys(options, [:path, :acl])
|
113
|
+
options[:version] ||= -1
|
114
|
+
|
115
|
+
req_id = setup_call(options)
|
116
|
+
rc = super(req_id, options[:path], options[:acl], options[:callback], options[:version])
|
117
|
+
|
118
|
+
{ :req_id => req_id, :rc => rc }
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_acl(options = {})
|
122
|
+
assert_open
|
123
|
+
assert_supported_keys(options, [:path, :callback, :callback_context])
|
124
|
+
assert_required_keys(options, [:path])
|
125
|
+
|
126
|
+
req_id = setup_call(options)
|
127
|
+
rc, acls, stat = super(req_id, options[:path], options[:callback])
|
128
|
+
|
129
|
+
rv = { :req_id => req_id, :rc => rc }
|
130
|
+
options[:callback] ? rv : rv.merge(:acl => acls, :stat => Stat.new(stat))
|
131
|
+
end
|
132
|
+
|
133
|
+
def state
|
134
|
+
super
|
135
|
+
end
|
136
|
+
|
137
|
+
def connected?
|
138
|
+
super
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
def setup_call(opts)
|
143
|
+
req_id = nil
|
144
|
+
@req_mutex.synchronize {
|
145
|
+
req_id = @current_req_id
|
146
|
+
@current_req_id += 1
|
147
|
+
setup_completion(req_id, opts) if opts[:callback]
|
148
|
+
setup_watcher(req_id, opts) if opts[:watcher]
|
149
|
+
}
|
150
|
+
req_id
|
151
|
+
end
|
152
|
+
|
153
|
+
def setup_watcher(req_id, call_opts)
|
154
|
+
@watcher_reqs[req_id] = { :watcher => call_opts[:watcher],
|
155
|
+
:context => call_opts[:watcher_context] }
|
156
|
+
end
|
157
|
+
|
158
|
+
def connecting?
|
159
|
+
super
|
160
|
+
end
|
161
|
+
|
162
|
+
def associating?
|
163
|
+
super
|
164
|
+
end
|
165
|
+
|
166
|
+
# TODO: Sanitize user mistakes by unregistering watchers from ops that
|
167
|
+
# don't return ZOK (except wexists)? Make users clean up after themselves for now.
|
168
|
+
def unregister_watcher(req_id)
|
169
|
+
@req_mutex.synchronize {
|
170
|
+
@watcher_reqs.delete(req_id)
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
# must be supplied by parent class impl.
|
175
|
+
def assert_open
|
176
|
+
super
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ZookeeperACLs
|
2
|
+
class Id
|
3
|
+
attr_reader :scheme, :id
|
4
|
+
def initialize(hash)
|
5
|
+
@scheme = hash[:scheme]
|
6
|
+
@id = hash[:id]
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_hash
|
10
|
+
{ :id => id, :scheme => scheme }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ACL
|
15
|
+
attr_reader :perms, :id
|
16
|
+
def initialize(hash)
|
17
|
+
@perms = hash[:perms]
|
18
|
+
v = hash[:id]
|
19
|
+
@id = v.kind_of?(Hash) ? Id.new(v) : v
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_hash
|
23
|
+
{ :perms => perms, :id => id.to_hash }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
ZOO_PERM_READ = 0
|
28
|
+
ZOO_PERM_WRITE = 1
|
29
|
+
ZOO_PERM_CREATE = 2
|
30
|
+
ZOO_PERM_DELETE = 4
|
31
|
+
ZOO_PERM_ADMIN = 8
|
32
|
+
ZOO_PERM_ALL = ZOO_PERM_READ | ZOO_PERM_WRITE | ZOO_PERM_CREATE | ZOO_PERM_DELETE | ZOO_PERM_ADMIN
|
33
|
+
|
34
|
+
ZOO_ANYONE_ID_UNSAFE = Id.new(:scheme => "world", :id => "anyone")
|
35
|
+
ZOO_AUTH_IDS = Id.new(:scheme => "auth", :id => "")
|
36
|
+
|
37
|
+
ZOO_OPEN_ACL_UNSAFE = [ACL.new(:perms => ZOO_PERM_ALL, :id => ZOO_ANYONE_ID_UNSAFE)]
|
38
|
+
ZOO_READ_ACL_UNSAFE = [ACL.new(:perms => ZOO_PERM_READ, :id => ZOO_ANYONE_ID_UNSAFE)]
|
39
|
+
ZOO_CREATOR_ALL_ACL = [ACL.new(:perms => ZOO_PERM_ALL, :id => ZOO_AUTH_IDS)]
|
40
|
+
end
|
@@ -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[:string], 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[:strings], 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,97 @@
|
|
1
|
+
require 'zookeeper/exceptions'
|
2
|
+
|
3
|
+
module ZookeeperCommon
|
4
|
+
# sigh, i guess define this here?
|
5
|
+
ZKRB_GLOBAL_CB_REQ = -1
|
6
|
+
|
7
|
+
def self.included(mod)
|
8
|
+
mod.extend(ZookeeperCommon::ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def logger
|
13
|
+
@logger ||= Logger.new('/dev/null') # UNIX: YOU MUST USE IT!
|
14
|
+
end
|
15
|
+
|
16
|
+
def logger=(logger)
|
17
|
+
@logger = logger
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
def setup_call(opts)
|
23
|
+
req_id = nil
|
24
|
+
@req_mutex.synchronize {
|
25
|
+
req_id = @current_req_id
|
26
|
+
@current_req_id += 1
|
27
|
+
setup_completion(req_id, opts) if opts[:callback]
|
28
|
+
setup_watcher(req_id, opts) if opts[:watcher]
|
29
|
+
}
|
30
|
+
req_id
|
31
|
+
end
|
32
|
+
|
33
|
+
def setup_watcher(req_id, call_opts)
|
34
|
+
@watcher_reqs[req_id] = { :watcher => call_opts[:watcher],
|
35
|
+
:context => call_opts[:watcher_context] }
|
36
|
+
end
|
37
|
+
|
38
|
+
def setup_completion(req_id, call_opts)
|
39
|
+
@completion_reqs[req_id] = { :callback => call_opts[:callback],
|
40
|
+
:context => call_opts[:callback_context] }
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_watcher(req_id)
|
44
|
+
@req_mutex.synchronize {
|
45
|
+
req_id != ZKRB_GLOBAL_CB_REQ ? @watcher_reqs.delete(req_id) : @watcher_reqs[req_id]
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_completion(req_id)
|
50
|
+
@req_mutex.synchronize { @completion_reqs.delete(req_id) }
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def dispatch_next_callback
|
55
|
+
hash = get_next_event
|
56
|
+
return nil unless hash
|
57
|
+
|
58
|
+
logger.debug { "dispatch_next_callback got event: #{hash.inspect}" }
|
59
|
+
|
60
|
+
is_completion = hash.has_key?(:rc)
|
61
|
+
|
62
|
+
hash[:stat] = ZookeeperStat::Stat.new(hash[:stat]) if hash.has_key?(:stat)
|
63
|
+
hash[:acl] = hash[:acl].map { |acl| ZookeeperACLs::ACL.new(acl) } if hash[:acl]
|
64
|
+
|
65
|
+
callback_context = is_completion ? get_completion(hash[:req_id]) : get_watcher(hash[:req_id])
|
66
|
+
callback = is_completion ? callback_context[:callback] : callback_context[:watcher]
|
67
|
+
hash[:context] = callback_context[:context]
|
68
|
+
|
69
|
+
# TODO: Eventually enforce derivation from Zookeeper::Callback
|
70
|
+
if callback.respond_to?(:call)
|
71
|
+
callback.call(hash)
|
72
|
+
else
|
73
|
+
# puts "dispatch_next_callback found non-callback => #{callback.inspect}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def assert_supported_keys(args, supported)
|
79
|
+
unless (args.keys - supported).empty?
|
80
|
+
raise ZookeeperExceptions::ZookeeperException::BadArguments, # this heirarchy is kind of retarded
|
81
|
+
"Supported arguments are: #{supported.inspect}, but arguments #{args.keys.inspect} were supplied instead"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def assert_required_keys(args, required)
|
86
|
+
unless (required - args.keys).empty?
|
87
|
+
raise ZookeeperExceptions::ZookeeperException::BadArguments,
|
88
|
+
"Required arguments are: #{required.inspect}, but only the arguments #{args.keys.inspect} were supplied."
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# supplied by parent class impl.
|
93
|
+
def logger
|
94
|
+
self.class.logger
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
@@ -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
|