zookeeper 0.9.3-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.gitignore +10 -0
  2. data/CHANGELOG +119 -0
  3. data/Gemfile +17 -0
  4. data/LICENSE +23 -0
  5. data/Manifest +29 -0
  6. data/README.markdown +59 -0
  7. data/Rakefile +139 -0
  8. data/examples/cloud_config.rb +125 -0
  9. data/ext/.gitignore +6 -0
  10. data/ext/Rakefile +51 -0
  11. data/ext/c_zookeeper.rb +212 -0
  12. data/ext/dbg.h +53 -0
  13. data/ext/depend +5 -0
  14. data/ext/extconf.rb +85 -0
  15. data/ext/generate_gvl_code.rb +316 -0
  16. data/ext/zkc-3.3.5.tar.gz +0 -0
  17. data/ext/zkrb_wrapper.c +731 -0
  18. data/ext/zkrb_wrapper.h +330 -0
  19. data/ext/zkrb_wrapper_compat.c +15 -0
  20. data/ext/zkrb_wrapper_compat.h +11 -0
  21. data/ext/zookeeper_base.rb +211 -0
  22. data/ext/zookeeper_c.c +725 -0
  23. data/ext/zookeeper_lib.c +677 -0
  24. data/ext/zookeeper_lib.h +172 -0
  25. data/java/zookeeper_base.rb +477 -0
  26. data/lib/zookeeper.rb +297 -0
  27. data/lib/zookeeper/acls.rb +40 -0
  28. data/lib/zookeeper/callbacks.rb +91 -0
  29. data/lib/zookeeper/common.rb +174 -0
  30. data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
  31. data/lib/zookeeper/constants.rb +57 -0
  32. data/lib/zookeeper/em_client.rb +55 -0
  33. data/lib/zookeeper/exceptions.rb +100 -0
  34. data/lib/zookeeper/stat.rb +21 -0
  35. data/lib/zookeeper/version.rb +6 -0
  36. data/notes.txt +14 -0
  37. data/spec/c_zookeeper_spec.rb +50 -0
  38. data/spec/chrooted_connection_spec.rb +81 -0
  39. data/spec/default_watcher_spec.rb +41 -0
  40. data/spec/em_spec.rb +51 -0
  41. data/spec/log4j.properties +17 -0
  42. data/spec/shared/all_success_return_values.rb +10 -0
  43. data/spec/shared/connection_examples.rb +1018 -0
  44. data/spec/spec_helper.rb +119 -0
  45. data/spec/support/progress_formatter.rb +15 -0
  46. data/spec/zookeeper_spec.rb +24 -0
  47. data/test/test_basic.rb +37 -0
  48. data/test/test_callback1.rb +36 -0
  49. data/test/test_close.rb +16 -0
  50. data/test/test_esoteric.rb +7 -0
  51. data/test/test_watcher1.rb +56 -0
  52. data/test/test_watcher2.rb +52 -0
  53. metadata +181 -0
data/lib/zookeeper.rb ADDED
@@ -0,0 +1,297 @@
1
+ # Ruby wrapper for the Zookeeper C API
2
+
3
+ require 'thread'
4
+ require 'monitor'
5
+ require 'forwardable'
6
+ require 'logger'
7
+
8
+ require 'zookeeper/common'
9
+ require 'zookeeper/constants'
10
+ require 'zookeeper/callbacks'
11
+ require 'zookeeper/exceptions'
12
+ require 'zookeeper/stat'
13
+ require 'zookeeper/acls'
14
+
15
+
16
+ if defined?(::JRUBY_VERSION)
17
+ $LOAD_PATH.unshift(File.expand_path('../java', File.dirname(__FILE__))).uniq!
18
+ else
19
+ $LOAD_PATH.unshift(File.expand_path('../ext', File.dirname(__FILE__))).uniq!
20
+ end
21
+
22
+ require 'zookeeper_base'
23
+
24
+ class Zookeeper < ZookeeperBase
25
+ unless defined?(@@logger)
26
+ @@logger = Logger.new($stderr).tap { |l| l.level = Logger::ERROR }
27
+ end
28
+
29
+ def self.logger
30
+ @@logger
31
+ end
32
+
33
+ def self.logger=(logger)
34
+ @@logger = logger
35
+ end
36
+
37
+ def reopen(timeout=10, watcher=nil)
38
+ warn "WARN: ZookeeperBase#reopen watcher argument is now ignored" if watcher
39
+ super
40
+ end
41
+
42
+ def initialize(host, timeout=10, watcher=nil)
43
+ super
44
+ end
45
+
46
+ def get(options = {})
47
+ assert_open
48
+ assert_supported_keys(options, [:path, :watcher, :watcher_context, :callback, :callback_context])
49
+ assert_required_keys(options, [:path])
50
+
51
+ req_id = setup_call(:get, options)
52
+ rc, value, stat = super(req_id, options[:path], options[:callback], options[:watcher])
53
+
54
+ rv = { :req_id => req_id, :rc => rc }
55
+ options[:callback] ? rv : rv.merge(:data => value, :stat => Stat.new(stat))
56
+ end
57
+
58
+ def set(options = {})
59
+ assert_open
60
+ assert_supported_keys(options, [:path, :data, :version, :callback, :callback_context])
61
+ assert_required_keys(options, [:path])
62
+ assert_valid_data_size!(options[:data])
63
+ options[:version] ||= -1
64
+
65
+ req_id = setup_call(:set, options)
66
+ rc, stat = super(req_id, options[:path], options[:data], options[:callback], options[:version])
67
+
68
+ rv = { :req_id => req_id, :rc => rc }
69
+ options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
70
+ end
71
+
72
+ def get_children(options = {})
73
+ assert_open
74
+ assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
75
+ assert_required_keys(options, [:path])
76
+
77
+ req_id = setup_call(:get_children, options)
78
+ rc, children, stat = super(req_id, options[:path], options[:callback], options[:watcher])
79
+
80
+ rv = { :req_id => req_id, :rc => rc }
81
+ options[:callback] ? rv : rv.merge(:children => children, :stat => Stat.new(stat))
82
+ end
83
+
84
+ def stat(options = {})
85
+ assert_open
86
+ assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
87
+ assert_required_keys(options, [:path])
88
+
89
+ req_id = setup_call(:stat, options)
90
+ rc, stat = exists(req_id, options[:path], options[:callback], options[:watcher])
91
+
92
+ rv = { :req_id => req_id, :rc => rc }
93
+ options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
94
+ end
95
+
96
+ def create(options = {})
97
+ assert_open
98
+ assert_supported_keys(options, [:path, :data, :acl, :ephemeral, :sequence, :callback, :callback_context])
99
+ assert_required_keys(options, [:path])
100
+ assert_valid_data_size!(options[:data])
101
+
102
+ flags = 0
103
+ flags |= ZOO_EPHEMERAL if options[:ephemeral]
104
+ flags |= ZOO_SEQUENCE if options[:sequence]
105
+
106
+ options[:acl] ||= ZOO_OPEN_ACL_UNSAFE
107
+
108
+ req_id = setup_call(:create, options)
109
+ rc, newpath = super(req_id, options[:path], options[:data], options[:callback], options[:acl], flags)
110
+
111
+ rv = { :req_id => req_id, :rc => rc }
112
+ options[:callback] ? rv : rv.merge(:path => newpath)
113
+ end
114
+
115
+ def delete(options = {})
116
+ assert_open
117
+ assert_supported_keys(options, [:path, :version, :callback, :callback_context])
118
+ assert_required_keys(options, [:path])
119
+ options[:version] ||= -1
120
+
121
+ req_id = setup_call(:delete, options)
122
+ rc = super(req_id, options[:path], options[:version], options[:callback])
123
+
124
+ { :req_id => req_id, :rc => rc }
125
+ end
126
+
127
+ # this method is *only* asynchronous
128
+ #
129
+ # @note There is a discrepancy between the zkc and java versions. zkc takes
130
+ # a string_callback_t, java takes a VoidCallback. You should most likely use
131
+ # the ZookeeperCallbacks::VoidCallback and not rely on the string value.
132
+ #
133
+ def sync(options = {})
134
+ assert_open
135
+ assert_supported_keys(options, [:path, :callback, :callback_context])
136
+ assert_required_keys(options, [:path, :callback])
137
+
138
+ req_id = setup_call(:sync, options)
139
+
140
+ rc = super(req_id, options[:path]) # we don't pass options[:callback] here as this method is *always* async
141
+
142
+ { :req_id => req_id, :rc => rc }
143
+ end
144
+
145
+ def set_acl(options = {})
146
+ assert_open
147
+ assert_supported_keys(options, [:path, :acl, :version, :callback, :callback_context])
148
+ assert_required_keys(options, [:path, :acl])
149
+ options[:version] ||= -1
150
+
151
+ req_id = setup_call(:set_acl, options)
152
+ rc = super(req_id, options[:path], options[:acl], options[:callback], options[:version])
153
+
154
+ { :req_id => req_id, :rc => rc }
155
+ end
156
+
157
+ def get_acl(options = {})
158
+ assert_open
159
+ assert_supported_keys(options, [:path, :callback, :callback_context])
160
+ assert_required_keys(options, [:path])
161
+
162
+ req_id = setup_call(:get_acl, options)
163
+ rc, acls, stat = super(req_id, options[:path], options[:callback])
164
+
165
+ rv = { :req_id => req_id, :rc => rc }
166
+ options[:callback] ? rv : rv.merge(:acl => acls, :stat => Stat.new(stat))
167
+ end
168
+
169
+ # close this client and any underyling connections
170
+ def close
171
+ super
172
+ end
173
+
174
+ def state
175
+ super
176
+ end
177
+
178
+ def connected?
179
+ super
180
+ end
181
+
182
+ def connecting?
183
+ super
184
+ end
185
+
186
+ def associating?
187
+ super
188
+ end
189
+
190
+ # There are some operations that are dangerous in the context of the event
191
+ # dispatch thread (because they would block further event delivery). This
192
+ # method allows clients to know if they're currently executing in the context of an
193
+ # event.
194
+ #
195
+ # @returns [true,false] true if the current thread is the event dispatch thread
196
+ def event_dispatch_thread?
197
+ super
198
+ end
199
+
200
+ # for expert use only. set the underlying debug level for the C layer, has no
201
+ # effect in java
202
+ #
203
+ # @private
204
+ def self.set_debug_level(val)
205
+ if defined?(::CZookeeper)
206
+ CZookeeper.set_debug_level(val.to_i)
207
+ end
208
+ end
209
+
210
+ # @private
211
+ def self.get_debug_level
212
+ if defined?(::CZookeeper)
213
+ CZookeeper.get_debug_level
214
+ end
215
+ end
216
+
217
+ class << self
218
+ # @private
219
+ alias :debug_level= :set_debug_level
220
+
221
+ # @private
222
+ alias :debug_level :get_debug_level
223
+ end
224
+
225
+ # DEPRECATED: use the class-level method instead
226
+ def set_debug_level(val)
227
+ super
228
+ end
229
+
230
+ # has the underlying connection been closed?
231
+ def closed?
232
+ super
233
+ end
234
+
235
+ # is the event delivery system running?
236
+ def running?
237
+ super
238
+ end
239
+
240
+ # return the session id of the current connection as an Fixnum
241
+ def session_id
242
+ super
243
+ end
244
+
245
+ # Return the passwd portion of this connection's credentials as a String
246
+ def session_passwd
247
+ super
248
+ end
249
+
250
+ protected
251
+ # used during shutdown, awaken the event delivery thread if it's blocked
252
+ # waiting for the next event
253
+ def wake_event_loop!
254
+ super
255
+ end
256
+
257
+ # starts the event delivery subsystem going. after calling this method, running? will be true
258
+ def setup_dispatch_thread!
259
+ super
260
+ end
261
+
262
+ # TODO: describe what this does
263
+ def get_default_global_watcher
264
+ super
265
+ end
266
+
267
+ def logger
268
+ Zookeeper.logger
269
+ end
270
+
271
+ def assert_valid_data_size!(data)
272
+ return if data.nil?
273
+
274
+ data = data.to_s
275
+ if data.length >= 1048576 # one megabyte
276
+ raise ZookeeperException::DataTooLargeException, "data must be smaller than 1 MiB, your data starts with: #{data[0..32].inspect}"
277
+ end
278
+ nil
279
+ end
280
+
281
+ private
282
+ # TODO: Sanitize user mistakes by unregistering watchers from ops that
283
+ # don't return ZOK (except wexists)? Make users clean up after themselves for now.
284
+ #
285
+ # XXX: is this dead code?
286
+ def unregister_watcher(req_id)
287
+ @mutex.synchronize {
288
+ @watcher_reqs.delete(req_id)
289
+ }
290
+ end
291
+
292
+ # must be supplied by parent class impl.
293
+ def assert_open
294
+ super
295
+ end
296
+ end
297
+
@@ -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,91 @@
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, :string, :context
49
+
50
+ alias path string
51
+
52
+ def initialize_context(hash)
53
+ @return_code, @string, @context = hash[:rc], hash[:string], hash[:context]
54
+ end
55
+ end
56
+
57
+ class StringsCallback < Callback
58
+ ## aget_children, awget_children
59
+ attr_reader :return_code, :children, :stat
60
+
61
+ def initialize_context(hash)
62
+ @return_code, @children, @stat, @context = hash[:rc], hash[:strings], hash[:stat], hash[:context]
63
+ end
64
+ end
65
+
66
+ class StatCallback < Callback
67
+ ## aset, aexists, awexists
68
+ attr_reader :return_code, :stat
69
+
70
+ def initialize_context(hash)
71
+ @return_code, @stat, @context = hash[:rc], hash[:stat], hash[:context]
72
+ end
73
+ end
74
+
75
+ class VoidCallback < Callback
76
+ ## adelete, aset_acl, add_auth
77
+ attr_reader :return_code
78
+
79
+ def initialize_context(hash)
80
+ @return_code, @context = hash[:rc], hash[:context]
81
+ end
82
+ end
83
+
84
+ class ACLCallback < Callback
85
+ ## aget_acl
86
+ attr_reader :return_code, :acl, :stat
87
+ def initialize_context(hash)
88
+ @return_code, @acl, @stat, @context = hash[:rc], hash[:acl], hash[:stat], hash[:context]
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,174 @@
1
+ require 'zookeeper/exceptions'
2
+
3
+ module ZookeeperCommon
4
+ # sigh, i guess define this here?
5
+ ZKRB_GLOBAL_CB_REQ = -1
6
+
7
+ def event_dispatch_thread?
8
+ @dispatcher && (@dispatcher == Thread.current)
9
+ end
10
+
11
+ protected
12
+ def get_next_event(blocking=true)
13
+ @event_queue.pop(!blocking).tap do |event|
14
+ logger.debug { "#{self.class}##{__method__} delivering event #{event.inspect}" }
15
+ end
16
+ rescue ThreadError
17
+ nil
18
+ end
19
+
20
+ def setup_call(meth_name, opts)
21
+ req_id = nil
22
+ @mutex.synchronize {
23
+ req_id = @current_req_id
24
+ @current_req_id += 1
25
+ setup_completion(req_id, meth_name, opts) if opts[:callback]
26
+ setup_watcher(req_id, opts) if opts[:watcher]
27
+ }
28
+ req_id
29
+ end
30
+
31
+ def setup_watcher(req_id, call_opts)
32
+ @watcher_reqs[req_id] = { :watcher => call_opts[:watcher],
33
+ :context => call_opts[:watcher_context] }
34
+ end
35
+
36
+ # as a hack, to provide consistency between the java implementation and the C
37
+ # implementation when dealing w/ chrooted connections, we override this in
38
+ # ext/zookeeper_base.rb to wrap the callback in a chroot-path-stripping block.
39
+ #
40
+ # we don't use meth_name here, but we need it in the C implementation
41
+ #
42
+ def setup_completion(req_id, meth_name, call_opts)
43
+ @completion_reqs[req_id] = { :callback => call_opts[:callback],
44
+ :context => call_opts[:callback_context] }
45
+ end
46
+
47
+ def get_watcher(req_id)
48
+ @mutex.synchronize {
49
+ (req_id == ZKRB_GLOBAL_CB_REQ) ? @watcher_reqs[req_id] : @watcher_reqs.delete(req_id)
50
+ }
51
+ end
52
+
53
+ def get_completion(req_id)
54
+ @mutex.synchronize { @completion_reqs.delete(req_id) }
55
+ end
56
+
57
+ def setup_dispatch_thread!
58
+ logger.debug { "starting dispatch thread" }
59
+ @dispatcher ||= Thread.new do
60
+ while true
61
+ begin
62
+ dispatch_next_callback(get_next_event(true))
63
+ rescue QueueWithPipe::ShutdownException
64
+ logger.info { "dispatch thread exiting, got shutdown exception" }
65
+ break
66
+ rescue Exception => e
67
+ $stderr.puts ["#{e.class}: #{e.message}", e.backtrace.map { |n| "\t#{n}" }.join("\n")].join("\n")
68
+ end
69
+ end
70
+ signal_dispatch_thread_exit!
71
+ end
72
+ end
73
+
74
+ # this method is part of the reopen/close code, and is responsible for
75
+ # shutting down the dispatch thread.
76
+ #
77
+ # @dispatcher will be nil when this method exits
78
+ #
79
+ def stop_dispatch_thread!
80
+ logger.debug { "#{self.class}##{__method__}" }
81
+
82
+ if @dispatcher
83
+ if @dispatcher.join(0)
84
+ @dispatcher = nil
85
+ return
86
+ end
87
+
88
+ @mutex.synchronize do
89
+ event_queue.graceful_close!
90
+
91
+ # we now release the mutex so that dispatch_next_callback can grab it
92
+ # to do what it needs to do while delivering events
93
+ #
94
+ # wait for a maximum of 2 sec for dispatcher to signal exit (should be
95
+ # fast)
96
+ @dispatch_shutdown_cond.wait(2)
97
+
98
+ # wait for another 2 sec for the thread to join
99
+ unless @dispatcher.join(2)
100
+ logger.error { "Dispatch thread did not join cleanly, continuing" }
101
+ end
102
+ @dispatcher = nil
103
+ end
104
+ end
105
+ end
106
+
107
+ def signal_dispatch_thread_exit!
108
+ @mutex.synchronize do
109
+ logger.debug { "dispatch thread exiting!" }
110
+ @dispatch_shutdown_cond.broadcast
111
+ end
112
+ end
113
+
114
+ def dispatch_next_callback(hash)
115
+ return nil unless hash
116
+
117
+ Zookeeper.logger.debug { "get_next_event returned: #{prettify_event(hash).inspect}" }
118
+
119
+ is_completion = hash.has_key?(:rc)
120
+
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
+
124
+ callback_context = is_completion ? get_completion(hash[:req_id]) : get_watcher(hash[:req_id])
125
+
126
+ # When connectivity to the server has been lost (as indicated by SESSION_EVENT)
127
+ # we want to rerun the callback at a later time when we eventually do have
128
+ # a valid response.
129
+ if hash[:type] == ZookeeperConstants::ZOO_SESSION_EVENT
130
+ is_completion ? setup_completion(hash[:req_id], callback_context) : setup_watcher(hash[:req_id], callback_context)
131
+ end
132
+ if callback_context
133
+ callback = is_completion ? callback_context[:callback] : callback_context[:watcher]
134
+
135
+ hash[:context] = callback_context[:context]
136
+
137
+ # TODO: Eventually enforce derivation from Zookeeper::Callback
138
+ if callback.respond_to?(:call)
139
+ callback.call(hash)
140
+ else
141
+ # puts "dispatch_next_callback found non-callback => #{callback.inspect}"
142
+ end
143
+ else
144
+ logger.warn { "Duplicate event received (no handler for req_id #{hash[:req_id]}, event: #{hash.inspect}" }
145
+ end
146
+ true
147
+ end
148
+
149
+ def assert_supported_keys(args, supported)
150
+ unless (args.keys - supported).empty?
151
+ raise ZookeeperExceptions::ZookeeperException::BadArguments, # this heirarchy is kind of retarded
152
+ "Supported arguments are: #{supported.inspect}, but arguments #{args.keys.inspect} were supplied instead"
153
+ end
154
+ end
155
+
156
+ def assert_required_keys(args, required)
157
+ unless (required - args.keys).empty?
158
+ raise ZookeeperExceptions::ZookeeperException::BadArguments,
159
+ "Required arguments are: #{required.inspect}, but only the arguments #{args.keys.inspect} were supplied."
160
+ end
161
+ end
162
+
163
+ private
164
+ def prettify_event(hash)
165
+ hash.dup.tap do |h|
166
+ # 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[:req_id] = :global_session if h[:req_id] == -1
170
+ end
171
+ end
172
+ end
173
+
174
+ require 'zookeeper/common/queue_with_pipe'