slyphon-zookeeper 0.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
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