mongo 1.8.6 → 1.12.5

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.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/LICENSE +1 -1
  4. data/README.md +114 -282
  5. data/Rakefile +18 -4
  6. data/VERSION +1 -1
  7. data/bin/mongo_console +27 -5
  8. data/lib/mongo/bulk_write_collection_view.rb +387 -0
  9. data/lib/mongo/collection.rb +283 -222
  10. data/lib/mongo/collection_writer.rb +364 -0
  11. data/lib/mongo/{util → connection}/node.rb +58 -6
  12. data/lib/mongo/{util → connection}/pool.rb +61 -37
  13. data/lib/mongo/{util → connection}/pool_manager.rb +72 -22
  14. data/lib/mongo/{util → connection}/sharding_pool_manager.rb +13 -0
  15. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  16. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  17. data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
  18. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection.rb +19 -0
  21. data/lib/mongo/cursor.rb +183 -57
  22. data/lib/mongo/db.rb +302 -138
  23. data/lib/mongo/exception.rb +145 -0
  24. data/lib/mongo/functional/authentication.rb +455 -0
  25. data/lib/mongo/{util → functional}/logging.rb +23 -7
  26. data/lib/mongo/functional/read_preference.rb +183 -0
  27. data/lib/mongo/functional/scram.rb +556 -0
  28. data/lib/mongo/functional/uri_parser.rb +409 -0
  29. data/lib/mongo/{util → functional}/write_concern.rb +21 -9
  30. data/lib/mongo/functional.rb +20 -0
  31. data/lib/mongo/gridfs/grid.rb +19 -8
  32. data/lib/mongo/gridfs/grid_ext.rb +14 -0
  33. data/lib/mongo/gridfs/grid_file_system.rb +17 -4
  34. data/lib/mongo/gridfs/grid_io.rb +21 -9
  35. data/lib/mongo/gridfs.rb +18 -0
  36. data/lib/mongo/legacy.rb +76 -7
  37. data/lib/mongo/mongo_client.rb +246 -206
  38. data/lib/mongo/mongo_replica_set_client.rb +65 -15
  39. data/lib/mongo/mongo_sharded_client.rb +18 -3
  40. data/lib/mongo/networking.rb +47 -18
  41. data/lib/mongo/{util → utils}/conversions.rb +18 -3
  42. data/lib/mongo/{util → utils}/core_ext.rb +15 -32
  43. data/lib/mongo/{util → utils}/server_version.rb +15 -0
  44. data/lib/mongo/{util → utils}/support.rb +22 -55
  45. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  46. data/lib/mongo/utils.rb +19 -0
  47. data/lib/mongo.rb +44 -26
  48. data/mongo.gemspec +2 -2
  49. data/test/functional/authentication_test.rb +31 -10
  50. data/test/functional/bulk_api_stress_test.rb +133 -0
  51. data/test/functional/bulk_write_collection_view_test.rb +1198 -0
  52. data/test/functional/client_test.rb +627 -0
  53. data/test/functional/collection_test.rb +1419 -654
  54. data/test/functional/collection_writer_test.rb +83 -0
  55. data/test/functional/conversions_test.rb +46 -2
  56. data/test/functional/cursor_fail_test.rb +17 -9
  57. data/test/functional/cursor_message_test.rb +28 -15
  58. data/test/functional/cursor_test.rb +300 -165
  59. data/test/functional/db_api_test.rb +294 -264
  60. data/test/functional/db_connection_test.rb +15 -3
  61. data/test/functional/db_test.rb +165 -99
  62. data/test/functional/grid_file_system_test.rb +124 -112
  63. data/test/functional/grid_io_test.rb +17 -3
  64. data/test/functional/grid_test.rb +16 -2
  65. data/test/functional/pool_test.rb +99 -10
  66. data/test/functional/safe_test.rb +18 -4
  67. data/test/functional/ssl_test.rb +29 -0
  68. data/test/functional/support_test.rb +14 -0
  69. data/test/functional/timeout_test.rb +27 -27
  70. data/test/functional/uri_test.rb +268 -22
  71. data/test/functional/write_concern_test.rb +19 -5
  72. data/test/helpers/general.rb +50 -0
  73. data/test/helpers/test_unit.rb +476 -0
  74. data/test/replica_set/authentication_test.rb +28 -11
  75. data/test/replica_set/basic_test.rb +79 -23
  76. data/test/replica_set/client_test.rb +253 -124
  77. data/test/replica_set/connection_test.rb +59 -37
  78. data/test/replica_set/count_test.rb +18 -2
  79. data/test/replica_set/cursor_test.rb +30 -8
  80. data/test/replica_set/insert_test.rb +109 -2
  81. data/test/replica_set/max_values_test.rb +85 -10
  82. data/test/replica_set/pinning_test.rb +66 -2
  83. data/test/replica_set/query_test.rb +17 -3
  84. data/test/replica_set/read_preference_test.rb +115 -96
  85. data/test/replica_set/refresh_test.rb +59 -9
  86. data/test/replica_set/replication_ack_test.rb +32 -11
  87. data/test/replica_set/ssl_test.rb +32 -0
  88. data/test/sharded_cluster/basic_test.rb +73 -25
  89. data/test/shared/authentication/basic_auth_shared.rb +260 -0
  90. data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
  91. data/test/shared/authentication/gssapi_shared.rb +176 -0
  92. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  93. data/test/shared/authentication/scram_shared.rb +92 -0
  94. data/test/shared/ssl_shared.rb +235 -0
  95. data/test/test_helper.rb +47 -196
  96. data/test/threading/basic_test.rb +42 -2
  97. data/test/tools/mongo_config.rb +175 -35
  98. data/test/tools/mongo_config_test.rb +15 -1
  99. data/test/unit/client_test.rb +186 -57
  100. data/test/unit/collection_test.rb +44 -54
  101. data/test/unit/connection_test.rb +160 -71
  102. data/test/unit/cursor_test.rb +37 -3
  103. data/test/unit/db_test.rb +38 -14
  104. data/test/unit/grid_test.rb +15 -1
  105. data/test/unit/mongo_sharded_client_test.rb +30 -14
  106. data/test/unit/node_test.rb +16 -1
  107. data/test/unit/pool_manager_test.rb +21 -4
  108. data/test/unit/read_pref_test.rb +386 -1
  109. data/test/unit/read_test.rb +27 -13
  110. data/test/unit/safe_test.rb +22 -8
  111. data/test/unit/sharding_pool_manager_test.rb +25 -4
  112. data/test/unit/write_concern_test.rb +23 -9
  113. data.tar.gz.sig +0 -0
  114. metadata +80 -54
  115. metadata.gz.sig +0 -0
  116. data/lib/mongo/exceptions.rb +0 -65
  117. data/lib/mongo/util/read_preference.rb +0 -112
  118. data/lib/mongo/util/socket_util.rb +0 -20
  119. data/lib/mongo/util/ssl_socket.rb +0 -51
  120. data/lib/mongo/util/tcp_socket.rb +0 -62
  121. data/lib/mongo/util/thread_local_variable_manager.rb +0 -11
  122. data/lib/mongo/util/unix_socket.rb +0 -23
  123. data/lib/mongo/util/uri_parser.rb +0 -337
  124. data/test/functional/connection_test.rb +0 -449
  125. data/test/functional/threading_test.rb +0 -95
  126. data/test/replica_set/complex_connect_test.rb +0 -64
  127. data/test/shared/authentication.rb +0 -66
  128. data/test/unit/pool_test.rb +0 -9
  129. data/test/unit/util_test.rb +0 -55
@@ -1,6 +1,16 @@
1
- require 'set'
2
- require 'socket'
3
- require 'thread'
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
4
14
 
5
15
  module Mongo
6
16
 
@@ -9,6 +19,22 @@ module Mongo
9
19
  include Mongo::Logging
10
20
  include Mongo::Networking
11
21
  include Mongo::WriteConcern
22
+ include Mongo::Authentication
23
+
24
+ # Wire version
25
+ RELEASE_2_4_AND_BEFORE = 0 # Everything before we started tracking.
26
+ AGG_RETURNS_CURSORS = 1 # The aggregation command may now be requested to return cursors.
27
+ BATCH_COMMANDS = 2 # insert, update, and delete batch command
28
+ MONGODB_3_0 = 3 # listCollections and listIndexes commands, SCRAM-SHA-1 auth mechanism
29
+ MAX_WIRE_VERSION = MONGODB_3_0 # supported by this client implementation
30
+ MIN_WIRE_VERSION = RELEASE_2_4_AND_BEFORE # supported by this client implementation
31
+
32
+ # Server command headroom
33
+ COMMAND_HEADROOM = 16_384
34
+ APPEND_HEADROOM = COMMAND_HEADROOM / 2
35
+ SERIALIZE_HEADROOM = APPEND_HEADROOM / 2
36
+
37
+ DEFAULT_MAX_WRITE_BATCH_SIZE = 1000
12
38
 
13
39
  Mutex = ::Mutex
14
40
  ConditionVariable = ::ConditionVariable
@@ -16,8 +42,10 @@ module Mongo
16
42
  DEFAULT_HOST = 'localhost'
17
43
  DEFAULT_PORT = 27017
18
44
  DEFAULT_DB_NAME = 'test'
19
- GENERIC_OPTS = [:ssl, :auths, :logger, :connect]
45
+ DEFAULT_OP_TIMEOUT = 20
46
+ GENERIC_OPTS = [:auths, :logger, :connect, :db_name]
20
47
  TIMEOUT_OPTS = [:timeout, :op_timeout, :connect_timeout]
48
+ SSL_OPTS = [:ssl, :ssl_key, :ssl_cert, :ssl_verify, :ssl_ca_cert, :ssl_key_pass_phrase]
21
49
  POOL_OPTS = [:pool_size, :pool_timeout]
22
50
  READ_PREFERENCE_OPTS = [:read, :tag_sets, :secondary_acceptable_latency_ms]
23
51
  WRITE_CONCERN_OPTS = [:w, :j, :fsync, :wtimeout]
@@ -36,10 +64,14 @@ module Mongo
36
64
  :pool_timeout,
37
65
  :primary_pool,
38
66
  :socket_class,
67
+ :socket_opts,
39
68
  :op_timeout,
40
69
  :tag_sets,
41
70
  :acceptable_latency,
42
- :read
71
+ :read,
72
+ :max_wire_version,
73
+ :min_wire_version,
74
+ :max_write_batch_size
43
75
 
44
76
  # Create a connection to single MongoDB instance.
45
77
  #
@@ -55,33 +87,50 @@ module Mongo
55
87
  # MongoClient#arbiters. This is useful if your application needs to connect manually to nodes other
56
88
  # than the primary.
57
89
  #
58
- # @param [String] host
59
- # @param [Integer] port specify a port number here if only one host is being specified.
60
- #
61
- # @option opts [String, Integer, Symbol] :w (1) Set default number of nodes to which a write
62
- # should be acknowledged
63
- # @option opts [Boolean] :j (false) Set journal acknowledgement
64
- # @option opts [Integer] :wtimeout (nil) Set replica set acknowledgement timeout
65
- # @option opts [Boolean] :fsync (false) Set fsync acknowledgement.
66
- #
67
- # Notes about write concern options:
68
- # Write concern options are propagated to objects instantiated from this MongoClient.
69
- # These defaults can be overridden upon instantiation of any object by explicitly setting an options hash
70
- # on initialization.
71
- # @option opts [Boolean] :slave_ok (false) Must be set to +true+ when connecting
72
- # to a single, slave node.
73
- # @option opts [Logger, #debug] :logger (nil) A Logger instance for debugging driver ops. Note that
74
- # logging negatively impacts performance; therefore, it should not be used for high-performance apps.
75
- # @option opts [Integer] :pool_size (1) The maximum number of socket self.connections allowed per
76
- # connection pool. Note: this setting is relevant only for multi-threaded applications.
77
- # @option opts [Float] :timeout (5.0) When all of the self.connections a pool are checked out,
78
- # this is the number of seconds to wait for a new connection to be released before throwing an exception.
79
- # Note: this setting is relevant only for multi-threaded applications (which in Ruby are rare).
80
- # @option opts [Float] :op_timeout (nil) The number of seconds to wait for a read operation to time out.
81
- # Disabled by default.
82
- # @option opts [Float] :connect_timeout (nil) The number of seconds to wait before timing out a
83
- # connection attempt.
84
- # @option opts [Boolean] :ssl (false) If true, create the connection to the server using SSL.
90
+ # @overload initialize(host, port, opts={})
91
+ # @param [String] host hostname for the target MongoDB server.
92
+ # @param [Integer] port specify a port number here if only one host is being specified.
93
+ # @param [Hash] opts hash of optional settings and configuration values.
94
+ #
95
+ # @option opts [String, Integer, Symbol] :w (1) Set default number of nodes to which a write
96
+ # should be acknowledged.
97
+ # @option opts [Integer] :wtimeout (nil) Set replica set acknowledgement timeout.
98
+ # @option opts [Boolean] :j (false) If true, block until write operations have been committed
99
+ # to the journal. Cannot be used in combination with 'fsync'. Prior to MongoDB 2.6 this option was
100
+ # ignored if the server was running without journaling. Starting with MongoDB 2.6, write operations will
101
+ # fail with an exception if this option is used when the server is running without journaling.
102
+ # @option opts [Boolean] :fsync (false) If true, and the server is running without journaling, blocks until
103
+ # the server has synced all data files to disk. If the server is running with journaling, this acts the same as
104
+ # the 'j' option, blocking until write operations have been committed to the journal.
105
+ # Cannot be used in combination with 'j'.
106
+ #
107
+ # Notes about Write-Concern Options:
108
+ # Write concern options are propagated to objects instantiated from this MongoClient.
109
+ # These defaults can be overridden upon instantiation of any object by explicitly setting an options hash
110
+ # on initialization.
111
+ #
112
+ # @option opts [Boolean] :ssl (false) If true, create the connection to the server using SSL.
113
+ # @option opts [String] :ssl_cert (nil) The certificate file used to identify the local connection against MongoDB.
114
+ # @option opts [String] :ssl_key (nil) The private keyfile used to identify the local connection against MongoDB.
115
+ # Note that even if the key is stored in the same file as the certificate, both need to be explicitly specified.
116
+ # @option opts [String] :ssl_key_pass_phrase (nil) A passphrase for the private key.
117
+ # @option opts [Boolean] :ssl_verify (nil) Specifies whether or not peer certification validation should occur.
118
+ # @option opts [String] :ssl_ca_cert (nil) The ca_certs file contains a set of concatenated "certification authority"
119
+ # certificates, which are used to validate certificates passed from the other end of the connection.
120
+ # Required for :ssl_verify.
121
+ # @option opts [Boolean] :slave_ok (false) Must be set to +true+ when connecting
122
+ # to a single, slave node.
123
+ # @option opts [Logger, #debug] :logger (nil) A Logger instance for debugging driver ops. Note that
124
+ # logging negatively impacts performance; therefore, it should not be used for high-performance apps.
125
+ # @option opts [Integer] :pool_size (1) The maximum number of socket self.connections allowed per
126
+ # connection pool. Note: this setting is relevant only for multi-threaded applications.
127
+ # @option opts [Float] :pool_timeout (5.0) When all of the self.connections a pool are checked out,
128
+ # this is the number of seconds to wait for a new connection to be released before throwing an exception.
129
+ # Note: this setting is relevant only for multi-threaded applications.
130
+ # @option opts [Float] :op_timeout (DEFAULT_OP_TIMEOUT) The number of seconds to wait for a read operation to time out.
131
+ # Set to DEFAULT_OP_TIMEOUT (20) by default. A value of nil may be specified explicitly.
132
+ # @option opts [Float] :connect_timeout (nil) The number of seconds to wait before timing out a
133
+ # connection attempt.
85
134
  #
86
135
  # @example localhost, 27017 (or <code>ENV["MONGODB_URI"]</code> if available)
87
136
  # MongoClient.new
@@ -90,7 +139,7 @@ module Mongo
90
139
  # MongoClient.new("localhost")
91
140
  #
92
141
  # @example localhost, 3000, max 5 self.connections, with max 5 seconds of wait time.
93
- # MongoClient.new("localhost", 3000, :pool_size => 5, :timeout => 5)
142
+ # MongoClient.new("localhost", 3000, :pool_size => 5, :pool_timeout => 5)
94
143
  #
95
144
  # @example localhost, 3000, where this node may be a slave
96
145
  # MongoClient.new("localhost", 3000, :slave_ok => true)
@@ -104,10 +153,8 @@ module Mongo
104
153
  # driver fails to connect to a replica set with that name.
105
154
  #
106
155
  # @raise [MongoArgumentError] If called with no arguments and <code>ENV["MONGODB_URI"]</code> implies a replica set.
107
- #
108
- # @core self.connections
109
156
  def initialize(*args)
110
- opts = args.last.is_a?(Hash) ? args.pop : {}
157
+ opts = args.last.is_a?(Hash) ? args.pop : {}
111
158
  @host, @port = parse_init(args[0], args[1], opts)
112
159
 
113
160
  # Lock for request ids.
@@ -119,9 +166,15 @@ module Mongo
119
166
  @mongos = false
120
167
 
121
168
  # Not set for direct connection
122
- @tag_sets = []
169
+ @tag_sets = []
123
170
  @acceptable_latency = 15
124
171
 
172
+ @max_bson_size = nil
173
+ @max_message_size = nil
174
+ @max_wire_version = nil
175
+ @min_wire_version = nil
176
+ @max_write_batch_size = nil
177
+
125
178
  check_opts(opts)
126
179
  setup(opts.dup)
127
180
  end
@@ -153,8 +206,7 @@ module Mongo
153
206
  #
154
207
  # @deprecated
155
208
  def self.multi(nodes, opts={})
156
- warn "MongoClient.multi is now deprecated and will be removed in v2.0. Please use MongoReplicaSetClient.new instead."
157
-
209
+ warn 'MongoClient.multi is now deprecated and will be removed in v2.0. Please use MongoReplicaSetClient.new instead.'
158
210
  MongoReplicaSetClient.new(nodes, opts)
159
211
  end
160
212
 
@@ -166,28 +218,14 @@ module Mongo
166
218
  # @param uri [String]
167
219
  # A string of the format mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]
168
220
  #
169
- # @param opts Any of the options available for MongoClient.new
221
+ # @param [Hash] extra_opts Any of the options available for MongoClient.new
170
222
  #
171
223
  # @return [Mongo::MongoClient, Mongo::MongoReplicaSetClient]
172
224
  def self.from_uri(uri = ENV['MONGODB_URI'], extra_opts={})
173
- parser = URIParser.new uri
225
+ parser = URIParser.new(uri)
174
226
  parser.connection(extra_opts)
175
227
  end
176
228
 
177
- def parse_init(host, port, opts)
178
- if host.nil? && port.nil? && ENV.has_key?('MONGODB_URI')
179
- parser = URIParser.new(ENV['MONGODB_URI'])
180
- if parser.replicaset?
181
- raise MongoArgumentError,
182
- "ENV['MONGODB_URI'] implies a replica set."
183
- end
184
- opts.merge! parser.connection_options
185
- [parser.host, parser.port]
186
- else
187
- [host || DEFAULT_HOST, port || DEFAULT_PORT]
188
- end
189
- end
190
-
191
229
  # The host name used for this connection.
192
230
  #
193
231
  # @return [String]
@@ -206,8 +244,7 @@ module Mongo
206
244
  [@host, @port]
207
245
  end
208
246
 
209
- # Fsync, then lock the mongod process against writes. Use this to get
210
- # the datafiles in a state safe for snapshotting, backing up, etc.
247
+ # Flush all pending writes to datafiles.
211
248
  #
212
249
  # @return [BSON::OrderedHash] the command response
213
250
  def lock!
@@ -231,83 +268,15 @@ module Mongo
231
268
  self['admin']['$cmd.sys.unlock'].find_one
232
269
  end
233
270
 
234
- # Apply each of the saved database authentications.
235
- #
236
- # @return [Boolean] returns true if authentications exist and succeeds, false
237
- # if none exists.
238
- #
239
- # @raise [AuthenticationError] raises an exception if any one
240
- # authentication fails.
241
- def apply_saved_authentication(opts={})
242
- return false if @auths.empty?
243
- @auths.each do |auth|
244
- self[auth[:db_name]].issue_authentication(auth[:username], auth[:password], false,
245
- :socket => opts[:socket])
246
- end
247
- true
248
- end
249
-
250
- # Save an authentication to this connection. When connecting,
251
- # the connection will attempt to re-authenticate on every db
252
- # specified in the list of auths. This method is called automatically
253
- # by DB#authenticate.
254
- #
255
- # Note: this method will not actually issue an authentication command. To do that,
256
- # either run MongoClient#apply_saved_authentication or DB#authenticate.
257
- #
258
- # @param [String] db_name
259
- # @param [String] username
260
- # @param [String] password
261
- #
262
- # @return [Hash] a hash representing the authentication just added.
263
- def add_auth(db_name, username, password)
264
- if @auths.any? {|a| a[:db_name] == db_name}
265
- raise MongoArgumentError, "Cannot apply multiple authentications to database '#{db_name}'"
266
- end
267
-
268
- auth = {
269
- :db_name => db_name,
270
- :username => username,
271
- :password => password
272
- }
273
- @auths << auth
274
- auth
275
- end
276
-
277
- # Remove a saved authentication for this connection.
278
- #
279
- # @param [String] db_name
280
- #
281
- # @return [Boolean]
282
- def remove_auth(db_name)
283
- return unless @auths
284
- @auths.reject! { |a| a[:db_name] == db_name } ? true : false
285
- end
286
-
287
- # Remove all authentication information stored in this connection.
288
- #
289
- # @return [true] this operation return true because it always succeeds.
290
- def clear_auths
291
- @auths = []
292
- true
293
- end
294
-
295
- def authenticate_pools
296
- @primary_pool.authenticate_existing
297
- end
298
-
299
- def logout_pools(db)
300
- @primary_pool.logout_existing(db)
301
- end
302
-
303
271
  # Return a hash with all database names
304
272
  # and their respective sizes on disk.
305
273
  #
306
274
  # @return [Hash]
307
275
  def database_info
308
276
  doc = self['admin'].command({:listDatabases => 1})
309
- doc['databases'].each_with_object({}) do |db, info|
277
+ doc['databases'].inject({}) do |info, db|
310
278
  info[db['name']] = db['sizeOnDisk'].to_i
279
+ info
311
280
  end
312
281
  end
313
282
 
@@ -321,80 +290,63 @@ module Mongo
321
290
  # Return a database with the given name.
322
291
  # See DB#new for valid options hash parameters.
323
292
  #
324
- # @param [String] db_name a valid database name.
325
- # @param [Hash] opts options to be passed to the DB constructor.
326
- #
327
- # @return [Mongo::DB]
293
+ # @param name [String] The name of the database.
294
+ # @param opts [Hash] A hash of options to be passed to the DB constructor.
328
295
  #
329
- # @core databases db-instance_method
330
- def db(db_name=nil, opts={})
331
- if !db_name && uri = ENV['MONGODB_URI']
332
- db_name = uri[%r{/([^/\?]+)(\?|$)}, 1]
333
- end
334
-
335
- db_name ||= DEFAULT_DB_NAME
336
-
337
- DB.new(db_name, self, opts)
296
+ # @return [DB] The DB instance.
297
+ def db(name = nil, opts = {})
298
+ DB.new(name || @db_name || DEFAULT_DB_NAME, self, opts)
338
299
  end
339
300
 
340
- # Shortcut for returning a database. Use DB#db to accept options.
301
+ # Shortcut for returning a database. Use MongoClient#db to accept options.
341
302
  #
342
- # @param [String] db_name a valid database name.
303
+ # @param name [String] The name of the database.
343
304
  #
344
- # @return [Mongo::DB]
345
- #
346
- # @core databases []-instance_method
347
- def [](db_name)
348
- DB.new(db_name, self)
305
+ # @return [DB] The DB instance.
306
+ def [](name)
307
+ DB.new(name, self)
349
308
  end
350
309
 
351
- def refresh
352
- end
310
+ def refresh; end
353
311
 
354
312
  def pinned_pool
355
313
  @primary_pool
356
314
  end
357
315
 
358
- def pin_pool(pool, read_prefs)
359
- end
316
+ def pin_pool(pool, read_prefs); end
360
317
 
361
- def unpin_pool
362
- end
318
+ def unpin_pool; end
363
319
 
364
320
  # Drop a database.
365
321
  #
366
- # @param [String] name name of an existing database.
367
- def drop_database(name)
368
- self[name].command(:dropDatabase => 1)
322
+ # @param database [String] name of an existing database.
323
+ def drop_database(database)
324
+ self[database].command(:dropDatabase => 1)
369
325
  end
370
326
 
371
327
  # Copy the database +from+ to +to+ on localhost. The +from+ database is
372
328
  # assumed to be on localhost, but an alternate host can be specified.
373
329
  #
374
- # @param [String] from name of the database to copy from.
375
- # @param [String] to name of the database to copy to.
376
- # @param [String] from_host host of the 'from' database.
377
- # @param [String] username username for authentication against from_db (>=1.3.x).
378
- # @param [String] password password for authentication against from_db (>=1.3.x).
379
- def copy_database(from, to, from_host=DEFAULT_HOST, username=nil, password=nil)
380
- oh = BSON::OrderedHash.new
381
- oh[:copydb] = 1
382
- oh[:fromhost] = from_host
383
- oh[:fromdb] = from
384
- oh[:todb] = to
385
- if username || password
386
- unless username && password
387
- raise MongoArgumentError, "Both username and password must be supplied for authentication."
388
- end
389
- nonce_cmd = BSON::OrderedHash.new
390
- nonce_cmd[:copydbgetnonce] = 1
391
- nonce_cmd[:fromhost] = from_host
392
- result = self["admin"].command(nonce_cmd)
393
- oh[:nonce] = result["nonce"]
394
- oh[:username] = username
395
- oh[:key] = Mongo::Support.auth_key(username, password, oh[:nonce])
330
+ # @param from [String] name of the database to copy from.
331
+ # @param to [String] name of the database to copy to.
332
+ # @param from_host [String] host of the 'from' database.
333
+ # @param username [String] username (applies to 'from' db)
334
+ # @param password [String] password (applies to 'from' db)
335
+ #
336
+ # @note This command only supports the MONGODB-CR authentication mechanism.
337
+ def copy_database(
338
+ from,
339
+ to,
340
+ from_host = DEFAULT_HOST,
341
+ username = nil,
342
+ password = nil,
343
+ mechanism = 'SCRAM-SHA-1'
344
+ )
345
+ if wire_version_feature?(MONGODB_3_0) && mechanism == 'SCRAM-SHA-1'
346
+ copy_db_scram(username, password, from_host, from, to)
347
+ else
348
+ copy_db_mongodb_cr(username, password, from_host, from, to)
396
349
  end
397
- self["admin"].command(oh)
398
350
  end
399
351
 
400
352
  # Checks if a server is alive. This command will return immediately
@@ -402,14 +354,14 @@ module Mongo
402
354
  #
403
355
  # @return [Hash]
404
356
  def ping
405
- self["admin"].command({:ping => 1})
357
+ self['admin'].command({:ping => 1})
406
358
  end
407
359
 
408
360
  # Get the build information for the current connection.
409
361
  #
410
362
  # @return [Hash]
411
363
  def server_info
412
- self["admin"].command({:buildinfo => 1})
364
+ self['admin'].command({:buildinfo => 1})
413
365
  end
414
366
 
415
367
  # Get the build version of the current server.
@@ -417,7 +369,7 @@ module Mongo
417
369
  # @return [Mongo::ServerVersion]
418
370
  # object allowing easy comparability of version.
419
371
  def server_version
420
- ServerVersion.new(server_info["version"])
372
+ ServerVersion.new(server_info['version'])
421
373
  end
422
374
 
423
375
  # Is it okay to connect to a slave?
@@ -440,9 +392,7 @@ module Mongo
440
392
  # @raise [ConnectionFailure] if unable to connect to any host or port.
441
393
  def connect
442
394
  close
443
-
444
395
  config = check_is_master(host_port)
445
-
446
396
  if config
447
397
  if config['ismaster'] == 1 || config['ismaster'] == true
448
398
  @read_primary = true
@@ -454,14 +404,21 @@ module Mongo
454
404
  @mongos = true
455
405
  end
456
406
 
457
- @max_bson_size = config['maxBsonObjectSize']
407
+ @max_bson_size = config['maxBsonObjectSize']
458
408
  @max_message_size = config['maxMessageSizeBytes']
409
+ @max_wire_version = config['maxWireVersion']
410
+ @min_wire_version = config['minWireVersion']
411
+ @max_write_batch_size = config['maxWriteBatchSize']
412
+ check_wire_version_in_range
459
413
  set_primary(host_port)
460
414
  end
461
415
 
462
- if !connected?
463
- raise ConnectionFailure, "Failed to connect to a master node at #{host_port.join(":")}"
416
+ unless connected?
417
+ raise ConnectionFailure,
418
+ "Failed to connect to a master node at #{host_port.join(":")}"
464
419
  end
420
+
421
+ true
465
422
  end
466
423
  alias :reconnect :connect
467
424
 
@@ -484,7 +441,7 @@ module Mongo
484
441
  ping
485
442
  true
486
443
 
487
- rescue ConnectionFailure
444
+ rescue ConnectionFailure, OperationTimeout
488
445
  false
489
446
  end
490
447
 
@@ -508,7 +465,7 @@ module Mongo
508
465
  def close
509
466
  @primary_pool.close if @primary_pool
510
467
  @primary_pool = nil
511
- @primary = nil
468
+ @primary = nil
512
469
  end
513
470
 
514
471
  # Returns the maximum BSON object size as returned by the core server.
@@ -523,6 +480,30 @@ module Mongo
523
480
  @max_message_size || max_bson_size * MESSAGE_SIZE_FACTOR
524
481
  end
525
482
 
483
+ def max_wire_version
484
+ @max_wire_version || 0
485
+ end
486
+
487
+ def min_wire_version
488
+ @min_wire_version || 0
489
+ end
490
+
491
+ def max_write_batch_size
492
+ @max_write_batch_size || DEFAULT_MAX_WRITE_BATCH_SIZE
493
+ end
494
+
495
+ def wire_version_feature?(feature)
496
+ min_wire_version <= feature && feature <= max_wire_version
497
+ end
498
+
499
+ def primary_wire_version_feature?(feature)
500
+ min_wire_version <= feature && feature <= max_wire_version
501
+ end
502
+
503
+ def use_write_command?(write_concern)
504
+ write_concern[:w] != 0 && primary_wire_version_feature?(Mongo::MongoClient::BATCH_COMMANDS)
505
+ end
506
+
526
507
  # Checkout a socket for reading (i.e., a secondary node).
527
508
  # Note: this is overridden in MongoReplicaSetClient.
528
509
  def checkout_reader(read_preference)
@@ -555,13 +536,13 @@ module Mongo
555
536
  begin
556
537
  host, port = *node
557
538
  config = nil
558
- socket = @socket_class.new(host, port, @op_timeout, @connect_timeout)
539
+ socket = @socket_class.new(host, port, @op_timeout, @connect_timeout, @socket_opts)
559
540
  if @connect_timeout
560
541
  Timeout::timeout(@connect_timeout, OperationTimeout) do
561
- config = self['admin'].command({:ismaster => 1}, :socket => socket)
542
+ config = self['admin'].command({:isMaster => 1}, :socket => socket)
562
543
  end
563
544
  else
564
- config = self['admin'].command({:ismaster => 1}, :socket => socket)
545
+ config = self['admin'].command({:isMaster => 1}, :socket => socket)
565
546
  end
566
547
  rescue OperationFailure, SocketError, SystemCallError, IOError
567
548
  close
@@ -579,7 +560,8 @@ module Mongo
579
560
  POOL_OPTS +
580
561
  READ_PREFERENCE_OPTS +
581
562
  WRITE_CONCERN_OPTS +
582
- TIMEOUT_OPTS
563
+ TIMEOUT_OPTS +
564
+ SSL_OPTS
583
565
  end
584
566
 
585
567
  def check_opts(opts)
@@ -593,11 +575,40 @@ module Mongo
593
575
  # Parse option hash
594
576
  def setup(opts)
595
577
  @slave_ok = opts.delete(:slave_ok)
578
+ @ssl = opts.delete(:ssl)
579
+ @unix = @host ? @host.end_with?('.sock') : false
580
+
581
+ # if ssl options are present, but ssl is nil/false raise for misconfig
582
+ ssl_opts = opts.keys.select { |k| k.to_s.start_with?('ssl') }
583
+ if ssl_opts.size > 0 && !@ssl
584
+ raise MongoArgumentError, "SSL has not been enabled (:ssl=false) " +
585
+ "but the following SSL related options were " +
586
+ "specified: #{ssl_opts.join(', ')}"
587
+ end
596
588
 
597
- @ssl = opts.delete(:ssl)
598
- @unix = @host ? @host.end_with?('.sock') : false
599
-
589
+ @socket_opts = {}
600
590
  if @ssl
591
+ # construct ssl socket opts
592
+ @socket_opts[:key] = opts.delete(:ssl_key)
593
+ @socket_opts[:cert] = opts.delete(:ssl_cert)
594
+ @socket_opts[:verify] = opts.delete(:ssl_verify)
595
+ @socket_opts[:ca_cert] = opts.delete(:ssl_ca_cert)
596
+ @socket_opts[:key_pass_phrase] = opts.delete(:ssl_key_pass_phrase)
597
+
598
+ # verify peer requires ca_cert, raise if only one is present
599
+ if @socket_opts[:verify] && !@socket_opts[:ca_cert]
600
+ raise MongoArgumentError,
601
+ 'If :ssl_verify_mode has been specified, then you must include ' +
602
+ ':ssl_ca_cert in order to perform server validation.'
603
+ end
604
+
605
+ # if we have a keyfile passphrase but no key file, raise
606
+ if @socket_opts[:key_pass_phrase] && !@socket_opts[:key]
607
+ raise MongoArgumentError,
608
+ 'If :ssl_key_pass_phrase has been specified, then you must include ' +
609
+ ':ssl_key, the passphrase-protected keyfile.'
610
+ end
611
+
601
612
  @socket_class = Mongo::SSLSocket
602
613
  elsif @unix
603
614
  @socket_class = Mongo::UNIXSocket
@@ -605,25 +616,25 @@ module Mongo
605
616
  @socket_class = Mongo::TCPSocket
606
617
  end
607
618
 
608
- # Authentication objects
609
- @auths = opts.delete(:auths) || []
619
+ @db_name = opts.delete(:db_name)
620
+ @auths = opts.delete(:auths) || Set.new
610
621
 
611
622
  # Pool size and timeout.
612
623
  @pool_size = opts.delete(:pool_size) || 1
613
624
  if opts[:timeout]
614
- warn "The :timeout option has been deprecated " +
615
- "and will be removed in the 2.0 release. Use :pool_timeout instead."
625
+ warn 'The :timeout option has been deprecated ' +
626
+ 'and will be removed in the 2.0 release. ' +
627
+ 'Use :pool_timeout instead.'
616
628
  end
617
629
  @pool_timeout = opts.delete(:pool_timeout) || opts.delete(:timeout) || 5.0
618
630
 
619
631
  # Timeout on socket read operation.
620
- @op_timeout = opts.delete(:op_timeout) || nil
632
+ @op_timeout = opts.key?(:op_timeout) ? opts.delete(:op_timeout) : DEFAULT_OP_TIMEOUT
621
633
 
622
634
  # Timeout on socket connect.
623
635
  @connect_timeout = opts.delete(:connect_timeout) || 30
624
636
 
625
- @logger = opts.delete(:logger) || nil
626
-
637
+ @logger = opts.delete(:logger)
627
638
  if @logger
628
639
  write_logging_startup_message
629
640
  end
@@ -647,11 +658,40 @@ module Mongo
647
658
 
648
659
  private
649
660
 
650
- # Set the specified node as primary.
661
+ # Parses client initialization info from MONGODB_URI env variable
662
+ def parse_init(host, port, opts)
663
+ if host.nil? && port.nil? && ENV.has_key?('MONGODB_URI')
664
+ parser = URIParser.new(ENV['MONGODB_URI'])
665
+ if parser.replicaset?
666
+ raise MongoArgumentError,
667
+ 'ENV[\'MONGODB_URI\'] implies a replica set.'
668
+ end
669
+ opts.merge!(parser.connection_options)
670
+ [parser.host, parser.port]
671
+ else
672
+ host = host[1...-1] if host && host[0,1] == '[' # ipv6 support
673
+ [host || DEFAULT_HOST, port || DEFAULT_PORT]
674
+ end
675
+ end
676
+
677
+ # Set the specified node as primary
651
678
  def set_primary(node)
652
- host, port = *node
653
- @primary = [host, port]
679
+ host, port = *node
680
+ @primary = [host, port]
654
681
  @primary_pool = Pool.new(self, host, port, :size => @pool_size, :timeout => @pool_timeout)
655
682
  end
683
+
684
+ # calculate wire version in range
685
+ def check_wire_version_in_range
686
+ unless MIN_WIRE_VERSION <= max_wire_version &&
687
+ MAX_WIRE_VERSION >= min_wire_version
688
+ close
689
+ raise ConnectionFailure,
690
+ "Client wire-version range #{MIN_WIRE_VERSION} to " +
691
+ "#{MAX_WIRE_VERSION} does not support server range " +
692
+ "#{min_wire_version} to #{max_wire_version}, please update " +
693
+ "clients or servers"
694
+ end
695
+ end
656
696
  end
657
697
  end