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 +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
|
|