mongo 1.4.0 → 1.5.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/docs/HISTORY.md +15 -0
  2. data/docs/REPLICA_SETS.md +19 -7
  3. data/lib/mongo.rb +1 -0
  4. data/lib/mongo/collection.rb +1 -1
  5. data/lib/mongo/connection.rb +29 -351
  6. data/lib/mongo/cursor.rb +88 -6
  7. data/lib/mongo/gridfs/grid.rb +4 -2
  8. data/lib/mongo/gridfs/grid_file_system.rb +4 -2
  9. data/lib/mongo/networking.rb +345 -0
  10. data/lib/mongo/repl_set_connection.rb +236 -191
  11. data/lib/mongo/util/core_ext.rb +45 -0
  12. data/lib/mongo/util/logging.rb +5 -0
  13. data/lib/mongo/util/node.rb +6 -4
  14. data/lib/mongo/util/pool.rb +73 -26
  15. data/lib/mongo/util/pool_manager.rb +100 -30
  16. data/lib/mongo/util/uri_parser.rb +29 -21
  17. data/lib/mongo/version.rb +1 -1
  18. data/test/bson/binary_test.rb +6 -8
  19. data/test/bson/bson_test.rb +1 -0
  20. data/test/bson/ordered_hash_test.rb +2 -0
  21. data/test/bson/test_helper.rb +0 -17
  22. data/test/collection_test.rb +22 -0
  23. data/test/connection_test.rb +1 -1
  24. data/test/cursor_test.rb +3 -3
  25. data/test/load/thin/load.rb +4 -7
  26. data/test/replica_sets/basic_test.rb +46 -0
  27. data/test/replica_sets/connect_test.rb +35 -58
  28. data/test/replica_sets/count_test.rb +15 -6
  29. data/test/replica_sets/insert_test.rb +6 -7
  30. data/test/replica_sets/query_test.rb +4 -6
  31. data/test/replica_sets/read_preference_test.rb +112 -8
  32. data/test/replica_sets/refresh_test.rb +66 -36
  33. data/test/replica_sets/refresh_with_threads_test.rb +55 -0
  34. data/test/replica_sets/replication_ack_test.rb +3 -6
  35. data/test/replica_sets/rs_test_helper.rb +12 -6
  36. data/test/replica_sets/threading_test.rb +111 -0
  37. data/test/test_helper.rb +9 -2
  38. data/test/threading_test.rb +14 -6
  39. data/test/tools/repl_set_manager.rb +55 -40
  40. data/test/unit/collection_test.rb +2 -1
  41. data/test/unit/connection_test.rb +8 -8
  42. data/test/unit/grid_test.rb +4 -2
  43. data/test/unit/pool_manager_test.rb +1 -0
  44. data/test/unit/read_test.rb +17 -5
  45. data/test/uri_test.rb +9 -4
  46. metadata +13 -28
  47. data/test/replica_sets/connection_string_test.rb +0 -29
  48. data/test/replica_sets/pooled_insert_test.rb +0 -58
  49. data/test/replica_sets/query_secondaries.rb +0 -109
@@ -1,5 +1,20 @@
1
1
  # MongoDB Ruby Driver History
2
2
 
3
+ ### 1.5.0.rc0
4
+ 2011-11-18
5
+
6
+ Fix bugs associated with replica set refresh.
7
+
8
+ ### 1.4.1
9
+ 2011-10-17
10
+
11
+ If you're using 1.4.0, this is a necessary upgrade.
12
+
13
+ * Simplified replica set refresh.
14
+ * Fix bugs associated with replica set refresh.
15
+ * Make cursor smart enough to continue functioning
16
+ even if a refresh is triggered.
17
+
3
18
  ### 1.4.0
4
19
  2011-9-19
5
20
 
@@ -28,31 +28,43 @@ Imagine that either the master node or one of the read nodes goes offline. How w
28
28
 
29
29
  If any read operation fails, the driver will raise a *ConnectionFailure* exception. It then becomes the client's responsibility to decide how to handle this.
30
30
 
31
- If the client decides to retry, it's not guaranteed that another member of the replica set will have been promoted to master right away, so it's still possible that the driver will raise another *ConnectionFailure*. However, once a member has been promoted to master, typically within a few seconds, subsequent operations will succeed.
31
+ If the client decides to retry, it's not guaranteed that another member of the replica set will have been promoted to master right away, so it's still possible that the driver will raise another *ConnectionFailure*. However, once a member has been promoted to master, typically within a few seconds, subsequent operations will succeed. *Note that this does not prevent
32
+ exception in the event of a primary failover.*
32
33
 
33
34
  The driver will essentially cycle through all known seed addresses until a node identifies itself as master.
34
35
 
35
36
  ### Refresh mode
36
37
 
37
38
  You can now specify a refresh mode and refresh interval for a replica set connection. This will help to ensure that
38
- changes to a replica set's configuration are quickly reflected on the driver side. Refresh mode is
39
- enabled in synchronous mode by default. Here's how to specify this explicitly:
39
+ changes to a replica set's configuration are quickly reflected on the driver side. In particular, if you change
40
+ the state of any secondary node, the automated refresh will ensure that this state is recorded on the client side.
41
+ If you add a secondary that responds to pings much faster than the existing nodes, then the new secondary will
42
+ be used for reads.
40
43
 
41
- @connection = ReplSetConnection.new(['n1.mydb.net', 27017], :refresh_mode => :sync)
44
+ Refresh mode is disabled by default.
42
45
 
43
- If you want to refresh to happen via a background thread, use the `:async` mode:
46
+ However, if you expect to make live changes to your secondaries, and you want this to be reflected without
47
+ having to manually restart your app server, then you should enable it. You can enable this mode
48
+ synchronously, which will refresh the replica set data in a synchronous fashion (which may
49
+ ocassionally slow down your queries):
44
50
 
45
- @connection = ReplSetConnection.new(['n1.mydb.net', 27017], :refresh_mode => :async)
51
+ @connection = ReplSetConnection.new(['n1.mydb.net', 27017], :refresh_mode => :sync)
46
52
 
47
53
  If you want to change the default refresh interval of 90 seconds, you can do so like this:
48
54
 
49
- @connection = ReplSetConnection.new(['n1.mydb.net', 27017], :refresh_mode => :async,
55
+ @connection = ReplSetConnection.new(['n1.mydb.net', 27017], :refresh_mode => :sync,
50
56
  :refresh_interval => 60)
51
57
 
58
+ Do not set this value to anything lower than 30, or you may start to experience performance issues.
59
+
52
60
  You can also disable refresh mode altogether:
53
61
 
54
62
  @connection = ReplSetConnection.new(['n1.mydb.net', 27017], :refresh_mode => false)
55
63
 
64
+ And you can call `refresh` manually on any replica set connection:
65
+
66
+ @connection.refresh
67
+
56
68
  ### Recovery
57
69
 
58
70
  Driver users may wish to wrap their database calls with failure recovery code. Here's one possibility, which will attempt to connection
@@ -65,6 +65,7 @@ require 'mongo/util/ssl_socket'
65
65
  require 'mongo/util/uri_parser'
66
66
 
67
67
  require 'mongo/collection'
68
+ require 'mongo/networking'
68
69
  require 'mongo/connection'
69
70
  require 'mongo/repl_set_connection'
70
71
  require 'mongo/cursor'
@@ -217,7 +217,7 @@ module Mongo
217
217
  max_scan = opts.delete(:max_scan)
218
218
  return_key = opts.delete(:return_key)
219
219
  transformer = opts.delete(:transformer)
220
- show_disk_loc = opts.delete(:max_scan)
220
+ show_disk_loc = opts.delete(:show_disk_loc)
221
221
  read = opts.delete(:read) || @read_preference
222
222
 
223
223
  if timeout == false && !block_given?
@@ -19,26 +19,26 @@
19
19
  require 'set'
20
20
  require 'socket'
21
21
  require 'thread'
22
-
23
22
  module Mongo
24
23
 
25
- # Instantiates and manages connections to MongoDB.
24
+ # Instantiates and manages self.connections to MongoDB.
26
25
  class Connection
27
26
  include Mongo::Logging
27
+ include Mongo::Networking
28
28
 
29
29
  TCPSocket = ::TCPSocket
30
30
  Mutex = ::Mutex
31
31
  ConditionVariable = ::ConditionVariable
32
32
 
33
+ Thread.abort_on_exception = true
34
+
33
35
  DEFAULT_PORT = 27017
34
- STANDARD_HEADER_SIZE = 16
35
- RESPONSE_HEADER_SIZE = 20
36
36
 
37
- attr_reader :logger, :size, :auths, :primary, :safe, :host_to_try,
38
- :pool_size, :connect_timeout, :primary_pool, :socket_class
37
+ mongo_thread_local_accessor :connections
39
38
 
40
- # Counter for generating unique request ids.
41
- @@current_request_id = 0
39
+ attr_reader :logger, :size, :auths, :primary, :safe, :host_to_try,
40
+ :pool_size, :connect_timeout, :pool_timeout,
41
+ :primary_pool, :socket_class
42
42
 
43
43
  # Create a connection to single MongoDB instance.
44
44
  #
@@ -63,9 +63,9 @@ module Mongo
63
63
  # to a single, slave node.
64
64
  # @option opts [Logger, #debug] :logger (nil) A Logger instance for debugging driver ops. Note that
65
65
  # logging negatively impacts performance; therefore, it should not be used for high-performance apps.
66
- # @option opts [Integer] :pool_size (1) The maximum number of socket connections allowed per
66
+ # @option opts [Integer] :pool_size (1) The maximum number of socket self.connections allowed per
67
67
  # connection pool. Note: this setting is relevant only for multi-threaded applications.
68
- # @option opts [Float] :pool_timeout (5.0) When all of the connections a pool are checked out,
68
+ # @option opts [Float] :pool_timeout (5.0) When all of the self.connections a pool are checked out,
69
69
  # this is the number of seconds to wait for a new connection to be released before throwing an exception.
70
70
  # Note: this setting is relevant only for multi-threaded applications (which in Ruby are rare).
71
71
  # @option opts [Float] :op_timeout (nil) The number of seconds to wait for a read operation to time out.
@@ -80,7 +80,7 @@ module Mongo
80
80
  # @example localhost, 27017
81
81
  # Connection.new("localhost")
82
82
  #
83
- # @example localhost, 3000, max 5 connections, with max 5 seconds of wait time.
83
+ # @example localhost, 3000, max 5 self.connections, with max 5 seconds of wait time.
84
84
  # Connection.new("localhost", 3000, :pool_size => 5, :timeout => 5)
85
85
  #
86
86
  # @example localhost, 3000, where this node may be a slave
@@ -91,7 +91,7 @@ module Mongo
91
91
  # @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
92
92
  # driver fails to connect to a replica set with that name.
93
93
  #
94
- # @core connections
94
+ # @core self.connections
95
95
  def initialize(host=nil, port=nil, opts={})
96
96
  @host_to_try = format_pair(host, port)
97
97
 
@@ -379,125 +379,12 @@ module Mongo
379
379
  @slave_ok
380
380
  end
381
381
 
382
- # Send a message to MongoDB, adding the necessary headers.
383
- #
384
- # @param [Integer] operation a MongoDB opcode.
385
- # @param [BSON::ByteBuffer] message a message to send to the database.
386
- #
387
- # @option opts [Symbol] :connection (:writer) The connection to which
388
- # this message should be sent. Valid options are :writer and :reader.
389
- #
390
- # @return [Integer] number of bytes sent
391
- def send_message(operation, message, opts={})
392
- if opts.is_a?(String)
393
- warn "Connection#send_message no longer takes a string log message. " +
394
- "Logging is now handled within the Collection and Cursor classes."
395
- opts = {}
396
- end
397
-
398
- connection = opts.fetch(:connection, :writer)
399
-
400
- begin
401
- add_message_headers(message, operation)
402
- packed_message = message.to_s
403
-
404
- if connection == :writer
405
- socket = checkout_writer
406
- else
407
- socket = checkout_reader
408
- end
409
-
410
- send_message_on_socket(packed_message, socket)
411
- ensure
412
- checkin(socket)
413
- end
414
- end
415
-
416
- # Sends a message to the database, waits for a response, and raises
417
- # an exception if the operation has failed.
418
- #
419
- # @param [Integer] operation a MongoDB opcode.
420
- # @param [BSON::ByteBuffer] message a message to send to the database.
421
- # @param [String] db_name the name of the database. used on call to get_last_error.
422
- # @param [Hash] last_error_params parameters to be sent to getLastError. See DB#error for
423
- # available options.
424
- #
425
- # @see DB#get_last_error for valid last error params.
426
- #
427
- # @return [Hash] The document returned by the call to getlasterror.
428
- def send_message_with_safe_check(operation, message, db_name, log_message=nil, last_error_params=false)
429
- docs = num_received = cursor_id = ''
430
- add_message_headers(message, operation)
431
-
432
- last_error_message = BSON::ByteBuffer.new
433
- build_last_error_message(last_error_message, db_name, last_error_params)
434
- last_error_id = add_message_headers(last_error_message, Mongo::Constants::OP_QUERY)
435
-
436
- packed_message = message.append!(last_error_message).to_s
437
- begin
438
- sock = checkout_writer
439
- @safe_mutexes[sock].synchronize do
440
- send_message_on_socket(packed_message, sock)
441
- docs, num_received, cursor_id = receive(sock, last_error_id)
442
- end
443
- ensure
444
- checkin(sock)
445
- end
446
-
447
- if num_received == 1 && (error = docs[0]['err'] || docs[0]['errmsg'])
448
- close if error == "not master"
449
- error = "wtimeout" if error == "timeout"
450
- raise OperationFailure.new(docs[0]['code'].to_s + ': ' + error, docs[0]['code'], docs[0])
451
- end
452
-
453
- docs[0]
454
- end
455
-
456
- # Sends a message to the database and waits for the response.
457
- #
458
- # @param [Integer] operation a MongoDB opcode.
459
- # @param [BSON::ByteBuffer] message a message to send to the database.
460
- # @param [String] log_message this is currently a no-op and will be removed.
461
- # @param [Socket] socket a socket to use in lieu of checking out a new one.
462
- # @param [Boolean] command (false) indicate whether this is a command. If this is a command,
463
- # the message will be sent to the primary node.
464
- # @param [Boolean] command (false) indicate whether the cursor should be exhausted. Set
465
- # this to true only when the OP_QUERY_EXHAUST flag is set.
466
- #
467
- # @return [Array]
468
- # An array whose indexes include [0] documents returned, [1] number of document received,
469
- # and [3] a cursor_id.
470
- def receive_message(operation, message, log_message=nil, socket=nil, command=false, read=:primary, exhaust=false)
471
- request_id = add_message_headers(message, operation)
472
- packed_message = message.to_s
473
- begin
474
- if socket
475
- sock = socket
476
- should_checkin = false
477
- else
478
- if command
479
- sock = checkout_writer
480
- elsif read == :primary
481
- sock = checkout_writer
482
- elsif read == :secondary
483
- sock = checkout_reader
484
- else
485
- sock = checkout_tagged(read)
486
- end
487
- should_checkin = true
488
- end
489
-
490
- result = ''
491
- @safe_mutexes[sock].synchronize do
492
- send_message_on_socket(packed_message, sock)
493
- result = receive(sock, request_id, exhaust)
494
- end
495
- ensure
496
- if should_checkin
497
- checkin(sock)
498
- end
499
- end
500
- result
382
+ def get_socket_from_thread_local
383
+ Thread.current[:socket_map] ||= {}
384
+ Thread.current[:socket_map][self] ||= {}
385
+ Thread.current[:socket_map][self][:writer] ||= checkout_writer
386
+ Thread.current[:socket_map][self][:reader] =
387
+ Thread.current[:socket_map][self][:writer]
501
388
  end
502
389
 
503
390
  # Create a new socket and attempt to connect to master.
@@ -536,7 +423,7 @@ module Mongo
536
423
  # NOTE: Do check if this needs to be more stringent.
537
424
  # Probably not since if any node raises a connection failure, all nodes will be closed.
538
425
  def connected?
539
- @primary_pool && @primary_pool.host && @primary_pool.port
426
+ @primary_pool && !@primary_pool.closed?
540
427
  end
541
428
 
542
429
  # Determine if the connection is active. In a normal case the *server_info* operation
@@ -564,6 +451,13 @@ module Mongo
564
451
  end
565
452
  alias :primary? :read_primary?
566
453
 
454
+ # The socket pool that this connection reads from.
455
+ #
456
+ # @return [Mongo::Pool]
457
+ def read_pool
458
+ @primary_pool
459
+ end
460
+
567
461
  # The value of the read preference. Because
568
462
  # this is a single-node connection, the value
569
463
  # is +:primary+, and the connection will read
@@ -604,16 +498,12 @@ module Mongo
604
498
  # Checkin a socket used for reading.
605
499
  # Note: this is overridden in ReplSetConnection.
606
500
  def checkin_reader(socket)
607
- warn "Connection#checkin_writer is not deprecated and will be removed " +
608
- "in driver v2.0. Use Connection#checkin instead."
609
501
  checkin(socket)
610
502
  end
611
503
 
612
504
  # Checkin a socket used for writing.
613
505
  # Note: this is overridden in ReplSetConnection.
614
506
  def checkin_writer(socket)
615
- warn "Connection#checkin_writer is not deprecated and will be removed " +
616
- "in driver v2.0. Use Connection#checkin instead."
617
507
  checkin(socket)
618
508
  end
619
509
 
@@ -651,7 +541,7 @@ module Mongo
651
541
  warn "The :timeout option has been deprecated " +
652
542
  "and will be removed in the 2.0 release. Use :pool_timeout instead."
653
543
  end
654
- @timeout = opts[:pool_timeout] || opts[:timeout] || 5.0
544
+ @pool_timeout = opts[:pool_timeout] || opts[:timeout] || 5.0
655
545
 
656
546
  # Timeout on socket read operation.
657
547
  @op_timeout = opts[:op_timeout] || nil
@@ -666,10 +556,6 @@ module Mongo
666
556
  # Global safe option. This is false by default.
667
557
  @safe = opts[:safe] || false
668
558
 
669
- # Create a mutex when a new key, in this case a socket,
670
- # is added to the hash.
671
- @safe_mutexes = Hash.new { |h, k| h[k] = Mutex.new }
672
-
673
559
  # Condition variable for signal and wait
674
560
  @queue = ConditionVariable.new
675
561
 
@@ -680,8 +566,7 @@ module Mongo
680
566
  @logger = opts[:logger] || nil
681
567
 
682
568
  if @logger
683
- @logger.debug("MongoDB logging. Please note that logging negatively impacts performance " +
684
- "and should be disabled for high-performance production apps.")
569
+ write_logging_startup_message
685
570
  end
686
571
 
687
572
  should_connect = opts.fetch(:connect, true)
@@ -743,214 +628,7 @@ module Mongo
743
628
  def set_primary(node)
744
629
  host, port = *node
745
630
  @primary = [host, port]
746
- @primary_pool = Pool.new(self, host, port, :size => @pool_size, :timeout => @timeout)
747
- end
748
-
749
- ## Low-level connection methods.
750
-
751
- def receive(sock, cursor_id, exhaust=false)
752
- begin
753
- if exhaust
754
- docs = []
755
- num_received = 0
756
-
757
- while(cursor_id != 0) do
758
- receive_header(sock, cursor_id, exhaust)
759
- number_received, cursor_id = receive_response_header(sock)
760
- new_docs, n = read_documents(number_received, sock)
761
- docs += new_docs
762
- num_received += n
763
- end
764
-
765
- return [docs, num_received, cursor_id]
766
- else
767
- receive_header(sock, cursor_id, exhaust)
768
- number_received, cursor_id = receive_response_header(sock)
769
- docs, num_received = read_documents(number_received, sock)
770
-
771
- return [docs, num_received, cursor_id]
772
- end
773
- rescue Mongo::ConnectionFailure => ex
774
- close
775
- raise ex
776
- end
777
- end
778
-
779
- def receive_header(sock, expected_response, exhaust=false)
780
- header = receive_message_on_socket(16, sock)
781
- size, request_id, response_to = header.unpack('VVV')
782
- if !exhaust && expected_response != response_to
783
- raise Mongo::ConnectionFailure, "Expected response #{expected_response} but got #{response_to}"
784
- end
785
-
786
- unless header.size == STANDARD_HEADER_SIZE
787
- raise "Short read for DB response header: " +
788
- "expected #{STANDARD_HEADER_SIZE} bytes, saw #{header.size}"
789
- end
790
- nil
791
- end
792
-
793
- def receive_response_header(sock)
794
- header_buf = receive_message_on_socket(RESPONSE_HEADER_SIZE, sock)
795
- if header_buf.length != RESPONSE_HEADER_SIZE
796
- raise "Short read for DB response header; " +
797
- "expected #{RESPONSE_HEADER_SIZE} bytes, saw #{header_buf.length}"
798
- end
799
- flags, cursor_id_a, cursor_id_b, starting_from, number_remaining = header_buf.unpack('VVVVV')
800
- check_response_flags(flags)
801
- cursor_id = (cursor_id_b << 32) + cursor_id_a
802
- [number_remaining, cursor_id]
803
- end
804
-
805
- def check_response_flags(flags)
806
- if flags & Mongo::Constants::REPLY_CURSOR_NOT_FOUND != 0
807
- raise Mongo::OperationFailure, "Query response returned CURSOR_NOT_FOUND. " +
808
- "Either an invalid cursor was specified, or the cursor may have timed out on the server."
809
- elsif flags & Mongo::Constants::REPLY_QUERY_FAILURE != 0
810
- # Getting odd failures when a exception is raised here.
811
- end
812
- end
813
-
814
- def read_documents(number_received, sock)
815
- docs = []
816
- number_remaining = number_received
817
- while number_remaining > 0 do
818
- buf = receive_message_on_socket(4, sock)
819
- size = buf.unpack('V')[0]
820
- buf << receive_message_on_socket(size - 4, sock)
821
- number_remaining -= 1
822
- docs << BSON::BSON_CODER.deserialize(buf)
823
- end
824
- [docs, number_received]
825
- end
826
-
827
- # Constructs a getlasterror message. This method is used exclusively by
828
- # Connection#send_message_with_safe_check.
829
- #
830
- # Because it modifies message by reference, we don't need to return it.
831
- def build_last_error_message(message, db_name, opts)
832
- message.put_int(0)
833
- BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.$cmd")
834
- message.put_int(0)
835
- message.put_int(-1)
836
- cmd = BSON::OrderedHash.new
837
- cmd[:getlasterror] = 1
838
- if opts.is_a?(Hash)
839
- opts.assert_valid_keys(:w, :wtimeout, :fsync)
840
- cmd.merge!(opts)
841
- end
842
- message.put_binary(BSON::BSON_CODER.serialize(cmd, false).to_s)
843
- nil
844
- end
845
-
846
- # Prepares a message for transmission to MongoDB by
847
- # constructing a valid message header.
848
- #
849
- # Note: this method modifies message by reference.
850
- #
851
- # @return [Integer] the request id used in the header
852
- def add_message_headers(message, operation)
853
- headers = [
854
- # Message size.
855
- 16 + message.size,
856
-
857
- # Unique request id.
858
- request_id = get_request_id,
859
-
860
- # Response id.
861
- 0,
862
-
863
- # Opcode.
864
- operation
865
- ].pack('VVVV')
866
-
867
- message.prepend!(headers)
868
-
869
- request_id
870
- end
871
-
872
- # Increment and return the next available request id.
873
- #
874
- # return [Integer]
875
- def get_request_id
876
- request_id = ''
877
- @id_lock.synchronize do
878
- request_id = @@current_request_id += 1
879
- end
880
- request_id
881
- end
882
-
883
- # Low-level method for sending a message on a socket.
884
- # Requires a packed message and an available socket,
885
- #
886
- # @return [Integer] number of bytes sent
887
- def send_message_on_socket(packed_message, socket)
888
- begin
889
- total_bytes_sent = socket.send(packed_message, 0)
890
- if total_bytes_sent != packed_message.size
891
- packed_message.slice!(0, total_bytes_sent)
892
- while packed_message.size > 0
893
- byte_sent = socket.send(packed_message, 0)
894
- total_bytes_sent += byte_sent
895
- packed_message.slice!(0, byte_sent)
896
- end
897
- end
898
- total_bytes_sent
899
- rescue => ex
900
- close
901
- raise ConnectionFailure, "Operation failed with the following exception: #{ex}"
902
- end
903
- end
904
-
905
- # Low-level method for receiving data from socket.
906
- # Requires length and an available socket.
907
- def receive_message_on_socket(length, socket)
908
- begin
909
- if @op_timeout
910
- message = nil
911
- Mongo::TimeoutHandler.timeout(@op_timeout, OperationTimeout) do
912
- message = receive_data(length, socket)
913
- end
914
- else
915
- message = receive_data(length, socket)
916
- end
917
- rescue => ex
918
- close
919
-
920
- if ex.class == OperationTimeout
921
- raise OperationTimeout, "Timed out waiting on socket read."
922
- else
923
- raise ConnectionFailure, "Operation failed with the following exception: #{ex}"
924
- end
925
- end
926
- message
927
- end
928
-
929
- def receive_data(length, socket)
930
- message = new_binary_string
931
- socket.read(length, message)
932
- raise ConnectionFailure, "connection closed" unless message && message.length > 0
933
- if message.length < length
934
- chunk = new_binary_string
935
- while message.length < length
936
- socket.read(length - message.length, chunk)
937
- raise ConnectionFailure, "connection closed" unless chunk.length > 0
938
- message << chunk
939
- end
940
- end
941
- message
942
- end
943
-
944
- if defined?(Encoding)
945
- BINARY_ENCODING = Encoding.find("binary")
946
-
947
- def new_binary_string
948
- "".force_encoding(BINARY_ENCODING)
949
- end
950
- else
951
- def new_binary_string
952
- ""
953
- end
631
+ @primary_pool = Pool.new(self, host, port, :size => @pool_size, :timeout => @pool_timeout)
954
632
  end
955
633
  end
956
634
  end