mongo 1.3.0 → 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 (185) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/{LICENSE.txt → LICENSE} +1 -1
  4. data/README.md +122 -271
  5. data/Rakefile +25 -209
  6. data/VERSION +1 -0
  7. data/bin/mongo_console +31 -9
  8. data/lib/mongo/bulk_write_collection_view.rb +387 -0
  9. data/lib/mongo/collection.rb +576 -269
  10. data/lib/mongo/collection_writer.rb +364 -0
  11. data/lib/mongo/connection/node.rb +249 -0
  12. data/lib/mongo/connection/pool.rb +340 -0
  13. data/lib/mongo/connection/pool_manager.rb +320 -0
  14. data/lib/mongo/connection/sharding_pool_manager.rb +67 -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 +7 -875
  21. data/lib/mongo/cursor.rb +403 -117
  22. data/lib/mongo/db.rb +444 -243
  23. data/lib/mongo/exception.rb +145 -0
  24. data/lib/mongo/functional/authentication.rb +455 -0
  25. data/lib/mongo/functional/logging.rb +85 -0
  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/functional/write_concern.rb +66 -0
  30. data/lib/mongo/functional.rb +20 -0
  31. data/lib/mongo/gridfs/grid.rb +30 -24
  32. data/lib/mongo/gridfs/grid_ext.rb +6 -10
  33. data/lib/mongo/gridfs/grid_file_system.rb +38 -20
  34. data/lib/mongo/gridfs/grid_io.rb +84 -75
  35. data/lib/mongo/gridfs.rb +18 -0
  36. data/lib/mongo/legacy.rb +140 -0
  37. data/lib/mongo/mongo_client.rb +697 -0
  38. data/lib/mongo/mongo_replica_set_client.rb +535 -0
  39. data/lib/mongo/mongo_sharded_client.rb +159 -0
  40. data/lib/mongo/networking.rb +372 -0
  41. data/lib/mongo/{util → utils}/conversions.rb +29 -8
  42. data/lib/mongo/{util → utils}/core_ext.rb +28 -18
  43. data/lib/mongo/{util → utils}/server_version.rb +4 -6
  44. data/lib/mongo/{util → utils}/support.rb +29 -31
  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 +51 -50
  48. data/mongo.gemspec +29 -32
  49. data/test/functional/authentication_test.rb +39 -0
  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 +2175 -0
  54. data/test/functional/collection_writer_test.rb +83 -0
  55. data/test/{conversions_test.rb → functional/conversions_test.rb} +47 -3
  56. data/test/functional/cursor_fail_test.rb +57 -0
  57. data/test/functional/cursor_message_test.rb +56 -0
  58. data/test/functional/cursor_test.rb +683 -0
  59. data/test/functional/db_api_test.rb +835 -0
  60. data/test/functional/db_connection_test.rb +25 -0
  61. data/test/functional/db_test.rb +348 -0
  62. data/test/functional/grid_file_system_test.rb +285 -0
  63. data/test/{grid_io_test.rb → functional/grid_io_test.rb} +72 -11
  64. data/test/{grid_test.rb → functional/grid_test.rb} +88 -15
  65. data/test/functional/pool_test.rb +136 -0
  66. data/test/functional/safe_test.rb +98 -0
  67. data/test/functional/ssl_test.rb +29 -0
  68. data/test/functional/support_test.rb +62 -0
  69. data/test/functional/timeout_test.rb +60 -0
  70. data/test/functional/uri_test.rb +446 -0
  71. data/test/functional/write_concern_test.rb +118 -0
  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 +37 -0
  75. data/test/replica_set/basic_test.rb +189 -0
  76. data/test/replica_set/client_test.rb +393 -0
  77. data/test/replica_set/connection_test.rb +138 -0
  78. data/test/replica_set/count_test.rb +66 -0
  79. data/test/replica_set/cursor_test.rb +220 -0
  80. data/test/replica_set/insert_test.rb +157 -0
  81. data/test/replica_set/max_values_test.rb +151 -0
  82. data/test/replica_set/pinning_test.rb +105 -0
  83. data/test/replica_set/query_test.rb +73 -0
  84. data/test/replica_set/read_preference_test.rb +219 -0
  85. data/test/replica_set/refresh_test.rb +211 -0
  86. data/test/replica_set/replication_ack_test.rb +95 -0
  87. data/test/replica_set/ssl_test.rb +32 -0
  88. data/test/sharded_cluster/basic_test.rb +203 -0
  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 +53 -94
  96. data/test/threading/basic_test.rb +120 -0
  97. data/test/tools/mongo_config.rb +708 -0
  98. data/test/tools/mongo_config_test.rb +160 -0
  99. data/test/unit/client_test.rb +381 -0
  100. data/test/unit/collection_test.rb +89 -53
  101. data/test/unit/connection_test.rb +282 -32
  102. data/test/unit/cursor_test.rb +206 -8
  103. data/test/unit/db_test.rb +55 -13
  104. data/test/unit/grid_test.rb +43 -16
  105. data/test/unit/mongo_sharded_client_test.rb +48 -0
  106. data/test/unit/node_test.rb +93 -0
  107. data/test/unit/pool_manager_test.rb +111 -0
  108. data/test/unit/read_pref_test.rb +406 -0
  109. data/test/unit/read_test.rb +159 -0
  110. data/test/unit/safe_test.rb +69 -36
  111. data/test/unit/sharding_pool_manager_test.rb +84 -0
  112. data/test/unit/write_concern_test.rb +175 -0
  113. data.tar.gz.sig +3 -0
  114. metadata +227 -216
  115. metadata.gz.sig +0 -0
  116. data/docs/CREDITS.md +0 -123
  117. data/docs/FAQ.md +0 -116
  118. data/docs/GridFS.md +0 -158
  119. data/docs/HISTORY.md +0 -244
  120. data/docs/RELEASES.md +0 -33
  121. data/docs/REPLICA_SETS.md +0 -72
  122. data/docs/TUTORIAL.md +0 -247
  123. data/docs/WRITE_CONCERN.md +0 -28
  124. data/lib/mongo/exceptions.rb +0 -71
  125. data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
  126. data/lib/mongo/repl_set_connection.rb +0 -342
  127. data/lib/mongo/test.rb +0 -20
  128. data/lib/mongo/util/pool.rb +0 -177
  129. data/lib/mongo/util/uri_parser.rb +0 -185
  130. data/test/async/collection_test.rb +0 -224
  131. data/test/async/connection_test.rb +0 -24
  132. data/test/async/cursor_test.rb +0 -162
  133. data/test/async/worker_pool_test.rb +0 -99
  134. data/test/auxillary/1.4_features.rb +0 -166
  135. data/test/auxillary/authentication_test.rb +0 -68
  136. data/test/auxillary/autoreconnect_test.rb +0 -41
  137. data/test/auxillary/fork_test.rb +0 -30
  138. data/test/auxillary/repl_set_auth_test.rb +0 -58
  139. data/test/auxillary/slave_connection_test.rb +0 -36
  140. data/test/auxillary/threaded_authentication_test.rb +0 -101
  141. data/test/bson/binary_test.rb +0 -15
  142. data/test/bson/bson_test.rb +0 -649
  143. data/test/bson/byte_buffer_test.rb +0 -208
  144. data/test/bson/hash_with_indifferent_access_test.rb +0 -38
  145. data/test/bson/json_test.rb +0 -17
  146. data/test/bson/object_id_test.rb +0 -154
  147. data/test/bson/ordered_hash_test.rb +0 -204
  148. data/test/bson/timestamp_test.rb +0 -24
  149. data/test/collection_test.rb +0 -910
  150. data/test/connection_test.rb +0 -309
  151. data/test/cursor_fail_test.rb +0 -75
  152. data/test/cursor_message_test.rb +0 -43
  153. data/test/cursor_test.rb +0 -483
  154. data/test/db_api_test.rb +0 -726
  155. data/test/db_connection_test.rb +0 -15
  156. data/test/db_test.rb +0 -287
  157. data/test/grid_file_system_test.rb +0 -243
  158. data/test/load/resque/load.rb +0 -21
  159. data/test/load/resque/processor.rb +0 -26
  160. data/test/load/thin/load.rb +0 -24
  161. data/test/load/unicorn/load.rb +0 -23
  162. data/test/load/unicorn/unicorn.rb +0 -29
  163. data/test/replica_sets/connect_test.rb +0 -94
  164. data/test/replica_sets/connection_string_test.rb +0 -32
  165. data/test/replica_sets/count_test.rb +0 -35
  166. data/test/replica_sets/insert_test.rb +0 -53
  167. data/test/replica_sets/pooled_insert_test.rb +0 -55
  168. data/test/replica_sets/query_secondaries.rb +0 -96
  169. data/test/replica_sets/query_test.rb +0 -51
  170. data/test/replica_sets/replication_ack_test.rb +0 -66
  171. data/test/replica_sets/rs_test_helper.rb +0 -27
  172. data/test/safe_test.rb +0 -68
  173. data/test/support/hash_with_indifferent_access.rb +0 -186
  174. data/test/support/keys.rb +0 -45
  175. data/test/support_test.rb +0 -18
  176. data/test/threading/threading_with_large_pool_test.rb +0 -90
  177. data/test/threading_test.rb +0 -87
  178. data/test/tools/auth_repl_set_manager.rb +0 -14
  179. data/test/tools/load.rb +0 -58
  180. data/test/tools/repl_set_manager.rb +0 -266
  181. data/test/tools/sharding_manager.rb +0 -202
  182. data/test/tools/test.rb +0 -4
  183. data/test/unit/pool_test.rb +0 -9
  184. data/test/unit/repl_set_connection_test.rb +0 -59
  185. data/test/uri_test.rb +0 -91
@@ -0,0 +1,697 @@
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.
14
+
15
+ module Mongo
16
+
17
+ # Instantiates and manages self.connections to MongoDB.
18
+ class MongoClient
19
+ include Mongo::Logging
20
+ include Mongo::Networking
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
38
+
39
+ Mutex = ::Mutex
40
+ ConditionVariable = ::ConditionVariable
41
+
42
+ DEFAULT_HOST = 'localhost'
43
+ DEFAULT_PORT = 27017
44
+ DEFAULT_DB_NAME = 'test'
45
+ DEFAULT_OP_TIMEOUT = 20
46
+ GENERIC_OPTS = [:auths, :logger, :connect, :db_name]
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]
49
+ POOL_OPTS = [:pool_size, :pool_timeout]
50
+ READ_PREFERENCE_OPTS = [:read, :tag_sets, :secondary_acceptable_latency_ms]
51
+ WRITE_CONCERN_OPTS = [:w, :j, :fsync, :wtimeout]
52
+ CLIENT_ONLY_OPTS = [:slave_ok]
53
+
54
+ mongo_thread_local_accessor :connections
55
+
56
+ attr_reader :logger,
57
+ :size,
58
+ :auths,
59
+ :primary,
60
+ :write_concern,
61
+ :host_to_try,
62
+ :pool_size,
63
+ :connect_timeout,
64
+ :pool_timeout,
65
+ :primary_pool,
66
+ :socket_class,
67
+ :socket_opts,
68
+ :op_timeout,
69
+ :tag_sets,
70
+ :acceptable_latency,
71
+ :read,
72
+ :max_wire_version,
73
+ :min_wire_version,
74
+ :max_write_batch_size
75
+
76
+ # Create a connection to single MongoDB instance.
77
+ #
78
+ # If no args are provided, it will check <code>ENV["MONGODB_URI"]</code>.
79
+ #
80
+ # You may specify whether connection to slave is permitted.
81
+ # In all cases, the default host is "localhost" and the default port is 27017.
82
+ #
83
+ # If you're connecting to a replica set, you'll need to use MongoReplicaSetClient.new instead.
84
+ #
85
+ # Once connected to a replica set, you can find out which nodes are primary, secondary, and
86
+ # arbiters with the corresponding accessors: MongoClient#primary, MongoClient#secondaries, and
87
+ # MongoClient#arbiters. This is useful if your application needs to connect manually to nodes other
88
+ # than the primary.
89
+ #
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.
134
+ #
135
+ # @example localhost, 27017 (or <code>ENV["MONGODB_URI"]</code> if available)
136
+ # MongoClient.new
137
+ #
138
+ # @example localhost, 27017
139
+ # MongoClient.new("localhost")
140
+ #
141
+ # @example localhost, 3000, max 5 self.connections, with max 5 seconds of wait time.
142
+ # MongoClient.new("localhost", 3000, :pool_size => 5, :pool_timeout => 5)
143
+ #
144
+ # @example localhost, 3000, where this node may be a slave
145
+ # MongoClient.new("localhost", 3000, :slave_ok => true)
146
+ #
147
+ # @example Unix Domain Socket
148
+ # MongoClient.new("/var/run/mongodb.sock")
149
+ #
150
+ # @see http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby
151
+ #
152
+ # @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
153
+ # driver fails to connect to a replica set with that name.
154
+ #
155
+ # @raise [MongoArgumentError] If called with no arguments and <code>ENV["MONGODB_URI"]</code> implies a replica set.
156
+ def initialize(*args)
157
+ opts = args.last.is_a?(Hash) ? args.pop : {}
158
+ @host, @port = parse_init(args[0], args[1], opts)
159
+
160
+ # Lock for request ids.
161
+ @id_lock = Mutex.new
162
+
163
+ # Connection pool for primary node
164
+ @primary = nil
165
+ @primary_pool = nil
166
+ @mongos = false
167
+
168
+ # Not set for direct connection
169
+ @tag_sets = []
170
+ @acceptable_latency = 15
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
+
178
+ check_opts(opts)
179
+ setup(opts.dup)
180
+ end
181
+
182
+ # DEPRECATED
183
+ #
184
+ # Initialize a connection to a MongoDB replica set using an array of seed nodes.
185
+ #
186
+ # The seed nodes specified will be used on the initial connection to the replica set, but note
187
+ # that this list of nodes will be replaced by the list of canonical nodes returned by running the
188
+ # is_master command on the replica set.
189
+ #
190
+ # @param nodes [Array] An array of arrays, each of which specifies a host and port.
191
+ # @param opts [Hash] Any of the available options that can be passed to MongoClient.new.
192
+ #
193
+ # @option opts [String] :rs_name (nil) The name of the replica set to connect to. An exception will be
194
+ # raised if unable to connect to a replica set with this name.
195
+ # @option opts [Boolean] :read_secondary (false) When true, this connection object will pick a random slave
196
+ # to send reads to.
197
+ #
198
+ # @example
199
+ # Mongo::MongoClient.multi([["db1.example.com", 27017], ["db2.example.com", 27017]])
200
+ #
201
+ # @example This connection will read from a random secondary node.
202
+ # Mongo::MongoClient.multi([["db1.example.com", 27017], ["db2.example.com", 27017], ["db3.example.com", 27017]],
203
+ # :read_secondary => true)
204
+ #
205
+ # @return [Mongo::MongoClient]
206
+ #
207
+ # @deprecated
208
+ def self.multi(nodes, opts={})
209
+ warn 'MongoClient.multi is now deprecated and will be removed in v2.0. Please use MongoReplicaSetClient.new instead.'
210
+ MongoReplicaSetClient.new(nodes, opts)
211
+ end
212
+
213
+ # Initialize a connection to MongoDB using the MongoDB URI spec.
214
+ #
215
+ # Since MongoClient.new cannot be used with any <code>ENV["MONGODB_URI"]</code> that has multiple hosts (implying a replicaset),
216
+ # you may use this when the type of your connection varies by environment and should be determined solely from <code>ENV["MONGODB_URI"]</code>.
217
+ #
218
+ # @param uri [String]
219
+ # A string of the format mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]
220
+ #
221
+ # @param [Hash] extra_opts Any of the options available for MongoClient.new
222
+ #
223
+ # @return [Mongo::MongoClient, Mongo::MongoReplicaSetClient]
224
+ def self.from_uri(uri = ENV['MONGODB_URI'], extra_opts={})
225
+ parser = URIParser.new(uri)
226
+ parser.connection(extra_opts)
227
+ end
228
+
229
+ # The host name used for this connection.
230
+ #
231
+ # @return [String]
232
+ def host
233
+ @primary_pool.host
234
+ end
235
+
236
+ # The port used for this connection.
237
+ #
238
+ # @return [Integer]
239
+ def port
240
+ @primary_pool.port
241
+ end
242
+
243
+ def host_port
244
+ [@host, @port]
245
+ end
246
+
247
+ # Flush all pending writes to datafiles.
248
+ #
249
+ # @return [BSON::OrderedHash] the command response
250
+ def lock!
251
+ cmd = BSON::OrderedHash.new
252
+ cmd[:fsync] = 1
253
+ cmd[:lock] = true
254
+ self['admin'].command(cmd)
255
+ end
256
+
257
+ # Is this database locked against writes?
258
+ #
259
+ # @return [Boolean]
260
+ def locked?
261
+ [1, true].include? self['admin']['$cmd.sys.inprog'].find_one['fsyncLock']
262
+ end
263
+
264
+ # Unlock a previously fsync-locked mongod process.
265
+ #
266
+ # @return [BSON::OrderedHash] command response
267
+ def unlock!
268
+ self['admin']['$cmd.sys.unlock'].find_one
269
+ end
270
+
271
+ # Return a hash with all database names
272
+ # and their respective sizes on disk.
273
+ #
274
+ # @return [Hash]
275
+ def database_info
276
+ doc = self['admin'].command({:listDatabases => 1})
277
+ doc['databases'].inject({}) do |info, db|
278
+ info[db['name']] = db['sizeOnDisk'].to_i
279
+ info
280
+ end
281
+ end
282
+
283
+ # Return an array of database names.
284
+ #
285
+ # @return [Array]
286
+ def database_names
287
+ database_info.keys
288
+ end
289
+
290
+ # Return a database with the given name.
291
+ # See DB#new for valid options hash parameters.
292
+ #
293
+ # @param name [String] The name of the database.
294
+ # @param opts [Hash] A hash of options to be passed to the DB constructor.
295
+ #
296
+ # @return [DB] The DB instance.
297
+ def db(name = nil, opts = {})
298
+ DB.new(name || @db_name || DEFAULT_DB_NAME, self, opts)
299
+ end
300
+
301
+ # Shortcut for returning a database. Use MongoClient#db to accept options.
302
+ #
303
+ # @param name [String] The name of the database.
304
+ #
305
+ # @return [DB] The DB instance.
306
+ def [](name)
307
+ DB.new(name, self)
308
+ end
309
+
310
+ def refresh; end
311
+
312
+ def pinned_pool
313
+ @primary_pool
314
+ end
315
+
316
+ def pin_pool(pool, read_prefs); end
317
+
318
+ def unpin_pool; end
319
+
320
+ # Drop a database.
321
+ #
322
+ # @param database [String] name of an existing database.
323
+ def drop_database(database)
324
+ self[database].command(:dropDatabase => 1)
325
+ end
326
+
327
+ # Copy the database +from+ to +to+ on localhost. The +from+ database is
328
+ # assumed to be on localhost, but an alternate host can be specified.
329
+ #
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)
349
+ end
350
+ end
351
+
352
+ # Checks if a server is alive. This command will return immediately
353
+ # even if the server is in a lock.
354
+ #
355
+ # @return [Hash]
356
+ def ping
357
+ self['admin'].command({:ping => 1})
358
+ end
359
+
360
+ # Get the build information for the current connection.
361
+ #
362
+ # @return [Hash]
363
+ def server_info
364
+ self['admin'].command({:buildinfo => 1})
365
+ end
366
+
367
+ # Get the build version of the current server.
368
+ #
369
+ # @return [Mongo::ServerVersion]
370
+ # object allowing easy comparability of version.
371
+ def server_version
372
+ ServerVersion.new(server_info['version'])
373
+ end
374
+
375
+ # Is it okay to connect to a slave?
376
+ #
377
+ # @return [Boolean]
378
+ def slave_ok?
379
+ @slave_ok
380
+ end
381
+
382
+ def mongos?
383
+ @mongos
384
+ end
385
+
386
+ # Create a new socket and attempt to connect to master.
387
+ # If successful, sets host and port to master and returns the socket.
388
+ #
389
+ # If connecting to a replica set, this method will replace the
390
+ # initially-provided seed list with any nodes known to the set.
391
+ #
392
+ # @raise [ConnectionFailure] if unable to connect to any host or port.
393
+ def connect
394
+ close
395
+ config = check_is_master(host_port)
396
+ if config
397
+ if config['ismaster'] == 1 || config['ismaster'] == true
398
+ @read_primary = true
399
+ elsif @slave_ok
400
+ @read_primary = false
401
+ end
402
+
403
+ if config.has_key?('msg') && config['msg'] == 'isdbgrid'
404
+ @mongos = true
405
+ end
406
+
407
+ @max_bson_size = config['maxBsonObjectSize']
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
413
+ set_primary(host_port)
414
+ end
415
+
416
+ unless connected?
417
+ raise ConnectionFailure,
418
+ "Failed to connect to a master node at #{host_port.join(":")}"
419
+ end
420
+
421
+ true
422
+ end
423
+ alias :reconnect :connect
424
+
425
+ # It's possible that we defined connected as all nodes being connected???
426
+ # NOTE: Do check if this needs to be more stringent.
427
+ # Probably not since if any node raises a connection failure, all nodes will be closed.
428
+ def connected?
429
+ !!(@primary_pool && !@primary_pool.closed?)
430
+ end
431
+
432
+ # Determine if the connection is active. In a normal case the *server_info* operation
433
+ # will be performed without issues, but if the connection was dropped by the server or
434
+ # for some reason the sockets are unsynchronized, a ConnectionFailure will be raised and
435
+ # the return will be false.
436
+ #
437
+ # @return [Boolean]
438
+ def active?
439
+ return false unless connected?
440
+
441
+ ping
442
+ true
443
+
444
+ rescue ConnectionFailure, OperationTimeout
445
+ false
446
+ end
447
+
448
+ # Determine whether we're reading from a primary node. If false,
449
+ # this connection connects to a secondary node and @slave_ok is true.
450
+ #
451
+ # @return [Boolean]
452
+ def read_primary?
453
+ @read_primary
454
+ end
455
+ alias :primary? :read_primary?
456
+
457
+ # The socket pool that this connection reads from.
458
+ #
459
+ # @return [Mongo::Pool]
460
+ def read_pool
461
+ @primary_pool
462
+ end
463
+
464
+ # Close the connection to the database.
465
+ def close
466
+ @primary_pool.close if @primary_pool
467
+ @primary_pool = nil
468
+ @primary = nil
469
+ end
470
+
471
+ # Returns the maximum BSON object size as returned by the core server.
472
+ # Use the 4MB default when the server doesn't report this.
473
+ #
474
+ # @return [Integer]
475
+ def max_bson_size
476
+ @max_bson_size || DEFAULT_MAX_BSON_SIZE
477
+ end
478
+
479
+ def max_message_size
480
+ @max_message_size || max_bson_size * MESSAGE_SIZE_FACTOR
481
+ end
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
+
507
+ # Checkout a socket for reading (i.e., a secondary node).
508
+ # Note: this is overridden in MongoReplicaSetClient.
509
+ def checkout_reader(read_preference)
510
+ connect unless connected?
511
+ @primary_pool.checkout
512
+ end
513
+
514
+ # Checkout a socket for writing (i.e., a primary node).
515
+ # Note: this is overridden in MongoReplicaSetClient.
516
+ def checkout_writer
517
+ connect unless connected?
518
+ @primary_pool.checkout
519
+ end
520
+
521
+ # Check a socket back into its pool.
522
+ # Note: this is overridden in MongoReplicaSetClient.
523
+ def checkin(socket)
524
+ if @primary_pool && socket && socket.pool
525
+ socket.checkin
526
+ end
527
+ end
528
+
529
+ # Internal method for checking isMaster() on a given node.
530
+ #
531
+ # @param node [Array] Port and host for the target node
532
+ # @return [Hash] Response from isMaster()
533
+ #
534
+ # @private
535
+ def check_is_master(node)
536
+ begin
537
+ host, port = *node
538
+ config = nil
539
+ socket = @socket_class.new(host, port, @op_timeout, @connect_timeout, @socket_opts)
540
+ if @connect_timeout
541
+ Timeout::timeout(@connect_timeout, OperationTimeout) do
542
+ config = self['admin'].command({:isMaster => 1}, :socket => socket)
543
+ end
544
+ else
545
+ config = self['admin'].command({:isMaster => 1}, :socket => socket)
546
+ end
547
+ rescue OperationFailure, SocketError, SystemCallError, IOError
548
+ close
549
+ ensure
550
+ socket.close unless socket.nil? || socket.closed?
551
+ end
552
+ config
553
+ end
554
+
555
+ protected
556
+
557
+ def valid_opts
558
+ GENERIC_OPTS +
559
+ CLIENT_ONLY_OPTS +
560
+ POOL_OPTS +
561
+ READ_PREFERENCE_OPTS +
562
+ WRITE_CONCERN_OPTS +
563
+ TIMEOUT_OPTS +
564
+ SSL_OPTS
565
+ end
566
+
567
+ def check_opts(opts)
568
+ bad_opts = opts.keys.reject { |opt| valid_opts.include?(opt) }
569
+
570
+ unless bad_opts.empty?
571
+ bad_opts.each {|opt| warn "#{opt} is not a valid option for #{self.class}"}
572
+ end
573
+ end
574
+
575
+ # Parse option hash
576
+ def setup(opts)
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
588
+
589
+ @socket_opts = {}
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
+
612
+ @socket_class = Mongo::SSLSocket
613
+ elsif @unix
614
+ @socket_class = Mongo::UNIXSocket
615
+ else
616
+ @socket_class = Mongo::TCPSocket
617
+ end
618
+
619
+ @db_name = opts.delete(:db_name)
620
+ @auths = opts.delete(:auths) || Set.new
621
+
622
+ # Pool size and timeout.
623
+ @pool_size = opts.delete(:pool_size) || 1
624
+ if opts[:timeout]
625
+ warn 'The :timeout option has been deprecated ' +
626
+ 'and will be removed in the 2.0 release. ' +
627
+ 'Use :pool_timeout instead.'
628
+ end
629
+ @pool_timeout = opts.delete(:pool_timeout) || opts.delete(:timeout) || 5.0
630
+
631
+ # Timeout on socket read operation.
632
+ @op_timeout = opts.key?(:op_timeout) ? opts.delete(:op_timeout) : DEFAULT_OP_TIMEOUT
633
+
634
+ # Timeout on socket connect.
635
+ @connect_timeout = opts.delete(:connect_timeout) || 30
636
+
637
+ @logger = opts.delete(:logger)
638
+ if @logger
639
+ write_logging_startup_message
640
+ end
641
+
642
+ # Determine read preference
643
+ if defined?(@slave_ok) && (@slave_ok) || defined?(@read_secondary) && @read_secondary
644
+ @read = :secondary_preferred
645
+ else
646
+ @read = opts.delete(:read) || :primary
647
+ end
648
+ Mongo::ReadPreference::validate(@read)
649
+
650
+ @tag_sets = opts.delete(:tag_sets) || []
651
+ @acceptable_latency = opts.delete(:secondary_acceptable_latency_ms) || 15
652
+
653
+ # Connection level write concern options.
654
+ @write_concern = get_write_concern(opts)
655
+
656
+ connect if opts.fetch(:connect, true)
657
+ end
658
+
659
+ private
660
+
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
678
+ def set_primary(node)
679
+ host, port = *node
680
+ @primary = [host, port]
681
+ @primary_pool = Pool.new(self, host, port, :size => @pool_size, :timeout => @pool_timeout)
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
696
+ end
697
+ end