zkruby 3.4.4.rc3 → 3.4.4.rc4
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/lib/em_zkruby.rb +3 -1
- data/lib/zkruby/async_op.rb +3 -2
- data/lib/zkruby/client.rb +3 -16
- data/lib/zkruby/conn.rb +108 -0
- data/lib/zkruby/enum.rb +6 -2
- data/lib/zkruby/eventmachine.rb +44 -32
- data/lib/zkruby/protocol.rb +0 -1
- data/lib/zkruby/session.rb +42 -36
- data/lib/zkruby/socket.rb +66 -0
- data/lib/zkruby/version.rb +1 -1
- data/lib/zkruby/zkruby.rb +1 -0
- data/lib/zkruby.rb +0 -1
- data/spec/enum_spec.rb +2 -0
- data/spec/eventmachine_spec.rb +7 -15
- data/spec/rubyio_spec.rb +2 -2
- data/spec/server_helper.rb +7 -7
- data/spec/shared/basic.rb +5 -3
- data/spec/shared/performance.rb +2 -9
- data/spec/shared/watch.rb +2 -2
- data/spec/spec_helper.rb +4 -1
- data/zkruby.gemspec +4 -3
- metadata +50 -21
- data/jute/lib/hoe/jute.rb +0 -56
- data/lib/zkruby/rubyio.rb +0 -198
data/lib/em_zkruby.rb
CHANGED
data/lib/zkruby/async_op.rb
CHANGED
|
@@ -30,7 +30,7 @@ module ZooKeeper
|
|
|
30
30
|
@event_loop = event_loop
|
|
31
31
|
@operation = operation
|
|
32
32
|
@callback = callback
|
|
33
|
-
@mutex,@cv =
|
|
33
|
+
@mutex,@cv = Mutex.new(), ConditionVariable.new()
|
|
34
34
|
begin
|
|
35
35
|
execute()
|
|
36
36
|
rescue ZooKeeper::Error => ex
|
|
@@ -181,7 +181,8 @@ module ZooKeeper
|
|
|
181
181
|
event_loop.pop_event_queue()
|
|
182
182
|
end
|
|
183
183
|
else
|
|
184
|
-
mutex.synchronize {
|
|
184
|
+
mutex.synchronize {
|
|
185
|
+
logger.debug("Async op is waiting")
|
|
185
186
|
cv.wait(mutex) unless resumed?
|
|
186
187
|
}
|
|
187
188
|
end
|
data/lib/zkruby/client.rb
CHANGED
|
@@ -117,26 +117,14 @@ module ZooKeeper
|
|
|
117
117
|
# @return [Client]
|
|
118
118
|
def self.connect(addresses,options={},&block)
|
|
119
119
|
|
|
120
|
-
binding_module = if Strand.event_machine?
|
|
121
|
-
require 'zkruby/eventmachine'
|
|
122
|
-
ZooKeeper::EventMachine::Binding
|
|
123
|
-
else
|
|
124
|
-
require 'zkruby/rubyio'
|
|
125
|
-
ZooKeeper::RubyIO::Binding
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
logger.debug { "Using binding #{binding_module}" }
|
|
129
120
|
session = Session.new(addresses,options)
|
|
130
|
-
# Extend the appropriate #connect method into the session
|
|
131
|
-
session.extend(binding_module)
|
|
132
|
-
|
|
133
121
|
client = Client.new(session)
|
|
134
122
|
|
|
135
123
|
session.start(client)
|
|
136
124
|
|
|
137
125
|
return client unless block_given?
|
|
138
126
|
|
|
139
|
-
storage =
|
|
127
|
+
storage = Thread.current[CURRENT] ||= []
|
|
140
128
|
storage.push(client)
|
|
141
129
|
begin
|
|
142
130
|
yield client
|
|
@@ -151,13 +139,12 @@ module ZooKeeper
|
|
|
151
139
|
# current ZK client
|
|
152
140
|
def self.current
|
|
153
141
|
#We'd use if key? here if strand supported it
|
|
154
|
-
|
|
142
|
+
Thread.current[CURRENT].last if Thread.current.key?(CURRENT)
|
|
155
143
|
end
|
|
156
144
|
|
|
157
145
|
# Allow ZK a chance to send its data/ping
|
|
158
|
-
# particularly required for the eventmachine binding
|
|
159
146
|
def self.pass
|
|
160
|
-
|
|
147
|
+
Thread.pass
|
|
161
148
|
end
|
|
162
149
|
|
|
163
150
|
class WatchEvent
|
data/lib/zkruby/conn.rb
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require 'zkruby/socket'
|
|
2
|
+
module ZooKeeper
|
|
3
|
+
|
|
4
|
+
class Connection
|
|
5
|
+
include ZooKeeper::Protocol
|
|
6
|
+
include Slf4r::Logger
|
|
7
|
+
|
|
8
|
+
attr_reader :session
|
|
9
|
+
|
|
10
|
+
def initialize(session)
|
|
11
|
+
@session = session
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run(host,port,timeout)
|
|
15
|
+
@write_queue = Queue.new()
|
|
16
|
+
|
|
17
|
+
begin
|
|
18
|
+
sock = Socket.tcp_connect_timeout(host,port,timeout)
|
|
19
|
+
sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
20
|
+
sock.sync=true
|
|
21
|
+
write_thread = Thread.new(sock) { |sock| write_loop(sock) }
|
|
22
|
+
begin
|
|
23
|
+
session.prime_connection(self)
|
|
24
|
+
read_loop(sock)
|
|
25
|
+
ensure
|
|
26
|
+
disconnect(sock)
|
|
27
|
+
end
|
|
28
|
+
write_thread.join
|
|
29
|
+
rescue Errno::ECONNREFUSED
|
|
30
|
+
logger.warn{"Connection refused to #{host}:#{port}"}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# This is called from random client threads (including the event loop)
|
|
35
|
+
def send_data(data)
|
|
36
|
+
@write_queue.push(data) if data
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
# Since this runs in its very own thread and has no timers
|
|
42
|
+
# we can use boring blocking IO
|
|
43
|
+
def write_loop(socket)
|
|
44
|
+
Thread.current[:name] = "ZK::WriteLoop #{self} #{socket} #{session}"
|
|
45
|
+
begin
|
|
46
|
+
while !socket.closed? && data = @write_queue.pop()
|
|
47
|
+
socket.write(data)
|
|
48
|
+
logger.debug { "Sent: #{data.unpack("H*")[0]}" }
|
|
49
|
+
end
|
|
50
|
+
logger.debug { "Write loop finished" }
|
|
51
|
+
rescue Exception => ex
|
|
52
|
+
logger.warn( "Exception in write loop",ex )
|
|
53
|
+
# Make sure we break out of the read loop
|
|
54
|
+
disconnect(socket)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def read_loop(socket)
|
|
59
|
+
ping = 0
|
|
60
|
+
until socket.closed?
|
|
61
|
+
begin
|
|
62
|
+
data = socket.read_timeout(512,session.ping_interval)
|
|
63
|
+
if data.nil?
|
|
64
|
+
logger.debug { "Read timed out" }
|
|
65
|
+
ping += 1
|
|
66
|
+
case ping
|
|
67
|
+
when 1 ; session.ping()
|
|
68
|
+
when 2
|
|
69
|
+
logger.warn{"No response to ping in #{session.ping_interval}*2"}
|
|
70
|
+
break
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
logger.debug { "Received (#{data.length})" + data.unpack("H*")[0] }
|
|
74
|
+
receive_data(data)
|
|
75
|
+
ping = 0
|
|
76
|
+
end
|
|
77
|
+
rescue EOFError
|
|
78
|
+
# This is how we expect to end - send a close packet and the
|
|
79
|
+
# server closes the socket
|
|
80
|
+
logger.debug { "EOF reading from socket" }
|
|
81
|
+
break
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @api protocol
|
|
87
|
+
def receive_records(packet_io)
|
|
88
|
+
session.receive_records(packet_io)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def disconnect(socket)
|
|
92
|
+
@write_queue.push(nil)
|
|
93
|
+
socket.close if socket and !socket.closed?
|
|
94
|
+
rescue Exception => ex
|
|
95
|
+
#oh well
|
|
96
|
+
logger.debug("Exception closing socket",ex)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
module ZooKeeperBinding
|
|
102
|
+
|
|
103
|
+
# connect and read from the socket until disconnected
|
|
104
|
+
def self.connect(session,host,port,timeout)
|
|
105
|
+
ZooKeeper::Connection.new(session).run(host,port,timeout)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
data/lib/zkruby/enum.rb
CHANGED
|
@@ -32,11 +32,11 @@ module Enumeration
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def |(num)
|
|
35
|
-
|
|
35
|
+
@index | num
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def &(num)
|
|
39
|
-
|
|
39
|
+
@index & num
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def to_sym
|
|
@@ -46,6 +46,10 @@ module Enumeration
|
|
|
46
46
|
def to_s
|
|
47
47
|
"#{super} (:#{@name} [#{@index}])"
|
|
48
48
|
end
|
|
49
|
+
|
|
50
|
+
def coerce(other)
|
|
51
|
+
[self,other]
|
|
52
|
+
end
|
|
49
53
|
end
|
|
50
54
|
|
|
51
55
|
module ClassMethods
|
data/lib/zkruby/eventmachine.rb
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
require 'eventmachine'
|
|
2
|
+
require 'empathy'
|
|
2
3
|
|
|
3
4
|
if defined?(JRUBY_VERSION) && JRUBY_VERSION =~ /1\.6\.5.*/
|
|
4
5
|
raise "Fibers are broken in JRuby 1.6.5 (See JRUBY-6170)"
|
|
5
6
|
end
|
|
6
7
|
|
|
7
|
-
# Tell Strand that we want to consider event machine
|
|
8
|
-
Strand.reload()
|
|
9
|
-
|
|
10
8
|
module ZooKeeper
|
|
11
9
|
module EventMachine
|
|
12
10
|
|
|
13
|
-
class
|
|
11
|
+
class Connection < ::EM::Connection
|
|
14
12
|
include Protocol
|
|
15
13
|
include Slf4r::Logger
|
|
16
14
|
|
|
@@ -31,34 +29,37 @@ module ZooKeeper
|
|
|
31
29
|
end
|
|
32
30
|
|
|
33
31
|
# This "loop" is a means of keeping all the session activity
|
|
34
|
-
# on the session
|
|
32
|
+
# on the session fiber
|
|
35
33
|
def read_loop()
|
|
36
34
|
event,*args = Fiber.yield
|
|
37
35
|
if (event == :connection_completed)
|
|
38
36
|
logger.debug("Connection completed")
|
|
39
37
|
session.prime_connection(self)
|
|
40
38
|
|
|
41
|
-
@timer =
|
|
42
|
-
|
|
39
|
+
@timer = ::EventMachine.add_timer(session.ping_interval) do
|
|
40
|
+
resume(:connect_timer)
|
|
43
41
|
end
|
|
44
42
|
|
|
45
43
|
ping = 0
|
|
44
|
+
unbound = false
|
|
46
45
|
# If session sleeps or waits in here then our yield/resumes are going to get out of sync
|
|
47
|
-
|
|
46
|
+
until unbound
|
|
48
47
|
event,*args = Fiber.yield
|
|
48
|
+
logger.debug { "Received event #{event} with #{args}" }
|
|
49
49
|
case event
|
|
50
50
|
when :connect_timer
|
|
51
51
|
if session.connected?
|
|
52
|
-
@timer =
|
|
53
|
-
|
|
52
|
+
@timer = ::EventMachine.add_periodic_timer(session.ping_interval) do
|
|
53
|
+
resume(:ping_timer)
|
|
54
54
|
end
|
|
55
55
|
else
|
|
56
|
-
|
|
56
|
+
logger.warn("Connection timed out")
|
|
57
|
+
break;
|
|
57
58
|
end
|
|
58
59
|
when :ping_timer
|
|
59
60
|
case ping
|
|
60
61
|
when 1 then session.ping
|
|
61
|
-
when 2 then
|
|
62
|
+
when 2 then break;
|
|
62
63
|
end
|
|
63
64
|
ping += 1
|
|
64
65
|
when :receive_records
|
|
@@ -66,44 +67,55 @@ module ZooKeeper
|
|
|
66
67
|
ping = 0
|
|
67
68
|
session.receive_records(packet_io)
|
|
68
69
|
when :unbind
|
|
69
|
-
|
|
70
|
+
unbound = true
|
|
71
|
+
else
|
|
72
|
+
logger.error("Unexpected resume - #{event}")
|
|
73
|
+
break;
|
|
70
74
|
end
|
|
71
75
|
end
|
|
72
76
|
end
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
ensure
|
|
78
|
+
@fiber = nil
|
|
79
|
+
::EventMachine.cancel_timer(@timer) if @timer
|
|
80
|
+
close_connection() unless unbound
|
|
75
81
|
end
|
|
76
82
|
|
|
77
83
|
def connection_completed()
|
|
78
|
-
|
|
79
|
-
rescue Exception => ex
|
|
80
|
-
logger.error("Exception in connection_completed",ex)
|
|
84
|
+
resume(:connection_completed)
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
def receive_records(packet_io)
|
|
84
|
-
|
|
85
|
-
rescue Exception => ex
|
|
86
|
-
logger.error("Exception in receive_records",ex)
|
|
88
|
+
resume(:receive_records,packet_io)
|
|
87
89
|
end
|
|
88
90
|
|
|
89
|
-
def
|
|
90
|
-
|
|
91
|
+
def unbind(reason)
|
|
92
|
+
logger.warn{"Connection #{self} unbound due to #{reason}"} if reason
|
|
93
|
+
resume(:unbind)
|
|
91
94
|
end
|
|
92
95
|
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
private
|
|
97
|
+
def resume(event,*args)
|
|
98
|
+
@fiber.resume(event,*args) if @fiber
|
|
95
99
|
rescue Exception => ex
|
|
96
|
-
logger.error("Exception
|
|
100
|
+
logger.error("Exception resuming #{@fiber} for event #{event}",ex)
|
|
97
101
|
end
|
|
98
|
-
|
|
99
102
|
end
|
|
103
|
+
end #module EventMachine
|
|
104
|
+
|
|
105
|
+
end #module ZooKeeper
|
|
106
|
+
|
|
107
|
+
module Empathy
|
|
100
108
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
109
|
+
module EM
|
|
110
|
+
module ZooKeeperBinding
|
|
111
|
+
def self.connect(session,host,port,timeout)
|
|
112
|
+
conn = ::EventMachine.connect(host,port,ZooKeeper::EventMachine::Connection,session,timeout)
|
|
104
113
|
conn.read_loop
|
|
105
114
|
end
|
|
106
115
|
end #class Binding
|
|
116
|
+
end #module EM
|
|
117
|
+
|
|
118
|
+
create_delegate_module('ZooKeeperBinding',:connect)
|
|
119
|
+
|
|
120
|
+
end #module Empathy
|
|
107
121
|
|
|
108
|
-
end #module EventMachine
|
|
109
|
-
end #module ZooKeeper
|
data/lib/zkruby/protocol.rb
CHANGED
data/lib/zkruby/session.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'set'
|
|
2
|
-
require '
|
|
3
|
-
require '
|
|
4
|
-
#TODO Move async_op into this file
|
|
2
|
+
require 'thread'
|
|
3
|
+
require 'monitor'
|
|
5
4
|
require 'zkruby/async_op'
|
|
6
5
|
module ZooKeeper
|
|
7
6
|
|
|
@@ -9,8 +8,6 @@ module ZooKeeper
|
|
|
9
8
|
#
|
|
10
9
|
# @note this is a private API not intended for client use
|
|
11
10
|
class Session
|
|
12
|
-
# TODO this class is too big
|
|
13
|
-
|
|
14
11
|
# There are multiple threads of execution involved in a session
|
|
15
12
|
# Client threads - send requests
|
|
16
13
|
# Connection/Read thread
|
|
@@ -23,7 +20,7 @@ module ZooKeeper
|
|
|
23
20
|
# conjunction with processing all entries in @pending_queue
|
|
24
21
|
#
|
|
25
22
|
# All interaction with the event loop occurs via a Queue
|
|
26
|
-
include
|
|
23
|
+
include MonitorMixin
|
|
27
24
|
|
|
28
25
|
DEFAULT_TIMEOUT = 4
|
|
29
26
|
DEFAULT_CONNECT_DELAY = 0.2
|
|
@@ -115,8 +112,7 @@ module ZooKeeper
|
|
|
115
112
|
end
|
|
116
113
|
end
|
|
117
114
|
|
|
118
|
-
#
|
|
119
|
-
# called when the connection has dropped from either end
|
|
115
|
+
# TODO: Merge all this into a connect loop called from start
|
|
120
116
|
def disconnected()
|
|
121
117
|
logger.info { "Disconnected id=#{@session_id}, keeper=:#{@session_state}, client=:#{@client_state}" }
|
|
122
118
|
|
|
@@ -145,20 +141,18 @@ module ZooKeeper
|
|
|
145
141
|
raise ProtocolError, "Already started!" unless @session_state.nil?
|
|
146
142
|
@session_state = :disconnected
|
|
147
143
|
@disconnect_time = Time.now
|
|
148
|
-
logger.debug
|
|
144
|
+
logger.debug {"Starting new zookeeper client session for #{client}"}
|
|
149
145
|
@event_loop = EventLoop.new(client)
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
# This is the read/connect thread
|
|
147
|
+
Thread.new {
|
|
148
|
+
Thread.current[:name] = "ZK::Session #{self}"
|
|
149
|
+
reconnect()
|
|
150
|
+
while active?
|
|
151
|
+
delay = rand() * @max_connect_delay
|
|
152
|
+
sleep(delay)
|
|
152
153
|
reconnect()
|
|
153
|
-
while active?
|
|
154
|
-
delay = rand() * @max_connect_delay
|
|
155
|
-
Strand.sleep(delay)
|
|
156
|
-
reconnect()
|
|
157
|
-
end
|
|
158
|
-
rescue Exception => ex
|
|
159
|
-
logger.error("Exception in connect loop",ex)
|
|
160
154
|
end
|
|
161
|
-
|
|
155
|
+
logger.debug {"Session #{self} complete" }
|
|
162
156
|
}
|
|
163
157
|
end
|
|
164
158
|
|
|
@@ -198,6 +192,11 @@ module ZooKeeper
|
|
|
198
192
|
[:connected,:disconnected].include?(@session_state)
|
|
199
193
|
end
|
|
200
194
|
|
|
195
|
+
def calculate_timeouts()
|
|
196
|
+
@ping_interval = timeout * 2.0/7.0
|
|
197
|
+
@connect_timeout = timeout / 2.0
|
|
198
|
+
end
|
|
199
|
+
|
|
201
200
|
def queue_request(request,op,opcode,response=nil,watch_type=nil,watcher=nil,ptype=Packet,&callback)
|
|
202
201
|
synchronize do
|
|
203
202
|
raise ProtocolError, "Client closed #{@client_state}" unless @client_state == :ready
|
|
@@ -262,8 +261,8 @@ module ZooKeeper
|
|
|
262
261
|
|
|
263
262
|
def parse_options(options)
|
|
264
263
|
@timeout = options.fetch(:timeout,DEFAULT_TIMEOUT)
|
|
264
|
+
calculate_timeouts()
|
|
265
265
|
@max_connect_delay = options.fetch(:connect_delay,DEFAULT_CONNECT_DELAY)
|
|
266
|
-
@connect_timeout = options.fetch(:connect_timeout,@timeout * 1.0 / 7.0)
|
|
267
266
|
@scheme = options.fetch(:scheme,nil)
|
|
268
267
|
@auth = options.fetch(:auth,nil)
|
|
269
268
|
@chroot = options.fetch(:chroot,"").chomp("/")
|
|
@@ -273,8 +272,14 @@ module ZooKeeper
|
|
|
273
272
|
#Rotate address
|
|
274
273
|
host,port = @addresses.shift
|
|
275
274
|
@addresses.push([host,port])
|
|
276
|
-
logger.debug { "Connecting id=#{@session_id} to #{host}:#{port} with timeout=#{@connect_timeout}" }
|
|
277
|
-
|
|
275
|
+
logger.debug { "Connecting id=#{@session_id} to #{host}:#{port} with timeout=#{@connect_timeout} #{ZooKeeperBinding.inspect}" }
|
|
276
|
+
begin
|
|
277
|
+
ZooKeeperBinding.connect(self,host,port,@connect_timeout)
|
|
278
|
+
rescue Exception => ex
|
|
279
|
+
logger.warn("Exception in connect loop", ex)
|
|
280
|
+
ensure
|
|
281
|
+
disconnected()
|
|
282
|
+
end
|
|
278
283
|
end
|
|
279
284
|
|
|
280
285
|
def session_expired(reason=:expired)
|
|
@@ -297,9 +302,10 @@ module ZooKeeper
|
|
|
297
302
|
session_expired()
|
|
298
303
|
else
|
|
299
304
|
@timeout = result.time_out.to_f / 1000.0
|
|
305
|
+
calculate_timeouts()
|
|
300
306
|
@session_id = result.session_id
|
|
301
307
|
@session_passwd = result.passwd
|
|
302
|
-
logger.info { "Connected session_id=#{@session_id}, timeout=#{@
|
|
308
|
+
logger.info { "Connected session_id=#{@session_id}, timeout=#{@timeout}, ping=#{@ping_interval}" }
|
|
303
309
|
|
|
304
310
|
# Why 2 / 7 of the timeout?. If a binding sees no server response in this period it is required to
|
|
305
311
|
# generate a ping request
|
|
@@ -386,13 +392,11 @@ module ZooKeeper
|
|
|
386
392
|
|
|
387
393
|
if (packet.xid.to_i != header.xid.to_i)
|
|
388
394
|
|
|
389
|
-
logger.error { "Bad XID! expected=#{packet.xid}, received=#{header.xid}" }
|
|
390
|
-
|
|
391
395
|
# Treat this like a dropped connection, and then force the connection
|
|
392
396
|
# to be dropped. But wait for the connection to notify us before
|
|
393
397
|
# we actually update our keeper_state
|
|
394
398
|
invoke_response(*packet.error(:disconnected))
|
|
395
|
-
|
|
399
|
+
raise ProtocolError, "Bad XID. expected=#{packet.xid}, received=#{header.xid}"
|
|
396
400
|
else
|
|
397
401
|
@last_zxid_seen = header.zxid
|
|
398
402
|
|
|
@@ -435,7 +439,7 @@ module ZooKeeper
|
|
|
435
439
|
elsif watch.respond_to?(:call)
|
|
436
440
|
callback = watch
|
|
437
441
|
else
|
|
438
|
-
|
|
442
|
+
logger.error("Bad watcher #{watch}")
|
|
439
443
|
end
|
|
440
444
|
@event_loop.invoke(callback,state,unchroot(path),event)
|
|
441
445
|
end
|
|
@@ -458,7 +462,7 @@ module ZooKeeper
|
|
|
458
462
|
# client requests are rejected
|
|
459
463
|
# we can receive watch and ping notifications after this
|
|
460
464
|
# but the server drops the connection as soon as this
|
|
461
|
-
# packet
|
|
465
|
+
# packet is received
|
|
462
466
|
if @pending_queue.empty? && @session_state == :connected && @close_packet
|
|
463
467
|
logger.debug { "Sending close packet!" }
|
|
464
468
|
send_packet(@close_packet)
|
|
@@ -519,16 +523,16 @@ module ZooKeeper
|
|
|
519
523
|
include Slf4r::Logger
|
|
520
524
|
|
|
521
525
|
def initialize(client)
|
|
522
|
-
@event_queue =
|
|
526
|
+
@event_queue = Queue.new()
|
|
523
527
|
|
|
524
528
|
@alive = true
|
|
525
|
-
@event_thread =
|
|
529
|
+
@event_thread = Thread.new() do
|
|
526
530
|
logger.debug { "Starting event loop" }
|
|
527
|
-
|
|
528
|
-
|
|
531
|
+
Thread.current[:name] = "ZK::EventLoop #{self}"
|
|
532
|
+
Thread.current[CURRENT] = [ client ]
|
|
529
533
|
begin
|
|
530
534
|
pop_event_queue until dead?
|
|
531
|
-
logger.
|
|
535
|
+
logger.info { "Finished event loop" }
|
|
532
536
|
rescue Exception => ex
|
|
533
537
|
logger.error("Uncaught exception in event loop",ex)
|
|
534
538
|
end
|
|
@@ -542,7 +546,8 @@ module ZooKeeper
|
|
|
542
546
|
# @api async_op
|
|
543
547
|
def pop_event_queue
|
|
544
548
|
#We're alive until we get a nil result from #stop
|
|
545
|
-
|
|
549
|
+
logger.debug { "Popping event queue" }
|
|
550
|
+
queued = @alive ? @event_queue.pop : nil
|
|
546
551
|
if queued
|
|
547
552
|
begin
|
|
548
553
|
callback,*args = queued
|
|
@@ -561,7 +566,7 @@ module ZooKeeper
|
|
|
561
566
|
end
|
|
562
567
|
|
|
563
568
|
def invoke_close(callback,*args)
|
|
564
|
-
|
|
569
|
+
Thread.new do
|
|
565
570
|
@event_thread.join()
|
|
566
571
|
callback.call(*args)
|
|
567
572
|
end
|
|
@@ -570,11 +575,12 @@ module ZooKeeper
|
|
|
570
575
|
# @api session
|
|
571
576
|
def stop
|
|
572
577
|
@event_queue.push(nil)
|
|
578
|
+
@event_thread.join()
|
|
573
579
|
end
|
|
574
580
|
|
|
575
581
|
# @api async_op
|
|
576
582
|
def current?
|
|
577
|
-
|
|
583
|
+
Thread.current == @event_thread
|
|
578
584
|
end
|
|
579
585
|
end
|
|
580
586
|
end # Session
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
|
|
3
|
+
class Socket
|
|
4
|
+
|
|
5
|
+
HAS_NONBLOCKING_CONNECT = RUBY_PLATFORM != "java"|| Gem::Version.new(JRUBY_VERSION.dup) >= Gem::Version.new("1.6.7")
|
|
6
|
+
|
|
7
|
+
def self.tcp_connect_timeout(host,port,timeout = 0)
|
|
8
|
+
|
|
9
|
+
if HAS_NONBLOCKING_CONNECT && timeout > 0
|
|
10
|
+
# TODO: This is a blocking DNS lookup!!!!, possibly even a reverse lookup if host is a numberic address
|
|
11
|
+
addr = self.getaddrinfo(host, nil)
|
|
12
|
+
sock = Socket.new(self.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
|
|
13
|
+
sockaddr = Socket.pack_sockaddr_in(port, addr[0][3])
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
sock.connect_nonblock(sockaddr)
|
|
17
|
+
return sock
|
|
18
|
+
rescue Errno::EINPROGRESS
|
|
19
|
+
begin
|
|
20
|
+
#Note: JRuby raises Connection Refused instead of populating error array
|
|
21
|
+
read,write,errors = Socket.select(nil, [sock], [sock], timeout)
|
|
22
|
+
optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_ERROR)
|
|
23
|
+
sockerr = (optval.unpack "i")[0]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
case sockerr
|
|
27
|
+
when 0 # Errno::NOERROR::Errno
|
|
28
|
+
begin
|
|
29
|
+
sock.connect_nonblock(sockaddr)
|
|
30
|
+
return sock
|
|
31
|
+
rescue Errno::EISCONN
|
|
32
|
+
#Woohoo! we're connected
|
|
33
|
+
return sock
|
|
34
|
+
end
|
|
35
|
+
when Errno::EINPROGRESS
|
|
36
|
+
# must be a timeout
|
|
37
|
+
logger.warn{"Connect timeout to #{host}:#{port}"}
|
|
38
|
+
return nil
|
|
39
|
+
when Errno::ECONNREFUSED::Errno
|
|
40
|
+
raise Errno::ECONNREFUSED, "Connection refused to #{ host }:#{ port }"
|
|
41
|
+
else
|
|
42
|
+
raise Errno::ENOTCONN, "Connection to #{ host }:#{ port } failed: #{sockerr}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
# JRuby prior to 1.6.7 cannot do non-blocking connects, which means there is
|
|
47
|
+
# no way to properly implement the connection-timeout
|
|
48
|
+
# See http://jira.codehaus.org/browse/JRUBY-5165
|
|
49
|
+
# In any case this should be encapsulated in TCPSocket.open(host,port,timeout)
|
|
50
|
+
self.tcp(host,port)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def read_timeout(maxlen,timeout)
|
|
56
|
+
begin
|
|
57
|
+
return read_nonblock(maxlen)
|
|
58
|
+
rescue IO::WaitReadable
|
|
59
|
+
selected = IO.select([self],[],[],timeout)
|
|
60
|
+
return nil unless selected
|
|
61
|
+
retry
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
data/lib/zkruby/version.rb
CHANGED
data/lib/zkruby/zkruby.rb
CHANGED
data/lib/zkruby.rb
CHANGED
data/spec/enum_spec.rb
CHANGED
data/spec/eventmachine_spec.rb
CHANGED
|
@@ -1,29 +1,21 @@
|
|
|
1
1
|
require 'server_helper'
|
|
2
|
-
require 'shared/binding'
|
|
3
2
|
require 'zkruby/eventmachine'
|
|
3
|
+
require 'shared/binding'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Empathy.empathise(ZooKeeper)
|
|
6
|
+
|
|
7
|
+
describe Empathy::EM::ZooKeeperBinding do
|
|
6
8
|
|
|
7
9
|
include Slf4r::Logger
|
|
8
10
|
|
|
9
11
|
around(:each) do |example|
|
|
10
|
-
|
|
11
|
-
Strand.new() do
|
|
12
|
-
begin
|
|
13
|
-
example.run
|
|
14
|
-
rescue Exception => ex
|
|
15
|
-
logger.error("Exception in example",ex)
|
|
16
|
-
ensure
|
|
17
|
-
EM::stop
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
}
|
|
12
|
+
Empathy.run { example.run }
|
|
21
13
|
end
|
|
22
14
|
|
|
23
15
|
it "should be running in event machine" do
|
|
24
|
-
|
|
16
|
+
Empathy.event_machine?.should be_true
|
|
25
17
|
end
|
|
26
18
|
|
|
19
|
+
let (:pass_every) { 3 }
|
|
27
20
|
it_should_behave_like "a zookeeper client binding"
|
|
28
|
-
|
|
29
21
|
end
|
data/spec/rubyio_spec.rb
CHANGED
data/spec/server_helper.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module ZooKeeperServerManager
|
|
4
4
|
|
|
5
5
|
include Slf4r::Logger
|
|
6
6
|
|
|
@@ -9,17 +9,17 @@ module ZooKeeperServerHelper
|
|
|
9
9
|
def jruby_safe_system(arg)
|
|
10
10
|
arg = "#{arg} &" if JRUBY_COMPAT_SYSTEM
|
|
11
11
|
system(arg)
|
|
12
|
-
|
|
12
|
+
sleep(3) if JRUBY_COMPAT_SYSTEM
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def restart_cluster(delay=0)
|
|
16
16
|
jruby_safe_system("../../bin/zkServer.sh stop >> zk.out")
|
|
17
|
-
|
|
17
|
+
sleep(delay) if delay > 0
|
|
18
18
|
jruby_safe_system("../../bin/zkServer.sh start >> zk.out")
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def get_addresses()
|
|
22
|
-
"
|
|
22
|
+
"127.0.0.1:2181"
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def safe_close(zk)
|
|
@@ -34,10 +34,10 @@ module ZooKeeperServerHelper
|
|
|
34
34
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
include
|
|
37
|
+
include ZooKeeperServerManager
|
|
38
38
|
|
|
39
39
|
restart_cluster()
|
|
40
|
-
|
|
40
|
+
sleep(3)
|
|
41
41
|
require 'net/telnet'
|
|
42
42
|
t = Net::Telnet.new("Host" => "localhost", "Port" => 2181)
|
|
43
43
|
properties = t.cmd("mntr")
|
|
@@ -45,5 +45,5 @@ properties = t.cmd("mntr")
|
|
|
45
45
|
RSpec.configure do |c|
|
|
46
46
|
#Exclude multi unless we are on a 3.4 server
|
|
47
47
|
c.filter_run_excluding :multi => true unless properties
|
|
48
|
-
c.filter_run_excluding :perf => true
|
|
48
|
+
#c.filter_run_excluding :perf => true
|
|
49
49
|
end
|
data/spec/shared/basic.rb
CHANGED
|
@@ -4,8 +4,10 @@ shared_examples_for "basic integration" do
|
|
|
4
4
|
@zk.create("/zkruby","node for zk ruby testing",ZK::ACL_OPEN_UNSAFE) unless @zk.exists?("/zkruby")
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
+
context("normal functions") do
|
|
7
8
|
it "should return a stat for the root path" do
|
|
8
|
-
|
|
9
|
+
|
|
10
|
+
stat = @zk.stat("/")
|
|
9
11
|
stat.should be_a ZooKeeper::Data::Stat
|
|
10
12
|
end
|
|
11
13
|
|
|
@@ -40,7 +42,7 @@ shared_examples_for "basic integration" do
|
|
|
40
42
|
@zk.delete("/zkruby/rspec",-1)
|
|
41
43
|
@zk.exists?("/zkruby/rspec").should be_false
|
|
42
44
|
end
|
|
43
|
-
|
|
45
|
+
end
|
|
44
46
|
context "exceptions" do
|
|
45
47
|
|
|
46
48
|
it "should raise ZK::Error for synchronous method" do
|
|
@@ -147,7 +149,7 @@ shared_examples_for "basic integration" do
|
|
|
147
149
|
context "auto reconnect" do
|
|
148
150
|
|
|
149
151
|
it "should stay connected" do
|
|
150
|
-
|
|
152
|
+
sleep(@zk.timeout * 2.0)
|
|
151
153
|
@zk.exists?("/zkruby").should be_true
|
|
152
154
|
end
|
|
153
155
|
|
data/spec/shared/performance.rb
CHANGED
|
@@ -11,17 +11,13 @@ shared_examples_for "performance" do
|
|
|
11
11
|
op = nil
|
|
12
12
|
start = Time.now
|
|
13
13
|
count = 0
|
|
14
|
-
pass_every = 5
|
|
15
14
|
first_error = true
|
|
16
15
|
6000.times do
|
|
17
16
|
count += 1
|
|
18
17
|
this_index = count
|
|
19
18
|
op = @zk.create("#{path}/","hello", ZK::ACL_OPEN_UNSAFE,:sequential,:ephemeral) { }
|
|
20
19
|
op.on_error { |ex| puts "Error @ #{this_index}" if first_error; first_error = false }
|
|
21
|
-
if count % pass_every == 0
|
|
22
|
-
#puts "Passing @ #{count}"
|
|
23
|
-
ZK.pass
|
|
24
|
-
end
|
|
20
|
+
ZK.pass if pass_every && count % pass_every == 0
|
|
25
21
|
end
|
|
26
22
|
|
|
27
23
|
op.value
|
|
@@ -34,10 +30,7 @@ shared_examples_for "performance" do
|
|
|
34
30
|
children.each do |child|
|
|
35
31
|
op = @zk.get("#{path}/#{child}") { }
|
|
36
32
|
count += 1
|
|
37
|
-
if count % pass_every == 0
|
|
38
|
-
#puts "Passing @ #{count}"
|
|
39
|
-
ZK.pass
|
|
40
|
-
end
|
|
33
|
+
ZK.pass if pass_every && count % pass_every == 0
|
|
41
34
|
end
|
|
42
35
|
|
|
43
36
|
op.value
|
data/spec/shared/watch.rb
CHANGED
|
@@ -18,7 +18,7 @@ shared_examples_for "watches" do
|
|
|
18
18
|
stat,data = @zk.get(path,watch)
|
|
19
19
|
# set the data on the 2nd session
|
|
20
20
|
@zk2.set(path,"newdata",stat.version)
|
|
21
|
-
|
|
21
|
+
sleep(2)
|
|
22
22
|
watch_results.size().should == 1
|
|
23
23
|
watch_results[0][1].should == path
|
|
24
24
|
watch_results[0][2].should === :node_data_changed
|
|
@@ -31,7 +31,7 @@ shared_examples_for "watches" do
|
|
|
31
31
|
|
|
32
32
|
stat,children = @zk.children("/zkruby",watch)
|
|
33
33
|
path = @zk2.create("/zkruby/rspec_watch","somedata",ZK::ACL_OPEN_UNSAFE,:ephemeral,:sequential)
|
|
34
|
-
|
|
34
|
+
sleep(2)
|
|
35
35
|
watch_results.size().should == 1
|
|
36
36
|
watch_results[0][1].should == "/zkruby"
|
|
37
37
|
watch_results[0][2].should === :node_children_changed
|
data/spec/spec_helper.rb
CHANGED
|
@@ -3,10 +3,13 @@ require 'zkruby/zkruby'
|
|
|
3
3
|
|
|
4
4
|
Logging.logger.root.level = :warn
|
|
5
5
|
Logging.logger.root.appenders = Logging.appenders.stdout(:layout => Logging.layouts.pattern(:pattern => '%r %c [%T] %-5l: %m\n'))
|
|
6
|
-
#Logging.logger[ZooKeeper::
|
|
6
|
+
#Logging.logger[ZooKeeper::Connection].level = :debug
|
|
7
|
+
#Logging.logger['ZooKeeper::EventMachine::Connection'].level = :debug
|
|
7
8
|
#Logging.logger["ZooKeeper::RubyIO::Binding"].level = :debug
|
|
8
9
|
#Logging.logger[ZooKeeper::Session].level = :debug
|
|
10
|
+
#Logging.logger[ZooKeeper::AsyncOp].level = :debug
|
|
9
11
|
#Logging.logger["ZooKeeper::EventMachine::ClientConn"].level = :debug
|
|
10
12
|
#Logging.logger["ZooKeeper::Session::Ping"].level = :error
|
|
11
13
|
|
|
12
14
|
Thread.current[:name] = "Rspec::Main"
|
|
15
|
+
|
data/zkruby.gemspec
CHANGED
|
@@ -14,23 +14,24 @@ Gem::Specification.new do |s|
|
|
|
14
14
|
s.description = %q{Supports full ZooKeeper API, synchronous or asynchronous style, watches etc.. with implementations over EventMachine or plain old Ruby IO/Threads}
|
|
15
15
|
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
|
17
|
-
s.files
|
|
17
|
+
s.files << 'lib/jute/zookeeper.rb'
|
|
18
18
|
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
|
19
19
|
s.require_paths = ["lib"]
|
|
20
20
|
|
|
21
|
-
s.has_rdoc = 'yard'
|
|
22
21
|
# Yard options in .yardopts
|
|
23
22
|
|
|
24
23
|
s.add_dependency 'slf4r' , '~> 0.4.2'
|
|
25
|
-
s.add_dependency 'strand', '~> 0.2.0.rc0'
|
|
26
24
|
s.add_dependency 'bindata', '~> 1.4.1'
|
|
27
25
|
|
|
28
26
|
s.add_development_dependency 'eventmachine', '>= 0.12.10'
|
|
27
|
+
s.add_development_dependency 'empathy', '>=0.1.0'
|
|
29
28
|
s.add_development_dependency 'logging', '>= 1.4.1'
|
|
29
|
+
s.add_development_dependency 'ruby-prof'
|
|
30
30
|
|
|
31
31
|
s.add_development_dependency("rake")
|
|
32
32
|
s.add_development_dependency("rspec")
|
|
33
33
|
s.add_development_dependency("yard")
|
|
34
|
+
s.add_development_dependency("kramdown")
|
|
34
35
|
|
|
35
36
|
# s.add_development_dependency("jute")
|
|
36
37
|
s.add_development_dependency "citrus" , '~> 2.4.0'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: zkruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.4.4.
|
|
4
|
+
version: 3.4.4.rc4
|
|
5
5
|
prerelease: 6
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2013-07-27 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: slf4r
|
|
@@ -28,13 +28,13 @@ dependencies:
|
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
29
|
version: 0.4.2
|
|
30
30
|
- !ruby/object:Gem::Dependency
|
|
31
|
-
name:
|
|
31
|
+
name: bindata
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
|
33
33
|
none: false
|
|
34
34
|
requirements:
|
|
35
35
|
- - ~>
|
|
36
36
|
- !ruby/object:Gem::Version
|
|
37
|
-
version:
|
|
37
|
+
version: 1.4.1
|
|
38
38
|
type: :runtime
|
|
39
39
|
prerelease: false
|
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -42,31 +42,31 @@ dependencies:
|
|
|
42
42
|
requirements:
|
|
43
43
|
- - ~>
|
|
44
44
|
- !ruby/object:Gem::Version
|
|
45
|
-
version:
|
|
45
|
+
version: 1.4.1
|
|
46
46
|
- !ruby/object:Gem::Dependency
|
|
47
|
-
name:
|
|
47
|
+
name: eventmachine
|
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
|
49
49
|
none: false
|
|
50
50
|
requirements:
|
|
51
|
-
- -
|
|
51
|
+
- - ! '>='
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version:
|
|
54
|
-
type: :
|
|
53
|
+
version: 0.12.10
|
|
54
|
+
type: :development
|
|
55
55
|
prerelease: false
|
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
57
|
none: false
|
|
58
58
|
requirements:
|
|
59
|
-
- -
|
|
59
|
+
- - ! '>='
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
61
|
+
version: 0.12.10
|
|
62
62
|
- !ruby/object:Gem::Dependency
|
|
63
|
-
name:
|
|
63
|
+
name: empathy
|
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
|
65
65
|
none: false
|
|
66
66
|
requirements:
|
|
67
67
|
- - ! '>='
|
|
68
68
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: 0.
|
|
69
|
+
version: 0.1.0
|
|
70
70
|
type: :development
|
|
71
71
|
prerelease: false
|
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -74,7 +74,7 @@ dependencies:
|
|
|
74
74
|
requirements:
|
|
75
75
|
- - ! '>='
|
|
76
76
|
- !ruby/object:Gem::Version
|
|
77
|
-
version: 0.
|
|
77
|
+
version: 0.1.0
|
|
78
78
|
- !ruby/object:Gem::Dependency
|
|
79
79
|
name: logging
|
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -91,6 +91,22 @@ dependencies:
|
|
|
91
91
|
- - ! '>='
|
|
92
92
|
- !ruby/object:Gem::Version
|
|
93
93
|
version: 1.4.1
|
|
94
|
+
- !ruby/object:Gem::Dependency
|
|
95
|
+
name: ruby-prof
|
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
|
97
|
+
none: false
|
|
98
|
+
requirements:
|
|
99
|
+
- - ! '>='
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0'
|
|
102
|
+
type: :development
|
|
103
|
+
prerelease: false
|
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
105
|
+
none: false
|
|
106
|
+
requirements:
|
|
107
|
+
- - ! '>='
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
94
110
|
- !ruby/object:Gem::Dependency
|
|
95
111
|
name: rake
|
|
96
112
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -139,6 +155,22 @@ dependencies:
|
|
|
139
155
|
- - ! '>='
|
|
140
156
|
- !ruby/object:Gem::Version
|
|
141
157
|
version: '0'
|
|
158
|
+
- !ruby/object:Gem::Dependency
|
|
159
|
+
name: kramdown
|
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
|
161
|
+
none: false
|
|
162
|
+
requirements:
|
|
163
|
+
- - ! '>='
|
|
164
|
+
- !ruby/object:Gem::Version
|
|
165
|
+
version: '0'
|
|
166
|
+
type: :development
|
|
167
|
+
prerelease: false
|
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
169
|
+
none: false
|
|
170
|
+
requirements:
|
|
171
|
+
- - ! '>='
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '0'
|
|
142
174
|
- !ruby/object:Gem::Dependency
|
|
143
175
|
name: citrus
|
|
144
176
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -170,7 +202,6 @@ files:
|
|
|
170
202
|
- README.rdoc
|
|
171
203
|
- Rakefile
|
|
172
204
|
- jute/jute.citrus
|
|
173
|
-
- jute/lib/hoe/jute.rb
|
|
174
205
|
- jute/lib/jute.rb
|
|
175
206
|
- jute/lib/jute/task.rb
|
|
176
207
|
- lib/em_zkruby.rb
|
|
@@ -178,12 +209,13 @@ files:
|
|
|
178
209
|
- lib/zkruby/async_op.rb
|
|
179
210
|
- lib/zkruby/bindata.rb
|
|
180
211
|
- lib/zkruby/client.rb
|
|
212
|
+
- lib/zkruby/conn.rb
|
|
181
213
|
- lib/zkruby/enum.rb
|
|
182
214
|
- lib/zkruby/eventmachine.rb
|
|
183
215
|
- lib/zkruby/multi.rb
|
|
184
216
|
- lib/zkruby/protocol.rb
|
|
185
|
-
- lib/zkruby/rubyio.rb
|
|
186
217
|
- lib/zkruby/session.rb
|
|
218
|
+
- lib/zkruby/socket.rb
|
|
187
219
|
- lib/zkruby/util.rb
|
|
188
220
|
- lib/zkruby/version.rb
|
|
189
221
|
- lib/zkruby/zkruby.rb
|
|
@@ -221,9 +253,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
221
253
|
- - ! '>='
|
|
222
254
|
- !ruby/object:Gem::Version
|
|
223
255
|
version: '0'
|
|
224
|
-
segments:
|
|
225
|
-
- 0
|
|
226
|
-
hash: 2131471662065326967
|
|
227
256
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
228
257
|
none: false
|
|
229
258
|
requirements:
|
|
@@ -232,9 +261,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
232
261
|
version: 1.3.1
|
|
233
262
|
requirements: []
|
|
234
263
|
rubyforge_project:
|
|
235
|
-
rubygems_version: 1.8.
|
|
264
|
+
rubygems_version: 1.8.25
|
|
236
265
|
signing_key:
|
|
237
266
|
specification_version: 3
|
|
238
267
|
summary: Pure Ruby language binding for ZooKeeper
|
|
239
268
|
test_files: []
|
|
240
|
-
has_rdoc:
|
|
269
|
+
has_rdoc:
|
data/jute/lib/hoe/jute.rb
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
|
|
3
|
-
module Hoe::Jute
|
|
4
|
-
attr_accessor :jute
|
|
5
|
-
attr_accessor :jute_tasks
|
|
6
|
-
attr_accessor :jute_modules
|
|
7
|
-
|
|
8
|
-
#attr_accessor :jute_compiler
|
|
9
|
-
def initialize_jute
|
|
10
|
-
self.jute_tasks = [:test,:spec,:package]
|
|
11
|
-
#dependency 'jute' # if jute is ever a separate gem
|
|
12
|
-
dependency 'citrus', '~> 2.4.0', :development
|
|
13
|
-
dependency 'bindata', '~> 1.4.1'
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def define_jute_tasks
|
|
17
|
-
|
|
18
|
-
found = try_load_jute()
|
|
19
|
-
|
|
20
|
-
if found
|
|
21
|
-
jute_compiler = ::Jute::Compiler.new()
|
|
22
|
-
jute_files = self.spec.files.find_all { |f| f =~ /\.jute$/ }
|
|
23
|
-
|
|
24
|
-
record_files = jute_files.map { |f| f.pathmap("%{src,lib}X.rb") }
|
|
25
|
-
self.clean_globs += record_files
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
rule ".rb" => ["%{lib,src}X.jute"] do |t|
|
|
29
|
-
File.open(t.source) do |input|
|
|
30
|
-
File.open(t.name,"w") do |output|
|
|
31
|
-
puts "compiling #{input.inspect} to #{output.inspect}"
|
|
32
|
-
jute_compiler.compile(input,output,jute_modules)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
desc "generate jute records" unless jute_files.empty?
|
|
38
|
-
task :jute
|
|
39
|
-
|
|
40
|
-
task :jute => record_files
|
|
41
|
-
|
|
42
|
-
jute_tasks.each do |t|
|
|
43
|
-
task t => [:jute]
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def try_load_jute()
|
|
49
|
-
require 'jute'
|
|
50
|
-
rescue LoadError => err
|
|
51
|
-
warn "%p while trying to load jute: %s" % [ err.class, err.message ]
|
|
52
|
-
false
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
|
data/lib/zkruby/rubyio.rb
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
require 'socket'
|
|
2
|
-
require 'thread'
|
|
3
|
-
|
|
4
|
-
# Binding over standard ruby sockets
|
|
5
|
-
#
|
|
6
|
-
# Manages 3 threads per zookeeper session
|
|
7
|
-
#
|
|
8
|
-
# Read thread
|
|
9
|
-
# manages connecting to and reading from the tcp socket. Uses non blocking io to manage timeouts
|
|
10
|
-
# and initiate the required ping requests.
|
|
11
|
-
#
|
|
12
|
-
# Write thread
|
|
13
|
-
# each new connection spawns a new thread. Requests coming from the session in response
|
|
14
|
-
# to multiple threads are written to a blocking queue. While the connection is alive
|
|
15
|
-
# this thread reads from the queue and writes to the socket, all in blocking fashion
|
|
16
|
-
# TODO: Is it really ok to do a non-blocking read during a blocking write?
|
|
17
|
-
#
|
|
18
|
-
# Event thread
|
|
19
|
-
# All response and watch callbacks are put on another blocking queue to be read and executed
|
|
20
|
-
# by this thread.
|
|
21
|
-
#
|
|
22
|
-
# All interaction with the session is synchronized
|
|
23
|
-
#
|
|
24
|
-
# Client synchronous code is implemented with a condition variable that waits on the callback/errback
|
|
25
|
-
#
|
|
26
|
-
|
|
27
|
-
# JRuby does not define Errno::NOERROR
|
|
28
|
-
unless defined? Errno::NOERROR
|
|
29
|
-
class Errno::NOERROR < SystemCallError
|
|
30
|
-
Errno = 0
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
module ZooKeeper::RubyIO
|
|
36
|
-
|
|
37
|
-
class Connection
|
|
38
|
-
include ZooKeeper::Protocol
|
|
39
|
-
include Slf4r::Logger
|
|
40
|
-
include Socket::Constants
|
|
41
|
-
|
|
42
|
-
HAS_NONBLOCKING_CONNECT = RUBY_PLATFORM != "java"|| Gem::Version.new(JRUBY_VERSION.dup) >= Gem::Version.new("1.6.7")
|
|
43
|
-
SOL_TCP = IPPROTO_TCP unless defined? ::Socket::SOL_TCP
|
|
44
|
-
|
|
45
|
-
attr_reader :session
|
|
46
|
-
|
|
47
|
-
def initialize(host,port,timeout,session)
|
|
48
|
-
@session = session
|
|
49
|
-
@write_queue = Queue.new()
|
|
50
|
-
|
|
51
|
-
if HAS_NONBLOCKING_CONNECT
|
|
52
|
-
addr = Socket.getaddrinfo(host, nil)
|
|
53
|
-
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
|
|
54
|
-
sock.setsockopt(SOL_SOCKET, SO_LINGER, [0,-1].pack("ii"))
|
|
55
|
-
begin
|
|
56
|
-
sock.setsockopt(SOL_TCP, TCP_NODELAY,[0].pack("i_"))
|
|
57
|
-
rescue
|
|
58
|
-
# JRuby defines SOL_TCP, but it doesn't work
|
|
59
|
-
sock.setsockopt(IPPROTO_TCP, TCP_NODELAY,[0].pack("i_"))
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
sockaddr = Socket.pack_sockaddr_in(port, addr[0][3])
|
|
63
|
-
begin
|
|
64
|
-
sock.connect_nonblock(sockaddr)
|
|
65
|
-
rescue Errno::EINPROGRESS
|
|
66
|
-
|
|
67
|
-
begin
|
|
68
|
-
read,write,errors = IO.select(nil, [sock], nil, timeout)
|
|
69
|
-
optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_ERROR)
|
|
70
|
-
sockerr = (optval.unpack "i")[0]
|
|
71
|
-
rescue Exception => ex
|
|
72
|
-
#JRuby raises Connection Refused instead of populating error array
|
|
73
|
-
logger.warn( "Exception from non blocking select", ex )
|
|
74
|
-
sockerr=-1
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
if sockerr == Errno::NOERROR::Errno
|
|
78
|
-
begin
|
|
79
|
-
sock.connect_nonblock(sockaddr)
|
|
80
|
-
rescue Errno::EISCONN
|
|
81
|
-
#Woohoo! we're connected
|
|
82
|
-
rescue Exception => ex
|
|
83
|
-
logger.warn( "Exception after successful connect",ex )
|
|
84
|
-
sock = nil
|
|
85
|
-
end
|
|
86
|
-
else
|
|
87
|
-
if sockerr == Errno::ECONNREFUSED::Errno
|
|
88
|
-
logger.warn("Connection refused to #{ host }:#{ port }")
|
|
89
|
-
else
|
|
90
|
-
logger.warn("Connection to #{ host }:#{ port } failed: #{sockerr}")
|
|
91
|
-
end
|
|
92
|
-
sock = nil
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
else
|
|
96
|
-
# JRuby prior to 1.6.7 cannot do non-blocking connects, which means there is
|
|
97
|
-
# no way to properly implement the connection-timeout
|
|
98
|
-
# See http://jira.codehaus.org/browse/JRUBY-5165
|
|
99
|
-
# In any case this should be encapsulated in TCPSocket.open(host,port,timeout)
|
|
100
|
-
logger.warn { "Using blocking connect (JRuby < 1.6.7)" }
|
|
101
|
-
begin
|
|
102
|
-
sock = TCPSocket.new(host,port.to_i)
|
|
103
|
-
rescue Errno::ECONNREFUSED
|
|
104
|
-
logger.warn("TCP Connection refused to #{host}:#{port}")
|
|
105
|
-
sock = nil
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
if sock
|
|
110
|
-
Thread.new(sock) { |sock| write_loop(sock) }
|
|
111
|
-
read_loop(sock)
|
|
112
|
-
disconnect(sock)
|
|
113
|
-
end
|
|
114
|
-
session.disconnected()
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# This is called from random client threads
|
|
118
|
-
def send_data(data)
|
|
119
|
-
@write_queue.push(data)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# Since this runs in its very own thread and has no timers
|
|
123
|
-
# we can use boring blocking IO
|
|
124
|
-
def write_loop(socket)
|
|
125
|
-
Thread.current[:name] = "ZooKeeper::RubyIO::WriteLoop"
|
|
126
|
-
begin
|
|
127
|
-
until socket.closed?
|
|
128
|
-
data = @write_queue.pop()
|
|
129
|
-
if socket.write(data) != data.length()
|
|
130
|
-
#TODO - will this really ever happen
|
|
131
|
-
logger.warn("Incomplete write!")
|
|
132
|
-
end
|
|
133
|
-
logger.debug { "Sending: " + data.unpack("H*")[0] }
|
|
134
|
-
end
|
|
135
|
-
logger.debug { "Write loop finished" }
|
|
136
|
-
rescue Exception => ex
|
|
137
|
-
logger.warn("Exception in write loop",ex)
|
|
138
|
-
# Make sure we break out of the read loop
|
|
139
|
-
disconnect(socket)
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def read_loop(socket)
|
|
144
|
-
Thread.current[:name] = "ZooKeeper::RubyIO::ReadLoop"
|
|
145
|
-
session.prime_connection(self)
|
|
146
|
-
ping = 0
|
|
147
|
-
until socket.closed?
|
|
148
|
-
begin
|
|
149
|
-
data = socket.read_nonblock(1024)
|
|
150
|
-
logger.debug { "Received (#{data.length})" + data.unpack("H*")[0] }
|
|
151
|
-
receive_data(data)
|
|
152
|
-
ping = 0
|
|
153
|
-
rescue IO::WaitReadable
|
|
154
|
-
select_result = IO.select([socket],[],[],session.ping_interval)
|
|
155
|
-
unless select_result
|
|
156
|
-
ping += 1
|
|
157
|
-
# two timeouts in a row mean we need to send a ping
|
|
158
|
-
case ping
|
|
159
|
-
when 1 ; session.ping()
|
|
160
|
-
when 2
|
|
161
|
-
logger.warn{"No response to ping in #{session.ping_interval}*2"}
|
|
162
|
-
break
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
rescue EOFError
|
|
166
|
-
# This is how we expect to end - send a close packet and the
|
|
167
|
-
# server closes the socket
|
|
168
|
-
logger.debug { "EOF reading from socket" }
|
|
169
|
-
break
|
|
170
|
-
rescue Exception => ex
|
|
171
|
-
logger.warn( "#{ex.class} exception in readloop",ex )
|
|
172
|
-
break
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
# @api protocol
|
|
178
|
-
def receive_records(packet_io)
|
|
179
|
-
session.receive_records(packet_io)
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
private
|
|
183
|
-
def disconnect(socket)
|
|
184
|
-
socket.close if socket and !socket.closed?
|
|
185
|
-
rescue Exception => ex
|
|
186
|
-
#oh well
|
|
187
|
-
logger.debug("Exception closing socket",ex)
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
end #Class connection
|
|
191
|
-
|
|
192
|
-
module Binding
|
|
193
|
-
def connect(host,port,timeout)
|
|
194
|
-
Connection.new(host,port,timeout,self)
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
|