mongo 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. data/{LICENSE.txt → LICENSE} +0 -0
  2. data/README.md +124 -111
  3. data/Rakefile +9 -325
  4. data/VERSION +1 -0
  5. data/bin/mongo_console +4 -4
  6. data/examples/admin.rb +43 -0
  7. data/examples/capped.rb +22 -0
  8. data/examples/cursor.rb +48 -0
  9. data/examples/gridfs.rb +44 -0
  10. data/examples/index_test.rb +126 -0
  11. data/examples/info.rb +31 -0
  12. data/examples/queries.rb +74 -0
  13. data/examples/replica_set.rb +26 -0
  14. data/examples/simple.rb +25 -0
  15. data/examples/strict.rb +35 -0
  16. data/examples/types.rb +36 -0
  17. data/{test/load → examples/web}/thin/load.rb +3 -1
  18. data/{test/load → examples/web}/unicorn/load.rb +5 -3
  19. data/lib/mongo.rb +8 -10
  20. data/lib/mongo/collection.rb +134 -114
  21. data/lib/mongo/cursor.rb +21 -14
  22. data/lib/mongo/db.rb +30 -28
  23. data/lib/mongo/exceptions.rb +1 -1
  24. data/lib/mongo/gridfs/grid.rb +8 -7
  25. data/lib/mongo/gridfs/grid_ext.rb +1 -1
  26. data/lib/mongo/gridfs/grid_file_system.rb +6 -5
  27. data/lib/mongo/gridfs/grid_io.rb +22 -19
  28. data/lib/mongo/legacy.rb +82 -0
  29. data/lib/mongo/{connection.rb → mongo_client.rb} +82 -61
  30. data/lib/mongo/{repl_set_connection.rb → mongo_replica_set_client.rb} +54 -39
  31. data/lib/mongo/{sharded_connection.rb → mongo_sharded_client.rb} +9 -9
  32. data/lib/mongo/networking.rb +25 -20
  33. data/lib/mongo/util/conversions.rb +1 -1
  34. data/lib/mongo/util/core_ext.rb +1 -1
  35. data/lib/mongo/util/logging.rb +20 -4
  36. data/lib/mongo/util/node.rb +16 -16
  37. data/lib/mongo/util/pool.rb +56 -27
  38. data/lib/mongo/util/pool_manager.rb +28 -27
  39. data/lib/mongo/util/server_version.rb +1 -1
  40. data/lib/mongo/util/sharding_pool_manager.rb +8 -8
  41. data/lib/mongo/util/ssl_socket.rb +1 -5
  42. data/lib/mongo/util/support.rb +24 -8
  43. data/lib/mongo/util/tcp_socket.rb +0 -4
  44. data/lib/mongo/util/uri_parser.rb +54 -38
  45. data/lib/mongo/util/write_concern.rb +67 -0
  46. data/mongo.gemspec +21 -32
  47. data/test/auxillary/{1.4_features.rb → 1.4_feature_test.rb} +4 -5
  48. data/test/auxillary/authentication_test.rb +18 -20
  49. data/test/auxillary/autoreconnect_test.rb +3 -5
  50. data/test/auxillary/fork_test.rb +5 -7
  51. data/test/auxillary/repl_set_auth_test.rb +13 -15
  52. data/test/auxillary/slave_connection_test.rb +8 -7
  53. data/test/auxillary/threaded_authentication_test.rb +15 -17
  54. data/test/bson/binary_test.rb +1 -1
  55. data/test/bson/bson_test.rb +60 -36
  56. data/test/bson/byte_buffer_test.rb +1 -1
  57. data/test/bson/hash_with_indifferent_access_test.rb +2 -2
  58. data/test/bson/json_test.rb +1 -2
  59. data/test/bson/object_id_test.rb +1 -2
  60. data/test/bson/ordered_hash_test.rb +1 -1
  61. data/test/bson/timestamp_test.rb +1 -1
  62. data/test/{collection_test.rb → functional/collection_test.rb} +57 -57
  63. data/test/{connection_test.rb → functional/connection_test.rb} +75 -89
  64. data/test/{conversions_test.rb → functional/conversions_test.rb} +1 -1
  65. data/test/{cursor_fail_test.rb → functional/cursor_fail_test.rb} +3 -29
  66. data/test/{cursor_message_test.rb → functional/cursor_message_test.rb} +1 -1
  67. data/test/{cursor_test.rb → functional/cursor_test.rb} +5 -1
  68. data/test/{db_api_test.rb → functional/db_api_test.rb} +8 -9
  69. data/test/{db_connection_test.rb → functional/db_connection_test.rb} +3 -5
  70. data/test/{db_test.rb → functional/db_test.rb} +13 -13
  71. data/test/{grid_file_system_test.rb → functional/grid_file_system_test.rb} +2 -2
  72. data/test/{grid_io_test.rb → functional/grid_io_test.rb} +6 -6
  73. data/test/{grid_test.rb → functional/grid_test.rb} +4 -10
  74. data/test/{pool_test.rb → functional/pool_test.rb} +1 -1
  75. data/test/functional/safe_test.rb +84 -0
  76. data/test/{support_test.rb → functional/support_test.rb} +1 -1
  77. data/test/{threading_test.rb → functional/threading_test.rb} +9 -9
  78. data/test/{timeout_test.rb → functional/timeout_test.rb} +1 -1
  79. data/test/{uri_test.rb → functional/uri_test.rb} +1 -1
  80. data/test/functional/write_concern_test.rb +104 -0
  81. data/test/replica_set/basic_test.rb +139 -0
  82. data/test/replica_set/client_test.rb +255 -0
  83. data/test/replica_set/complex_connect_test.rb +62 -0
  84. data/test/replica_set/connection_test.rb +255 -0
  85. data/test/{replica_sets → replica_set}/count_test.rb +17 -14
  86. data/test/replica_set/cursor_test.rb +75 -0
  87. data/test/{replica_sets → replica_set}/insert_test.rb +19 -16
  88. data/test/replica_set/query_test.rb +64 -0
  89. data/test/replica_set/refresh_test.rb +153 -0
  90. data/test/{replica_sets → replica_set}/replication_ack_test.rb +21 -17
  91. data/test/sharded_cluster/basic_test.rb +31 -50
  92. data/test/support/hash_with_indifferent_access.rb +1 -1
  93. data/test/test_helper.rb +56 -9
  94. data/test/threading/threading_with_large_pool_test.rb +8 -8
  95. data/test/tools/mongo_config.rb +270 -58
  96. data/test/tools/mongo_config_test.rb +146 -0
  97. data/test/unit/client_test.rb +230 -0
  98. data/test/unit/collection_test.rb +45 -32
  99. data/test/unit/connection_test.rb +82 -74
  100. data/test/unit/cursor_test.rb +14 -6
  101. data/test/unit/db_test.rb +8 -8
  102. data/test/unit/grid_test.rb +11 -11
  103. data/test/unit/node_test.rb +24 -24
  104. data/test/unit/pool_manager_test.rb +13 -13
  105. data/test/unit/pool_test.rb +1 -1
  106. data/test/unit/read_test.rb +21 -26
  107. data/test/unit/safe_test.rb +52 -33
  108. data/test/unit/util_test.rb +55 -0
  109. data/test/unit/write_concern_test.rb +161 -0
  110. metadata +158 -171
  111. data/docs/CREDITS.md +0 -123
  112. data/docs/FAQ.md +0 -116
  113. data/docs/GRID_FS.md +0 -158
  114. data/docs/HISTORY.md +0 -392
  115. data/docs/READ_PREFERENCE.md +0 -99
  116. data/docs/RELEASES.md +0 -54
  117. data/docs/REPLICA_SETS.md +0 -113
  118. data/docs/TAILABLE_CURSORS.md +0 -51
  119. data/docs/TUTORIAL.md +0 -356
  120. data/docs/WRITE_CONCERN.md +0 -31
  121. data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
  122. data/lib/mongo/version.rb +0 -3
  123. data/test/bson/test_helper.rb +0 -30
  124. data/test/replica_sets/basic_test.rb +0 -119
  125. data/test/replica_sets/complex_connect_test.rb +0 -57
  126. data/test/replica_sets/complex_read_preference_test.rb +0 -237
  127. data/test/replica_sets/connect_test.rb +0 -156
  128. data/test/replica_sets/cursor_test.rb +0 -70
  129. data/test/replica_sets/pooled_insert_test.rb +0 -57
  130. data/test/replica_sets/query_test.rb +0 -50
  131. data/test/replica_sets/read_preference_test.rb +0 -234
  132. data/test/replica_sets/refresh_test.rb +0 -156
  133. data/test/replica_sets/refresh_with_threads_test.rb +0 -60
  134. data/test/replica_sets/rs_test_helper.rb +0 -39
  135. data/test/safe_test.rb +0 -68
  136. data/test/sharded_cluster/mongo_config_test.rb +0 -126
  137. data/test/sharded_cluster/sc_test_helper.rb +0 -39
  138. data/test/tools/repl_set_manager.rb +0 -418
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2011 10gen Inc.
4
+ # Copyright (C) 2008-2012 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
19
19
  module Mongo
20
20
 
21
21
  # Instantiates and manages connections to a MongoDB sharded cluster for high availability.
22
- class ShardedConnection < ReplSetConnection
22
+ class MongoShardedClient < MongoReplicaSetClient
23
23
 
24
24
  SHARDED_CLUSTER_OPTS = [:refresh_mode, :refresh_interval]
25
25
 
@@ -34,9 +34,9 @@ module Mongo
34
34
  #
35
35
  # @option opts [String] :name (nil) The name of the sharded cluster to connect to. You
36
36
  # can use this option to verify that you're connecting to the right sharded cluster.
37
- # @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
38
- # propagated to DB objects instantiated off of this Connection. This
39
- # default can be overridden upon instantiation of any DB by explicitly setting a :safe value
37
+ # @option opts [Hash] ::w (1), :j (false), :wtimeout (false), :fsync (false) Set the default write concern
38
+ # propagated to DB objects instantiated off of this MongoClient. This
39
+ # default can be overridden upon instantiation of any DB by explicitly setting a write concern values
40
40
  # on initialization.
41
41
  # @option opts [Logger] :logger (nil) Logger instance to receive driver operation log.
42
42
  # @option opts [Integer] :pool_size (1) The maximum number of socket connections allowed per
@@ -58,7 +58,7 @@ module Mongo
58
58
  # The purpose of seed nodes is to permit the driver to find at least one sharded cluster member even if a member is down.
59
59
  #
60
60
  # @example Connect to a sharded cluster and provide two seed nodes.
61
- # Mongo::ShardedConnection.new(['localhost:30000', 'localhost:30001'])
61
+ # MongoShardedClient.new(['localhost:30000', 'localhost:30001'])
62
62
  #
63
63
  # @raise [MongoArgumentError] This is raised for usage errors.
64
64
  #
@@ -71,14 +71,14 @@ module Mongo
71
71
  if nodes.empty? and ENV.has_key?('MONGODB_URI')
72
72
  parser = URIParser.new ENV['MONGODB_URI']
73
73
  if parser.direct?
74
- raise MongoArgumentError, "Mongo::ShardedConnection.new called with no arguments, but ENV['MONGODB_URI'] implies a direct connection."
74
+ raise MongoArgumentError, "Mongo::MongoShardedClient.new called with no arguments, but ENV['MONGODB_URI'] implies a direct connection."
75
75
  end
76
76
  opts = parser.connection_options.merge! opts
77
77
  nodes = [parser.nodes]
78
78
  end
79
79
 
80
80
  unless nodes.length > 0
81
- raise MongoArgumentError, "A ShardedConnection requires at least one seed node."
81
+ raise MongoArgumentError, "A MongoShardedClient requires at least one seed node."
82
82
  end
83
83
 
84
84
  @seeds = nodes.map do |host_port|
@@ -118,7 +118,7 @@ module Mongo
118
118
  end
119
119
 
120
120
  def inspect
121
- "<Mongo::ShardedConnection:0x#{self.object_id.to_s(16)} @seeds=#{@seeds.inspect} " +
121
+ "<Mongo::MongoShardedClient:0x#{self.object_id.to_s(16)} @seeds=#{@seeds.inspect} " +
122
122
  "@connected=#{@connected}>"
123
123
  end
124
124
 
@@ -18,7 +18,7 @@ module Mongo
18
18
  # @return [Integer] number of bytes sent
19
19
  def send_message(operation, message, opts={})
20
20
  if opts.is_a?(String)
21
- warn "Connection#send_message no longer takes a string log message. " +
21
+ warn "MongoClient#send_message no longer takes a string log message. " +
22
22
  "Logging is now handled within the Collection and Cursor classes."
23
23
  opts = {}
24
24
  end
@@ -56,12 +56,11 @@ module Mongo
56
56
  # @see DB#get_last_error for valid last error params.
57
57
  #
58
58
  # @return [Hash] The document returned by the call to getlasterror.
59
- def send_message_with_safe_check(operation, message, db_name, log_message=nil, last_error_params=false)
59
+ def send_message_with_gle(operation, message, db_name, log_message=nil, write_concern=false)
60
60
  docs = num_received = cursor_id = ''
61
61
  add_message_headers(message, operation)
62
62
 
63
- last_error_message = BSON::ByteBuffer.new
64
- build_last_error_message(last_error_message, db_name, last_error_params)
63
+ last_error_message = build_get_last_error_message(db_name, write_concern)
65
64
  last_error_id = add_message_headers(last_error_message, Mongo::Constants::OP_QUERY)
66
65
 
67
66
  packed_message = message.append!(last_error_message).to_s
@@ -181,7 +180,7 @@ module Mongo
181
180
 
182
181
  # unpacks to flags, cursor_id_a, cursor_id_b, starting_from, number_remaining
183
182
  flags, cursor_id_a, cursor_id_b, _, number_remaining = header_buf.unpack('VVVVV')
184
-
183
+
185
184
  check_response_flags(flags)
186
185
  cursor_id = (cursor_id_b << 32) + cursor_id_a
187
186
  [number_remaining, cursor_id]
@@ -209,23 +208,28 @@ module Mongo
209
208
  [docs, number_received]
210
209
  end
211
210
 
212
- # Constructs a getlasterror message. This method is used exclusively by
213
- # Connection#send_message_with_safe_check.
214
- #
215
- # Because it modifies message by reference, we don't need to return it.
216
- def build_last_error_message(message, db_name, opts)
211
+ def build_command_message(db_name, query, projection=nil, skip=0, limit=-1)
212
+ message = BSON::ByteBuffer.new
217
213
  message.put_int(0)
218
214
  BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.$cmd")
219
- message.put_int(0)
220
- message.put_int(-1)
221
- cmd = BSON::OrderedHash.new
222
- cmd[:getlasterror] = 1
223
- if opts.is_a?(Hash)
224
- opts.assert_valid_keys(:w, :wtimeout, :fsync, :j)
225
- cmd.merge!(opts)
215
+ message.put_int(skip)
216
+ message.put_int(limit)
217
+ message.put_binary(BSON::BSON_CODER.serialize(query, false).to_s)
218
+ message.put_binary(BSON::BSON_CODER.serialize(projection, false).to_s) if projection
219
+ message
220
+ end
221
+
222
+ # Constructs a getlasterror message. This method is used exclusively by
223
+ # MongoClient#send_message_with_gle.
224
+ def build_get_last_error_message(db_name, write_concern)
225
+ gle = BSON::OrderedHash.new
226
+ gle[:getlasterror] = 1
227
+ if write_concern.is_a?(Hash)
228
+ write_concern.assert_valid_keys(:w, :wtimeout, :fsync, :j)
229
+ gle.merge!(write_concern)
230
+ gle.delete(:w) if gle[:w] == 1
226
231
  end
227
- message.put_binary(BSON::BSON_CODER.serialize(cmd, false).to_s)
228
- nil
232
+ build_command_message(db_name, gle)
229
233
  end
230
234
 
231
235
  # Prepares a message for transmission to MongoDB by
@@ -282,6 +286,7 @@ module Mongo
282
286
  end
283
287
  total_bytes_sent
284
288
  rescue => ex
289
+ socket.close
285
290
  raise ConnectionFailure, "Operation failed with the following exception: #{ex}:#{ex.message}"
286
291
  end
287
292
  end
@@ -306,7 +311,7 @@ module Mongo
306
311
  def receive_data(length, socket)
307
312
  message = new_binary_string
308
313
  socket.read(length, message)
309
-
314
+
310
315
  raise ConnectionFailure, "connection closed" unless message && message.length > 0
311
316
  if message.length < length
312
317
  chunk = new_binary_string
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2011 10gen Inc.
4
+ # Copyright (C) 2008-2012 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2011 10gen Inc.
4
+ # Copyright (C) 2008-2012 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -29,17 +29,28 @@ module Mongo
29
29
  # Execute the block and log the operation described by name and payload.
30
30
  def instrument(name, payload = {})
31
31
  start_time = Time.now
32
- res = yield
33
- log_operation(name, payload, start_time)
32
+ res = Logging.instrumenter.instrument(name, payload) do
33
+ yield
34
+ end
35
+ duration = Time.now - start_time
36
+ log_operation(name, payload, duration)
34
37
  res
35
38
  end
36
39
 
40
+ def self.instrumenter
41
+ @instrumenter || Instrumenter
42
+ end
43
+
44
+ def self.instrumenter=(instrumenter)
45
+ @instrumenter = instrumenter
46
+ end
47
+
37
48
  protected
38
49
 
39
- def log_operation(name, payload, start_time)
50
+ def log_operation(name, payload, duration)
40
51
  @logger && @logger.debug do
41
52
  msg = "MONGODB "
42
- msg << "(#{((Time.now - start_time) * 1000).to_i}ms) "
53
+ msg << "(%.1fms) " % (duration * 1000)
43
54
  msg << "#{payload[:database]}['#{payload[:collection]}'].#{name}("
44
55
  msg << payload.values_at(:selector, :document, :documents, :fields ).compact.map(&:inspect).join(', ') + ")"
45
56
  msg << ".skip(#{payload[:skip]})" if payload[:skip]
@@ -49,5 +60,10 @@ module Mongo
49
60
  end
50
61
  end
51
62
 
63
+ module Instrumenter
64
+ def self.instrument(name, payload = {})
65
+ yield
66
+ end
67
+ end
52
68
  end
53
69
  end
@@ -1,10 +1,10 @@
1
1
  module Mongo
2
2
  class Node
3
3
 
4
- attr_accessor :host, :port, :address, :config, :connection, :socket, :last_state
4
+ attr_accessor :host, :port, :address, :config, :client, :socket, :last_state
5
5
 
6
- def initialize(connection, host_port)
7
- @connection = connection
6
+ def initialize(client, host_port)
7
+ @client = client
8
8
  @host, @port = split_node(host_port)
9
9
  @address = "#{@host}:#{@port}"
10
10
  @config = nil
@@ -29,11 +29,11 @@ module Mongo
29
29
  # return nil.
30
30
  def connect
31
31
  begin
32
- socket = @connection.socket_class.new(@host, @port,
33
- @connection.op_timeout, @connection.connect_timeout
32
+ socket = @client.socket_class.new(@host, @port,
33
+ @client.op_timeout, @client.connect_timeout
34
34
  )
35
35
  rescue OperationTimeout, ConnectionFailure, OperationFailure, SocketError, SystemCallError, IOError => ex
36
- @connection.log(:debug, "Failed connection to #{host_string} with #{ex.class}, #{ex.message}.")
36
+ @client.log(:debug, "Failed connection to #{host_string} with #{ex.class}, #{ex.message}.")
37
37
  socket.close if socket
38
38
  end
39
39
 
@@ -54,7 +54,7 @@ module Mongo
54
54
 
55
55
  def active?
56
56
  begin
57
- result = @connection['admin'].command({:ping => 1}, :socket => @socket)
57
+ result = @client['admin'].command({:ping => 1}, :socket => @socket)
58
58
  rescue OperationFailure, SocketError, SystemCallError, IOError
59
59
  return nil
60
60
  end
@@ -66,16 +66,16 @@ module Mongo
66
66
  # matches with the name provided.
67
67
  def set_config
68
68
  begin
69
- @config = @connection['admin'].command({:ismaster => 1}, :socket => @socket)
69
+ @config = @client['admin'].command({:ismaster => 1}, :socket => @socket)
70
70
 
71
71
  if @config['msg']
72
- @connection.log(:warn, "#{config['msg']}")
72
+ @client.log(:warn, "#{config['msg']}")
73
73
  end
74
74
 
75
75
  check_set_membership(config)
76
76
  check_set_name(config)
77
77
  rescue ConnectionFailure, OperationFailure, OperationTimeout, SocketError, SystemCallError, IOError => ex
78
- @connection.log(:warn, "Attempted connection to node #{host_string} raised " +
78
+ @client.log(:warn, "Attempted connection to node #{host_string} raised " +
79
79
  "#{ex.class}: #{ex.message}")
80
80
 
81
81
  # Socket may already be nil from issuing command
@@ -145,12 +145,12 @@ module Mongo
145
145
  end
146
146
 
147
147
  host = host_port[0]
148
- port = host_port[1].nil? ? Connection::DEFAULT_PORT : host_port[1].to_i
148
+ port = host_port[1].nil? ? MongoClient::DEFAULT_PORT : host_port[1].to_i
149
149
 
150
150
  [host, port]
151
151
  end
152
152
 
153
- # Ensure that this node is a healty member of a replica set.
153
+ # Ensure that this node is a healthy member of a replica set.
154
154
  def check_set_membership(config)
155
155
  if !config.has_key?('hosts')
156
156
  message = "Will not connect to #{host_string} because it's not a member " +
@@ -165,13 +165,13 @@ module Mongo
165
165
 
166
166
  # Ensure that this node is part of a replica set of the expected name.
167
167
  def check_set_name(config)
168
- if @connection.replica_set_name
168
+ if @client.replica_set_name
169
169
  if !config['setName']
170
- @connection.log(:warn, "Could not verify replica set name for member #{host_string} " +
170
+ @client.log(:warn, "Could not verify replica set name for member #{host_string} " +
171
171
  "because ismaster does not return name in this version of MongoDB")
172
- elsif @connection.replica_set_name != config['setName']
172
+ elsif @client.replica_set_name != config['setName']
173
173
  message = "Attempting to connect to replica set '#{config['setName']}' on member #{host_string} " +
174
- "but expected '#{@connection.replica_set_name}'"
174
+ "but expected '#{@client.replica_set_name}'"
175
175
  raise ReplicaSetConnectionError, message
176
176
  end
177
177
  end
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  # --
4
- # Copyright (C) 2008-2011 10gen Inc.
4
+ # Copyright (C) 2008-2012 10gen Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -21,12 +21,17 @@ module Mongo
21
21
  MAX_PING_TIME = 1_000_000
22
22
  PRUNE_INTERVAL = 10_000
23
23
 
24
- attr_accessor :host, :port, :address,
25
- :size, :timeout, :safe, :checked_out, :connection
24
+ attr_accessor :host,
25
+ :port,
26
+ :address,
27
+ :size,
28
+ :timeout,
29
+ :checked_out,
30
+ :client
26
31
 
27
32
  # Create a new pool of connections.
28
- def initialize(connection, host, port, opts={})
29
- @connection = connection
33
+ def initialize(client, host, port, opts={})
34
+ @client = client
30
35
 
31
36
  @host, @port = host, port
32
37
 
@@ -43,25 +48,28 @@ module Mongo
43
48
  # Mutex for synchronizing pool access
44
49
  @connection_mutex = Mutex.new
45
50
 
51
+ # Mutex for synchronizing pings
52
+ @ping_mutex = Mutex.new
53
+
46
54
  # Condition variable for signal and wait
47
55
  @queue = ConditionVariable.new
48
56
 
49
57
  # Operations to perform on a socket
50
58
  @socket_ops = Hash.new { |h, k| h[k] = [] }
51
59
 
52
- @sockets = []
53
- @pids = {}
54
- @checked_out = []
55
- @ping_time = nil
56
- @last_ping = nil
57
- @closed = false
60
+ @sockets = []
61
+ @pids = {}
62
+ @checked_out = []
63
+ @ping_time = nil
64
+ @last_ping = nil
65
+ @closed = false
58
66
  @threads_to_sockets = {}
59
67
  @checkout_counter = 0
60
68
  end
61
69
 
62
70
  # Close this pool.
63
71
  #
64
- # @option opts [Boolean] :soft (false) If true,
72
+ # @option opts [Boolean]:soft (false) If true,
65
73
  # close only those sockets that are not checked out.
66
74
  def close(opts={})
67
75
  @connection_mutex.synchronize do
@@ -85,6 +93,29 @@ module Mongo
85
93
  @closed
86
94
  end
87
95
 
96
+ def up?
97
+ !@closed
98
+ end
99
+
100
+ def matches_mode(mode)
101
+ if mode == :primary && @node.secondary? ||
102
+ mode == :secondary && @node.primary?
103
+ false
104
+ else
105
+ true
106
+ end
107
+ end
108
+
109
+ def matches_tag_set(tag_set)
110
+ tag_set.all? do |tag, value|
111
+ tags.has_key?(tag) && tags[tag] == value
112
+ end
113
+ end
114
+
115
+ def matches_tag_sets(tag_sets)
116
+ tag_sets.all? {|set| matches_tag_set(set)}
117
+ end
118
+
88
119
  def inspect
89
120
  "#<Mongo::Pool:0x#{self.object_id.to_s(16)} @host=#{@host} @port=#{port} " +
90
121
  "@ping_time=#{@ping_time} #{@checked_out.size}/#{@size} sockets available " +
@@ -102,15 +133,13 @@ module Mongo
102
133
  # Refresh ping time only if we haven't
103
134
  # checked within the last five minutes.
104
135
  def ping_time
105
- if !@last_ping
106
- @last_ping = Time.now
107
- @ping_time = refresh_ping_time
108
- elsif Time.now - @last_ping > 300
109
- @last_ping = Time.now
110
- @ping_time = refresh_ping_time
111
- else
112
- @ping_time
136
+ @ping_mutex.synchronize do
137
+ if !@last_ping || (Time.now - @last_ping) > 300
138
+ @ping_time = refresh_ping_time
139
+ @last_ping = Time.now
140
+ end
113
141
  end
142
+ @ping_time
114
143
  end
115
144
 
116
145
  # Return the time it takes on average
@@ -139,7 +168,7 @@ module Mongo
139
168
 
140
169
  def ping
141
170
  begin
142
- return self.connection['admin'].command({:ping => 1}, :socket => @node.socket, :timeout => 1)
171
+ return self.client['admin'].command({:ping => 1}, :socket => @node.socket, :timeout => MAX_PING_TIME)
143
172
  rescue ConnectionFailure, OperationFailure, SocketError, SystemCallError, IOError
144
173
  return false
145
174
  end
@@ -163,7 +192,7 @@ module Mongo
163
192
  # therefore, it runs within a mutex.
164
193
  def checkout_new_socket
165
194
  begin
166
- socket = @connection.socket_class.new(@host, @port, @connection.op_timeout)
195
+ socket = @client.socket_class.new(@host, @port, @client.op_timeout)
167
196
  socket.pool = self
168
197
  rescue => ex
169
198
  socket.close if socket
@@ -173,7 +202,7 @@ module Mongo
173
202
 
174
203
  # If any saved authentications exist, we want to apply those
175
204
  # when creating new sockets.
176
- @connection.apply_saved_authentication(:socket => socket)
205
+ @client.apply_saved_authentication(:socket => socket)
177
206
 
178
207
  @sockets << socket
179
208
  @pids[socket] = Process.pid
@@ -190,7 +219,7 @@ module Mongo
190
219
  @connection_mutex.synchronize do
191
220
  @sockets.each do |socket|
192
221
  @socket_ops[socket] << Proc.new do
193
- @connection.apply_saved_authentication(:socket => socket)
222
+ @client.apply_saved_authentication(:socket => socket)
194
223
  end
195
224
  end
196
225
  end
@@ -202,7 +231,7 @@ module Mongo
202
231
  @connection_mutex.synchronize do
203
232
  @sockets.each do |socket|
204
233
  @socket_ops[socket] << Proc.new do
205
- @connection.db(db).issue_logout(:socket => socket)
234
+ @client.db(db).issue_logout(:socket => socket)
206
235
  end
207
236
  end
208
237
  end
@@ -246,7 +275,7 @@ module Mongo
246
275
  # pool size has not been exceeded. Otherwise, wait for the next
247
276
  # available socket.
248
277
  def checkout
249
- @connection.connect if !@connection.connected?
278
+ @client.connect if !@client.connected?
250
279
  start_time = Time.now
251
280
  loop do
252
281
  if (Time.now - start_time) > @timeout
@@ -297,7 +326,7 @@ module Mongo
297
326
 
298
327
  socket = checkout_new_socket
299
328
  end
300
-
329
+
301
330
  return socket
302
331
  else
303
332
  # Otherwise, wait