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/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