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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +122 -271
- data/Rakefile +25 -209
- data/VERSION +1 -0
- data/bin/mongo_console +31 -9
- data/lib/mongo/bulk_write_collection_view.rb +387 -0
- data/lib/mongo/collection.rb +576 -269
- data/lib/mongo/collection_writer.rb +364 -0
- data/lib/mongo/connection/node.rb +249 -0
- data/lib/mongo/connection/pool.rb +340 -0
- data/lib/mongo/connection/pool_manager.rb +320 -0
- data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
- data/lib/mongo/connection/socket/socket_util.rb +37 -0
- data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
- data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
- data/lib/mongo/connection/socket/unix_socket.rb +39 -0
- data/lib/mongo/connection/socket.rb +18 -0
- data/lib/mongo/connection.rb +7 -875
- data/lib/mongo/cursor.rb +403 -117
- data/lib/mongo/db.rb +444 -243
- data/lib/mongo/exception.rb +145 -0
- data/lib/mongo/functional/authentication.rb +455 -0
- data/lib/mongo/functional/logging.rb +85 -0
- data/lib/mongo/functional/read_preference.rb +183 -0
- data/lib/mongo/functional/scram.rb +556 -0
- data/lib/mongo/functional/uri_parser.rb +409 -0
- data/lib/mongo/functional/write_concern.rb +66 -0
- data/lib/mongo/functional.rb +20 -0
- data/lib/mongo/gridfs/grid.rb +30 -24
- data/lib/mongo/gridfs/grid_ext.rb +6 -10
- data/lib/mongo/gridfs/grid_file_system.rb +38 -20
- data/lib/mongo/gridfs/grid_io.rb +84 -75
- data/lib/mongo/gridfs.rb +18 -0
- data/lib/mongo/legacy.rb +140 -0
- data/lib/mongo/mongo_client.rb +697 -0
- data/lib/mongo/mongo_replica_set_client.rb +535 -0
- data/lib/mongo/mongo_sharded_client.rb +159 -0
- data/lib/mongo/networking.rb +372 -0
- data/lib/mongo/{util → utils}/conversions.rb +29 -8
- data/lib/mongo/{util → utils}/core_ext.rb +28 -18
- data/lib/mongo/{util → utils}/server_version.rb +4 -6
- data/lib/mongo/{util → utils}/support.rb +29 -31
- data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
- data/lib/mongo/utils.rb +19 -0
- data/lib/mongo.rb +51 -50
- data/mongo.gemspec +29 -32
- data/test/functional/authentication_test.rb +39 -0
- data/test/functional/bulk_api_stress_test.rb +133 -0
- data/test/functional/bulk_write_collection_view_test.rb +1198 -0
- data/test/functional/client_test.rb +627 -0
- data/test/functional/collection_test.rb +2175 -0
- data/test/functional/collection_writer_test.rb +83 -0
- data/test/{conversions_test.rb → functional/conversions_test.rb} +47 -3
- data/test/functional/cursor_fail_test.rb +57 -0
- data/test/functional/cursor_message_test.rb +56 -0
- data/test/functional/cursor_test.rb +683 -0
- data/test/functional/db_api_test.rb +835 -0
- data/test/functional/db_connection_test.rb +25 -0
- data/test/functional/db_test.rb +348 -0
- data/test/functional/grid_file_system_test.rb +285 -0
- data/test/{grid_io_test.rb → functional/grid_io_test.rb} +72 -11
- data/test/{grid_test.rb → functional/grid_test.rb} +88 -15
- data/test/functional/pool_test.rb +136 -0
- data/test/functional/safe_test.rb +98 -0
- data/test/functional/ssl_test.rb +29 -0
- data/test/functional/support_test.rb +62 -0
- data/test/functional/timeout_test.rb +60 -0
- data/test/functional/uri_test.rb +446 -0
- data/test/functional/write_concern_test.rb +118 -0
- data/test/helpers/general.rb +50 -0
- data/test/helpers/test_unit.rb +476 -0
- data/test/replica_set/authentication_test.rb +37 -0
- data/test/replica_set/basic_test.rb +189 -0
- data/test/replica_set/client_test.rb +393 -0
- data/test/replica_set/connection_test.rb +138 -0
- data/test/replica_set/count_test.rb +66 -0
- data/test/replica_set/cursor_test.rb +220 -0
- data/test/replica_set/insert_test.rb +157 -0
- data/test/replica_set/max_values_test.rb +151 -0
- data/test/replica_set/pinning_test.rb +105 -0
- data/test/replica_set/query_test.rb +73 -0
- data/test/replica_set/read_preference_test.rb +219 -0
- data/test/replica_set/refresh_test.rb +211 -0
- data/test/replica_set/replication_ack_test.rb +95 -0
- data/test/replica_set/ssl_test.rb +32 -0
- data/test/sharded_cluster/basic_test.rb +203 -0
- data/test/shared/authentication/basic_auth_shared.rb +260 -0
- data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
- data/test/shared/authentication/gssapi_shared.rb +176 -0
- data/test/shared/authentication/sasl_plain_shared.rb +96 -0
- data/test/shared/authentication/scram_shared.rb +92 -0
- data/test/shared/ssl_shared.rb +235 -0
- data/test/test_helper.rb +53 -94
- data/test/threading/basic_test.rb +120 -0
- data/test/tools/mongo_config.rb +708 -0
- data/test/tools/mongo_config_test.rb +160 -0
- data/test/unit/client_test.rb +381 -0
- data/test/unit/collection_test.rb +89 -53
- data/test/unit/connection_test.rb +282 -32
- data/test/unit/cursor_test.rb +206 -8
- data/test/unit/db_test.rb +55 -13
- data/test/unit/grid_test.rb +43 -16
- data/test/unit/mongo_sharded_client_test.rb +48 -0
- data/test/unit/node_test.rb +93 -0
- data/test/unit/pool_manager_test.rb +111 -0
- data/test/unit/read_pref_test.rb +406 -0
- data/test/unit/read_test.rb +159 -0
- data/test/unit/safe_test.rb +69 -36
- data/test/unit/sharding_pool_manager_test.rb +84 -0
- data/test/unit/write_concern_test.rb +175 -0
- data.tar.gz.sig +3 -0
- metadata +227 -216
- metadata.gz.sig +0 -0
- data/docs/CREDITS.md +0 -123
- data/docs/FAQ.md +0 -116
- data/docs/GridFS.md +0 -158
- data/docs/HISTORY.md +0 -244
- data/docs/RELEASES.md +0 -33
- data/docs/REPLICA_SETS.md +0 -72
- data/docs/TUTORIAL.md +0 -247
- data/docs/WRITE_CONCERN.md +0 -28
- data/lib/mongo/exceptions.rb +0 -71
- data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
- data/lib/mongo/repl_set_connection.rb +0 -342
- data/lib/mongo/test.rb +0 -20
- data/lib/mongo/util/pool.rb +0 -177
- data/lib/mongo/util/uri_parser.rb +0 -185
- data/test/async/collection_test.rb +0 -224
- data/test/async/connection_test.rb +0 -24
- data/test/async/cursor_test.rb +0 -162
- data/test/async/worker_pool_test.rb +0 -99
- data/test/auxillary/1.4_features.rb +0 -166
- data/test/auxillary/authentication_test.rb +0 -68
- data/test/auxillary/autoreconnect_test.rb +0 -41
- data/test/auxillary/fork_test.rb +0 -30
- data/test/auxillary/repl_set_auth_test.rb +0 -58
- data/test/auxillary/slave_connection_test.rb +0 -36
- data/test/auxillary/threaded_authentication_test.rb +0 -101
- data/test/bson/binary_test.rb +0 -15
- data/test/bson/bson_test.rb +0 -649
- data/test/bson/byte_buffer_test.rb +0 -208
- data/test/bson/hash_with_indifferent_access_test.rb +0 -38
- data/test/bson/json_test.rb +0 -17
- data/test/bson/object_id_test.rb +0 -154
- data/test/bson/ordered_hash_test.rb +0 -204
- data/test/bson/timestamp_test.rb +0 -24
- data/test/collection_test.rb +0 -910
- data/test/connection_test.rb +0 -309
- data/test/cursor_fail_test.rb +0 -75
- data/test/cursor_message_test.rb +0 -43
- data/test/cursor_test.rb +0 -483
- data/test/db_api_test.rb +0 -726
- data/test/db_connection_test.rb +0 -15
- data/test/db_test.rb +0 -287
- data/test/grid_file_system_test.rb +0 -243
- data/test/load/resque/load.rb +0 -21
- data/test/load/resque/processor.rb +0 -26
- data/test/load/thin/load.rb +0 -24
- data/test/load/unicorn/load.rb +0 -23
- data/test/load/unicorn/unicorn.rb +0 -29
- data/test/replica_sets/connect_test.rb +0 -94
- data/test/replica_sets/connection_string_test.rb +0 -32
- data/test/replica_sets/count_test.rb +0 -35
- data/test/replica_sets/insert_test.rb +0 -53
- data/test/replica_sets/pooled_insert_test.rb +0 -55
- data/test/replica_sets/query_secondaries.rb +0 -96
- data/test/replica_sets/query_test.rb +0 -51
- data/test/replica_sets/replication_ack_test.rb +0 -66
- data/test/replica_sets/rs_test_helper.rb +0 -27
- data/test/safe_test.rb +0 -68
- data/test/support/hash_with_indifferent_access.rb +0 -186
- data/test/support/keys.rb +0 -45
- data/test/support_test.rb +0 -18
- data/test/threading/threading_with_large_pool_test.rb +0 -90
- data/test/threading_test.rb +0 -87
- data/test/tools/auth_repl_set_manager.rb +0 -14
- data/test/tools/load.rb +0 -58
- data/test/tools/repl_set_manager.rb +0 -266
- data/test/tools/sharding_manager.rb +0 -202
- data/test/tools/test.rb +0 -4
- data/test/unit/pool_test.rb +0 -9
- data/test/unit/repl_set_connection_test.rb +0 -59
- data/test/uri_test.rb +0 -91
data/lib/mongo/connection.rb
CHANGED
@@ -1,887 +1,19 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# --
|
4
|
-
# Copyright (C) 2008-2011 10gen Inc.
|
1
|
+
# Copyright (C) 2009-2013 MongoDB, Inc.
|
5
2
|
#
|
6
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
4
|
# you may not use this file except in compliance with the License.
|
8
5
|
# You may obtain a copy of the License at
|
9
6
|
#
|
10
|
-
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
8
|
#
|
12
9
|
# Unless required by applicable law or agreed to in writing, software
|
13
10
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
12
|
# See the License for the specific language governing permissions and
|
16
13
|
# limitations under the License.
|
17
|
-
# ++
|
18
|
-
|
19
|
-
require 'set'
|
20
|
-
require 'socket'
|
21
|
-
require 'thread'
|
22
|
-
|
23
|
-
module Mongo
|
24
|
-
|
25
|
-
# Instantiates and manages connections to MongoDB.
|
26
|
-
class Connection
|
27
|
-
TCPSocket = ::TCPSocket
|
28
|
-
Mutex = ::Mutex
|
29
|
-
ConditionVariable = ::ConditionVariable
|
30
|
-
|
31
|
-
# Abort connections if a ConnectionError is raised.
|
32
|
-
Thread.abort_on_exception = true
|
33
|
-
|
34
|
-
DEFAULT_PORT = 27017
|
35
|
-
STANDARD_HEADER_SIZE = 16
|
36
|
-
RESPONSE_HEADER_SIZE = 20
|
37
|
-
|
38
|
-
attr_reader :logger, :size, :auths, :primary, :safe, :primary_pool, :host_to_try, :pool_size
|
39
|
-
|
40
|
-
# Counter for generating unique request ids.
|
41
|
-
@@current_request_id = 0
|
42
|
-
|
43
|
-
# Create a connection to single MongoDB instance.
|
44
|
-
#
|
45
|
-
# You may specify whether connection to slave is permitted.
|
46
|
-
# In all cases, the default host is "localhost" and the default port is 27017.
|
47
|
-
#
|
48
|
-
# If you're connecting to a replica set, you'll need to use ReplSetConnection.new instead.
|
49
|
-
#
|
50
|
-
# Once connected to a replica set, you can find out which nodes are primary, secondary, and
|
51
|
-
# arbiters with the corresponding accessors: Connection#primary, Connection#secondaries, and
|
52
|
-
# Connection#arbiters. This is useful if your application needs to connect manually to nodes other
|
53
|
-
# than the primary.
|
54
|
-
#
|
55
|
-
# @param [String, Hash] host.
|
56
|
-
# @param [Integer] port specify a port number here if only one host is being specified.
|
57
|
-
#
|
58
|
-
# @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
|
59
|
-
# propogated to DB objects instantiated off of this Connection. This
|
60
|
-
# default can be overridden upon instantiation of any DB by explicity setting a :safe value
|
61
|
-
# on initialization.
|
62
|
-
# @option opts [Boolean] :slave_ok (false) Must be set to +true+ when connecting
|
63
|
-
# to a single, slave node.
|
64
|
-
# @option opts [Logger, #debug] :logger (nil) A Logger instance for debugging driver ops. Note that
|
65
|
-
# logging negatively impacts performance; therefore, it should not be used for high-performance apps.
|
66
|
-
# @option opts [Integer] :pool_size (1) The maximum number of socket connections allowed per
|
67
|
-
# connection pool. Note: this setting is relevant only for multi-threaded applications.
|
68
|
-
# @option opts [Float] :timeout (5.0) When all of the connections a pool are checked out,
|
69
|
-
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
70
|
-
# Note: this setting is relevant only for multi-threaded applications (which in Ruby are rare).
|
71
|
-
# @option opts [Float] :op_timeout (nil) The number of seconds to wait for a read operation to time out.
|
72
|
-
# Disabled by default.
|
73
|
-
#
|
74
|
-
# @example localhost, 27017
|
75
|
-
# Connection.new
|
76
|
-
#
|
77
|
-
# @example localhost, 27017
|
78
|
-
# Connection.new("localhost")
|
79
|
-
#
|
80
|
-
# @example localhost, 3000, max 5 connections, with max 5 seconds of wait time.
|
81
|
-
# Connection.new("localhost", 3000, :pool_size => 5, :timeout => 5)
|
82
|
-
#
|
83
|
-
# @example localhost, 3000, where this node may be a slave
|
84
|
-
# Connection.new("localhost", 3000, :slave_ok => true)
|
85
|
-
#
|
86
|
-
# @see http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby
|
87
|
-
#
|
88
|
-
# @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
|
89
|
-
# driver fails to connect to a replica set with that name.
|
90
|
-
#
|
91
|
-
# @core connections
|
92
|
-
def initialize(host=nil, port=nil, opts={})
|
93
|
-
@host_to_try = format_pair(host, port)
|
94
|
-
|
95
|
-
# Host and port of current master.
|
96
|
-
@host = @port = nil
|
97
|
-
|
98
|
-
# slave_ok can be true only if one node is specified
|
99
|
-
@slave_ok = opts[:slave_ok]
|
100
|
-
|
101
|
-
setup(opts)
|
102
|
-
end
|
103
|
-
|
104
|
-
# DEPRECATED
|
105
|
-
#
|
106
|
-
# Initialize a connection to a MongoDB replica set using an array of seed nodes.
|
107
|
-
#
|
108
|
-
# The seed nodes specified will be used on the initial connection to the replica set, but note
|
109
|
-
# that this list of nodes will be replced by the list of canonical nodes returned by running the
|
110
|
-
# is_master command on the replica set.
|
111
|
-
#
|
112
|
-
# @param nodes [Array] An array of arrays, each of which specifies a host and port.
|
113
|
-
# @param opts [Hash] Any of the available options that can be passed to Connection.new.
|
114
|
-
#
|
115
|
-
# @option opts [String] :rs_name (nil) The name of the replica set to connect to. An exception will be
|
116
|
-
# raised if unable to connect to a replica set with this name.
|
117
|
-
# @option opts [Boolean] :read_secondary (false) When true, this connection object will pick a random slave
|
118
|
-
# to send reads to.
|
119
|
-
#
|
120
|
-
# @example
|
121
|
-
# Connection.multi([["db1.example.com", 27017], ["db2.example.com", 27017]])
|
122
|
-
#
|
123
|
-
# @example This connection will read from a random secondary node.
|
124
|
-
# Connection.multi([["db1.example.com", 27017], ["db2.example.com", 27017], ["db3.example.com", 27017]],
|
125
|
-
# :read_secondary => true)
|
126
|
-
#
|
127
|
-
# @return [Mongo::Connection]
|
128
|
-
#
|
129
|
-
# @deprecated
|
130
|
-
def self.multi(nodes, opts={})
|
131
|
-
warn "Connection.multi is now deprecated. Please use ReplSetConnection.new instead."
|
132
|
-
|
133
|
-
nodes << opts
|
134
|
-
ReplSetConnection.new(*nodes)
|
135
|
-
end
|
136
|
-
|
137
|
-
# Initialize a connection to MongoDB using the MongoDB URI spec:
|
138
|
-
#
|
139
|
-
# @param uri [String]
|
140
|
-
# A string of the format mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]
|
141
|
-
#
|
142
|
-
# @param opts Any of the options available for Connection.new
|
143
|
-
#
|
144
|
-
# @return [Mongo::Connection, Mongo::ReplSetConnection]
|
145
|
-
def self.from_uri(string, extra_opts={})
|
146
|
-
uri = URIParser.new(string)
|
147
|
-
opts = uri.connection_options
|
148
|
-
opts.merge!(extra_opts)
|
149
|
-
|
150
|
-
if uri.nodes.length == 1
|
151
|
-
opts.merge!({:auths => uri.auths})
|
152
|
-
Connection.new(uri.nodes[0][0], uri.nodes[0][1], opts)
|
153
|
-
elsif uri.nodes.length > 1
|
154
|
-
nodes = uri.nodes.clone
|
155
|
-
nodes_with_opts = nodes << opts
|
156
|
-
ReplSetConnection.new(*nodes_with_opts)
|
157
|
-
else
|
158
|
-
raise MongoArgumentError, "No nodes specified. Please ensure that you've provided at least one node."
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
# The host name used for this connection.
|
163
|
-
#
|
164
|
-
# @return [String]
|
165
|
-
def host
|
166
|
-
@primary_pool.host
|
167
|
-
end
|
168
|
-
|
169
|
-
# The port used for this connection.
|
170
|
-
#
|
171
|
-
# @return [Integer]
|
172
|
-
def port
|
173
|
-
@primary_pool.port
|
174
|
-
end
|
175
|
-
|
176
|
-
# Fsync, then lock the mongod process against writes. Use this to get
|
177
|
-
# the datafiles in a state safe for snapshotting, backing up, etc.
|
178
|
-
#
|
179
|
-
# @return [BSON::OrderedHash] the command response
|
180
|
-
def lock!
|
181
|
-
cmd = BSON::OrderedHash.new
|
182
|
-
cmd[:fsync] = 1
|
183
|
-
cmd[:lock] = true
|
184
|
-
self['admin'].command(cmd)
|
185
|
-
end
|
186
|
-
|
187
|
-
# Is this database locked against writes?
|
188
|
-
#
|
189
|
-
# @return [Boolean]
|
190
|
-
def locked?
|
191
|
-
self['admin']['$cmd.sys.inprog'].find_one['fsyncLock'] == 1
|
192
|
-
end
|
193
|
-
|
194
|
-
# Unlock a previously fsync-locked mongod process.
|
195
|
-
#
|
196
|
-
# @return [BSON::OrderedHash] command response
|
197
|
-
def unlock!
|
198
|
-
self['admin']['$cmd.sys.unlock'].find_one
|
199
|
-
end
|
200
|
-
|
201
|
-
# Apply each of the saved database authentications.
|
202
|
-
#
|
203
|
-
# @return [Boolean] returns true if authentications exist and succeeed, false
|
204
|
-
# if none exists.
|
205
|
-
#
|
206
|
-
# @raise [AuthenticationError] raises an exception if any one
|
207
|
-
# authentication fails.
|
208
|
-
def apply_saved_authentication(opts={})
|
209
|
-
return false if @auths.empty?
|
210
|
-
@auths.each do |auth|
|
211
|
-
self[auth['db_name']].issue_authentication(auth['username'], auth['password'], false,
|
212
|
-
:socket => opts[:socket])
|
213
|
-
end
|
214
|
-
true
|
215
|
-
end
|
216
|
-
|
217
|
-
# Save an authentication to this connection. When connecting,
|
218
|
-
# the connection will attempt to re-authenticate on every db
|
219
|
-
# specificed in the list of auths. This method is called automatically
|
220
|
-
# by DB#authenticate.
|
221
|
-
#
|
222
|
-
# Note: this method will not actually issue an authentication command. To do that,
|
223
|
-
# either run Connection#apply_saved_authentication or DB#authenticate.
|
224
|
-
#
|
225
|
-
# @param [String] db_name
|
226
|
-
# @param [String] username
|
227
|
-
# @param [String] password
|
228
|
-
#
|
229
|
-
# @return [Hash] a hash representing the authentication just added.
|
230
|
-
def add_auth(db_name, username, password)
|
231
|
-
remove_auth(db_name)
|
232
|
-
auth = {}
|
233
|
-
auth['db_name'] = db_name
|
234
|
-
auth['username'] = username
|
235
|
-
auth['password'] = password
|
236
|
-
@auths << auth
|
237
|
-
auth
|
238
|
-
end
|
239
|
-
|
240
|
-
# Remove a saved authentication for this connection.
|
241
|
-
#
|
242
|
-
# @param [String] db_name
|
243
|
-
#
|
244
|
-
# @return [Boolean]
|
245
|
-
def remove_auth(db_name)
|
246
|
-
return unless @auths
|
247
|
-
if @auths.reject! { |a| a['db_name'] == db_name }
|
248
|
-
true
|
249
|
-
else
|
250
|
-
false
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
# Remove all authenication information stored in this connection.
|
255
|
-
#
|
256
|
-
# @return [true] this operation return true because it always succeeds.
|
257
|
-
def clear_auths
|
258
|
-
@auths = []
|
259
|
-
true
|
260
|
-
end
|
261
|
-
|
262
|
-
def authenticate_pools
|
263
|
-
@primary_pool.authenticate_existing
|
264
|
-
end
|
265
|
-
|
266
|
-
def logout_pools(db)
|
267
|
-
@primary_pool.logout_existing(db)
|
268
|
-
end
|
269
|
-
|
270
|
-
# Return a hash with all database names
|
271
|
-
# and their respective sizes on disk.
|
272
|
-
#
|
273
|
-
# @return [Hash]
|
274
|
-
def database_info
|
275
|
-
doc = self['admin'].command({:listDatabases => 1})
|
276
|
-
doc['databases'].each_with_object({}) do |db, info|
|
277
|
-
info[db['name']] = db['sizeOnDisk'].to_i
|
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 [String] db_name a valid database name.
|
292
|
-
# @param [Hash] opts options to be passed to the DB constructor.
|
293
|
-
#
|
294
|
-
# @return [Mongo::DB]
|
295
|
-
#
|
296
|
-
# @core databases db-instance_method
|
297
|
-
def db(db_name, opts={})
|
298
|
-
DB.new(db_name, self, opts)
|
299
|
-
end
|
300
|
-
|
301
|
-
# Shortcut for returning a database. Use DB#db to accept options.
|
302
|
-
#
|
303
|
-
# @param [String] db_name a valid database name.
|
304
|
-
#
|
305
|
-
# @return [Mongo::DB]
|
306
|
-
#
|
307
|
-
# @core databases []-instance_method
|
308
|
-
def [](db_name)
|
309
|
-
DB.new(db_name, self, :safe => @safe)
|
310
|
-
end
|
311
|
-
|
312
|
-
# Drop a database.
|
313
|
-
#
|
314
|
-
# @param [String] name name of an existing database.
|
315
|
-
def drop_database(name)
|
316
|
-
self[name].command(:dropDatabase => 1)
|
317
|
-
end
|
318
|
-
|
319
|
-
# Copy the database +from+ to +to+ on localhost. The +from+ database is
|
320
|
-
# assumed to be on localhost, but an alternate host can be specified.
|
321
|
-
#
|
322
|
-
# @param [String] from name of the database to copy from.
|
323
|
-
# @param [String] to name of the database to copy to.
|
324
|
-
# @param [String] from_host host of the 'from' database.
|
325
|
-
# @param [String] username username for authentication against from_db (>=1.3.x).
|
326
|
-
# @param [String] password password for authentication against from_db (>=1.3.x).
|
327
|
-
def copy_database(from, to, from_host="localhost", username=nil, password=nil)
|
328
|
-
oh = BSON::OrderedHash.new
|
329
|
-
oh[:copydb] = 1
|
330
|
-
oh[:fromhost] = from_host
|
331
|
-
oh[:fromdb] = from
|
332
|
-
oh[:todb] = to
|
333
|
-
if username || password
|
334
|
-
unless username && password
|
335
|
-
raise MongoArgumentError, "Both username and password must be supplied for authentication."
|
336
|
-
end
|
337
|
-
nonce_cmd = BSON::OrderedHash.new
|
338
|
-
nonce_cmd[:copydbgetnonce] = 1
|
339
|
-
nonce_cmd[:fromhost] = from_host
|
340
|
-
result = self["admin"].command(nonce_cmd)
|
341
|
-
oh[:nonce] = result["nonce"]
|
342
|
-
oh[:username] = username
|
343
|
-
oh[:key] = Mongo::Support.auth_key(username, password, oh[:nonce])
|
344
|
-
end
|
345
|
-
self["admin"].command(oh)
|
346
|
-
end
|
347
|
-
|
348
|
-
# Checks if a server is alive. This command will return immediately
|
349
|
-
# even if the server is in a lock.
|
350
|
-
#
|
351
|
-
# @return [Hash]
|
352
|
-
def ping
|
353
|
-
self["admin"].command({:ping => 1})
|
354
|
-
end
|
355
|
-
|
356
|
-
# Get the build information for the current connection.
|
357
|
-
#
|
358
|
-
# @return [Hash]
|
359
|
-
def server_info
|
360
|
-
self["admin"].command({:buildinfo => 1})
|
361
|
-
end
|
362
|
-
|
363
|
-
|
364
|
-
# Get the build version of the current server.
|
365
|
-
#
|
366
|
-
# @return [Mongo::ServerVersion]
|
367
|
-
# object allowing easy comparability of version.
|
368
|
-
def server_version
|
369
|
-
ServerVersion.new(server_info["version"])
|
370
|
-
end
|
371
|
-
|
372
|
-
# Is it okay to connect to a slave?
|
373
|
-
#
|
374
|
-
# @return [Boolean]
|
375
|
-
def slave_ok?
|
376
|
-
@slave_ok
|
377
|
-
end
|
378
|
-
|
379
|
-
# Send a message to MongoDB, adding the necessary headers.
|
380
|
-
#
|
381
|
-
# @param [Integer] operation a MongoDB opcode.
|
382
|
-
# @param [BSON::ByteBuffer] message a message to send to the database.
|
383
|
-
#
|
384
|
-
# @return [Integer] number of bytes sent
|
385
|
-
def send_message(operation, message, log_message=nil)
|
386
|
-
begin
|
387
|
-
add_message_headers(message, operation)
|
388
|
-
packed_message = message.to_s
|
389
|
-
socket = checkout_writer
|
390
|
-
send_message_on_socket(packed_message, socket)
|
391
|
-
ensure
|
392
|
-
checkin_writer(socket)
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
|
-
# Sends a message to the database, waits for a response, and raises
|
397
|
-
# an exception if the operation has failed.
|
398
|
-
#
|
399
|
-
# @param [Integer] operation a MongoDB opcode.
|
400
|
-
# @param [BSON::ByteBuffer] message a message to send to the database.
|
401
|
-
# @param [String] db_name the name of the database. used on call to get_last_error.
|
402
|
-
# @param [Hash] last_error_params parameters to be sent to getLastError. See DB#error for
|
403
|
-
# available options.
|
404
|
-
#
|
405
|
-
# @see DB#get_last_error for valid last error params.
|
406
|
-
#
|
407
|
-
# @return [Hash] The document returned by the call to getlasterror.
|
408
|
-
def send_message_with_safe_check(operation, message, db_name, log_message=nil, last_error_params=false)
|
409
|
-
docs = num_received = cursor_id = ''
|
410
|
-
add_message_headers(message, operation)
|
411
|
-
|
412
|
-
last_error_message = BSON::ByteBuffer.new
|
413
|
-
build_last_error_message(last_error_message, db_name, last_error_params)
|
414
|
-
last_error_id = add_message_headers(last_error_message, Mongo::Constants::OP_QUERY)
|
415
|
-
|
416
|
-
packed_message = message.append!(last_error_message).to_s
|
417
|
-
begin
|
418
|
-
sock = checkout_writer
|
419
|
-
@safe_mutexes[sock].synchronize do
|
420
|
-
send_message_on_socket(packed_message, sock)
|
421
|
-
docs, num_received, cursor_id = receive(sock, last_error_id)
|
422
|
-
end
|
423
|
-
ensure
|
424
|
-
checkin_writer(sock)
|
425
|
-
end
|
426
|
-
|
427
|
-
if num_received == 1 && (error = docs[0]['err'] || docs[0]['errmsg'])
|
428
|
-
close if error == "not master"
|
429
|
-
error = "wtimeout" if error == "timeout"
|
430
|
-
raise Mongo::OperationFailure, docs[0]['code'].to_s + ': ' + error
|
431
|
-
end
|
432
|
-
|
433
|
-
docs[0]
|
434
|
-
end
|
435
|
-
|
436
|
-
# Sends a message to the database and waits for the response.
|
437
|
-
#
|
438
|
-
# @param [Integer] operation a MongoDB opcode.
|
439
|
-
# @param [BSON::ByteBuffer] message a message to send to the database.
|
440
|
-
# @param [Socket] socket a socket to use in lieu of checking out a new one.
|
441
|
-
#
|
442
|
-
# @return [Array]
|
443
|
-
# An array whose indexes include [0] documents returned, [1] number of document received,
|
444
|
-
# and [3] a cursor_id.
|
445
|
-
def receive_message(operation, message, log_message=nil, socket=nil, command=false)
|
446
|
-
request_id = add_message_headers(message, operation)
|
447
|
-
packed_message = message.to_s
|
448
|
-
begin
|
449
|
-
if socket
|
450
|
-
sock = socket
|
451
|
-
checkin = false
|
452
|
-
else
|
453
|
-
sock = (command ? checkout_writer : checkout_reader)
|
454
|
-
checkin = true
|
455
|
-
end
|
456
|
-
|
457
|
-
result = ''
|
458
|
-
@safe_mutexes[sock].synchronize do
|
459
|
-
send_message_on_socket(packed_message, sock)
|
460
|
-
result = receive(sock, request_id)
|
461
|
-
end
|
462
|
-
ensure
|
463
|
-
if checkin
|
464
|
-
command ? checkin_writer(sock) : checkin_reader(sock)
|
465
|
-
end
|
466
|
-
end
|
467
|
-
result
|
468
|
-
end
|
469
|
-
|
470
|
-
# Create a new socket and attempt to connect to master.
|
471
|
-
# If successful, sets host and port to master and returns the socket.
|
472
|
-
#
|
473
|
-
# If connecting to a replica set, this method will replace the
|
474
|
-
# initially-provided seed list with any nodes known to the set.
|
475
|
-
#
|
476
|
-
# @raise [ConnectionFailure] if unable to connect to any host or port.
|
477
|
-
def connect
|
478
|
-
close
|
479
|
-
|
480
|
-
config = check_is_master(@host_to_try)
|
481
|
-
if config
|
482
|
-
if config['ismaster'] == 1 || config['ismaster'] == true
|
483
|
-
@read_primary = true
|
484
|
-
elsif @slave_ok
|
485
|
-
@read_primary = false
|
486
|
-
end
|
487
|
-
|
488
|
-
set_primary(@host_to_try)
|
489
|
-
end
|
490
|
-
|
491
|
-
if connected?
|
492
|
-
BSON::BSON_CODER.update_max_bson_size(self)
|
493
|
-
else
|
494
|
-
raise ConnectionFailure, "Failed to connect to a master node at #{@host_to_try[0]}:#{@host_to_try[1]}"
|
495
|
-
end
|
496
|
-
end
|
497
|
-
alias :reconnect :connect
|
498
|
-
|
499
|
-
def connecting?
|
500
|
-
@nodes_to_try.length > 0
|
501
|
-
end
|
502
|
-
|
503
|
-
# It's possible that we defined connected as all nodes being connected???
|
504
|
-
# NOTE: Do check if this needs to be more stringent.
|
505
|
-
# Probably not since if any node raises a connection failure, all nodes will be closed.
|
506
|
-
def connected?
|
507
|
-
@primary_pool && @primary_pool.host && @primary_pool.port
|
508
|
-
end
|
509
|
-
|
510
|
-
# Determine if the connection is active. In a normal case the *server_info* operation
|
511
|
-
# will be performed without issues, but if the connection was dropped by the server or
|
512
|
-
# for some reason the sockets are unsynchronized, a ConnectionFailure will be raised and
|
513
|
-
# the return will be false.
|
514
|
-
#
|
515
|
-
# @return [Boolean]
|
516
|
-
def active?
|
517
|
-
return false unless connected?
|
518
|
-
|
519
|
-
ping
|
520
|
-
true
|
521
|
-
|
522
|
-
rescue ConnectionFailure
|
523
|
-
false
|
524
|
-
end
|
525
|
-
|
526
|
-
# Determine whether we're reading from a primary node. If false,
|
527
|
-
# this connection connects to a secondary node and @slave_ok is true.
|
528
|
-
#
|
529
|
-
# @return [Boolean]
|
530
|
-
def read_primary?
|
531
|
-
@read_primary
|
532
|
-
end
|
533
|
-
alias :primary? :read_primary?
|
534
|
-
|
535
|
-
# Close the connection to the database.
|
536
|
-
def close
|
537
|
-
@primary_pool.close if @primary_pool
|
538
|
-
@primary_pool = nil
|
539
|
-
@primary = nil
|
540
|
-
end
|
541
|
-
|
542
|
-
# Returns the maximum BSON object size as returned by the core server.
|
543
|
-
# Use the 4MB default when the server doesn't report this.
|
544
|
-
#
|
545
|
-
# @return [Integer]
|
546
|
-
def max_bson_size
|
547
|
-
config = self['admin'].command({:ismaster => 1})
|
548
|
-
config['maxBsonObjectSize'] || Mongo::DEFAULT_MAX_BSON_SIZE
|
549
|
-
end
|
550
|
-
|
551
|
-
# Checkout a socket for reading (i.e., a secondary node).
|
552
|
-
# Note: this is overridden in ReplSetConnection.
|
553
|
-
def checkout_reader
|
554
|
-
connect unless connected?
|
555
|
-
@primary_pool.checkout
|
556
|
-
end
|
557
|
-
|
558
|
-
# Checkout a socket for writing (i.e., a primary node).
|
559
|
-
# Note: this is overridden in ReplSetConnection.
|
560
|
-
def checkout_writer
|
561
|
-
connect unless connected?
|
562
|
-
@primary_pool.checkout
|
563
|
-
end
|
564
|
-
|
565
|
-
# Checkin a socket used for reading.
|
566
|
-
# Note: this is overridden in ReplSetConnection.
|
567
|
-
def checkin_reader(socket)
|
568
|
-
if @primary_pool
|
569
|
-
@primary_pool.checkin(socket)
|
570
|
-
end
|
571
|
-
end
|
572
|
-
|
573
|
-
# Checkin a socket used for writing.
|
574
|
-
# Note: this is overridden in ReplSetConnection.
|
575
|
-
def checkin_writer(socket)
|
576
|
-
if @primary_pool
|
577
|
-
@primary_pool.checkin(socket)
|
578
|
-
end
|
579
|
-
end
|
580
|
-
|
581
|
-
# Execute the block and log the operation described by name
|
582
|
-
# and payload.
|
583
|
-
# TODO: Not sure if this should take a block.
|
584
|
-
def instrument(name, payload = {}, &blk)
|
585
|
-
res = yield
|
586
|
-
log_operation(name, payload)
|
587
|
-
res
|
588
|
-
end
|
589
|
-
|
590
|
-
protected
|
591
|
-
|
592
|
-
# Generic initialization code.
|
593
|
-
def setup(opts)
|
594
|
-
# Authentication objects
|
595
|
-
@auths = opts.fetch(:auths, [])
|
596
|
-
|
597
|
-
# Lock for request ids.
|
598
|
-
@id_lock = Mutex.new
|
599
|
-
|
600
|
-
# Pool size and timeout.
|
601
|
-
@pool_size = opts[:pool_size] || 1
|
602
|
-
@timeout = opts[:timeout] || 5.0
|
603
|
-
|
604
|
-
# Timeout on socket read operation.
|
605
|
-
@op_timeout = opts[:op_timeout] || nil
|
606
|
-
|
607
|
-
# Mutex for synchronizing pool access
|
608
|
-
@connection_mutex = Mutex.new
|
609
|
-
|
610
|
-
# Global safe option. This is false by default.
|
611
|
-
@safe = opts[:safe] || false
|
612
|
-
|
613
|
-
# Create a mutex when a new key, in this case a socket,
|
614
|
-
# is added to the hash.
|
615
|
-
@safe_mutexes = Hash.new { |h, k| h[k] = Mutex.new }
|
616
|
-
|
617
|
-
# Condition variable for signal and wait
|
618
|
-
@queue = ConditionVariable.new
|
619
|
-
|
620
|
-
# Connection pool for primay node
|
621
|
-
@primary = nil
|
622
|
-
@primary_pool = nil
|
623
|
-
|
624
|
-
@logger = opts[:logger] || nil
|
625
|
-
|
626
|
-
if @logger
|
627
|
-
@logger.debug("MongoDB logging. Please note that logging negatively impacts performance " +
|
628
|
-
"and should be disabled for high-performance production apps.")
|
629
|
-
end
|
630
|
-
|
631
|
-
should_connect = opts.fetch(:connect, true)
|
632
|
-
connect if should_connect
|
633
|
-
end
|
634
|
-
|
635
|
-
## Configuration helper methods
|
636
|
-
|
637
|
-
# Returns a host-port pair.
|
638
|
-
#
|
639
|
-
# @return [Array]
|
640
|
-
#
|
641
|
-
# @private
|
642
|
-
def format_pair(host, port)
|
643
|
-
case host
|
644
|
-
when String
|
645
|
-
[host, port ? port.to_i : DEFAULT_PORT]
|
646
|
-
when nil
|
647
|
-
['localhost', DEFAULT_PORT]
|
648
|
-
end
|
649
|
-
end
|
650
|
-
|
651
|
-
## Logging methods
|
652
|
-
|
653
|
-
def log_operation(name, payload)
|
654
|
-
return unless @logger
|
655
|
-
msg = "#{payload[:database]}['#{payload[:collection]}'].#{name}("
|
656
|
-
msg += payload.values_at(:selector, :document, :documents, :fields ).compact.map(&:inspect).join(', ') + ")"
|
657
|
-
msg += ".skip(#{payload[:skip]})" if payload[:skip]
|
658
|
-
msg += ".limit(#{payload[:limit]})" if payload[:limit]
|
659
|
-
msg += ".sort(#{payload[:order]})" if payload[:order]
|
660
|
-
@logger.debug "MONGODB #{msg}"
|
661
|
-
end
|
662
|
-
|
663
|
-
private
|
664
|
-
|
665
|
-
## Methods for establishing a connection:
|
666
|
-
|
667
|
-
# If a ConnectionFailure is raised, this method will be called
|
668
|
-
# to close the connection and reset connection values.
|
669
|
-
# TODO: evaluate whether this method is actually necessary
|
670
|
-
def reset_connection
|
671
|
-
close
|
672
|
-
end
|
673
|
-
|
674
|
-
def check_is_master(node)
|
675
|
-
begin
|
676
|
-
host, port = *node
|
677
|
-
socket = TCPSocket.new(host, port)
|
678
|
-
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
679
|
-
|
680
|
-
config = self['admin'].command({:ismaster => 1}, :socket => socket)
|
681
|
-
rescue OperationFailure, SocketError, SystemCallError, IOError => ex
|
682
|
-
close
|
683
|
-
ensure
|
684
|
-
socket.close if socket
|
685
|
-
end
|
686
|
-
|
687
|
-
config
|
688
|
-
end
|
689
|
-
|
690
|
-
# Set the specified node as primary.
|
691
|
-
def set_primary(node)
|
692
|
-
host, port = *node
|
693
|
-
@primary = [host, port]
|
694
|
-
@primary_pool = Pool.new(self, host, port, :size => @pool_size, :timeout => @timeout)
|
695
|
-
end
|
696
|
-
|
697
|
-
## Low-level connection methods.
|
698
|
-
|
699
|
-
def receive(sock, expected_response)
|
700
|
-
begin
|
701
|
-
receive_header(sock, expected_response)
|
702
|
-
number_received, cursor_id = receive_response_header(sock)
|
703
|
-
read_documents(number_received, cursor_id, sock)
|
704
|
-
rescue Mongo::ConnectionFailure => ex
|
705
|
-
close
|
706
|
-
raise ex
|
707
|
-
end
|
708
|
-
end
|
709
|
-
|
710
|
-
def receive_header(sock, expected_response)
|
711
|
-
header = receive_message_on_socket(16, sock)
|
712
|
-
size, request_id, response_to = header.unpack('VVV')
|
713
|
-
if expected_response != response_to
|
714
|
-
raise Mongo::ConnectionFailure, "Expected response #{expected_response} but got #{response_to}"
|
715
|
-
end
|
716
|
-
|
717
|
-
unless header.size == STANDARD_HEADER_SIZE
|
718
|
-
raise "Short read for DB response header: " +
|
719
|
-
"expected #{STANDARD_HEADER_SIZE} bytes, saw #{header.size}"
|
720
|
-
end
|
721
|
-
nil
|
722
|
-
end
|
723
|
-
|
724
|
-
def receive_response_header(sock)
|
725
|
-
header_buf = receive_message_on_socket(RESPONSE_HEADER_SIZE, sock)
|
726
|
-
if header_buf.length != RESPONSE_HEADER_SIZE
|
727
|
-
raise "Short read for DB response header; " +
|
728
|
-
"expected #{RESPONSE_HEADER_SIZE} bytes, saw #{header_buf.length}"
|
729
|
-
end
|
730
|
-
flags, cursor_id_a, cursor_id_b, starting_from, number_remaining = header_buf.unpack('VVVVV')
|
731
|
-
check_response_flags(flags)
|
732
|
-
cursor_id = (cursor_id_b << 32) + cursor_id_a
|
733
|
-
[number_remaining, cursor_id]
|
734
|
-
end
|
735
|
-
|
736
|
-
def check_response_flags(flags)
|
737
|
-
if flags & Mongo::Constants::REPLY_CURSOR_NOT_FOUND != 0
|
738
|
-
raise Mongo::OperationFailure, "Query response returned CURSOR_NOT_FOUND. " +
|
739
|
-
"Either an invalid cursor was specified, or the cursor may have timed out on the server."
|
740
|
-
elsif flags & Mongo::Constants::REPLY_QUERY_FAILURE != 0
|
741
|
-
# Getting odd failures when a exception is raised here.
|
742
|
-
end
|
743
|
-
end
|
744
|
-
|
745
|
-
def read_documents(number_received, cursor_id, sock)
|
746
|
-
docs = []
|
747
|
-
number_remaining = number_received
|
748
|
-
while number_remaining > 0 do
|
749
|
-
buf = receive_message_on_socket(4, sock)
|
750
|
-
size = buf.unpack('V')[0]
|
751
|
-
buf << receive_message_on_socket(size - 4, sock)
|
752
|
-
number_remaining -= 1
|
753
|
-
docs << BSON::BSON_CODER.deserialize(buf)
|
754
|
-
end
|
755
|
-
[docs, number_received, cursor_id]
|
756
|
-
end
|
757
|
-
|
758
|
-
# Constructs a getlasterror message. This method is used exclusively by
|
759
|
-
# Connection#send_message_with_safe_check.
|
760
|
-
#
|
761
|
-
# Because it modifies message by reference, we don't need to return it.
|
762
|
-
def build_last_error_message(message, db_name, opts)
|
763
|
-
message.put_int(0)
|
764
|
-
BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.$cmd")
|
765
|
-
message.put_int(0)
|
766
|
-
message.put_int(-1)
|
767
|
-
cmd = BSON::OrderedHash.new
|
768
|
-
cmd[:getlasterror] = 1
|
769
|
-
if opts.is_a?(Hash)
|
770
|
-
opts.assert_valid_keys(:w, :wtimeout, :fsync)
|
771
|
-
cmd.merge!(opts)
|
772
|
-
end
|
773
|
-
message.put_binary(BSON::BSON_CODER.serialize(cmd, false).to_s)
|
774
|
-
nil
|
775
|
-
end
|
776
|
-
|
777
|
-
# Prepares a message for transmission to MongoDB by
|
778
|
-
# constructing a valid message header.
|
779
|
-
#
|
780
|
-
# Note: this method modifies message by reference.
|
781
|
-
#
|
782
|
-
# @return [Integer] the request id used in the header
|
783
|
-
def add_message_headers(message, operation)
|
784
|
-
headers = [
|
785
|
-
# Message size.
|
786
|
-
16 + message.size,
|
787
|
-
|
788
|
-
# Unique request id.
|
789
|
-
request_id = get_request_id,
|
790
|
-
|
791
|
-
# Response id.
|
792
|
-
0,
|
793
|
-
|
794
|
-
# Opcode.
|
795
|
-
operation
|
796
|
-
].pack('VVVV')
|
797
|
-
|
798
|
-
message.prepend!(headers)
|
799
|
-
|
800
|
-
request_id
|
801
|
-
end
|
802
|
-
|
803
|
-
# Increment and return the next available request id.
|
804
|
-
#
|
805
|
-
# return [Integer]
|
806
|
-
def get_request_id
|
807
|
-
request_id = ''
|
808
|
-
@id_lock.synchronize do
|
809
|
-
request_id = @@current_request_id += 1
|
810
|
-
end
|
811
|
-
request_id
|
812
|
-
end
|
813
|
-
|
814
|
-
# Low-level method for sending a message on a socket.
|
815
|
-
# Requires a packed message and an available socket,
|
816
|
-
#
|
817
|
-
# @return [Integer] number of bytes sent
|
818
|
-
def send_message_on_socket(packed_message, socket)
|
819
|
-
begin
|
820
|
-
total_bytes_sent = socket.send(packed_message, 0)
|
821
|
-
if total_bytes_sent != packed_message.size
|
822
|
-
packed_message.slice!(0, total_bytes_sent)
|
823
|
-
while packed_message.size > 0
|
824
|
-
byte_sent = socket.send(packed_message, 0)
|
825
|
-
total_bytes_sent += byte_sent
|
826
|
-
packed_message.slice!(0, byte_sent)
|
827
|
-
end
|
828
|
-
end
|
829
|
-
total_bytes_sent
|
830
|
-
rescue => ex
|
831
|
-
close
|
832
|
-
raise ConnectionFailure, "Operation failed with the following exception: #{ex}"
|
833
|
-
end
|
834
|
-
end
|
835
|
-
|
836
|
-
# Low-level method for receiving data from socket.
|
837
|
-
# Requires length and an available socket.
|
838
|
-
def receive_message_on_socket(length, socket)
|
839
|
-
begin
|
840
|
-
if @op_timeout
|
841
|
-
message = nil
|
842
|
-
Mongo::TimeoutHandler.timeout(@op_timeout, OperationTimeout) do
|
843
|
-
message = receive_data(length, socket)
|
844
|
-
end
|
845
|
-
else
|
846
|
-
message = receive_data(length, socket)
|
847
|
-
end
|
848
|
-
rescue => ex
|
849
|
-
close
|
850
|
-
|
851
|
-
if ex.class == OperationTimeout
|
852
|
-
raise OperationTimeout, "Timed out waiting on socket read."
|
853
|
-
else
|
854
|
-
raise ConnectionFailure, "Operation failed with the following exception: #{ex}"
|
855
|
-
end
|
856
|
-
end
|
857
|
-
message
|
858
|
-
end
|
859
|
-
|
860
|
-
def receive_data(length, socket)
|
861
|
-
message = new_binary_string
|
862
|
-
socket.read(length, message)
|
863
|
-
raise ConnectionFailure, "connection closed" unless message && message.length > 0
|
864
|
-
if message.length < length
|
865
|
-
chunk = new_binary_string
|
866
|
-
while message.length < length
|
867
|
-
socket.read(length - message.length, chunk)
|
868
|
-
raise ConnectionFailure, "connection closed" unless chunk.length > 0
|
869
|
-
message << chunk
|
870
|
-
end
|
871
|
-
end
|
872
|
-
message
|
873
|
-
end
|
874
|
-
|
875
|
-
if defined?(Encoding)
|
876
|
-
BINARY_ENCODING = Encoding.find("binary")
|
877
14
|
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
""
|
884
|
-
end
|
885
|
-
end
|
886
|
-
end
|
887
|
-
end
|
15
|
+
require 'mongo/connection/socket'
|
16
|
+
require 'mongo/connection/node'
|
17
|
+
require 'mongo/connection/pool'
|
18
|
+
require 'mongo/connection/pool_manager'
|
19
|
+
require 'mongo/connection/sharding_pool_manager'
|