zkruby 3.4.3 → 3.4.4.rc3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ #No hidden files (except for .gitignore)
2
+ .*
3
+ !.gitignore
4
+ !.yardopts
5
+ # Gems should not checking Gemfile.lock
6
+ Gemfile.lock
7
+ #Files generated by rake
8
+ lib/jute/
9
+ *.out
10
+ doc
11
+ pkg
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ -
2
+ History.txt
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rfuse.gemspec
4
+ gemspec
data/README.rdoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = zkruby
2
2
 
3
- * https://github.com/lwoggardner/zkruby
3
+ * http://rubygems.org/gems/zkruby
4
4
 
5
5
  == DESCRIPTION:
6
6
 
@@ -10,6 +10,9 @@ Pure ruby client for ZooKeeper (http://zookeeper.apache.org)
10
10
 
11
11
  Supports full ZooKeeper API, synchronous or asynchronous style, watches etc.. with implementations over EventMachine or plain old Ruby IO/Threads
12
12
 
13
+ Other ruby libraries for zookeeper tend to use the underlying C/Java client libraries while zkruby
14
+ implements the zookeeper wire protocol directly.
15
+
13
16
  Advantages:
14
17
  * Rubyist API - with block is asynchronous, without block is synchronous
15
18
  * Avoids conflicts between various Ruby threading models and the C/Java apis
@@ -18,9 +21,9 @@ Advantages:
18
21
 
19
22
  Disadvantages:
20
23
  * Duplicated code from Java/C libraries, particularly around herd effect protection
21
- * Maintain in parallel with breaking changes in protocol which are possibly more likely
22
- than breaking changes in the client API
23
- * Probably not as optimised in terms of performance (but your client code is ruby anyway)
24
+ * Needs to keep up with changes in wire protocol which are possibly more likely
25
+ than changes in the client API
26
+ * Possibly not as optimised in terms of performance (but your client code is ruby anyway)
24
27
  * Not production tested (yet- do you want to be the first?)
25
28
 
26
29
  == SYNOPSIS:
@@ -77,27 +80,27 @@ Disadvantages:
77
80
 
78
81
  == DEVELOPERS:
79
82
 
80
- Checkout the zookeeper source from http://zookeeper.apache.org
83
+ Download ZooKeeper from http://zookeeper.apache.org
81
84
 
82
- Checkout the zkruby source into the contrib directory
85
+ Create a conf/zoo.cfg file (copying sample.zoo.cfg is fine)
83
86
 
84
- Install hoe
87
+ Checkout the zkruby source into the contrib directory
85
88
 
86
- $ (sudo) gem install hoe
89
+ Copy (if different) src/zookeeper.jute to contrib/zkruby/src/zookeeper.jute
87
90
 
88
- Install other dependencies
91
+ Get gem dependencies
89
92
 
90
- $ rake check_extra_deps
93
+ $ bundle install
91
94
 
92
95
  Generate docs and run the tests/specs
93
96
 
94
- $ rake newb
97
+ $ rake
95
98
 
96
99
  == LICENSE:
97
100
 
98
101
  (The MIT License)
99
102
 
100
- Copyright (c) 2011
103
+ Copyright (c) 2012 Grant Gardner
101
104
 
102
105
  Permission is hereby granted, free of charge, to any person obtaining
103
106
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -1,39 +1,34 @@
1
- # -*- ruby -*-
2
- # hoe 2.12.5 goes looking for the plugins so we have to do it this way..
3
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/jute/lib'
1
+ #!/usr/bin/env rake
2
+ $:.unshift "jute/lib"
4
3
 
5
- require 'rubygems'
6
- require 'hoe'
4
+ require 'rake/clean'
5
+ require 'yard'
6
+ require './yard_ext/enum_handler.rb'
7
+ require "bundler/gem_tasks"
8
+ require 'rspec/core/rake_task'
9
+ require 'jute/task'
7
10
 
8
- begin
9
- require './yard_ext/enum_handler'
10
- rescue LoadError => err
11
- warn "%p while trying to load yard extensions: %s" % [ err.class, err.message ]
11
+ RSpec::Core::RakeTask.new
12
+ RSpec::Core::RakeTask.new(:perf_spec) do |t|
13
+ t.rspec_opts = "--tag perf"
12
14
  end
13
-
14
15
 
16
+ YARD::Rake::YardocTask.new
15
17
 
16
- # Hoe.plugin :compiler
17
- #Hoe.plugin :gem_prelude_sucks
18
- Hoe.plugin :git
19
- # Hoe.plugin :inline
20
- # Hoe.plugin :racc
21
- # Hoe.plugin :rubyforge
22
- Hoe.plugin :yard
23
- Hoe.plugin :jute
24
-
25
- Hoe.spec 'zkruby' do
26
- self.readme_file="README.rdoc"
27
- developer('Grant Gardner', 'grant@lastweekend.com.au')
28
- dependency 'slf4r' , '~> 0.4.2'
29
- dependency 'eventmachine', '~> 0.12.10', :development
30
- dependency 'strand', '~> 0.1.0', :development
31
- dependency 'logging', '>= 1.4.1', :development
32
- dependency 'rspec', '>=2.7.0', :development
33
- dependency 'hoe-yard', '>=0.1.2', :development
34
-
35
- self.jute_modules = {
18
+ Jute::Task.new() do |t|
19
+ t.modules = {
36
20
  "org.apache.zookeeper.data" => "ZooKeeper::Data",
37
21
  "org.apache.zookeeper.proto" => "ZooKeeper::Proto"}
38
22
  end
39
- # vim: syntax=ruby
23
+
24
+ task :perf_spec => :jute
25
+ task :spec => :jute
26
+ task :build => :jute
27
+ task :install => :jute
28
+ task :release => :jute
29
+ task :yard => :jute
30
+
31
+ task :default => [:spec,:yard]
32
+
33
+ CLEAN.include "*.out","Gemfile.lock",".yardoc/"
34
+ CLOBBER.include "doc/","pkg/","lib/jute"
data/jute/lib/hoe/jute.rb CHANGED
@@ -8,8 +8,8 @@ module Hoe::Jute
8
8
  #attr_accessor :jute_compiler
9
9
  def initialize_jute
10
10
  self.jute_tasks = [:test,:spec,:package]
11
- dependency 'citrus', '~> 2.4.0', :development
12
11
  #dependency 'jute' # if jute is ever a separate gem
12
+ dependency 'citrus', '~> 2.4.0', :development
13
13
  dependency 'bindata', '~> 1.4.1'
14
14
  end
15
15
 
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+ require 'rake/tasklib'
3
+ require 'jute'
4
+
5
+ class Jute::Task < Rake::TaskLib
6
+
7
+ attr_accessor :modules
8
+ attr_accessor :files
9
+ attr_accessor :pathmap
10
+
11
+ def initialize name = :jute
12
+
13
+ defaults
14
+
15
+ @name = name
16
+
17
+ yield self if block_given?
18
+
19
+ define_jute_tasks
20
+ end
21
+
22
+ def defaults
23
+ @files = "src/jute/*.jute"
24
+ @pathmap = "%{src,lib}X.rb"
25
+ end
26
+
27
+ def define_jute_tasks
28
+ desc "Compile jute files to ruby classes"
29
+ task jute_task_name
30
+
31
+ raise "modules hash must be defined" unless Hash === @modules
32
+ FileList.new(@files).each do | source |
33
+ target = source.pathmap(@pathmap)
34
+
35
+ target_dir = target.pathmap("%d")
36
+ directory target_dir
37
+
38
+ file target => [source,target_dir] do
39
+ compile_jute(source,target)
40
+ end
41
+ task jute_task_name => target
42
+ end
43
+ end
44
+
45
+ def jute_task_name
46
+ @name
47
+ end
48
+
49
+ def compile_jute(source,target)
50
+
51
+ @jute_compiler = ::Jute::Compiler.new() unless @jute_compiler
52
+
53
+ File.open(source) do |input|
54
+ File.open(target,"w") do |output|
55
+ puts "Compiling #{input.inspect} to #{output.inspect}"
56
+ @jute_compiler.compile(input,output,modules)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+
data/lib/em_zkruby.rb CHANGED
@@ -1,4 +1,4 @@
1
- # This is the main require for standard ruby io/thread based binding
1
+ # This is the main require for the eventmachine based binding
2
2
 
3
3
  require 'zkruby/zkruby'
4
4
  require 'zkruby/eventmachine'
@@ -0,0 +1,193 @@
1
+ module ZooKeeper
2
+
3
+ # Returned by asynchronous calls
4
+ #
5
+ # @example
6
+ # op = zk.stat("\apath") { |stat| something_with_stat() }
7
+ #
8
+ # op.async_rescue ZK::Error::SESSION_EXPIRED do
9
+ # puts "Ignoring session expired"
10
+ # result_when_session_expired()
11
+ # end
12
+ #
13
+ # op.async_rescue ZK::Error::CONNECTION_LOST do |ex|
14
+ # puts "Retrying stat due to connection lost"
15
+ # op.async_retry()
16
+ # # the result of this block is ignored!
17
+ # end
18
+ #
19
+ # begin
20
+ # result_of_somthing_with_stat = op.value
21
+ # rescue StandardError => ex
22
+ # puts "Oops"
23
+ # end
24
+ #
25
+ #
26
+ class AsyncOp
27
+
28
+ # @api private
29
+ def initialize(event_loop,callback,&operation)
30
+ @event_loop = event_loop
31
+ @operation = operation
32
+ @callback = callback
33
+ @mutex,@cv = Strand::Mutex.new(), Strand::ConditionVariable.new()
34
+ begin
35
+ execute()
36
+ rescue ZooKeeper::Error => ex
37
+ # Capture any initial exception
38
+ # The only expected condition is :session_expired
39
+ @op_error = ex
40
+ logger.debug { "Error during initial call #{ex}" }
41
+ end
42
+ end
43
+
44
+ # @param [Proc,#to_proc] block the error callback as a Proc
45
+ # @deprecated use {#async_rescue}
46
+ def errback=(block)
47
+ async_rescue(&block)
48
+ end
49
+
50
+ #Rescue asynchronous exceptions in a similar manner to normal
51
+ #ruby. Unfortunately rescue is a reserved word
52
+ # @param matches [Class,...] subclasses of Exception to match, defaults to {::StandardError}
53
+ # @param errblock the block to call if an error matches
54
+ # @return self
55
+ # @yieldparam [Exception] ex the exception raised by the async operation OR by its callback
56
+ def async_rescue(*matches,&errblock)
57
+ matches << StandardError if matches.empty?
58
+ rescue_blocks << [ matches ,errblock ]
59
+ if @op_error && matches.any? { |m| m === @op_error }
60
+ begin
61
+ @allow_retry = true
62
+ @op_rescue= [ nil, errblock.call(@op_error) ]
63
+ rescue StandardError => ex
64
+ @operation_rescue_result = [ ex, nil ]
65
+ ensure
66
+ @resumed = true
67
+ @op_error = nil
68
+ @allow_retry = false
69
+ end
70
+ end
71
+ self
72
+ end
73
+ alias :on_error :async_rescue
74
+ alias :op_rescue :async_rescue
75
+
76
+ # @deprecated
77
+ alias :errback :async_rescue
78
+
79
+
80
+ # Must only be called inside a block supplied to {#async_rescue}
81
+ # Common case is to retry on connection lost
82
+ # Retrying :session_expired is guaranteed to give infinite loops!
83
+ def async_retry()
84
+ raise ProtocolError "cannot retry outside of a rescue block" unless @allow_retry
85
+ begin
86
+ execute()
87
+ nil
88
+ rescue ZooKeeper::Error => ex
89
+ error,result = process_response(ex,nil)
90
+ if resumed?
91
+ raise error if error
92
+ return result
93
+ end
94
+ end
95
+ end
96
+
97
+ alias :op_retry :async_retry
98
+ alias :try_again :async_retry
99
+
100
+ # Wait for the async op to finish and returns its value
101
+ # @return result of the operation's callback or matched rescue handler
102
+ # @raise [StandardError] any unrescued exception
103
+ def value();
104
+ if @op_error
105
+ raise @op_error
106
+ elsif @op_rescue
107
+ error, result = @op_rescue
108
+ raise error if error
109
+ return result
110
+ else
111
+ wait_value()
112
+ end
113
+ end
114
+
115
+ # @api private
116
+ attr_accessor :backtrace
117
+
118
+ # @api private
119
+ def resume(op_error,response)
120
+ mutex.synchronize do
121
+ # remember this mutex is only used to wait for this response anyway
122
+ # so synchronizing here is not harmful even if processing the response
123
+ # includes a long running callback. (which can't create deadlocks
124
+ # by referencing this op!
125
+ @resumed = true
126
+ @error, @result = process_response(op_error,response)
127
+ cv.signal() if resumed?
128
+ end
129
+ end
130
+
131
+ private
132
+ attr_reader :callback, :operation, :event_loop
133
+ attr_reader :mutex, :cv, :error, :result
134
+
135
+ def execute()
136
+ @op_error = nil
137
+ @op_rescue = nil
138
+ @resumed = false
139
+ operation.call(self)
140
+ true
141
+ end
142
+
143
+ def resumed?
144
+ @resumed
145
+ end
146
+
147
+ def rescue_blocks
148
+ @rescue_blocks ||= []
149
+ end
150
+
151
+ def process_response(op_error,response)
152
+ logger.debug { "Processing response #{op_error} #{response}" }
153
+
154
+ # For ZooKeeper errors, set the backtrace to the original caller, rather than the ZK event loop
155
+ op_error.set_backtrace(@backtrace) if @backtrace && ZooKeeper::Error === op_error
156
+
157
+ begin
158
+ return [ nil, callback.call(response) ] unless op_error
159
+ rescue Exception => ex #enable clients to rescue Exceptions
160
+ op_error = ex
161
+ end
162
+
163
+ matches,rb = rescue_blocks.detect() { |matches,errblock| matches.any? { |m| m === op_error } }
164
+ return [ op_error, nil ] unless rb
165
+
166
+ begin
167
+ @allow_retry = true
168
+ return [ nil, rb.call(op_error) ]
169
+ rescue StandardError => ex
170
+ return [ ex , nil ]
171
+ ensure
172
+ @allow_retry = false
173
+ end
174
+ end
175
+
176
+ def wait_value()
177
+ if event_loop.current?
178
+ #Waiting in the event loop (eg made a synchronous call inside a callback)
179
+ #Keep processing events until we are resumed
180
+ until resumed? || event_loop.dead?
181
+ event_loop.pop_event_queue()
182
+ end
183
+ else
184
+ mutex.synchronize {
185
+ cv.wait(mutex) unless resumed?
186
+ }
187
+ end
188
+
189
+ raise error if error
190
+ result
191
+ end
192
+ end
193
+ end
data/lib/zkruby/client.rb CHANGED
@@ -48,7 +48,7 @@ module ZooKeeper
48
48
 
49
49
 
50
50
  # Combine permissions constants
51
- # @param [Perms] perms... list of permissions to combine, can be {Perms} constants, symbols or ints
51
+ # @param [Perms...] perms list of permissions to combine, can be {Perms} constants, symbols or ints
52
52
  # @return [Fixnum] integer representing the combined permission
53
53
  def self.perms(*perms)
54
54
  perms.inject(0) { | result, perm | result = result | Perms.get(perm) }
@@ -56,7 +56,7 @@ module ZooKeeper
56
56
 
57
57
  # Convenience method to create a zk Identity
58
58
  # @param [String] scheme
59
- # @param [String] identity
59
+ # @param [String] id
60
60
  # @return [Data::Identity] the encapsulated identity for the given scheme
61
61
  def self.id(scheme,id)
62
62
  Data::Identity.new(:scheme => scheme, :identity => id)
@@ -65,7 +65,7 @@ module ZooKeeper
65
65
  # Convenience method to create a zk ACL
66
66
  # ZK.acl(ZK.id("world","anyone"), ZK::Perms.DELETE, ZL::Perms.WRITE)
67
67
  # @param [Data::Identity] id
68
- # @param [Perms] *perms list of permissions
68
+ # @param [Perms...] perms list of permissions
69
69
  # @return [Data::ACL] an access control list
70
70
  # @see #perms
71
71
  #
@@ -108,8 +108,6 @@ module ZooKeeper
108
108
  CURRENT = :zookeeper_current
109
109
  # Main method for connecting to a client
110
110
  # @param addresses [Array<String>] list of host:port for the ZK cluster as Array or comma separated String
111
- # @option options [Class] :binding binding optional implementation class
112
- # either {EventMachine::Binding} or {RubyIO::Binding} but normally autodiscovered
113
111
  # @option options [String] :chroot chroot path.
114
112
  # All client calls will be made relative to this path
115
113
  # @option options [Watcher] :watch the default watcher
@@ -118,37 +116,48 @@ module ZooKeeper
118
116
  # @yieldparam [Client]
119
117
  # @return [Client]
120
118
  def self.connect(addresses,options={},&block)
121
- if options.has_key?(:binding)
122
- binding_type = options[:binding]
119
+
120
+ binding_module = if Strand.event_machine?
121
+ require 'zkruby/eventmachine'
122
+ ZooKeeper::EventMachine::Binding
123
123
  else
124
- binding_type = @bindings.detect { |b| b.available? }
125
- raise ProtocolError,"No available binding" unless binding_type
124
+ require 'zkruby/rubyio'
125
+ ZooKeeper::RubyIO::Binding
126
126
  end
127
- binding = binding_type.new()
128
- session = Session.new(binding,addresses,options)
129
- client = Client.new(binding)
130
- binding.start(client,session)
131
127
 
128
+ logger.debug { "Using binding #{binding_module}" }
129
+ session = Session.new(addresses,options)
130
+ # Extend the appropriate #connect method into the session
131
+ session.extend(binding_module)
132
+
133
+ client = Client.new(session)
134
+
135
+ session.start(client)
136
+
132
137
  return client unless block_given?
133
138
 
134
- binding_type.context() do |storage|
135
- @binding_storage = storage
136
- storage.current[CURRENT] ||= []
137
- storage.current[CURRENT].push(client)
138
- begin
139
- block.call(client)
140
- ensure
141
- storage.current[CURRENT].pop
142
- client.close() unless session.closed?
143
- end
139
+ storage = Strand.current[CURRENT] ||= []
140
+ storage.push(client)
141
+ begin
142
+ yield client
143
+ ensure
144
+ storage.pop
145
+ #TODO this will throw an exception if expired
146
+ client.close()
144
147
  end
145
148
  end
146
149
 
147
- # within the block supplied to {#connect} this will return the
150
+ # within the block supplied to {ZooKeeper.connect} this will return the
148
151
  # current ZK client
149
152
  def self.current
150
153
  #We'd use if key? here if strand supported it
151
- @binding_storage.current[CURRENT].last if @binding_storage.current[CURRENT]
154
+ Strand.current[CURRENT].last if Strand.current[CURRENT]
155
+ end
156
+
157
+ # Allow ZK a chance to send its data/ping
158
+ # particularly required for the eventmachine binding
159
+ def self.pass
160
+ Strand.pass
152
161
  end
153
162
 
154
163
  class WatchEvent
@@ -175,7 +184,8 @@ module ZooKeeper
175
184
  end
176
185
 
177
186
 
178
- # @abstract.
187
+ # @abstract
188
+ # The watch interface
179
189
  class Watcher
180
190
  # @param [KeeperState] state representing the session state
181
191
  # (:connected, :disconnected, :auth_failed, :session_expired)
@@ -243,7 +253,7 @@ module ZooKeeper
243
253
  # All calls operate asynchronously or synchronously based on whether a block is supplied
244
254
  #
245
255
  # Without a block, requests are executed synchronously and either return results directly or raise
246
- # a {Error}
256
+ # an {Error}
247
257
  #
248
258
  # With a block, the request returns immediately with a {AsyncOp}. When the server responds the
249
259
  # block is passed the results. Errors will be sent to an error callback if registered on the {AsyncOp}
@@ -257,35 +267,36 @@ module ZooKeeper
257
267
  # or with state :expired and event :none when the session is finalised
258
268
  class Client
259
269
 
270
+ attr_reader :session
260
271
  include Operations
261
272
  # @api private
262
273
  # See {::ZooKeeper.connect}
263
- def initialize(binding)
264
- @binding = binding
274
+ def initialize(session)
275
+ @session = session
265
276
  end
266
277
 
267
278
  # Session timeout, initially as supplied, but once connected is the negotiated
268
279
  # timeout with the server.
269
280
  def timeout
270
- @binding.session.timeout
281
+ session.timeout
271
282
  end
272
283
 
273
284
  # The currently registered default watcher
274
285
  def watcher
275
- @binding.session.watcher
286
+ session.watcher
276
287
  end
277
288
 
278
289
  # Assign the watcher to the session. This watcher will receive session connect/disconnect/expired
279
290
  # events as well as any path based watches registered to the API calls using the literal value "true"
280
- # @param [Watcher|Proc] watcher
291
+ # @param [Watcher,#process_watch,Proc] watcher
281
292
  def watcher=(watcher)
282
- @binding.session.watcher=watcher
293
+ session.watcher=watcher
283
294
  end
284
295
 
285
296
  # Retrieve the list of children at the given path
286
297
  # @overload children(path,watch=nil)
287
298
  # @param [String] path
288
- # @param [Watcher] if supplied sets a child watch on the given path
299
+ # @param [Watcher,#process_watch,Proc] if supplied sets a child watch on the given path
289
300
  # @return [Data::Stat,Array<String>] stat,children stat of path and the list of child nodes
290
301
  # @raise [Error]
291
302
  # @overload children(path,watch=nil)
@@ -321,7 +332,7 @@ module ZooKeeper
321
332
  # Retrieve data
322
333
  # @overload get(path,watch=nil)
323
334
  # @param [String] path
324
- # @param [Watcher] watch optional data watch to set on this path
335
+ # @param [Watcher,#process_watch,Proc] watch optional data watch to set on this path
325
336
  # @return [Data::Stat,String] stat,data at path
326
337
  # @raise [Error]
327
338
  # @overload get(path,watch=nil)
@@ -342,19 +353,19 @@ module ZooKeeper
342
353
  # Retrieve the {Data::Stat} of a path, or nil if the path does not exist
343
354
  # @overload exists(path,watch=nil)
344
355
  # @param [String] path
345
- # @param [Watcher] wath optional exists watch to set on this path
356
+ # @param [Watcher,#process_watch,Proc] watch optional exists watch to set on this path
346
357
  # @return [Data::Stat] Stat of the path or nil if the path does not exist
347
358
  # @raise [Error]
348
359
  # @overload exists(path,watch=nil)
349
360
  # @return [AsyncOp] asynchronous operation
350
361
  # @yieldparam [Data:Stat] stat Stat of the path or nil if the path did not exist
351
- def exists(path,watch=nil,&blk)
362
+ def exists(path,watch=nil,&callback)
352
363
  return synchronous_call(:exists,path,watch)[0] unless block_given?
353
364
  path = chroot(path)
354
365
 
355
366
  req = Proto::ExistsRequest.new(:path => path, :watch => watch)
356
367
  queue_request(req,:exists,3,Proto::ExistsResponse,:exists,watch,ExistsPacket) do | response |
357
- blk.call( response.nil? ? nil : response.stat )
368
+ callback.call( response.nil? ? nil : response.stat )
358
369
  end
359
370
  end
360
371
  alias :exists? :exists
@@ -445,13 +456,13 @@ module ZooKeeper
445
456
 
446
457
  # Close the session
447
458
  # @overload close()
448
- # @raise [Error]
459
+ # @raise [Error]
449
460
  # @overload close()
450
461
  # @return [AsyncOp] asynchronous operation
451
462
  # @yield [] callback invoked when session is closed
452
463
  def close(&blk)
453
464
  return synchronous_call(:close) unless block_given?
454
- @binding.close(&blk)
465
+ session.close(&blk)
455
466
  end
456
467
 
457
468
  # @api private
@@ -501,23 +512,26 @@ module ZooKeeper
501
512
  yield txn
502
513
  txn.commit
503
514
  end
504
- private
505
515
 
506
- def session
507
- @binding.session
508
- end
509
516
 
517
+ private
518
+
519
+ # This is where the magic happens!
510
520
  def synchronous_call(method,*args)
521
+ # Re-enter the calling method in asynchronous style
511
522
  op = self.send(method,*args) do |*results|
512
523
  results
513
524
  end
525
+
526
+ # Remove this call from the stored backtrace
514
527
  op.backtrace = op.backtrace[2..-1] if op.backtrace
515
528
 
529
+ # Wait for the asynchronous op to finish and return its value
516
530
  op.value
517
531
  end
518
532
 
519
533
  def queue_request(*args,&blk)
520
- op = @binding.queue_request(*args,&blk)
534
+ op = session.request(*args,&blk)
521
535
  op.backtrace = caller[1..-1]
522
536
  op
523
537
  end
@@ -540,7 +554,8 @@ module ZooKeeper
540
554
  # If the transaction fails none of these callbacks will be executed.
541
555
  class Transaction
542
556
  include Operations
543
- #:nodoc
557
+ # @api private
558
+ # See {Client#transaction}
544
559
  def initialize(client,session)
545
560
  @client = client
546
561
  @session = session