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