zkruby 3.4.3 → 3.4.4.rc3
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.
- data/.gitignore +11 -0
- data/.yardopts +2 -0
- data/Gemfile +4 -0
- data/README.rdoc +15 -12
- data/Rakefile +26 -31
- data/jute/lib/hoe/jute.rb +1 -1
- data/jute/lib/jute/task.rb +62 -0
- data/lib/em_zkruby.rb +1 -1
- data/lib/zkruby/async_op.rb +193 -0
- data/lib/zkruby/client.rb +61 -46
- data/lib/zkruby/enum.rb +2 -2
- data/lib/zkruby/eventmachine.rb +54 -131
- data/lib/zkruby/protocol.rb +37 -101
- data/lib/zkruby/rubyio.rb +94 -206
- data/lib/zkruby/session.rb +273 -137
- data/lib/zkruby/util.rb +80 -95
- data/lib/zkruby/version.rb +5 -0
- data/lib/zkruby/zkruby.rb +0 -6
- data/spec/eventmachine_spec.rb +9 -30
- data/spec/server_helper.rb +13 -9
- data/spec/shared/basic.rb +36 -2
- data/spec/shared/binding.rb +2 -0
- data/spec/shared/chroot.rb +30 -0
- data/spec/shared/multi.rb +1 -1
- data/spec/shared/performance.rb +50 -0
- data/spec/shared/watch.rb +2 -2
- data/spec/spec_helper.rb +3 -3
- data/zkruby.gemspec +38 -0
- metadata +109 -112
- data/.gemtest +0 -0
- data/Manifest.txt +0 -39
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
data/lib/zkruby/enum.rb
CHANGED
@@ -50,13 +50,13 @@ module Enumeration
|
|
50
50
|
|
51
51
|
module ClassMethods
|
52
52
|
|
53
|
-
# @param [
|
53
|
+
# @param [Symbol,Fixnum,Enumeration] ref
|
54
54
|
# @return [Enumeration] instance representing ref or nil if not found
|
55
55
|
def get(ref)
|
56
56
|
@enums[ref]
|
57
57
|
end
|
58
58
|
|
59
|
-
# @param [] ref
|
59
|
+
# @param [Symbol,Fixnum] ref
|
60
60
|
# @raise [KeyError] if ref not found
|
61
61
|
# @return [Enumeration]
|
62
62
|
def fetch(ref)
|
data/lib/zkruby/eventmachine.rb
CHANGED
@@ -4,7 +4,8 @@ if defined?(JRUBY_VERSION) && JRUBY_VERSION =~ /1\.6\.5.*/
|
|
4
4
|
raise "Fibers are broken in JRuby 1.6.5 (See JRUBY-6170)"
|
5
5
|
end
|
6
6
|
|
7
|
-
|
7
|
+
# Tell Strand that we want to consider event machine
|
8
|
+
Strand.reload()
|
8
9
|
|
9
10
|
module ZooKeeper
|
10
11
|
module EventMachine
|
@@ -13,6 +14,7 @@ module ZooKeeper
|
|
13
14
|
include Protocol
|
14
15
|
include Slf4r::Logger
|
15
16
|
|
17
|
+
attr_reader :session
|
16
18
|
unless EventMachine.methods.include?(:set_pending_connect_timeout)
|
17
19
|
def set_pending_connect_timeout(timeout)
|
18
20
|
|
@@ -20,6 +22,7 @@ module ZooKeeper
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def initialize(session,connect_timeout)
|
25
|
+
@fiber = Fiber.current
|
23
26
|
@session = session
|
24
27
|
@connect_timeout = connect_timeout
|
25
28
|
set_pending_connect_timeout(connect_timeout)
|
@@ -27,39 +30,60 @@ module ZooKeeper
|
|
27
30
|
logger.warn("Exception in initialize",ex)
|
28
31
|
end
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
# This "loop" is a means of keeping all the session activity
|
34
|
+
# on the session strand
|
35
|
+
def read_loop()
|
36
|
+
event,*args = Fiber.yield
|
37
|
+
if (event == :connection_completed)
|
38
|
+
logger.debug("Connection completed")
|
39
|
+
session.prime_connection(self)
|
34
40
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
@timer = EM.add_timer(@connect_timeout) do
|
42
|
+
@fiber.resume(:connect_timer)
|
43
|
+
end
|
44
|
+
|
45
|
+
ping = 0
|
46
|
+
# If session sleeps or waits in here then our yield/resumes are going to get out of sync
|
47
|
+
while true
|
48
|
+
event,*args = Fiber.yield
|
49
|
+
case event
|
50
|
+
when :connect_timer
|
51
|
+
if session.connected?
|
52
|
+
@timer = EM.add_periodic_timer(session.ping_interval) do
|
53
|
+
@fiber.resume(:ping_timer)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
close_connection()
|
57
|
+
end
|
58
|
+
when :ping_timer
|
59
|
+
case ping
|
60
|
+
when 1 then session.ping
|
61
|
+
when 2 then close_connection
|
48
62
|
end
|
49
|
-
|
63
|
+
ping += 1
|
64
|
+
when :receive_records
|
65
|
+
packet_io = args[0]
|
66
|
+
ping = 0
|
67
|
+
session.receive_records(packet_io)
|
68
|
+
when :unbind
|
69
|
+
break
|
50
70
|
end
|
51
|
-
else
|
52
|
-
close_connection()
|
53
71
|
end
|
54
72
|
end
|
73
|
+
EM.cancel_timer(@timer) if @timer
|
74
|
+
session.disconnected
|
75
|
+
end
|
55
76
|
|
77
|
+
def connection_completed()
|
78
|
+
@fiber.resume(:connection_completed)
|
56
79
|
rescue Exception => ex
|
57
|
-
logger.
|
80
|
+
logger.error("Exception in connection_completed",ex)
|
58
81
|
end
|
59
82
|
|
60
83
|
def receive_records(packet_io)
|
61
|
-
@
|
62
|
-
|
84
|
+
@fiber.resume(:receive_records,packet_io)
|
85
|
+
rescue Exception => ex
|
86
|
+
logger.error("Exception in receive_records",ex)
|
63
87
|
end
|
64
88
|
|
65
89
|
def disconnect()
|
@@ -67,120 +91,19 @@ module ZooKeeper
|
|
67
91
|
end
|
68
92
|
|
69
93
|
def unbind
|
70
|
-
|
71
|
-
@session.disconnected()
|
94
|
+
@fiber.resume(:unbind)
|
72
95
|
rescue Exception => ex
|
73
|
-
logger.
|
96
|
+
logger.error("Exception in unbind",ex)
|
74
97
|
end
|
75
98
|
|
76
99
|
end
|
77
100
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
include Slf4r::Logger
|
83
|
-
# We can use this binding if we are running in the reactor thread
|
84
|
-
def self.available?()
|
85
|
-
EM.reactor_running? && EM.reactor_thread?
|
101
|
+
module Binding
|
102
|
+
def connect(host,port,timeout)
|
103
|
+
conn = EM.connect(host,port,ZooKeeper::EventMachine::ClientConn,self,timeout)
|
104
|
+
conn.read_loop
|
86
105
|
end
|
87
|
-
|
88
|
-
def self.context(&context_block)
|
89
|
-
s = Strand.new() do
|
90
|
-
context_block.call(Strand)
|
91
|
-
end
|
92
|
-
s.join
|
93
|
-
end
|
94
|
-
|
95
|
-
attr_reader :client, :session
|
96
|
-
def start(client,session)
|
97
|
-
@client = client
|
98
|
-
@session = session
|
99
|
-
@session.start()
|
100
|
-
end
|
101
|
-
|
102
|
-
def connect(host,port,delay,timeout)
|
103
|
-
EM.add_timer(delay) do
|
104
|
-
EM.connect(host,port,ZooKeeper::EventMachine::ClientConn,@session,timeout)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# You are working in event machine it is up to you to ensure your callbacks do not block
|
109
|
-
def invoke(callback,*args)
|
110
|
-
callback.call(*args)
|
111
|
-
end
|
112
|
-
|
113
|
-
def queue_request(*args,&callback)
|
114
|
-
op = AsyncOp.new(self,&callback)
|
115
|
-
begin
|
116
|
-
@session.queue_request(*args) do |error,response|
|
117
|
-
op.resume(error,response)
|
118
|
-
end
|
119
|
-
rescue ZooKeeper::Error => ex
|
120
|
-
op.resume(ex,nil)
|
121
|
-
end
|
122
|
-
|
123
|
-
op
|
124
|
-
end
|
125
|
-
|
126
|
-
def close(&callback)
|
127
|
-
|
128
|
-
op = AsyncOp.new(self,&callback)
|
129
|
-
|
130
|
-
begin
|
131
|
-
@session.close() do |error,response|
|
132
|
-
op.resume(error,response)
|
133
|
-
end
|
134
|
-
rescue ZooKeeper::Error => ex
|
135
|
-
op.resume(ex,nil)
|
136
|
-
end
|
137
|
-
|
138
|
-
op
|
139
|
-
end
|
140
|
-
|
141
106
|
end #class Binding
|
142
107
|
|
143
|
-
class AsyncOp < ZooKeeper::AsyncOp
|
144
|
-
|
145
|
-
def initialize(binding,&callback)
|
146
|
-
@em_binding = binding
|
147
|
-
|
148
|
-
# Wrap the callback in its own Strand
|
149
|
-
@op_strand = Strand.new do
|
150
|
-
#immediately pause
|
151
|
-
error, response = Strand.yield
|
152
|
-
Strand.current[ZooKeeper::CURRENT] = [ @em_binding.client ]
|
153
|
-
raise error if error
|
154
|
-
callback.call(response)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def resume(error,response)
|
159
|
-
#TODO - raise issue in strand for resume to take arguments
|
160
|
-
op_strand.fiber.resume(error,response)
|
161
|
-
end
|
162
|
-
|
163
|
-
private
|
164
|
-
|
165
|
-
attr_reader :op_strand,:err_strand
|
166
|
-
|
167
|
-
def set_error_handler(errcallback)
|
168
|
-
@err_strand = Strand.new() do
|
169
|
-
begin
|
170
|
-
op_strand.value()
|
171
|
-
rescue StandardError => ex
|
172
|
-
Strand.current[ZooKeeper::CURRENT] = [ @em_binding.client ]
|
173
|
-
errcallback.call(ex)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def wait_value()
|
179
|
-
err_strand ? err_strand.value : op_strand.value
|
180
|
-
end
|
181
|
-
|
182
|
-
end #class AsyncOp
|
183
108
|
end #module EventMachine
|
184
109
|
end #module ZooKeeper
|
185
|
-
|
186
|
-
ZooKeeper.add_binding(ZooKeeper::EventMachine::Binding)
|
data/lib/zkruby/protocol.rb
CHANGED
@@ -5,46 +5,46 @@ module ZooKeeper
|
|
5
5
|
# client's shouldn't see this
|
6
6
|
class ProtocolError < IOError;end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
# Raw object protocol, very similar to EM's native ObjectProtocol
|
9
|
+
# Expects:
|
10
|
+
# #receive_data and #send_records to be invoked
|
11
|
+
# #receive_records and #send_data to be implemented
|
12
|
+
module Protocol
|
13
13
|
MIN_PACKET = 5 #TODO Work out what the min packet size really is
|
14
14
|
include Slf4r::Logger
|
15
15
|
|
16
16
|
def receive_data data # :nodoc:
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
18
|
+
@buffer ||= StringIO.new().set_encoding('binary')
|
19
|
+
@buffer.seek(0, IO::SEEK_END)
|
20
|
+
@buffer << data
|
21
|
+
@buffer.rewind
|
22
|
+
logger.debug { "Received #{data.length} bytes: buffer length = #{@buffer.length} pos = #{@buffer.pos}" }
|
23
|
+
loop do
|
24
|
+
if @buffer.length - @buffer.pos > MIN_PACKET
|
25
|
+
packet_size = @buffer.read(4).unpack("N").first
|
26
|
+
if (@buffer.length - @buffer.pos >= packet_size)
|
27
|
+
expected_pos = @buffer.pos + packet_size
|
28
|
+
# We just pass the buffer around and expect packet_size to be consumed
|
29
|
+
receive_records(@buffer)
|
30
|
+
if (@buffer.pos != expected_pos)
|
31
|
+
#this can happen during disconnection with left over packets
|
32
|
+
#the connection is dying anyway
|
33
|
+
leftover = @buffer.read(packet_size).unpack("H*")[0]
|
34
|
+
raise ProtocolError, "Records not consumed #{leftover}"
|
35
|
+
end
|
36
|
+
logger.debug { "Consumed packet #{packet_size}. Buffer pos=#{@buffer.pos}, length=#{@buffer.length}" }
|
37
|
+
next
|
38
|
+
else
|
39
|
+
# found the last partial packet
|
40
|
+
@buffer.seek(-4, IO::SEEK_CUR)
|
41
|
+
logger.debug { "Buffer contains #{@buffer.length} of #{packet_size} packet" }
|
35
42
|
end
|
36
|
-
logger.debug { "Consumed packet #{packet_size}. Buffer pos=#{@buffer.pos}, length=#{@buffer.length}" }
|
37
|
-
next
|
38
|
-
else
|
39
|
-
# found the last partial packet
|
40
|
-
@buffer.seek(-4, IO::SEEK_CUR)
|
41
|
-
logger.debug { "Buffer contains #{@buffer.length} of #{packet_size} packet" }
|
42
43
|
end
|
44
|
+
break
|
43
45
|
end
|
44
|
-
|
45
|
-
|
46
|
-
# reset the buffer
|
47
|
-
@buffer = StringIO.new(@buffer.read()) if @buffer.pos > 0
|
46
|
+
# reset the buffer
|
47
|
+
@buffer = StringIO.new(@buffer.read()) if @buffer.pos > 0
|
48
48
|
end
|
49
49
|
|
50
50
|
def receive_records(packet_io)
|
@@ -59,7 +59,7 @@ module ZooKeeper
|
|
59
59
|
bindata.each { |b| send_data(b) }
|
60
60
|
logger.debug { "Sent #{length} byte packet containing #{records.length} records" }
|
61
61
|
end
|
62
|
-
|
62
|
+
end
|
63
63
|
|
64
64
|
class Operation
|
65
65
|
attr_reader :op, :opcode, :request, :response, :callback
|
@@ -68,7 +68,7 @@ module ZooKeeper
|
|
68
68
|
@request=request;@response=response
|
69
69
|
@callback=callback
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
def path
|
73
73
|
#Every request has a path!
|
74
74
|
#TODO - path may be chrooted!
|
@@ -78,14 +78,14 @@ module ZooKeeper
|
|
78
78
|
|
79
79
|
class Packet < Operation
|
80
80
|
attr_reader :xid, :watch_type, :watcher
|
81
|
-
|
81
|
+
|
82
82
|
def initialize(xid,op,opcode,request,response,watch_type,watcher,callback)
|
83
83
|
super(op,opcode,request,response,callback)
|
84
84
|
@xid=xid;
|
85
85
|
@watch_type = watch_type; @watcher = watcher
|
86
86
|
end
|
87
87
|
|
88
|
-
|
88
|
+
|
89
89
|
def error(reason)
|
90
90
|
result(reason)[0..2] # don't need the watch
|
91
91
|
end
|
@@ -94,7 +94,7 @@ module ZooKeeper
|
|
94
94
|
error = nil
|
95
95
|
unless (Error::NONE === rc) then
|
96
96
|
error = Error.lookup(rc)
|
97
|
-
error = error.exception("ZooKeeper error for #{@op}(#{path}) ")
|
97
|
+
error = error.exception("ZooKeeper error #{error.to_sym} for #{@op}(#{path}) ")
|
98
98
|
end
|
99
99
|
[ callback, error ,response, watch_type ]
|
100
100
|
end
|
@@ -114,69 +114,5 @@ module ZooKeeper
|
|
114
114
|
Error::SESSION_EXPIRED == rc ? [ callback, nil, nil, nil ] : super(rc)
|
115
115
|
end
|
116
116
|
end
|
117
|
-
|
118
|
-
|
119
|
-
# Returned by asynchronous calls
|
120
|
-
#
|
121
|
-
# @example
|
122
|
-
# op = zk.stat("\apath") { |stat| something_with_stat() }
|
123
|
-
#
|
124
|
-
# op.on_error do |err|
|
125
|
-
# case err
|
126
|
-
# when ZK::Error::SESSION_EXPIRED
|
127
|
-
# puts "Ignoring session expired"
|
128
|
-
# else
|
129
|
-
# raise err
|
130
|
-
# end
|
131
|
-
# end
|
132
|
-
#
|
133
|
-
# begin
|
134
|
-
# result_of_somthing_with_stat = op.value
|
135
|
-
# rescue StandardError => ex
|
136
|
-
# puts "Oops, my error handler raised an exception"
|
137
|
-
# end
|
138
|
-
#
|
139
|
-
#
|
140
|
-
class AsyncOp
|
141
|
-
|
142
|
-
attr_accessor :backtrace
|
143
|
-
|
144
|
-
# Provide an error callback.
|
145
|
-
# @param block the error callback as a block
|
146
|
-
# @yieldparam [StandardError] the error raised by the zookeeper operation OR by its callback
|
147
|
-
def errback(&block)
|
148
|
-
set_error_handler(block)
|
149
|
-
end
|
150
|
-
|
151
|
-
# @param block the error callback as a Proc
|
152
|
-
def errback=(block)
|
153
|
-
set_error_handler(block)
|
154
|
-
end
|
155
|
-
|
156
|
-
alias :on_error :errback
|
157
|
-
|
158
|
-
# Wait for the async op to finish and returns its value
|
159
|
-
# will raise an exception if
|
160
|
-
# the operation itself fails and there is no error handler
|
161
|
-
# the callback raises a StandardError and there is no error handler
|
162
|
-
# the error handler raises StandardError
|
163
|
-
def value();
|
164
|
-
wait_value()
|
165
|
-
rescue ZooKeeper::Error => ex
|
166
|
-
# Set the backtrace to the original caller, rather than the ZK event loop
|
167
|
-
ex.set_backtrace(@backtrace) if @backtrace
|
168
|
-
raise ex
|
169
|
-
end
|
170
|
-
|
171
|
-
private
|
172
|
-
|
173
|
-
def set_error_handler(blk)
|
174
|
-
raise NotImplementedError, ":wait_result to be privately implemented by binding"
|
175
|
-
end
|
176
|
-
|
177
|
-
def wait_value();
|
178
|
-
raise NotImplementedError, ":wait_result to be privately implemented by binding"
|
179
|
-
end
|
180
|
-
end
|
181
117
|
end
|
182
118
|
|