zookeeper 0.9.4 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.dotfiles/rvmrc +1 -0
  2. data/.gitignore +3 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +22 -0
  5. data/CHANGELOG +38 -5
  6. data/Gemfile +18 -1
  7. data/README.markdown +2 -0
  8. data/Rakefile +47 -109
  9. data/ext/c_zookeeper.rb +10 -6
  10. data/ext/zookeeper_base.rb +23 -11
  11. data/ext/zookeeper_c.c +14 -10
  12. data/java/{zookeeper_base.rb → java_base.rb} +13 -12
  13. data/lib/zookeeper.rb +32 -244
  14. data/lib/zookeeper/acls.rb +17 -13
  15. data/lib/zookeeper/callbacks.rb +28 -11
  16. data/lib/zookeeper/client.rb +30 -0
  17. data/lib/zookeeper/client_methods.rb +241 -0
  18. data/lib/zookeeper/common.rb +13 -12
  19. data/lib/zookeeper/common/queue_with_pipe.rb +3 -7
  20. data/lib/zookeeper/compatibility.rb +135 -0
  21. data/lib/zookeeper/constants.rb +35 -1
  22. data/lib/zookeeper/em_client.rb +1 -1
  23. data/lib/zookeeper/exceptions.rb +117 -93
  24. data/lib/zookeeper/rake_tasks.rb +165 -0
  25. data/lib/zookeeper/stat.rb +16 -16
  26. data/lib/zookeeper/version.rb +2 -4
  27. data/scripts/upgrade-1.0-sed-alike.rb +46 -0
  28. data/spec/c_zookeeper_spec.rb +10 -9
  29. data/spec/chrooted_connection_spec.rb +2 -2
  30. data/spec/default_watcher_spec.rb +4 -4
  31. data/spec/em_spec.rb +1 -1
  32. data/spec/shared/connection_examples.rb +52 -37
  33. data/spec/spec_helper.rb +22 -84
  34. data/spec/support/00_spawn_zookeeper.rb +20 -0
  35. data/spec/support/zookeeper_spec_helpers.rb +84 -0
  36. data/spec/zookeeper_spec.rb +1 -1
  37. metadata +47 -34
  38. data/examples/cloud_config.rb +0 -125
  39. data/test/test_basic.rb +0 -37
  40. data/test/test_callback1.rb +0 -36
  41. data/test/test_close.rb +0 -16
  42. data/test/test_esoteric.rb +0 -7
  43. data/test/test_watcher1.rb +0 -56
  44. data/test/test_watcher2.rb +0 -52
@@ -0,0 +1,30 @@
1
+ # figure out what platform we're on
2
+ # this way there's no ambiguity about which file to include
3
+ # or which class we're subclassing.
4
+
5
+ if defined?(::JRUBY_VERSION)
6
+ require_relative('../../java/java_base')
7
+ else
8
+ require_relative('../../ext/zookeeper_base')
9
+ end
10
+
11
+
12
+ module Zookeeper
13
+ if defined?(::JRUBY_VERSION)
14
+ class Client < Zookeeper::JavaBase
15
+ end
16
+ else
17
+ class Client < Zookeeper::ZookeeperBase
18
+ end
19
+ end
20
+
21
+ def self.new(*a, &b)
22
+ Zookeeper::Client.new(*a, &b)
23
+ end
24
+ end
25
+
26
+
27
+ Zookeeper::Client.class_eval do
28
+ include Zookeeper::ClientMethods
29
+ end
30
+
@@ -0,0 +1,241 @@
1
+ module Zookeeper
2
+ module ClientMethods
3
+ include Constants
4
+ include ACLs
5
+
6
+ def reopen(timeout=10, watcher=nil)
7
+ warn "WARN: ZookeeperBase#reopen watcher argument is now ignored" if watcher
8
+ super
9
+ end
10
+
11
+ def initialize(host, timeout=10, watcher=nil)
12
+ super
13
+ end
14
+
15
+ def get(options = {})
16
+ assert_open
17
+ assert_supported_keys(options, [:path, :watcher, :watcher_context, :callback, :callback_context])
18
+ assert_required_keys(options, [:path])
19
+
20
+ req_id = setup_call(:get, options)
21
+ rc, value, stat = super(req_id, options[:path], options[:callback], options[:watcher])
22
+
23
+ rv = { :req_id => req_id, :rc => rc }
24
+ options[:callback] ? rv : rv.merge(:data => value, :stat => Stat.new(stat))
25
+ end
26
+
27
+ def set(options = {})
28
+ assert_open
29
+ assert_supported_keys(options, [:path, :data, :version, :callback, :callback_context])
30
+ assert_required_keys(options, [:path])
31
+ assert_valid_data_size!(options[:data])
32
+ options[:version] ||= -1
33
+
34
+ req_id = setup_call(:set, options)
35
+ rc, stat = super(req_id, options[:path], options[:data], options[:callback], options[:version])
36
+
37
+ rv = { :req_id => req_id, :rc => rc }
38
+ options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
39
+ end
40
+
41
+ def get_children(options = {})
42
+ assert_open
43
+ assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
44
+ assert_required_keys(options, [:path])
45
+
46
+ req_id = setup_call(:get_children, options)
47
+ rc, children, stat = super(req_id, options[:path], options[:callback], options[:watcher])
48
+
49
+ rv = { :req_id => req_id, :rc => rc }
50
+ options[:callback] ? rv : rv.merge(:children => children, :stat => Stat.new(stat))
51
+ end
52
+
53
+ def stat(options = {})
54
+ assert_open
55
+ assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
56
+ assert_required_keys(options, [:path])
57
+
58
+ req_id = setup_call(:stat, options)
59
+ rc, stat = exists(req_id, options[:path], options[:callback], options[:watcher])
60
+
61
+ rv = { :req_id => req_id, :rc => rc }
62
+ options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
63
+ end
64
+
65
+ def create(options = {})
66
+ assert_open
67
+ assert_supported_keys(options, [:path, :data, :acl, :ephemeral, :sequence, :callback, :callback_context])
68
+ assert_required_keys(options, [:path])
69
+ assert_valid_data_size!(options[:data])
70
+
71
+ flags = 0
72
+ flags |= ZOO_EPHEMERAL if options[:ephemeral]
73
+ flags |= ZOO_SEQUENCE if options[:sequence]
74
+
75
+ options[:acl] ||= ZOO_OPEN_ACL_UNSAFE
76
+
77
+ req_id = setup_call(:create, options)
78
+ rc, newpath = super(req_id, options[:path], options[:data], options[:callback], options[:acl], flags)
79
+
80
+ rv = { :req_id => req_id, :rc => rc }
81
+ options[:callback] ? rv : rv.merge(:path => newpath)
82
+ end
83
+
84
+ def delete(options = {})
85
+ assert_open
86
+ assert_supported_keys(options, [:path, :version, :callback, :callback_context])
87
+ assert_required_keys(options, [:path])
88
+ options[:version] ||= -1
89
+
90
+ req_id = setup_call(:delete, options)
91
+ rc = super(req_id, options[:path], options[:version], options[:callback])
92
+
93
+ { :req_id => req_id, :rc => rc }
94
+ end
95
+
96
+ # this method is *only* asynchronous
97
+ #
98
+ # @note There is a discrepancy between the zkc and java versions. zkc takes
99
+ # a string_callback_t, java takes a VoidCallback. You should most likely use
100
+ # the ZookeeperCallbacks::VoidCallback and not rely on the string value.
101
+ #
102
+ def sync(options = {})
103
+ assert_open
104
+ assert_supported_keys(options, [:path, :callback, :callback_context])
105
+ assert_required_keys(options, [:path, :callback])
106
+
107
+ req_id = setup_call(:sync, options)
108
+
109
+ rc = super(req_id, options[:path]) # we don't pass options[:callback] here as this method is *always* async
110
+
111
+ { :req_id => req_id, :rc => rc }
112
+ end
113
+
114
+ def set_acl(options = {})
115
+ assert_open
116
+ assert_supported_keys(options, [:path, :acl, :version, :callback, :callback_context])
117
+ assert_required_keys(options, [:path, :acl])
118
+ options[:version] ||= -1
119
+
120
+ req_id = setup_call(:set_acl, options)
121
+ rc = super(req_id, options[:path], options[:acl], options[:callback], options[:version])
122
+
123
+ { :req_id => req_id, :rc => rc }
124
+ end
125
+
126
+ def get_acl(options = {})
127
+ assert_open
128
+ assert_supported_keys(options, [:path, :callback, :callback_context])
129
+ assert_required_keys(options, [:path])
130
+
131
+ req_id = setup_call(:get_acl, options)
132
+ rc, acls, stat = super(req_id, options[:path], options[:callback])
133
+
134
+ rv = { :req_id => req_id, :rc => rc }
135
+ options[:callback] ? rv : rv.merge(:acl => acls, :stat => Stat.new(stat))
136
+ end
137
+
138
+ # close this client and any underyling connections
139
+ def close
140
+ super
141
+ end
142
+
143
+ def state
144
+ super
145
+ end
146
+
147
+ def connected?
148
+ super
149
+ end
150
+
151
+ def connecting?
152
+ super
153
+ end
154
+
155
+ def associating?
156
+ super
157
+ end
158
+
159
+ # There are some operations that are dangerous in the context of the event
160
+ # dispatch thread (because they would block further event delivery). This
161
+ # method allows clients to know if they're currently executing in the context of an
162
+ # event.
163
+ #
164
+ # @returns [true,false] true if the current thread is the event dispatch thread
165
+ def event_dispatch_thread?
166
+ super
167
+ end
168
+
169
+ # DEPRECATED: use the class-level method instead
170
+ def set_debug_level(val)
171
+ super
172
+ end
173
+
174
+ # has the underlying connection been closed?
175
+ def closed?
176
+ super
177
+ end
178
+
179
+ # is the event delivery system running?
180
+ def running?
181
+ super
182
+ end
183
+
184
+ # return the session id of the current connection as an Fixnum
185
+ def session_id
186
+ super
187
+ end
188
+
189
+ # Return the passwd portion of this connection's credentials as a String
190
+ def session_passwd
191
+ super
192
+ end
193
+
194
+ protected
195
+ # used during shutdown, awaken the event delivery thread if it's blocked
196
+ # waiting for the next event
197
+ def wake_event_loop!
198
+ super
199
+ end
200
+
201
+ # starts the event delivery subsystem going. after calling this method, running? will be true
202
+ def setup_dispatch_thread!
203
+ super
204
+ end
205
+
206
+ # TODO: describe what this does
207
+ def get_default_global_watcher
208
+ super
209
+ end
210
+
211
+ def logger
212
+ Zookeeper.logger
213
+ end
214
+
215
+ def assert_valid_data_size!(data)
216
+ return if data.nil?
217
+
218
+ data = data.to_s
219
+ if data.length >= 1048576 # one megabyte
220
+ raise Zookeeper::Exceptions::DataTooLargeException, "data must be smaller than 1 MiB, your data starts with: #{data[0..32].inspect}"
221
+ end
222
+ nil
223
+ end
224
+
225
+ private
226
+ # TODO: Sanitize user mistakes by unregistering watchers from ops that
227
+ # don't return ZOK (except wexists)? Make users clean up after themselves for now.
228
+ #
229
+ # XXX: is this dead code?
230
+ def unregister_watcher(req_id)
231
+ @mutex.synchronize {
232
+ @watcher_reqs.delete(req_id)
233
+ }
234
+ end
235
+
236
+ # must be supplied by parent class impl.
237
+ def assert_open
238
+ super
239
+ end
240
+ end # ClientMethods
241
+ end # Zookeeper
@@ -1,6 +1,8 @@
1
1
  require 'zookeeper/exceptions'
2
+ require 'zookeeper/common/queue_with_pipe'
2
3
 
3
- module ZookeeperCommon
4
+ module Zookeeper
5
+ module Common
4
6
  # sigh, i guess define this here?
5
7
  ZKRB_GLOBAL_CB_REQ = -1
6
8
 
@@ -27,7 +29,7 @@ protected
27
29
  }
28
30
  req_id
29
31
  end
30
-
32
+
31
33
  def setup_watcher(req_id, call_opts)
32
34
  @watcher_reqs[req_id] = { :watcher => call_opts[:watcher],
33
35
  :context => call_opts[:watcher_context] }
@@ -41,7 +43,7 @@ protected
41
43
  #
42
44
  def setup_completion(req_id, meth_name, call_opts)
43
45
  @completion_reqs[req_id] = { :callback => call_opts[:callback],
44
- :context => call_opts[:callback_context] }
46
+ :context => call_opts[:callback_context] }
45
47
  end
46
48
 
47
49
  def get_watcher(req_id)
@@ -118,15 +120,15 @@ protected
118
120
 
119
121
  is_completion = hash.has_key?(:rc)
120
122
 
121
- hash[:stat] = ZookeeperStat::Stat.new(hash[:stat]) if hash.has_key?(:stat)
122
- hash[:acl] = hash[:acl].map { |acl| ZookeeperACLs::ACL.new(acl) } if hash[:acl]
123
+ hash[:stat] = Zookeeper::Stat.new(hash[:stat]) if hash.has_key?(:stat)
124
+ hash[:acl] = hash[:acl].map { |acl| Zookeeper::ACLs::ACL.new(acl) } if hash[:acl]
123
125
 
124
126
  callback_context = is_completion ? get_completion(hash[:req_id]) : get_watcher(hash[:req_id])
125
127
 
126
128
  # When connectivity to the server has been lost (as indicated by SESSION_EVENT)
127
129
  # we want to rerun the callback at a later time when we eventually do have
128
130
  # a valid response.
129
- if hash[:type] == ZookeeperConstants::ZOO_SESSION_EVENT
131
+ if hash[:type] == Zookeeper::Constants::ZOO_SESSION_EVENT
130
132
  is_completion ? setup_completion(hash[:req_id], callback_context) : setup_watcher(hash[:req_id], callback_context)
131
133
  end
132
134
  if callback_context
@@ -148,14 +150,14 @@ protected
148
150
 
149
151
  def assert_supported_keys(args, supported)
150
152
  unless (args.keys - supported).empty?
151
- raise ZookeeperExceptions::ZookeeperException::BadArguments, # this heirarchy is kind of retarded
153
+ raise Zookeeper::Exceptions::BadArguments, # this heirarchy is kind of retarded
152
154
  "Supported arguments are: #{supported.inspect}, but arguments #{args.keys.inspect} were supplied instead"
153
155
  end
154
156
  end
155
157
 
156
158
  def assert_required_keys(args, required)
157
159
  unless (required - args.keys).empty?
158
- raise ZookeeperExceptions::ZookeeperException::BadArguments,
160
+ raise Zookeeper::Exceptions::BadArguments,
159
161
  "Required arguments are: #{required.inspect}, but only the arguments #{args.keys.inspect} were supplied."
160
162
  end
161
163
  end
@@ -164,11 +166,10 @@ private
164
166
  def prettify_event(hash)
165
167
  hash.dup.tap do |h|
166
168
  # pretty up the event display
167
- h[:type] = ZookeeperConstants::EVENT_TYPE_NAMES.fetch(h[:type]) if h[:type]
168
- h[:state] = ZookeeperConstants::STATE_NAMES.fetch(h[:state]) if h[:state]
169
+ h[:type] = Zookeeper::Constants::EVENT_TYPE_NAMES.fetch(h[:type]) if h[:type]
170
+ h[:state] = Zookeeper::Constants::STATE_NAMES.fetch(h[:state]) if h[:state]
169
171
  h[:req_id] = :global_session if h[:req_id] == -1
170
172
  end
171
173
  end
172
174
  end
173
-
174
- require 'zookeeper/common/queue_with_pipe'
175
+ end
@@ -1,4 +1,5 @@
1
- module ZookeeperCommon
1
+ module Zookeeper
2
+ module Common
2
3
  # Ceci n'est pas une pipe
3
4
  class QueueWithPipe
4
5
  extend Forwardable
@@ -13,14 +14,8 @@ module ZookeeperCommon
13
14
  KILL_TOKEN = Object.new unless defined?(KILL_TOKEN)
14
15
 
15
16
  def initialize
16
- # r, w = IO.pipe
17
- # @pipe = { :read => r, :write => w }
18
17
  @queue = Queue.new
19
18
 
20
- # with the EventMachine client, we want to let EM handle clearing the
21
- # event pipe, so we set this to false
22
- # @clear_reads_on_pop = true
23
-
24
19
  @mutex = Mutex.new
25
20
  @closed = false
26
21
  @graceful = false
@@ -76,3 +71,4 @@ module ZookeeperCommon
76
71
  end
77
72
  end
78
73
  end
74
+ end
@@ -0,0 +1,135 @@
1
+ module Zookeeper
2
+ # @private
3
+ def self.warn_about_compatability_once!
4
+ return if @warned_about_compatibility
5
+ @warned_about_compatibility = true
6
+
7
+ warn <<-EOS
8
+
9
+ -----------------------------------------------------------------------------
10
+
11
+ NOTICE: ZOOKEEPER BACKWARDS COMPATIBILTY EANBLED!!
12
+
13
+ THIS WILL NOT BE AUTOMATIC IN 1.1 !!
14
+
15
+ There was a major change to the organization of the Zookeeper gem between
16
+ 0.9 and 1.0, breaking backwards compatibility. To ease the transition,
17
+
18
+ #{__FILE__}
19
+
20
+ is automatically required. This will *not* be the case in 1.1.
21
+
22
+ -----------------------------------------------------------------------------
23
+ EOS
24
+ end
25
+
26
+ def self.warned_about_compatability?
27
+ !!@warned_about_compatability
28
+ end
29
+ end
30
+
31
+ Zookeeper.warn_about_compatability_once!
32
+
33
+ module Zookeeper
34
+ module Compatibility
35
+ def clean_backtrace
36
+ caller[0..-2].reject {|n| n =~ %r%/rspec/|\(eval\)|const_missing% }.map { |n| "\t#{n}" }.join("\n")
37
+ end
38
+ end
39
+ end
40
+
41
+ module ZookeeperConstants
42
+ include Zookeeper::Constants
43
+ end
44
+
45
+ module ZookeeperCallbacks
46
+ include Zookeeper::Callbacks
47
+ Callback = Base
48
+ end
49
+
50
+ module ZookeeperExceptions
51
+ include Zookeeper::Exceptions
52
+ end
53
+
54
+ module ZookeeperStat
55
+ extend Zookeeper::Compatibility
56
+ def self.const_missing(sym)
57
+ if sym == :Stat
58
+ warn "\nZookeeperStat::Stat is now Zookeeper::Stat, please update your code!\n#{clean_backtrace}"
59
+ # self.const_set(sym, Zookeeper::Stat)
60
+ Zookeeper::Stat
61
+ else
62
+ super
63
+ end
64
+ end
65
+ end
66
+
67
+ module ZookeeperACLs
68
+ extend Zookeeper::Compatibility
69
+ def self.const_missing(sym)
70
+ candidates = [Zookeeper::ACLs, Zookeeper::Constants, Zookeeper::ACLs::Constants]
71
+
72
+ candidates.each do |candidate|
73
+ if candidate.const_defined?(sym)
74
+ warn "\n#{self.name}::#{sym} is now located in #{candidate}::#{sym}, please update your code!\n#{clean_backtrace}"
75
+
76
+ c = candidate.const_get(sym)
77
+ # self.const_set(sym, c)
78
+ return c
79
+ end
80
+ end
81
+
82
+ super
83
+ end
84
+ end
85
+
86
+ module ZookeeperCommon
87
+ include Zookeeper::Common
88
+ extend Zookeeper::Compatibility
89
+
90
+ def self.const_missing(sym)
91
+ candidate = Zookeeper::Common
92
+
93
+ if candidate.const_defined?(sym)
94
+ warn "\n#{self.name}::#{sym} is now located in #{candidate}::#{sym}, please update your code!\n#{clean_backtrace}"
95
+
96
+ candidate.const_get(sym).tap do |c|
97
+ # self.const_set(sym, c)
98
+ end
99
+ else
100
+ super
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ # module Zookeeper
107
+ # include ZookeeperConstants
108
+ # include ZookeeperCallbacks
109
+ # include ZookeeperExceptions
110
+ # include ZookeeperCommon
111
+ # include ZookeeperStat
112
+ # include ZookeeperACLs
113
+ # end
114
+
115
+ module Zookeeper
116
+ extend Zookeeper::Compatibility
117
+ def self.const_missing(sym)
118
+ candidate =
119
+ case sym.to_s
120
+ when /Callback/
121
+ Zookeeper::Callbacks
122
+ end
123
+
124
+ if candidate.const_defined?(sym)
125
+ warn "\n#{self.name}::#{sym} is now located in #{candidate}::#{sym}, please update your code!\n#{clean_backtrace}"
126
+
127
+ candidate.const_get(sym).tap do |c|
128
+ # self.const_set(sym, c)
129
+ end
130
+ else
131
+ super
132
+ end
133
+ end
134
+ end
135
+