zkruby 3.4.4.rc3 → 3.4.4.rc4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/em_zkruby.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  # This is the main require for the eventmachine based binding
2
-
2
+ # Only use this if all use of zkruby will be within the EM Reactor
3
3
  require 'zkruby/zkruby'
4
4
  require 'zkruby/eventmachine'
5
+
6
+ Empathy::EM.empathise(ZooKeeper)
@@ -30,7 +30,7 @@ module ZooKeeper
30
30
  @event_loop = event_loop
31
31
  @operation = operation
32
32
  @callback = callback
33
- @mutex,@cv = Strand::Mutex.new(), Strand::ConditionVariable.new()
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 = Strand.current[CURRENT] ||= []
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
- Strand.current[CURRENT].last if Strand.current[CURRENT]
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
- Strand.pass
147
+ Thread.pass
161
148
  end
162
149
 
163
150
  class WatchEvent
@@ -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
- to_int | num
35
+ @index | num
36
36
  end
37
37
 
38
38
  def &(num)
39
- to_int & num
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
@@ -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 ClientConn < ::EM::Connection
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 strand
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 = EM.add_timer(@connect_timeout) do
42
- @fiber.resume(:connect_timer)
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
- while true
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 = EM.add_periodic_timer(session.ping_interval) do
53
- @fiber.resume(:ping_timer)
52
+ @timer = ::EventMachine.add_periodic_timer(session.ping_interval) do
53
+ resume(:ping_timer)
54
54
  end
55
55
  else
56
- close_connection()
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 close_connection
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
- break
70
+ unbound = true
71
+ else
72
+ logger.error("Unexpected resume - #{event}")
73
+ break;
70
74
  end
71
75
  end
72
76
  end
73
- EM.cancel_timer(@timer) if @timer
74
- session.disconnected
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
- @fiber.resume(:connection_completed)
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
- @fiber.resume(:receive_records,packet_io)
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 disconnect()
90
- close_connection()
91
+ def unbind(reason)
92
+ logger.warn{"Connection #{self} unbound due to #{reason}"} if reason
93
+ resume(:unbind)
91
94
  end
92
95
 
93
- def unbind
94
- @fiber.resume(:unbind)
96
+ private
97
+ def resume(event,*args)
98
+ @fiber.resume(event,*args) if @fiber
95
99
  rescue Exception => ex
96
- logger.error("Exception in unbind",ex)
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
- module Binding
102
- def connect(host,port,timeout)
103
- conn = EM.connect(host,port,ZooKeeper::EventMachine::ClientConn,self,timeout)
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
@@ -71,7 +71,6 @@ module ZooKeeper
71
71
 
72
72
  def path
73
73
  #Every request has a path!
74
- #TODO - path may be chrooted!
75
74
  request.path if request.respond_to?(:path)
76
75
  end
77
76
  end
@@ -1,7 +1,6 @@
1
1
  require 'set'
2
- require 'strand'
3
- require 'strand/monitor'
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 Strand::MonitorMixin
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
- # @api connection
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("Starting new zookeeper client session")
144
+ logger.debug {"Starting new zookeeper client session for #{client}"}
149
145
  @event_loop = EventLoop.new(client)
150
- Strand.new {
151
- begin
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
- logger.debug("Session complete")
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
- connect(host,port,@connect_timeout)
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=#{@time_out}, ping=#{@ping_interval}" }
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
- @conn.disconnect()
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
- raise ProtocolError("Bad watcher #{watch}")
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 arrives
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 = Strand::Queue.new()
526
+ @event_queue = Queue.new()
523
527
 
524
528
  @alive = true
525
- @event_thread = Strand.new() do
529
+ @event_thread = Thread.new() do
526
530
  logger.debug { "Starting event loop" }
527
- Strand.current[:name] = "ZooKeeper::EventLoop"
528
- Strand.current[CURRENT] = [ client ]
531
+ Thread.current[:name] = "ZK::EventLoop #{self}"
532
+ Thread.current[CURRENT] = [ client ]
529
533
  begin
530
534
  pop_event_queue until dead?
531
- logger.debug { "Finished event loop" }
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
- queued = @event_queue.pop if @alive
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
- Strand.new do
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
- Strand.current == @event_thread
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
+
@@ -1,5 +1,5 @@
1
1
 
2
2
  module ZooKeeper
3
3
  # Major/Minor numbers track zookeeper itself, final digit is our build number
4
- VERSION = "3.4.4.rc3"
4
+ VERSION = "3.4.4.rc4"
5
5
  end
data/lib/zkruby/zkruby.rb CHANGED
@@ -15,6 +15,7 @@ require 'zkruby/bindata'
15
15
  require 'jute/zookeeper'
16
16
  require 'zkruby/multi'
17
17
  require 'zkruby/protocol'
18
+ require 'zkruby/conn'
18
19
  require 'zkruby/session'
19
20
  require 'zkruby/client'
20
21
  # Utilities
data/lib/zkruby.rb CHANGED
@@ -1,4 +1,3 @@
1
1
  # This is the main require for standard ruby io/thread based binding
2
2
 
3
3
  require 'zkruby/zkruby'
4
- require 'zkruby/rubyio'
data/spec/enum_spec.rb CHANGED
@@ -24,6 +24,8 @@ describe Enumeration do
24
24
  t.should === 1
25
25
  end
26
26
 
27
+ it "should do coercion"
28
+
27
29
  it "should be useable in a mock" do
28
30
  m = mock("watchevent")
29
31
  m.should_receive(:test).with(TestEnum::TWO)
@@ -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
- describe ZooKeeper::EventMachine::Binding do
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
- EventMachine.run {
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
- Strand.event_machine?.should be_true
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
@@ -1,8 +1,8 @@
1
1
  require 'server_helper'
2
2
  require 'shared/binding'
3
- require 'zkruby/rubyio'
4
3
 
5
- describe ZooKeeper::RubyIO::Binding do
4
+ describe ZooKeeperBinding do
5
+ let (:pass_every) { nil }
6
6
  it_behaves_like "a zookeeper client binding"
7
7
  end
8
8
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- module ZooKeeperServerHelper
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
- Strand.sleep(3) if JRUBY_COMPAT_SYSTEM
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
- Strand::sleep(delay) if delay > 0
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
- "localhost:2181"
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 ZooKeeperServerHelper
37
+ include ZooKeeperServerManager
38
38
 
39
39
  restart_cluster()
40
- Strand.sleep(3)
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
- stat = @zk.stat("/")
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
- Strand.sleep(@zk.timeout * 2.0)
152
+ sleep(@zk.timeout * 2.0)
151
153
  @zk.exists?("/zkruby").should be_true
152
154
  end
153
155
 
@@ -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
- Strand.sleep(2)
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
- Strand.sleep(2)
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::RubyIO::Connection].level = :error
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 << 'lib/jute/zookeeper.rb'
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.rc3
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: 2012-12-17 00:00:00.000000000 Z
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: strand
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: 0.2.0.rc0
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: 0.2.0.rc0
45
+ version: 1.4.1
46
46
  - !ruby/object:Gem::Dependency
47
- name: bindata
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: 1.4.1
54
- type: :runtime
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: 1.4.1
61
+ version: 0.12.10
62
62
  - !ruby/object:Gem::Dependency
63
- name: eventmachine
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.12.10
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.12.10
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.24
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: yard
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
-