zookeeper-ng 1.5

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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.ctags_paths +1 -0
  3. data/.dotfiles/ruby-gemset +1 -0
  4. data/.dotfiles/ruby-version +1 -0
  5. data/.dotfiles/rvmrc +2 -0
  6. data/.gitignore +19 -0
  7. data/.gitmodules +3 -0
  8. data/.travis.yml +25 -0
  9. data/CHANGELOG +395 -0
  10. data/Gemfile +30 -0
  11. data/Guardfile +8 -0
  12. data/LICENSE +23 -0
  13. data/Manifest +29 -0
  14. data/README.markdown +85 -0
  15. data/Rakefile +121 -0
  16. data/cause-abort.rb +117 -0
  17. data/ext/.gitignore +6 -0
  18. data/ext/Rakefile +41 -0
  19. data/ext/c_zookeeper.rb +398 -0
  20. data/ext/common.h +17 -0
  21. data/ext/dbg.h +53 -0
  22. data/ext/depend +5 -0
  23. data/ext/event_lib.c +740 -0
  24. data/ext/event_lib.h +175 -0
  25. data/ext/extconf.rb +103 -0
  26. data/ext/generate_gvl_code.rb +321 -0
  27. data/ext/patches/zkc-3.3.5-network.patch +24 -0
  28. data/ext/patches/zkc-3.4.5-fetch-and-add.patch +16 -0
  29. data/ext/patches/zkc-3.4.5-logging.patch +41 -0
  30. data/ext/patches/zkc-3.4.5-out-of-order-ping.patch +163 -0
  31. data/ext/patches/zkc-3.4.5-overflow.patch +11 -0
  32. data/ext/patches/zkc-3.4.5-yosemite-htonl-fix.patch +102 -0
  33. data/ext/zkc-3.4.5.tar.gz +0 -0
  34. data/ext/zkrb.c +1075 -0
  35. data/ext/zkrb_wrapper.c +775 -0
  36. data/ext/zkrb_wrapper.h +350 -0
  37. data/ext/zkrb_wrapper_compat.c +15 -0
  38. data/ext/zkrb_wrapper_compat.h +11 -0
  39. data/ext/zookeeper_base.rb +256 -0
  40. data/java/java_base.rb +503 -0
  41. data/lib/zookeeper.rb +115 -0
  42. data/lib/zookeeper/acls.rb +44 -0
  43. data/lib/zookeeper/callbacks.rb +108 -0
  44. data/lib/zookeeper/client.rb +30 -0
  45. data/lib/zookeeper/client_methods.rb +282 -0
  46. data/lib/zookeeper/common.rb +122 -0
  47. data/lib/zookeeper/common/queue_with_pipe.rb +110 -0
  48. data/lib/zookeeper/compatibility.rb +138 -0
  49. data/lib/zookeeper/constants.rb +97 -0
  50. data/lib/zookeeper/continuation.rb +223 -0
  51. data/lib/zookeeper/core_ext.rb +58 -0
  52. data/lib/zookeeper/em_client.rb +55 -0
  53. data/lib/zookeeper/exceptions.rb +135 -0
  54. data/lib/zookeeper/forked.rb +19 -0
  55. data/lib/zookeeper/latch.rb +34 -0
  56. data/lib/zookeeper/logger.rb +39 -0
  57. data/lib/zookeeper/logger/forwarding_logger.rb +84 -0
  58. data/lib/zookeeper/monitor.rb +19 -0
  59. data/lib/zookeeper/rake_tasks.rb +165 -0
  60. data/lib/zookeeper/request_registry.rb +153 -0
  61. data/lib/zookeeper/stat.rb +21 -0
  62. data/lib/zookeeper/version.rb +4 -0
  63. data/notes.txt +14 -0
  64. data/scripts/upgrade-1.0-sed-alike.rb +46 -0
  65. data/spec/c_zookeeper_spec.rb +51 -0
  66. data/spec/chrooted_connection_spec.rb +83 -0
  67. data/spec/compatibilty_spec.rb +8 -0
  68. data/spec/default_watcher_spec.rb +41 -0
  69. data/spec/em_spec.rb +51 -0
  70. data/spec/ext/zookeeper_base_spec.rb +19 -0
  71. data/spec/forked_connection_spec.rb +124 -0
  72. data/spec/latch_spec.rb +24 -0
  73. data/spec/log4j.properties +17 -0
  74. data/spec/shared/all_success_return_values.rb +10 -0
  75. data/spec/shared/connection_examples.rb +1077 -0
  76. data/spec/spec_helper.rb +61 -0
  77. data/spec/support/00_logging.rb +38 -0
  78. data/spec/support/10_spawn_zookeeper.rb +24 -0
  79. data/spec/support/progress_formatter.rb +15 -0
  80. data/spec/support/zookeeper_spec_helpers.rb +96 -0
  81. data/spec/zookeeper_spec.rb +24 -0
  82. data/zookeeper.gemspec +38 -0
  83. data/zoomonkey/duplicates +3 -0
  84. data/zoomonkey/zoomonkey.rb +194 -0
  85. metadata +157 -0
data/lib/zookeeper.rb ADDED
@@ -0,0 +1,115 @@
1
+ # Ruby wrapper for the Zookeeper C API
2
+
3
+ require 'thread'
4
+ require 'monitor'
5
+ require 'forwardable'
6
+ require 'logger'
7
+ require 'benchmark'
8
+
9
+ module Zookeeper
10
+ ZOOKEEPER_ROOT = File.expand_path('../..', __FILE__)
11
+
12
+ # require a path relative to the lib directory
13
+ # this is to avoid monkeying explicitly with $LOAD_PATH
14
+ #
15
+ # @private
16
+ def self.require_lib(*relpaths)
17
+ relpaths.each do |relpath|
18
+ require File.join(ZOOKEEPER_ROOT, 'lib', relpath)
19
+ end
20
+ end
21
+
22
+ # require a path that's relative to ZOOKEEPER_ROOT
23
+ # @private
24
+ def self.require_root(*relpaths)
25
+ relpaths.each do |relpath|
26
+ require File.join(ZOOKEEPER_ROOT, relpath)
27
+ end
28
+ end
29
+ end
30
+
31
+ Zookeeper.require_lib(
32
+ 'zookeeper/core_ext',
33
+ 'zookeeper/monitor',
34
+ 'zookeeper/logger',
35
+ 'zookeeper/logger/forwarding_logger',
36
+ 'zookeeper/forked',
37
+ 'zookeeper/latch',
38
+ 'zookeeper/acls',
39
+ 'zookeeper/constants',
40
+ 'zookeeper/exceptions',
41
+ 'zookeeper/continuation',
42
+ 'zookeeper/common',
43
+ 'zookeeper/request_registry',
44
+ 'zookeeper/callbacks',
45
+ 'zookeeper/stat',
46
+ 'zookeeper/client_methods'
47
+ )
48
+
49
+ # ok, now we construct the client
50
+ Zookeeper.require_lib 'zookeeper/client'
51
+
52
+ module Zookeeper
53
+ include Constants
54
+ #::Logger.new($stderr).tap { |l| l.level = ENV['ZOOKEEPER_DEBUG'] ? ::Logger::DEBUG : ::Logger::ERROR }
55
+ #
56
+
57
+ @@logger = nil unless defined?(@@logger)
58
+
59
+ def self.logger
60
+ @@logger
61
+ end
62
+
63
+ def self.logger=(logger)
64
+ @@logger = logger
65
+ end
66
+
67
+ # @private
68
+ def self.deprecation_warnings?
69
+ @deprecation_warnings = true if @deprecation_warnings.nil?
70
+ end
71
+
72
+ # set this to false to mute Zookeeper related deprecation warnings...
73
+ # __AT YOUR PERIL__
74
+ def self.deprecation_warnings=(v)
75
+ @deprecation_warnings = v
76
+ end
77
+
78
+ # @private
79
+ def self.deprecation_warning(warning)
80
+ Kernel.warn(warning) if deprecation_warnings?
81
+ end
82
+
83
+ # for expert use only. set the underlying debug level for the C layer, has no
84
+ # effect in java
85
+ #
86
+ # @private
87
+ def self.set_debug_level(val)
88
+ if defined?(CZookeeper)
89
+ CZookeeper.set_debug_level(val.to_i)
90
+ end
91
+ end
92
+
93
+ # @private
94
+ def self.get_debug_level
95
+ if defined?(CZookeeper)
96
+ CZookeeper.get_debug_level
97
+ end
98
+ end
99
+
100
+ class << self
101
+ # @private
102
+ alias :debug_level= :set_debug_level
103
+
104
+ # @private
105
+ alias :debug_level :get_debug_level
106
+ end
107
+ end
108
+
109
+ # just for first test, get rid of this soon
110
+ Zookeeper.require_lib 'zookeeper/compatibility'
111
+
112
+ if ENV['ZKRB_DEBUG']
113
+ Zookeeper.debug_level = Zookeeper::Constants::ZOO_LOG_LEVEL_DEBUG
114
+ end
115
+
@@ -0,0 +1,44 @@
1
+ module Zookeeper
2
+ module ACLs
3
+ class Id
4
+ attr_reader :scheme, :id
5
+ def initialize(hash)
6
+ @scheme = hash[:scheme]
7
+ @id = hash[:id]
8
+ end
9
+
10
+ def to_hash
11
+ { :id => id, :scheme => scheme }
12
+ end
13
+ end
14
+
15
+ class ACL
16
+ attr_reader :perms, :id
17
+ def initialize(hash)
18
+ @perms = hash[:perms]
19
+ v = hash[:id]
20
+ @id = v.kind_of?(Hash) ? Id.new(v) : v
21
+ end
22
+
23
+ def to_hash
24
+ { :perms => perms, :id => id.to_hash }
25
+ end
26
+ end
27
+
28
+ module Constants
29
+ ZOO_PERM_READ = 1 << 0
30
+ ZOO_PERM_WRITE = 1 << 1
31
+ ZOO_PERM_CREATE = 1 << 2
32
+ ZOO_PERM_DELETE = 1 << 3
33
+ ZOO_PERM_ADMIN = 1 << 4
34
+ ZOO_PERM_ALL = ZOO_PERM_READ | ZOO_PERM_WRITE | ZOO_PERM_CREATE | ZOO_PERM_DELETE | ZOO_PERM_ADMIN
35
+
36
+ ZOO_ANYONE_ID_UNSAFE = Id.new(:scheme => "world", :id => "anyone")
37
+ ZOO_AUTH_IDS = Id.new(:scheme => "auth", :id => "")
38
+
39
+ ZOO_OPEN_ACL_UNSAFE = [ACL.new(:perms => ZOO_PERM_ALL, :id => ZOO_ANYONE_ID_UNSAFE)]
40
+ ZOO_READ_ACL_UNSAFE = [ACL.new(:perms => ZOO_PERM_READ, :id => ZOO_ANYONE_ID_UNSAFE)]
41
+ ZOO_CREATOR_ALL_ACL = [ACL.new(:perms => ZOO_PERM_ALL, :id => ZOO_AUTH_IDS)]
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,108 @@
1
+ module Zookeeper
2
+ module Callbacks
3
+ class Base
4
+ attr_reader :proc, :completed, :context
5
+
6
+ # allows for easier construction of a user callback block that will be
7
+ # called with the callback object itself as an argument.
8
+ #
9
+ # @example
10
+ #
11
+ # Base.create do |cb|
12
+ # puts "watcher callback called with argument: #{cb.inspect}"
13
+ # end
14
+ #
15
+ # "watcher callback called with argument: #<Zookeeper::Callbacks::Base:0x1018a3958 @state=3, @type=1, ...>"
16
+ #
17
+ #
18
+ def self.create
19
+ cb_inst = new { yield cb_inst }
20
+ end
21
+
22
+ def initialize
23
+ @completed = false
24
+ @proc = Proc.new do |hash|
25
+ initialize_context(hash)
26
+ yield if block_given?
27
+ @completed = true
28
+ end
29
+ end
30
+
31
+ def call(*args)
32
+ @proc.call(*args)
33
+ end
34
+
35
+ def completed?
36
+ @completed
37
+ end
38
+
39
+ def initialize_context(hash)
40
+ @context = nil
41
+ end
42
+ end
43
+
44
+ class WatcherCallback < Base
45
+ ## wexists, awexists, wget, awget, wget_children, awget_children
46
+ attr_reader :type, :state, :path
47
+
48
+ def initialize_context(hash)
49
+ @type, @state, @path, @context = hash[:type], hash[:state], hash[:path], hash[:context]
50
+ end
51
+ end
52
+
53
+ class DataCallback < Base
54
+ ## aget, awget
55
+ attr_reader :return_code, :data, :stat
56
+
57
+ def initialize_context(hash)
58
+ @return_code, @data, @stat, @context = hash[:rc], hash[:data], hash[:stat], hash[:context]
59
+ end
60
+ end
61
+
62
+ class StringCallback < Base
63
+ ## acreate, async
64
+ attr_reader :return_code, :string, :context
65
+
66
+ alias path string
67
+
68
+ def initialize_context(hash)
69
+ @return_code, @string, @context = hash[:rc], hash[:string], hash[:context]
70
+ end
71
+ end
72
+
73
+ class StringsCallback < Base
74
+ ## aget_children, awget_children
75
+ attr_reader :return_code, :children, :stat
76
+
77
+ def initialize_context(hash)
78
+ @return_code, @children, @stat, @context = hash[:rc], hash[:strings], hash[:stat], hash[:context]
79
+ end
80
+ end
81
+
82
+ class StatCallback < Base
83
+ ## aset, aexists, awexists
84
+ attr_reader :return_code, :stat
85
+
86
+ def initialize_context(hash)
87
+ @return_code, @stat, @context = hash[:rc], hash[:stat], hash[:context]
88
+ end
89
+ end
90
+
91
+ class VoidCallback < Base
92
+ ## adelete, aset_acl, add_auth
93
+ attr_reader :return_code
94
+
95
+ def initialize_context(hash)
96
+ @return_code, @context = hash[:rc], hash[:context]
97
+ end
98
+ end
99
+
100
+ class ACLCallback < Base
101
+ ## aget_acl
102
+ attr_reader :return_code, :acl, :stat
103
+ def initialize_context(hash)
104
+ @return_code, @acl, @stat, @context = hash[:rc], hash[:acl], hash[:stat], hash[:context]
105
+ end
106
+ end
107
+ end
108
+ end
@@ -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
+ Zookeeper.require_root('java/java_base')
7
+ else
8
+ Zookeeper.require_root('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,282 @@
1
+ module Zookeeper
2
+ module ClientMethods
3
+ extend Forwardable
4
+ include Constants
5
+ include ACLs
6
+ include Logger
7
+
8
+ # @req_registry is set up in the platform-specific base classes
9
+ def_delegators :@req_registry, :setup_call
10
+ private :setup_call
11
+
12
+ def reopen(timeout=10, watcher=nil, opts = {})
13
+ warn "WARN: ZookeeperBase#reopen watcher argument is now ignored" if watcher
14
+ super
15
+ end
16
+
17
+ def initialize(host, timeout=10, watcher=nil, opts = {})
18
+ super
19
+ end
20
+
21
+ def add_auth(options = {})
22
+ assert_open
23
+ assert_keys(options,
24
+ :supported => [:scheme, :cert],
25
+ :required => [:scheme, :cert])
26
+
27
+ req_id = setup_call(:add_auth, options)
28
+ rc = super(req_id, options[:scheme], options[:cert])
29
+
30
+ { :req_id => req_id, :rc => rc }
31
+ end
32
+
33
+ def get(options = {})
34
+ assert_open
35
+ assert_keys(options,
36
+ :supported => [:path, :watcher, :watcher_context, :callback, :callback_context],
37
+ :required => [:path])
38
+
39
+ req_id = setup_call(:get, options)
40
+ rc, value, stat = super(req_id, options[:path], options[:callback], options[:watcher])
41
+
42
+ rv = { :req_id => req_id, :rc => rc }
43
+ options[:callback] ? rv : rv.merge(:data => value, :stat => Stat.new(stat))
44
+ end
45
+
46
+ def set(options = {})
47
+ assert_open
48
+ assert_keys(options,
49
+ :supported => [:path, :data, :version, :callback, :callback_context],
50
+ :required => [:path])
51
+
52
+ assert_valid_data_size!(options[:data])
53
+ options[:version] ||= -1
54
+
55
+ req_id = setup_call(:set, options)
56
+ rc, stat = super(req_id, options[:path], options[:data], options[:callback], options[:version])
57
+
58
+ rv = { :req_id => req_id, :rc => rc }
59
+ options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
60
+ end
61
+
62
+ def get_children(options = {})
63
+ assert_open
64
+ assert_keys(options,
65
+ :supported => [:path, :callback, :callback_context, :watcher, :watcher_context],
66
+ :required => [:path])
67
+
68
+ req_id = setup_call(:get_children, options)
69
+ rc, children, stat = super(req_id, options[:path], options[:callback], options[:watcher])
70
+
71
+ rv = { :req_id => req_id, :rc => rc }
72
+ options[:callback] ? rv : rv.merge(:children => children, :stat => Stat.new(stat))
73
+ end
74
+
75
+ def stat(options = {})
76
+ assert_open
77
+ assert_keys(options,
78
+ :supported => [:path, :callback, :callback_context, :watcher, :watcher_context],
79
+ :required => [:path])
80
+
81
+ req_id = setup_call(:stat, options)
82
+ rc, stat = exists(req_id, options[:path], options[:callback], options[:watcher])
83
+
84
+ rv = { :req_id => req_id, :rc => rc }
85
+ options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
86
+ end
87
+
88
+ def create(options = {})
89
+ assert_open
90
+ assert_keys(options,
91
+ :supported => [:path, :data, :acl, :ephemeral, :sequence, :callback, :callback_context],
92
+ :required => [:path])
93
+
94
+ assert_valid_data_size!(options[:data])
95
+
96
+ flags = 0
97
+ flags |= ZOO_EPHEMERAL if options[:ephemeral]
98
+ flags |= ZOO_SEQUENCE if options[:sequence]
99
+
100
+ options[:acl] ||= ZOO_OPEN_ACL_UNSAFE
101
+
102
+ req_id = setup_call(:create, 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_open
111
+ assert_keys(options,
112
+ :supported => [:path, :version, :callback, :callback_context],
113
+ :required => [:path])
114
+
115
+ options[:version] ||= -1
116
+
117
+ req_id = setup_call(:delete, options)
118
+ rc = super(req_id, options[:path], options[:version], options[:callback])
119
+
120
+ { :req_id => req_id, :rc => rc }
121
+ end
122
+
123
+ # this method is *only* asynchronous
124
+ #
125
+ # @note There is a discrepancy between the zkc and java versions. zkc takes
126
+ # a string_callback_t, java takes a VoidCallback. You should most likely use
127
+ # the Zookeeper::Callbacks::VoidCallback and not rely on the string value.
128
+ #
129
+ def sync(options = {})
130
+ assert_open
131
+ assert_keys(options,
132
+ :supported => [:path, :callback, :callback_context],
133
+ :required => [:path, :callback])
134
+
135
+ req_id = setup_call(:sync, options)
136
+
137
+ rc = super(req_id, options[:path]) # we don't pass options[:callback] here as this method is *always* async
138
+
139
+ { :req_id => req_id, :rc => rc }
140
+ end
141
+
142
+ def set_acl(options = {})
143
+ assert_open
144
+ assert_keys(options,
145
+ :supported => [:path, :acl, :version, :callback, :callback_context],
146
+ :required => [:path, :acl])
147
+ options[:version] ||= -1
148
+
149
+ req_id = setup_call(:set_acl, options)
150
+ rc = super(req_id, options[:path], options[:acl], options[:callback], options[:version])
151
+
152
+ { :req_id => req_id, :rc => rc }
153
+ end
154
+
155
+ def get_acl(options = {})
156
+ assert_open
157
+ assert_keys(options,
158
+ :supported => [:path, :callback, :callback_context],
159
+ :required => [:path])
160
+
161
+ req_id = setup_call(:get_acl, options)
162
+ rc, acls, stat = super(req_id, options[:path], options[:callback])
163
+
164
+ rv = { :req_id => req_id, :rc => rc }
165
+ options[:callback] ? rv : rv.merge(:acl => acls, :stat => Stat.new(stat))
166
+ end
167
+
168
+ # close this client and any underlying connections
169
+ def close
170
+ super
171
+ end
172
+
173
+ def state
174
+ super
175
+ end
176
+
177
+ def connected?
178
+ super
179
+ end
180
+
181
+ def connecting?
182
+ super
183
+ end
184
+
185
+ def associating?
186
+ super
187
+ end
188
+
189
+ # There are some operations that are dangerous in the context of the event
190
+ # dispatch thread (because they would block further event delivery). This
191
+ # method allows clients to know if they're currently executing in the context of an
192
+ # event.
193
+ #
194
+ # @returns [true,false] true if the current thread is the event dispatch thread
195
+ def event_dispatch_thread?
196
+ super
197
+ end
198
+
199
+ # DEPRECATED: use the class-level method instead
200
+ def set_debug_level(val)
201
+ super
202
+ end
203
+
204
+ # has the underlying connection been closed?
205
+ def closed?
206
+ super
207
+ end
208
+
209
+ # is the event delivery system running?
210
+ def running?
211
+ super
212
+ end
213
+
214
+ # return the session id of the current connection as an Fixnum
215
+ def session_id
216
+ super
217
+ end
218
+
219
+ # Return the passwd portion of this connection's credentials as a String
220
+ def session_passwd
221
+ super
222
+ end
223
+
224
+ # stop all underlying threads in preparation for a fork()
225
+ def pause_before_fork_in_parent
226
+ super
227
+ end
228
+
229
+ # re-start all underlying threads after performing a fork()
230
+ def resume_after_fork_in_parent
231
+ super
232
+ end
233
+
234
+ protected
235
+ # used during shutdown, awaken the event delivery thread if it's blocked
236
+ # waiting for the next event
237
+ def wake_event_loop!
238
+ super
239
+ end
240
+
241
+ # starts the event delivery subsystem going. after calling this method, running? will be true
242
+ def setup_dispatch_thread!
243
+ super
244
+ end
245
+
246
+ # TODO: describe what this does
247
+ def get_default_global_watcher
248
+ super
249
+ end
250
+
251
+ def assert_valid_data_size!(data)
252
+ return if data.nil?
253
+
254
+ data = data.to_s
255
+ if data.length >= 1048576 # one megabyte
256
+ raise Zookeeper::Exceptions::DataTooLargeException, "data must be smaller than 1 MiB, your data starts with: #{data[0..32].inspect}"
257
+ end
258
+ nil
259
+ end
260
+
261
+ private
262
+ def assert_keys(args, opts={})
263
+ supported = opts[:supported] || []
264
+ required = opts[:required] || []
265
+
266
+ unless (args.keys - supported).empty?
267
+ raise Zookeeper::Exceptions::BadArguments,
268
+ "Supported arguments are: #{supported.inspect}, but arguments #{args.keys.inspect} were supplied instead"
269
+ end
270
+
271
+ unless (required - args.keys).empty?
272
+ raise Zookeeper::Exceptions::BadArguments,
273
+ "Required arguments are: #{required.inspect}, but only the arguments #{args.keys.inspect} were supplied."
274
+ end
275
+ end
276
+
277
+ # must be supplied by parent class impl.
278
+ def assert_open
279
+ super
280
+ end
281
+ end # ClientMethods
282
+ end # Zookeeper