mongo 1.10.0-java

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 (116) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +190 -0
  5. data/README.md +149 -0
  6. data/Rakefile +31 -0
  7. data/VERSION +1 -0
  8. data/bin/mongo_console +43 -0
  9. data/ext/jsasl/target/jsasl.jar +0 -0
  10. data/lib/mongo.rb +90 -0
  11. data/lib/mongo/bulk_write_collection_view.rb +380 -0
  12. data/lib/mongo/collection.rb +1164 -0
  13. data/lib/mongo/collection_writer.rb +364 -0
  14. data/lib/mongo/connection.rb +19 -0
  15. data/lib/mongo/connection/node.rb +239 -0
  16. data/lib/mongo/connection/pool.rb +347 -0
  17. data/lib/mongo/connection/pool_manager.rb +325 -0
  18. data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  21. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  22. data/lib/mongo/connection/socket/tcp_socket.rb +86 -0
  23. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  24. data/lib/mongo/cursor.rb +719 -0
  25. data/lib/mongo/db.rb +735 -0
  26. data/lib/mongo/exception.rb +88 -0
  27. data/lib/mongo/functional.rb +21 -0
  28. data/lib/mongo/functional/authentication.rb +318 -0
  29. data/lib/mongo/functional/logging.rb +85 -0
  30. data/lib/mongo/functional/read_preference.rb +174 -0
  31. data/lib/mongo/functional/sasl_java.rb +48 -0
  32. data/lib/mongo/functional/uri_parser.rb +374 -0
  33. data/lib/mongo/functional/write_concern.rb +66 -0
  34. data/lib/mongo/gridfs.rb +18 -0
  35. data/lib/mongo/gridfs/grid.rb +112 -0
  36. data/lib/mongo/gridfs/grid_ext.rb +53 -0
  37. data/lib/mongo/gridfs/grid_file_system.rb +163 -0
  38. data/lib/mongo/gridfs/grid_io.rb +484 -0
  39. data/lib/mongo/legacy.rb +140 -0
  40. data/lib/mongo/mongo_client.rb +702 -0
  41. data/lib/mongo/mongo_replica_set_client.rb +523 -0
  42. data/lib/mongo/mongo_sharded_client.rb +159 -0
  43. data/lib/mongo/networking.rb +370 -0
  44. data/lib/mongo/utils.rb +19 -0
  45. data/lib/mongo/utils/conversions.rb +110 -0
  46. data/lib/mongo/utils/core_ext.rb +70 -0
  47. data/lib/mongo/utils/server_version.rb +69 -0
  48. data/lib/mongo/utils/support.rb +80 -0
  49. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  50. data/mongo.gemspec +36 -0
  51. data/test/functional/authentication_test.rb +35 -0
  52. data/test/functional/bulk_api_stress_test.rb +133 -0
  53. data/test/functional/bulk_write_collection_view_test.rb +1129 -0
  54. data/test/functional/client_test.rb +565 -0
  55. data/test/functional/collection_test.rb +2073 -0
  56. data/test/functional/collection_writer_test.rb +83 -0
  57. data/test/functional/conversions_test.rb +163 -0
  58. data/test/functional/cursor_fail_test.rb +63 -0
  59. data/test/functional/cursor_message_test.rb +57 -0
  60. data/test/functional/cursor_test.rb +625 -0
  61. data/test/functional/db_api_test.rb +819 -0
  62. data/test/functional/db_connection_test.rb +27 -0
  63. data/test/functional/db_test.rb +344 -0
  64. data/test/functional/grid_file_system_test.rb +285 -0
  65. data/test/functional/grid_io_test.rb +252 -0
  66. data/test/functional/grid_test.rb +273 -0
  67. data/test/functional/pool_test.rb +62 -0
  68. data/test/functional/safe_test.rb +98 -0
  69. data/test/functional/ssl_test.rb +29 -0
  70. data/test/functional/support_test.rb +62 -0
  71. data/test/functional/timeout_test.rb +58 -0
  72. data/test/functional/uri_test.rb +330 -0
  73. data/test/functional/write_concern_test.rb +118 -0
  74. data/test/helpers/general.rb +50 -0
  75. data/test/helpers/test_unit.rb +317 -0
  76. data/test/replica_set/authentication_test.rb +35 -0
  77. data/test/replica_set/basic_test.rb +174 -0
  78. data/test/replica_set/client_test.rb +341 -0
  79. data/test/replica_set/complex_connect_test.rb +77 -0
  80. data/test/replica_set/connection_test.rb +138 -0
  81. data/test/replica_set/count_test.rb +64 -0
  82. data/test/replica_set/cursor_test.rb +212 -0
  83. data/test/replica_set/insert_test.rb +140 -0
  84. data/test/replica_set/max_values_test.rb +145 -0
  85. data/test/replica_set/pinning_test.rb +55 -0
  86. data/test/replica_set/query_test.rb +73 -0
  87. data/test/replica_set/read_preference_test.rb +214 -0
  88. data/test/replica_set/refresh_test.rb +175 -0
  89. data/test/replica_set/replication_ack_test.rb +94 -0
  90. data/test/replica_set/ssl_test.rb +32 -0
  91. data/test/sharded_cluster/basic_test.rb +197 -0
  92. data/test/shared/authentication/basic_auth_shared.rb +286 -0
  93. data/test/shared/authentication/bulk_api_auth_shared.rb +259 -0
  94. data/test/shared/authentication/gssapi_shared.rb +164 -0
  95. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  96. data/test/shared/ssl_shared.rb +235 -0
  97. data/test/test_helper.rb +56 -0
  98. data/test/threading/basic_test.rb +120 -0
  99. data/test/tools/mongo_config.rb +608 -0
  100. data/test/tools/mongo_config_test.rb +160 -0
  101. data/test/unit/client_test.rb +347 -0
  102. data/test/unit/collection_test.rb +166 -0
  103. data/test/unit/connection_test.rb +325 -0
  104. data/test/unit/cursor_test.rb +299 -0
  105. data/test/unit/db_test.rb +136 -0
  106. data/test/unit/grid_test.rb +76 -0
  107. data/test/unit/mongo_sharded_client_test.rb +48 -0
  108. data/test/unit/node_test.rb +93 -0
  109. data/test/unit/pool_manager_test.rb +142 -0
  110. data/test/unit/read_pref_test.rb +115 -0
  111. data/test/unit/read_test.rb +159 -0
  112. data/test/unit/safe_test.rb +158 -0
  113. data/test/unit/sharding_pool_manager_test.rb +84 -0
  114. data/test/unit/write_concern_test.rb +175 -0
  115. metadata +260 -0
  116. metadata.gz.sig +0 -0
@@ -0,0 +1,140 @@
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
+ module LegacyWriteConcern
17
+ @legacy_write_concern = true
18
+
19
+ def safe=(value)
20
+ @write_concern = value
21
+ end
22
+
23
+ def safe
24
+ if @write_concern[:w] == 0
25
+ return false
26
+ elsif @write_concern[:w] == 1
27
+ return true
28
+ else
29
+ return @write_concern
30
+ end
31
+ end
32
+
33
+ def self.from_uri(uri = ENV['MONGODB_URI'], extra_opts={})
34
+ parser = URIParser.new uri
35
+ parser.connection(extra_opts, true)
36
+ end
37
+ end
38
+ end
39
+
40
+ module Mongo
41
+ # @deprecated Use Mongo::MongoClient instead. Support will be removed after
42
+ # v2.0. Please see old documentation for the Connection class.
43
+ class Connection < MongoClient
44
+ include Mongo::LegacyWriteConcern
45
+
46
+ def initialize(*args)
47
+ if args.last.is_a?(Hash)
48
+ opts = args.pop
49
+ write_concern_from_legacy(opts)
50
+ args.push(opts)
51
+ end
52
+ super
53
+ end
54
+ end
55
+
56
+ # @deprecated Use Mongo::MongoReplicaSetClient instead. Support will be
57
+ # removed after v2.0. Please see old documentation for the
58
+ # ReplSetConnection class.
59
+ class ReplSetConnection < MongoReplicaSetClient
60
+ include Mongo::LegacyWriteConcern
61
+
62
+ def initialize(*args)
63
+ if args.last.is_a?(Hash)
64
+ opts = args.pop
65
+ write_concern_from_legacy(opts)
66
+ args.push(opts)
67
+ end
68
+ super
69
+ end
70
+ end
71
+
72
+ # @deprecated Use Mongo::MongoShardedClient instead. Support will be removed
73
+ # after v2.0. Please see old documentation for the ShardedConnection class.
74
+ class ShardedConnection < MongoShardedClient
75
+ include Mongo::LegacyWriteConcern
76
+
77
+ def initialize(*args)
78
+ if args.last.is_a?(Hash)
79
+ opts = args.pop
80
+ write_concern_from_legacy(opts)
81
+ args.push(opts)
82
+ end
83
+ super
84
+ end
85
+ end
86
+
87
+ class MongoClient
88
+ # @deprecated This method is no longer in use and never needs to be called
89
+ # directly. Support will be removed after v2.0
90
+ def authenticate_pools
91
+ @primary_pool.authenticate_existing
92
+ end
93
+
94
+ # @deprecated This method is no longer in use and never needs to be called
95
+ # directly. Support will be removed after v2.0
96
+ def logout_pools(database)
97
+ @primary_pool.logout_existing(database)
98
+ end
99
+
100
+ # @deprecated This method is no longer in use and never needs to be called
101
+ # directly. Support will be removed after v2.0
102
+ def apply_saved_authentication
103
+ true
104
+ end
105
+ end
106
+
107
+ class MongoReplicaSetClient
108
+ # @deprecated This method is no longer in use and never needs to be called
109
+ # directly. Support will be removed after v2.0
110
+ def authenticate_pools
111
+ @manager.pools.each { |pool| pool.authenticate_existing }
112
+ end
113
+
114
+ # @deprecated This method is no longer in use and never needs to be called
115
+ # directly. Support will be removed after v2.0
116
+ def logout_pools(database)
117
+ @manager.pools.each { |pool| pool.logout_existing(database) }
118
+ end
119
+ end
120
+
121
+ class DB
122
+ # @deprecated Please use MongoClient#issue_authentication instead. Support
123
+ # will be removed after v2.0
124
+ def issue_authentication(username, password, save_auth=true, opts={})
125
+ auth = Authentication.validate_credentials({
126
+ :db_name => self.name,
127
+ :username => username,
128
+ :password => password
129
+ })
130
+ opts[:save_auth] = save_auth
131
+ @client.issue_authentication(auth, opts)
132
+ end
133
+
134
+ # @deprecated Please use MongoClient#issue_logout instead. Support will be
135
+ # removed after v2.0
136
+ def issue_logout(opts={})
137
+ @client.issue_logout(self.name, opts)
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,702 @@
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
+ MAX_WIRE_VERSION = BATCH_COMMANDS # supported by this client implementation
29
+ MIN_WIRE_VERSION = RELEASE_2_4_AND_BEFORE # supported by this client implementation
30
+
31
+ # Server command headroom
32
+ COMMAND_HEADROOM = 16_384
33
+ APPEND_HEADROOM = COMMAND_HEADROOM / 2
34
+ SERIALIZE_HEADROOM = APPEND_HEADROOM / 2
35
+
36
+ DEFAULT_MAX_WRITE_BATCH_SIZE = 1000
37
+
38
+ Mutex = ::Mutex
39
+ ConditionVariable = ::ConditionVariable
40
+
41
+ DEFAULT_HOST = 'localhost'
42
+ DEFAULT_PORT = 27017
43
+ DEFAULT_DB_NAME = 'test'
44
+ GENERIC_OPTS = [:auths, :logger, :connect, :db_name]
45
+ TIMEOUT_OPTS = [:timeout, :op_timeout, :connect_timeout]
46
+ SSL_OPTS = [:ssl, :ssl_key, :ssl_cert, :ssl_verify, :ssl_ca_cert, :ssl_key_pass_phrase]
47
+ POOL_OPTS = [:pool_size, :pool_timeout]
48
+ READ_PREFERENCE_OPTS = [:read, :tag_sets, :secondary_acceptable_latency_ms]
49
+ WRITE_CONCERN_OPTS = [:w, :j, :fsync, :wtimeout]
50
+ CLIENT_ONLY_OPTS = [:slave_ok]
51
+
52
+ mongo_thread_local_accessor :connections
53
+
54
+ attr_reader :logger,
55
+ :size,
56
+ :auths,
57
+ :primary,
58
+ :write_concern,
59
+ :host_to_try,
60
+ :pool_size,
61
+ :connect_timeout,
62
+ :pool_timeout,
63
+ :primary_pool,
64
+ :socket_class,
65
+ :socket_opts,
66
+ :op_timeout,
67
+ :tag_sets,
68
+ :acceptable_latency,
69
+ :read,
70
+ :max_wire_version,
71
+ :min_wire_version,
72
+ :max_write_batch_size
73
+
74
+ # Create a connection to single MongoDB instance.
75
+ #
76
+ # If no args are provided, it will check <code>ENV["MONGODB_URI"]</code>.
77
+ #
78
+ # You may specify whether connection to slave is permitted.
79
+ # In all cases, the default host is "localhost" and the default port is 27017.
80
+ #
81
+ # If you're connecting to a replica set, you'll need to use MongoReplicaSetClient.new instead.
82
+ #
83
+ # Once connected to a replica set, you can find out which nodes are primary, secondary, and
84
+ # arbiters with the corresponding accessors: MongoClient#primary, MongoClient#secondaries, and
85
+ # MongoClient#arbiters. This is useful if your application needs to connect manually to nodes other
86
+ # than the primary.
87
+ #
88
+ # @overload initialize(host, port, opts={})
89
+ # @param [String] host hostname for the target MongoDB server.
90
+ # @param [Integer] port specify a port number here if only one host is being specified.
91
+ # @param [Hash] opts hash of optional settings and configuration values.
92
+ #
93
+ # @option opts [String, Integer, Symbol] :w (1) Set default number of nodes to which a write
94
+ # should be acknowledged.
95
+ # @option opts [Integer] :wtimeout (nil) Set replica set acknowledgement timeout.
96
+ # @option opts [Boolean] :j (false) If true, block until write operations have been committed
97
+ # to the journal. Cannot be used in combination with 'fsync'. Prior to MongoDB 2.6 this option was
98
+ # ignored if the server was running without journaling. Starting with MongoDB 2.6, write operations will
99
+ # fail with an exception if this option is used when the server is running without journaling.
100
+ # @option opts [Boolean] :fsync (false) If true, and the server is running without journaling, blocks until
101
+ # the server has synced all data files to disk. If the server is running with journaling, this acts the same as
102
+ # the 'j' option, blocking until write operations have been committed to the journal.
103
+ # Cannot be used in combination with 'j'.
104
+ #
105
+ # Notes about Write-Concern Options:
106
+ # Write concern options are propagated to objects instantiated from this MongoClient.
107
+ # These defaults can be overridden upon instantiation of any object by explicitly setting an options hash
108
+ # on initialization.
109
+ #
110
+ # @option opts [Boolean] :ssl (false) If true, create the connection to the server using SSL.
111
+ # @option opts [String] :ssl_cert (nil) The certificate file used to identify the local connection against MongoDB.
112
+ # @option opts [String] :ssl_key (nil) The private keyfile used to identify the local connection against MongoDB.
113
+ # Note that even if the key is stored in the same file as the certificate, both need to be explicitly specified.
114
+ # @option opts [String] :ssl_key_pass_phrase (nil) A passphrase for the private key.
115
+ # @option opts [Boolean] :ssl_verify (nil) Specifies whether or not peer certification validation should occur.
116
+ # @option opts [String] :ssl_ca_cert (nil) The ca_certs file contains a set of concatenated "certification authority"
117
+ # certificates, which are used to validate certificates passed from the other end of the connection.
118
+ # Required for :ssl_verify.
119
+ # @option opts [Boolean] :slave_ok (false) Must be set to +true+ when connecting
120
+ # to a single, slave node.
121
+ # @option opts [Logger, #debug] :logger (nil) A Logger instance for debugging driver ops. Note that
122
+ # logging negatively impacts performance; therefore, it should not be used for high-performance apps.
123
+ # @option opts [Integer] :pool_size (1) The maximum number of socket self.connections allowed per
124
+ # connection pool. Note: this setting is relevant only for multi-threaded applications.
125
+ # @option opts [Float] :pool_timeout (5.0) When all of the self.connections a pool are checked out,
126
+ # this is the number of seconds to wait for a new connection to be released before throwing an exception.
127
+ # Note: this setting is relevant only for multi-threaded applications.
128
+ # @option opts [Float] :op_timeout (nil) The number of seconds to wait for a read operation to time out.
129
+ # Disabled by default.
130
+ # @option opts [Float] :connect_timeout (nil) The number of seconds to wait before timing out a
131
+ # connection attempt.
132
+ #
133
+ # @example localhost, 27017 (or <code>ENV["MONGODB_URI"]</code> if available)
134
+ # MongoClient.new
135
+ #
136
+ # @example localhost, 27017
137
+ # MongoClient.new("localhost")
138
+ #
139
+ # @example localhost, 3000, max 5 self.connections, with max 5 seconds of wait time.
140
+ # MongoClient.new("localhost", 3000, :pool_size => 5, :pool_timeout => 5)
141
+ #
142
+ # @example localhost, 3000, where this node may be a slave
143
+ # MongoClient.new("localhost", 3000, :slave_ok => true)
144
+ #
145
+ # @example Unix Domain Socket
146
+ # MongoClient.new("/var/run/mongodb.sock")
147
+ #
148
+ # @see http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby
149
+ #
150
+ # @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
151
+ # driver fails to connect to a replica set with that name.
152
+ #
153
+ # @raise [MongoArgumentError] If called with no arguments and <code>ENV["MONGODB_URI"]</code> implies a replica set.
154
+ def initialize(*args)
155
+ opts = args.last.is_a?(Hash) ? args.pop : {}
156
+ @host, @port = parse_init(args[0], args[1], opts)
157
+
158
+ # Lock for request ids.
159
+ @id_lock = Mutex.new
160
+
161
+ # Connection pool for primary node
162
+ @primary = nil
163
+ @primary_pool = nil
164
+ @mongos = false
165
+
166
+ # Not set for direct connection
167
+ @tag_sets = []
168
+ @acceptable_latency = 15
169
+
170
+ @max_bson_size = nil
171
+ @max_message_size = nil
172
+ @max_wire_version = nil
173
+ @min_wire_version = nil
174
+ @max_write_batch_size = nil
175
+
176
+ check_opts(opts)
177
+ setup(opts.dup)
178
+ end
179
+
180
+ # DEPRECATED
181
+ #
182
+ # Initialize a connection to a MongoDB replica set using an array of seed nodes.
183
+ #
184
+ # The seed nodes specified will be used on the initial connection to the replica set, but note
185
+ # that this list of nodes will be replaced by the list of canonical nodes returned by running the
186
+ # is_master command on the replica set.
187
+ #
188
+ # @param nodes [Array] An array of arrays, each of which specifies a host and port.
189
+ # @param opts [Hash] Any of the available options that can be passed to MongoClient.new.
190
+ #
191
+ # @option opts [String] :rs_name (nil) The name of the replica set to connect to. An exception will be
192
+ # raised if unable to connect to a replica set with this name.
193
+ # @option opts [Boolean] :read_secondary (false) When true, this connection object will pick a random slave
194
+ # to send reads to.
195
+ #
196
+ # @example
197
+ # Mongo::MongoClient.multi([["db1.example.com", 27017], ["db2.example.com", 27017]])
198
+ #
199
+ # @example This connection will read from a random secondary node.
200
+ # Mongo::MongoClient.multi([["db1.example.com", 27017], ["db2.example.com", 27017], ["db3.example.com", 27017]],
201
+ # :read_secondary => true)
202
+ #
203
+ # @return [Mongo::MongoClient]
204
+ #
205
+ # @deprecated
206
+ def self.multi(nodes, opts={})
207
+ warn 'MongoClient.multi is now deprecated and will be removed in v2.0. Please use MongoReplicaSetClient.new instead.'
208
+ MongoReplicaSetClient.new(nodes, opts)
209
+ end
210
+
211
+ # Initialize a connection to MongoDB using the MongoDB URI spec.
212
+ #
213
+ # Since MongoClient.new cannot be used with any <code>ENV["MONGODB_URI"]</code> that has multiple hosts (implying a replicaset),
214
+ # you may use this when the type of your connection varies by environment and should be determined solely from <code>ENV["MONGODB_URI"]</code>.
215
+ #
216
+ # @param uri [String]
217
+ # A string of the format mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]
218
+ #
219
+ # @param [Hash] extra_opts Any of the options available for MongoClient.new
220
+ #
221
+ # @return [Mongo::MongoClient, Mongo::MongoReplicaSetClient]
222
+ def self.from_uri(uri = ENV['MONGODB_URI'], extra_opts={})
223
+ parser = URIParser.new(uri)
224
+ parser.connection(extra_opts)
225
+ end
226
+
227
+ # The host name used for this connection.
228
+ #
229
+ # @return [String]
230
+ def host
231
+ @primary_pool.host
232
+ end
233
+
234
+ # The port used for this connection.
235
+ #
236
+ # @return [Integer]
237
+ def port
238
+ @primary_pool.port
239
+ end
240
+
241
+ def host_port
242
+ [@host, @port]
243
+ end
244
+
245
+ # Flush all pending writes to datafiles.
246
+ #
247
+ # @return [BSON::OrderedHash] the command response
248
+ def lock!
249
+ cmd = BSON::OrderedHash.new
250
+ cmd[:fsync] = 1
251
+ cmd[:lock] = true
252
+ self['admin'].command(cmd)
253
+ end
254
+
255
+ # Is this database locked against writes?
256
+ #
257
+ # @return [Boolean]
258
+ def locked?
259
+ [1, true].include? self['admin']['$cmd.sys.inprog'].find_one['fsyncLock']
260
+ end
261
+
262
+ # Unlock a previously fsync-locked mongod process.
263
+ #
264
+ # @return [BSON::OrderedHash] command response
265
+ def unlock!
266
+ self['admin']['$cmd.sys.unlock'].find_one
267
+ end
268
+
269
+ # Return a hash with all database names
270
+ # and their respective sizes on disk.
271
+ #
272
+ # @return [Hash]
273
+ def database_info
274
+ doc = self['admin'].command({:listDatabases => 1})
275
+ doc['databases'].inject({}) do |info, db|
276
+ info[db['name']] = db['sizeOnDisk'].to_i
277
+ info
278
+ end
279
+ end
280
+
281
+ # Return an array of database names.
282
+ #
283
+ # @return [Array]
284
+ def database_names
285
+ database_info.keys
286
+ end
287
+
288
+ # Return a database with the given name.
289
+ # See DB#new for valid options hash parameters.
290
+ #
291
+ # @param name [String] The name of the database.
292
+ # @param opts [Hash] A hash of options to be passed to the DB constructor.
293
+ #
294
+ # @return [DB] The DB instance.
295
+ def db(name = nil, opts = {})
296
+ DB.new(name || @db_name || DEFAULT_DB_NAME, self, opts)
297
+ end
298
+
299
+ # Shortcut for returning a database. Use MongoClient#db to accept options.
300
+ #
301
+ # @param name [String] The name of the database.
302
+ #
303
+ # @return [DB] The DB instance.
304
+ def [](name)
305
+ DB.new(name, self)
306
+ end
307
+
308
+ def refresh; end
309
+
310
+ def pinned_pool
311
+ @primary_pool
312
+ end
313
+
314
+ def pin_pool(pool, read_prefs); end
315
+
316
+ def unpin_pool; end
317
+
318
+ # Drop a database.
319
+ #
320
+ # @param database [String] name of an existing database.
321
+ def drop_database(database)
322
+ self[database].command(:dropDatabase => 1)
323
+ end
324
+
325
+ # Copy the database +from+ to +to+ on localhost. The +from+ database is
326
+ # assumed to be on localhost, but an alternate host can be specified.
327
+ #
328
+ # @param from [String] name of the database to copy from.
329
+ # @param to [String] name of the database to copy to.
330
+ # @param from_host [String] host of the 'from' database.
331
+ # @param username [String] username (applies to 'from' db)
332
+ # @param password [String] password (applies to 'from' db)
333
+ #
334
+ # @note This command only supports the MONGODB-CR authentication mechanism.
335
+ def copy_database(from, to, from_host=DEFAULT_HOST, username=nil, password=nil)
336
+ oh = BSON::OrderedHash.new
337
+ oh[:copydb] = 1
338
+ oh[:fromhost] = from_host
339
+ oh[:fromdb] = from
340
+ oh[:todb] = to
341
+ if username || password
342
+ unless username && password
343
+ raise MongoArgumentError,
344
+ 'Both username and password must be supplied for authentication.'
345
+ end
346
+ nonce_cmd = BSON::OrderedHash.new
347
+ nonce_cmd[:copydbgetnonce] = 1
348
+ nonce_cmd[:fromhost] = from_host
349
+ result = self['admin'].command(nonce_cmd)
350
+ oh[:nonce] = result['nonce']
351
+ oh[:username] = username
352
+ oh[:key] = Mongo::Authentication.auth_key(username, password, oh[:nonce])
353
+ end
354
+ self['admin'].command(oh)
355
+ end
356
+
357
+ # Checks if a server is alive. This command will return immediately
358
+ # even if the server is in a lock.
359
+ #
360
+ # @return [Hash]
361
+ def ping
362
+ self['admin'].command({:ping => 1})
363
+ end
364
+
365
+ # Get the build information for the current connection.
366
+ #
367
+ # @return [Hash]
368
+ def server_info
369
+ self['admin'].command({:buildinfo => 1})
370
+ end
371
+
372
+ # Get the build version of the current server.
373
+ #
374
+ # @return [Mongo::ServerVersion]
375
+ # object allowing easy comparability of version.
376
+ def server_version
377
+ ServerVersion.new(server_info['version'])
378
+ end
379
+
380
+ # Is it okay to connect to a slave?
381
+ #
382
+ # @return [Boolean]
383
+ def slave_ok?
384
+ @slave_ok
385
+ end
386
+
387
+ def mongos?
388
+ @mongos
389
+ end
390
+
391
+ # Create a new socket and attempt to connect to master.
392
+ # If successful, sets host and port to master and returns the socket.
393
+ #
394
+ # If connecting to a replica set, this method will replace the
395
+ # initially-provided seed list with any nodes known to the set.
396
+ #
397
+ # @raise [ConnectionFailure] if unable to connect to any host or port.
398
+ def connect
399
+ close
400
+ config = check_is_master(host_port)
401
+ if config
402
+ if config['ismaster'] == 1 || config['ismaster'] == true
403
+ @read_primary = true
404
+ elsif @slave_ok
405
+ @read_primary = false
406
+ end
407
+
408
+ if config.has_key?('msg') && config['msg'] == 'isdbgrid'
409
+ @mongos = true
410
+ end
411
+
412
+ @max_bson_size = config['maxBsonObjectSize']
413
+ @max_message_size = config['maxMessageSizeBytes']
414
+ @max_wire_version = config['maxWireVersion']
415
+ @min_wire_version = config['minWireVersion']
416
+ @max_write_batch_size = config['maxWriteBatchSize']
417
+ check_wire_version_in_range
418
+ set_primary(host_port)
419
+ end
420
+
421
+ unless connected?
422
+ raise ConnectionFailure,
423
+ "Failed to connect to a master node at #{host_port.join(":")}"
424
+ end
425
+
426
+ true
427
+ end
428
+ alias :reconnect :connect
429
+
430
+ # It's possible that we defined connected as all nodes being connected???
431
+ # NOTE: Do check if this needs to be more stringent.
432
+ # Probably not since if any node raises a connection failure, all nodes will be closed.
433
+ def connected?
434
+ !!(@primary_pool && !@primary_pool.closed?)
435
+ end
436
+
437
+ # Determine if the connection is active. In a normal case the *server_info* operation
438
+ # will be performed without issues, but if the connection was dropped by the server or
439
+ # for some reason the sockets are unsynchronized, a ConnectionFailure will be raised and
440
+ # the return will be false.
441
+ #
442
+ # @return [Boolean]
443
+ def active?
444
+ return false unless connected?
445
+
446
+ ping
447
+ true
448
+
449
+ rescue ConnectionFailure
450
+ false
451
+ end
452
+
453
+ # Determine whether we're reading from a primary node. If false,
454
+ # this connection connects to a secondary node and @slave_ok is true.
455
+ #
456
+ # @return [Boolean]
457
+ def read_primary?
458
+ @read_primary
459
+ end
460
+ alias :primary? :read_primary?
461
+
462
+ # The socket pool that this connection reads from.
463
+ #
464
+ # @return [Mongo::Pool]
465
+ def read_pool
466
+ @primary_pool
467
+ end
468
+
469
+ # Close the connection to the database.
470
+ def close
471
+ @primary_pool.close if @primary_pool
472
+ @primary_pool = nil
473
+ @primary = nil
474
+ end
475
+
476
+ # Returns the maximum BSON object size as returned by the core server.
477
+ # Use the 4MB default when the server doesn't report this.
478
+ #
479
+ # @return [Integer]
480
+ def max_bson_size
481
+ @max_bson_size || DEFAULT_MAX_BSON_SIZE
482
+ end
483
+
484
+ def max_message_size
485
+ @max_message_size || max_bson_size * MESSAGE_SIZE_FACTOR
486
+ end
487
+
488
+ def max_wire_version
489
+ @max_wire_version || 0
490
+ end
491
+
492
+ def min_wire_version
493
+ @min_wire_version || 0
494
+ end
495
+
496
+ def max_write_batch_size
497
+ @max_write_batch_size || DEFAULT_MAX_WRITE_BATCH_SIZE
498
+ end
499
+
500
+ def wire_version_feature?(feature)
501
+ min_wire_version <= feature && feature <= max_wire_version
502
+ end
503
+
504
+ def primary_wire_version_feature?(feature)
505
+ min_wire_version <= feature && feature <= max_wire_version
506
+ end
507
+
508
+ def use_write_command?(write_concern)
509
+ write_concern[:w] != 0 && primary_wire_version_feature?(Mongo::MongoClient::BATCH_COMMANDS)
510
+ end
511
+
512
+ # Checkout a socket for reading (i.e., a secondary node).
513
+ # Note: this is overridden in MongoReplicaSetClient.
514
+ def checkout_reader(read_preference)
515
+ connect unless connected?
516
+ @primary_pool.checkout
517
+ end
518
+
519
+ # Checkout a socket for writing (i.e., a primary node).
520
+ # Note: this is overridden in MongoReplicaSetClient.
521
+ def checkout_writer
522
+ connect unless connected?
523
+ @primary_pool.checkout
524
+ end
525
+
526
+ # Check a socket back into its pool.
527
+ # Note: this is overridden in MongoReplicaSetClient.
528
+ def checkin(socket)
529
+ if @primary_pool && socket && socket.pool
530
+ socket.checkin
531
+ end
532
+ end
533
+
534
+ # Internal method for checking isMaster() on a given node.
535
+ #
536
+ # @param node [Array] Port and host for the target node
537
+ # @return [Hash] Response from isMaster()
538
+ #
539
+ # @private
540
+ def check_is_master(node)
541
+ begin
542
+ host, port = *node
543
+ config = nil
544
+ socket = @socket_class.new(host, port, @op_timeout, @connect_timeout, @socket_opts)
545
+ if @connect_timeout
546
+ Timeout::timeout(@connect_timeout, OperationTimeout) do
547
+ config = self['admin'].command({:isMaster => 1}, :socket => socket)
548
+ end
549
+ else
550
+ config = self['admin'].command({:isMaster => 1}, :socket => socket)
551
+ end
552
+ rescue OperationFailure, SocketError, SystemCallError, IOError
553
+ close
554
+ ensure
555
+ socket.close unless socket.nil? || socket.closed?
556
+ end
557
+ config
558
+ end
559
+
560
+ protected
561
+
562
+ def valid_opts
563
+ GENERIC_OPTS +
564
+ CLIENT_ONLY_OPTS +
565
+ POOL_OPTS +
566
+ READ_PREFERENCE_OPTS +
567
+ WRITE_CONCERN_OPTS +
568
+ TIMEOUT_OPTS +
569
+ SSL_OPTS
570
+ end
571
+
572
+ def check_opts(opts)
573
+ bad_opts = opts.keys.reject { |opt| valid_opts.include?(opt) }
574
+
575
+ unless bad_opts.empty?
576
+ bad_opts.each {|opt| warn "#{opt} is not a valid option for #{self.class}"}
577
+ end
578
+ end
579
+
580
+ # Parse option hash
581
+ def setup(opts)
582
+ @slave_ok = opts.delete(:slave_ok)
583
+ @ssl = opts.delete(:ssl)
584
+ @unix = @host ? @host.end_with?('.sock') : false
585
+
586
+ # if ssl options are present, but ssl is nil/false raise for misconfig
587
+ ssl_opts = opts.keys.select { |k| k.to_s.start_with?('ssl') }
588
+ if ssl_opts.size > 0 && !@ssl
589
+ raise MongoArgumentError, "SSL has not been enabled (:ssl=false) " +
590
+ "but the following SSL related options were " +
591
+ "specified: #{ssl_opts.join(', ')}"
592
+ end
593
+
594
+ @socket_opts = {}
595
+ if @ssl
596
+ # construct ssl socket opts
597
+ @socket_opts[:key] = opts.delete(:ssl_key)
598
+ @socket_opts[:cert] = opts.delete(:ssl_cert)
599
+ @socket_opts[:verify] = opts.delete(:ssl_verify)
600
+ @socket_opts[:ca_cert] = opts.delete(:ssl_ca_cert)
601
+ @socket_opts[:key_pass_phrase] = opts.delete(:ssl_key_pass_phrase)
602
+
603
+ # verify peer requires ca_cert, raise if only one is present
604
+ if @socket_opts[:verify] && !@socket_opts[:ca_cert]
605
+ raise MongoArgumentError,
606
+ 'If :ssl_verify_mode has been specified, then you must include ' +
607
+ ':ssl_ca_cert in order to perform server validation.'
608
+ end
609
+
610
+ # if we have a keyfile passphrase but no key file, raise
611
+ if @socket_opts[:key_pass_phrase] && !@socket_opts[:key]
612
+ raise MongoArgumentError,
613
+ 'If :ssl_key_pass_phrase has been specified, then you must include ' +
614
+ ':ssl_key, the passphrase-protected keyfile.'
615
+ end
616
+
617
+ @socket_class = Mongo::SSLSocket
618
+ elsif @unix
619
+ @socket_class = Mongo::UNIXSocket
620
+ else
621
+ @socket_class = Mongo::TCPSocket
622
+ end
623
+
624
+ @db_name = opts.delete(:db_name)
625
+ @auths = opts.delete(:auths) || Set.new
626
+
627
+ # Pool size and timeout.
628
+ @pool_size = opts.delete(:pool_size) || 1
629
+ if opts[:timeout]
630
+ warn 'The :timeout option has been deprecated ' +
631
+ 'and will be removed in the 2.0 release. ' +
632
+ 'Use :pool_timeout instead.'
633
+ end
634
+ @pool_timeout = opts.delete(:pool_timeout) || opts.delete(:timeout) || 5.0
635
+
636
+ # Timeout on socket read operation.
637
+ @op_timeout = opts.delete(:op_timeout)
638
+
639
+ # Timeout on socket connect.
640
+ @connect_timeout = opts.delete(:connect_timeout) || 30
641
+
642
+ @logger = opts.delete(:logger)
643
+ if @logger
644
+ write_logging_startup_message
645
+ end
646
+
647
+ # Determine read preference
648
+ if defined?(@slave_ok) && (@slave_ok) || defined?(@read_secondary) && @read_secondary
649
+ @read = :secondary_preferred
650
+ else
651
+ @read = opts.delete(:read) || :primary
652
+ end
653
+ Mongo::ReadPreference::validate(@read)
654
+
655
+ @tag_sets = opts.delete(:tag_sets) || []
656
+ @acceptable_latency = opts.delete(:secondary_acceptable_latency_ms) || 15
657
+
658
+ # Connection level write concern options.
659
+ @write_concern = get_write_concern(opts)
660
+
661
+ connect if opts.fetch(:connect, true)
662
+ end
663
+
664
+ private
665
+
666
+ # Parses client initialization info from MONGODB_URI env variable
667
+ def parse_init(host, port, opts)
668
+ if host.nil? && port.nil? && ENV.has_key?('MONGODB_URI')
669
+ parser = URIParser.new(ENV['MONGODB_URI'])
670
+ if parser.replicaset?
671
+ raise MongoArgumentError,
672
+ 'ENV[\'MONGODB_URI\'] implies a replica set.'
673
+ end
674
+ opts.merge!(parser.connection_options)
675
+ [parser.host, parser.port]
676
+ else
677
+ host = host[1...-1] if host && host[0,1] == '[' # ipv6 support
678
+ [host || DEFAULT_HOST, port || DEFAULT_PORT]
679
+ end
680
+ end
681
+
682
+ # Set the specified node as primary
683
+ def set_primary(node)
684
+ host, port = *node
685
+ @primary = [host, port]
686
+ @primary_pool = Pool.new(self, host, port, :size => @pool_size, :timeout => @pool_timeout)
687
+ end
688
+
689
+ # calculate wire version in range
690
+ def check_wire_version_in_range
691
+ unless MIN_WIRE_VERSION <= max_wire_version &&
692
+ MAX_WIRE_VERSION >= min_wire_version
693
+ close
694
+ raise ConnectionFailure,
695
+ "Client wire-version range #{MIN_WIRE_VERSION} to " +
696
+ "#{MAX_WIRE_VERSION} does not support server range " +
697
+ "#{min_wire_version} to #{max_wire_version}, please update " +
698
+ "clients or servers"
699
+ end
700
+ end
701
+ end
702
+ end