mongo 1.1.5 → 1.3.0
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.
- data/README.md +15 -15
- data/Rakefile +38 -17
- data/docs/FAQ.md +4 -0
- data/docs/HISTORY.md +59 -0
- data/docs/RELEASES.md +33 -0
- data/docs/REPLICA_SETS.md +13 -16
- data/lib/mongo/collection.rb +157 -69
- data/lib/mongo/connection.rb +189 -65
- data/lib/mongo/cursor.rb +43 -29
- data/lib/mongo/db.rb +63 -43
- data/lib/mongo/exceptions.rb +4 -1
- data/lib/mongo/gridfs/grid.rb +1 -1
- data/lib/mongo/gridfs/grid_ext.rb +1 -1
- data/lib/mongo/gridfs/grid_file_system.rb +1 -1
- data/lib/mongo/gridfs/grid_io.rb +89 -8
- data/lib/mongo/gridfs/grid_io_fix.rb +1 -1
- data/lib/mongo/repl_set_connection.rb +72 -20
- data/lib/mongo/test.rb +20 -0
- data/lib/mongo/util/conversions.rb +1 -1
- data/lib/mongo/util/core_ext.rb +11 -1
- data/lib/mongo/util/pool.rb +67 -15
- data/lib/mongo/util/server_version.rb +1 -1
- data/lib/mongo/util/support.rb +1 -1
- data/lib/mongo/util/uri_parser.rb +127 -13
- data/lib/mongo.rb +38 -2
- data/test/async/collection_test.rb +224 -0
- data/test/async/connection_test.rb +24 -0
- data/test/async/cursor_test.rb +162 -0
- data/test/async/worker_pool_test.rb +99 -0
- data/test/auxillary/fork_test.rb +30 -0
- data/test/auxillary/repl_set_auth_test.rb +58 -0
- data/test/auxillary/threaded_authentication_test.rb +101 -0
- data/test/bson/bson_test.rb +140 -28
- data/test/bson/byte_buffer_test.rb +18 -0
- data/test/bson/object_id_test.rb +14 -1
- data/test/bson/ordered_hash_test.rb +7 -0
- data/test/bson/timestamp_test.rb +24 -0
- data/test/collection_test.rb +104 -15
- data/test/connection_test.rb +78 -2
- data/test/conversions_test.rb +10 -11
- data/test/cursor_fail_test.rb +1 -1
- data/test/cursor_message_test.rb +1 -1
- data/test/cursor_test.rb +33 -4
- data/test/db_api_test.rb +30 -52
- data/test/db_test.rb +3 -3
- data/test/grid_file_system_test.rb +0 -1
- data/test/grid_io_test.rb +72 -1
- data/test/grid_test.rb +16 -16
- data/test/load/resque/load.rb +21 -0
- data/test/load/resque/processor.rb +26 -0
- data/test/load/thin/load.rb +24 -0
- data/test/load/unicorn/load.rb +23 -0
- data/test/load/unicorn/unicorn.rb +29 -0
- data/test/replica_sets/connect_test.rb +11 -1
- data/test/replica_sets/connection_string_test.rb +32 -0
- data/test/replica_sets/query_secondaries.rb +16 -0
- data/test/replica_sets/query_test.rb +10 -0
- data/test/replica_sets/replication_ack_test.rb +2 -0
- data/test/replica_sets/rs_test_helper.rb +9 -11
- data/test/support/hash_with_indifferent_access.rb +0 -13
- data/test/support_test.rb +0 -1
- data/test/test_helper.rb +27 -8
- data/test/tools/auth_repl_set_manager.rb +14 -0
- data/test/tools/load.rb +58 -0
- data/test/tools/repl_set_manager.rb +34 -9
- data/test/tools/sharding_manager.rb +202 -0
- data/test/tools/test.rb +3 -12
- data/test/unit/collection_test.rb +20 -24
- data/test/unit/connection_test.rb +4 -18
- data/test/unit/cursor_test.rb +16 -6
- data/test/unit/db_test.rb +10 -11
- data/test/unit/repl_set_connection_test.rb +0 -23
- data/test/unit/safe_test.rb +3 -3
- data/test/uri_test.rb +91 -0
- metadata +49 -12
- data/docs/1.0_UPGRADE.md +0 -21
data/lib/mongo/connection.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# encoding: UTF-8
|
|
2
2
|
|
|
3
3
|
# --
|
|
4
|
-
# Copyright (C) 2008-
|
|
4
|
+
# Copyright (C) 2008-2011 10gen Inc.
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
7
|
# you may not use this file except in compliance with the License.
|
|
@@ -35,7 +35,7 @@ module Mongo
|
|
|
35
35
|
STANDARD_HEADER_SIZE = 16
|
|
36
36
|
RESPONSE_HEADER_SIZE = 20
|
|
37
37
|
|
|
38
|
-
attr_reader :logger, :size, :auths, :primary, :safe, :primary_pool, :host_to_try
|
|
38
|
+
attr_reader :logger, :size, :auths, :primary, :safe, :primary_pool, :host_to_try, :pool_size
|
|
39
39
|
|
|
40
40
|
# Counter for generating unique request ids.
|
|
41
41
|
@@current_request_id = 0
|
|
@@ -55,18 +55,21 @@ module Mongo
|
|
|
55
55
|
# @param [String, Hash] host.
|
|
56
56
|
# @param [Integer] port specify a port number here if only one host is being specified.
|
|
57
57
|
#
|
|
58
|
-
# @option
|
|
58
|
+
# @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
|
|
59
59
|
# propogated to DB objects instantiated off of this Connection. This
|
|
60
60
|
# default can be overridden upon instantiation of any DB by explicity setting a :safe value
|
|
61
61
|
# on initialization.
|
|
62
|
-
# @option
|
|
62
|
+
# @option opts [Boolean] :slave_ok (false) Must be set to +true+ when connecting
|
|
63
63
|
# to a single, slave node.
|
|
64
|
-
# @option
|
|
65
|
-
#
|
|
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
|
|
66
67
|
# connection pool. Note: this setting is relevant only for multi-threaded applications.
|
|
67
|
-
# @option
|
|
68
|
+
# @option opts [Float] :timeout (5.0) When all of the connections a pool are checked out,
|
|
68
69
|
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
|
69
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.
|
|
70
73
|
#
|
|
71
74
|
# @example localhost, 27017
|
|
72
75
|
# Connection.new
|
|
@@ -86,16 +89,16 @@ module Mongo
|
|
|
86
89
|
# driver fails to connect to a replica set with that name.
|
|
87
90
|
#
|
|
88
91
|
# @core connections
|
|
89
|
-
def initialize(host=nil, port=nil,
|
|
92
|
+
def initialize(host=nil, port=nil, opts={})
|
|
90
93
|
@host_to_try = format_pair(host, port)
|
|
91
94
|
|
|
92
95
|
# Host and port of current master.
|
|
93
96
|
@host = @port = nil
|
|
94
97
|
|
|
95
98
|
# slave_ok can be true only if one node is specified
|
|
96
|
-
@slave_ok =
|
|
99
|
+
@slave_ok = opts[:slave_ok]
|
|
97
100
|
|
|
98
|
-
setup(
|
|
101
|
+
setup(opts)
|
|
99
102
|
end
|
|
100
103
|
|
|
101
104
|
# DEPRECATED
|
|
@@ -109,9 +112,9 @@ module Mongo
|
|
|
109
112
|
# @param nodes [Array] An array of arrays, each of which specifies a host and port.
|
|
110
113
|
# @param opts [Hash] Any of the available options that can be passed to Connection.new.
|
|
111
114
|
#
|
|
112
|
-
# @option
|
|
115
|
+
# @option opts [String] :rs_name (nil) The name of the replica set to connect to. An exception will be
|
|
113
116
|
# raised if unable to connect to a replica set with this name.
|
|
114
|
-
# @option
|
|
117
|
+
# @option opts [Boolean] :read_secondary (false) When true, this connection object will pick a random slave
|
|
115
118
|
# to send reads to.
|
|
116
119
|
#
|
|
117
120
|
# @example
|
|
@@ -138,20 +141,38 @@ module Mongo
|
|
|
138
141
|
#
|
|
139
142
|
# @param opts Any of the options available for Connection.new
|
|
140
143
|
#
|
|
141
|
-
# @return [Mongo::Connection]
|
|
142
|
-
def self.from_uri(
|
|
143
|
-
|
|
144
|
-
opts
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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)
|
|
150
157
|
else
|
|
151
158
|
raise MongoArgumentError, "No nodes specified. Please ensure that you've provided at least one node."
|
|
152
159
|
end
|
|
153
160
|
end
|
|
154
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
|
+
|
|
155
176
|
# Fsync, then lock the mongod process against writes. Use this to get
|
|
156
177
|
# the datafiles in a state safe for snapshotting, backing up, etc.
|
|
157
178
|
#
|
|
@@ -184,10 +205,11 @@ module Mongo
|
|
|
184
205
|
#
|
|
185
206
|
# @raise [AuthenticationError] raises an exception if any one
|
|
186
207
|
# authentication fails.
|
|
187
|
-
def apply_saved_authentication
|
|
208
|
+
def apply_saved_authentication(opts={})
|
|
188
209
|
return false if @auths.empty?
|
|
189
210
|
@auths.each do |auth|
|
|
190
|
-
self[auth['db_name']].
|
|
211
|
+
self[auth['db_name']].issue_authentication(auth['username'], auth['password'], false,
|
|
212
|
+
:socket => opts[:socket])
|
|
191
213
|
end
|
|
192
214
|
true
|
|
193
215
|
end
|
|
@@ -237,6 +259,14 @@ module Mongo
|
|
|
237
259
|
true
|
|
238
260
|
end
|
|
239
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
|
+
|
|
240
270
|
# Return a hash with all database names
|
|
241
271
|
# and their respective sizes on disk.
|
|
242
272
|
#
|
|
@@ -259,12 +289,13 @@ module Mongo
|
|
|
259
289
|
# See DB#new for valid options hash parameters.
|
|
260
290
|
#
|
|
261
291
|
# @param [String] db_name a valid database name.
|
|
292
|
+
# @param [Hash] opts options to be passed to the DB constructor.
|
|
262
293
|
#
|
|
263
294
|
# @return [Mongo::DB]
|
|
264
295
|
#
|
|
265
296
|
# @core databases db-instance_method
|
|
266
|
-
def db(db_name,
|
|
267
|
-
DB.new(db_name, self,
|
|
297
|
+
def db(db_name, opts={})
|
|
298
|
+
DB.new(db_name, self, opts)
|
|
268
299
|
end
|
|
269
300
|
|
|
270
301
|
# Shortcut for returning a database. Use DB#db to accept options.
|
|
@@ -314,13 +345,22 @@ module Mongo
|
|
|
314
345
|
self["admin"].command(oh)
|
|
315
346
|
end
|
|
316
347
|
|
|
317
|
-
|
|
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.
|
|
318
357
|
#
|
|
319
358
|
# @return [Hash]
|
|
320
359
|
def server_info
|
|
321
360
|
self["admin"].command({:buildinfo => 1})
|
|
322
361
|
end
|
|
323
362
|
|
|
363
|
+
|
|
324
364
|
# Get the build version of the current server.
|
|
325
365
|
#
|
|
326
366
|
# @return [Mongo::ServerVersion]
|
|
@@ -406,7 +446,13 @@ module Mongo
|
|
|
406
446
|
request_id = add_message_headers(message, operation)
|
|
407
447
|
packed_message = message.to_s
|
|
408
448
|
begin
|
|
409
|
-
|
|
449
|
+
if socket
|
|
450
|
+
sock = socket
|
|
451
|
+
checkin = false
|
|
452
|
+
else
|
|
453
|
+
sock = (command ? checkout_writer : checkout_reader)
|
|
454
|
+
checkin = true
|
|
455
|
+
end
|
|
410
456
|
|
|
411
457
|
result = ''
|
|
412
458
|
@safe_mutexes[sock].synchronize do
|
|
@@ -414,7 +460,9 @@ module Mongo
|
|
|
414
460
|
result = receive(sock, request_id)
|
|
415
461
|
end
|
|
416
462
|
ensure
|
|
417
|
-
|
|
463
|
+
if checkin
|
|
464
|
+
command ? checkin_writer(sock) : checkin_reader(sock)
|
|
465
|
+
end
|
|
418
466
|
end
|
|
419
467
|
result
|
|
420
468
|
end
|
|
@@ -427,17 +475,26 @@ module Mongo
|
|
|
427
475
|
#
|
|
428
476
|
# @raise [ConnectionFailure] if unable to connect to any host or port.
|
|
429
477
|
def connect
|
|
430
|
-
|
|
478
|
+
close
|
|
431
479
|
|
|
432
480
|
config = check_is_master(@host_to_try)
|
|
433
|
-
if
|
|
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
|
+
|
|
434
488
|
set_primary(@host_to_try)
|
|
435
489
|
end
|
|
436
490
|
|
|
437
|
-
if
|
|
491
|
+
if connected?
|
|
492
|
+
BSON::BSON_CODER.update_max_bson_size(self)
|
|
493
|
+
else
|
|
438
494
|
raise ConnectionFailure, "Failed to connect to a master node at #{@host_to_try[0]}:#{@host_to_try[1]}"
|
|
439
495
|
end
|
|
440
496
|
end
|
|
497
|
+
alias :reconnect :connect
|
|
441
498
|
|
|
442
499
|
def connecting?
|
|
443
500
|
@nodes_to_try.length > 0
|
|
@@ -450,10 +507,45 @@ module Mongo
|
|
|
450
507
|
@primary_pool && @primary_pool.host && @primary_pool.port
|
|
451
508
|
end
|
|
452
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
|
+
|
|
453
535
|
# Close the connection to the database.
|
|
454
536
|
def close
|
|
455
537
|
@primary_pool.close if @primary_pool
|
|
456
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
|
|
457
549
|
end
|
|
458
550
|
|
|
459
551
|
# Checkout a socket for reading (i.e., a secondary node).
|
|
@@ -486,26 +578,37 @@ module Mongo
|
|
|
486
578
|
end
|
|
487
579
|
end
|
|
488
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
|
+
|
|
489
590
|
protected
|
|
490
591
|
|
|
491
592
|
# Generic initialization code.
|
|
492
|
-
|
|
493
|
-
def setup(options)
|
|
593
|
+
def setup(opts)
|
|
494
594
|
# Authentication objects
|
|
495
|
-
@auths =
|
|
595
|
+
@auths = opts.fetch(:auths, [])
|
|
496
596
|
|
|
497
597
|
# Lock for request ids.
|
|
498
598
|
@id_lock = Mutex.new
|
|
499
599
|
|
|
500
600
|
# Pool size and timeout.
|
|
501
|
-
@pool_size =
|
|
502
|
-
@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
|
|
503
606
|
|
|
504
607
|
# Mutex for synchronizing pool access
|
|
505
608
|
@connection_mutex = Mutex.new
|
|
506
609
|
|
|
507
610
|
# Global safe option. This is false by default.
|
|
508
|
-
@safe =
|
|
611
|
+
@safe = opts[:safe] || false
|
|
509
612
|
|
|
510
613
|
# Create a mutex when a new key, in this case a socket,
|
|
511
614
|
# is added to the hash.
|
|
@@ -518,9 +621,14 @@ module Mongo
|
|
|
518
621
|
@primary = nil
|
|
519
622
|
@primary_pool = nil
|
|
520
623
|
|
|
521
|
-
@logger
|
|
624
|
+
@logger = opts[:logger] || nil
|
|
522
625
|
|
|
523
|
-
|
|
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)
|
|
524
632
|
connect if should_connect
|
|
525
633
|
end
|
|
526
634
|
|
|
@@ -540,6 +648,18 @@ module Mongo
|
|
|
540
648
|
end
|
|
541
649
|
end
|
|
542
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
|
+
|
|
543
663
|
private
|
|
544
664
|
|
|
545
665
|
## Methods for establishing a connection:
|
|
@@ -549,17 +669,6 @@ module Mongo
|
|
|
549
669
|
# TODO: evaluate whether this method is actually necessary
|
|
550
670
|
def reset_connection
|
|
551
671
|
close
|
|
552
|
-
@primary = nil
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
# Primary is defined as either a master node or a slave if
|
|
556
|
-
# :slave_ok has been set to +true+.
|
|
557
|
-
#
|
|
558
|
-
# If a primary node is discovered, we set the the @host and @port and
|
|
559
|
-
# apply any saved authentication.
|
|
560
|
-
# TODO: simplify
|
|
561
|
-
def is_primary?(config)
|
|
562
|
-
config && (config['ismaster'] == 1 || config['ismaster'] == true) || @slave_ok
|
|
563
672
|
end
|
|
564
673
|
|
|
565
674
|
def check_is_master(node)
|
|
@@ -568,7 +677,7 @@ module Mongo
|
|
|
568
677
|
socket = TCPSocket.new(host, port)
|
|
569
678
|
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
570
679
|
|
|
571
|
-
config = self['admin'].command({:ismaster => 1}, :
|
|
680
|
+
config = self['admin'].command({:ismaster => 1}, :socket => socket)
|
|
572
681
|
rescue OperationFailure, SocketError, SystemCallError, IOError => ex
|
|
573
682
|
close
|
|
574
683
|
ensure
|
|
@@ -578,16 +687,13 @@ module Mongo
|
|
|
578
687
|
config
|
|
579
688
|
end
|
|
580
689
|
|
|
581
|
-
# Set the specified node as primary
|
|
582
|
-
# apply any saved authentication credentials.
|
|
690
|
+
# Set the specified node as primary.
|
|
583
691
|
def set_primary(node)
|
|
584
692
|
host, port = *node
|
|
585
693
|
@primary = [host, port]
|
|
586
694
|
@primary_pool = Pool.new(self, host, port, :size => @pool_size, :timeout => @timeout)
|
|
587
|
-
apply_saved_authentication
|
|
588
695
|
end
|
|
589
696
|
|
|
590
|
-
|
|
591
697
|
## Low-level connection methods.
|
|
592
698
|
|
|
593
699
|
def receive(sock, expected_response)
|
|
@@ -673,7 +779,7 @@ module Mongo
|
|
|
673
779
|
#
|
|
674
780
|
# Note: this method modifies message by reference.
|
|
675
781
|
#
|
|
676
|
-
# @
|
|
782
|
+
# @return [Integer] the request id used in the header
|
|
677
783
|
def add_message_headers(message, operation)
|
|
678
784
|
headers = [
|
|
679
785
|
# Message size.
|
|
@@ -731,19 +837,37 @@ module Mongo
|
|
|
731
837
|
# Requires length and an available socket.
|
|
732
838
|
def receive_message_on_socket(length, socket)
|
|
733
839
|
begin
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
while message.length < length
|
|
739
|
-
socket.read(length - message.length, chunk)
|
|
740
|
-
raise ConnectionFailure, "connection closed" unless chunk.length > 0
|
|
741
|
-
message << chunk
|
|
840
|
+
if @op_timeout
|
|
841
|
+
message = nil
|
|
842
|
+
Mongo::TimeoutHandler.timeout(@op_timeout, OperationTimeout) do
|
|
843
|
+
message = receive_data(length, socket)
|
|
742
844
|
end
|
|
845
|
+
else
|
|
846
|
+
message = receive_data(length, socket)
|
|
743
847
|
end
|
|
744
848
|
rescue => ex
|
|
745
849
|
close
|
|
746
|
-
|
|
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
|
|
747
871
|
end
|
|
748
872
|
message
|
|
749
873
|
end
|
data/lib/mongo/cursor.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# encoding: UTF-8
|
|
2
2
|
|
|
3
|
-
# Copyright (C) 2008-
|
|
3
|
+
# Copyright (C) 2008-2011 10gen Inc.
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
6
|
# you may not use this file except in compliance with the License.
|
|
@@ -23,7 +23,7 @@ module Mongo
|
|
|
23
23
|
|
|
24
24
|
attr_reader :collection, :selector, :fields,
|
|
25
25
|
:order, :hint, :snapshot, :timeout,
|
|
26
|
-
:full_collection_name
|
|
26
|
+
:full_collection_name, :transformer
|
|
27
27
|
|
|
28
28
|
# Create a new cursor.
|
|
29
29
|
#
|
|
@@ -33,26 +33,29 @@ module Mongo
|
|
|
33
33
|
# @return [Cursor]
|
|
34
34
|
#
|
|
35
35
|
# @core cursors constructor_details
|
|
36
|
-
def initialize(collection,
|
|
36
|
+
def initialize(collection, opts={})
|
|
37
|
+
@cursor_id = nil
|
|
38
|
+
|
|
37
39
|
@db = collection.db
|
|
38
40
|
@collection = collection
|
|
39
41
|
@connection = @db.connection
|
|
40
42
|
@logger = @connection.logger
|
|
41
43
|
|
|
42
|
-
@selector =
|
|
43
|
-
@fields = convert_fields_for_query(
|
|
44
|
-
@skip =
|
|
45
|
-
@limit =
|
|
46
|
-
@order =
|
|
47
|
-
@hint =
|
|
48
|
-
@snapshot =
|
|
49
|
-
@timeout =
|
|
50
|
-
@explain =
|
|
51
|
-
@socket =
|
|
52
|
-
@tailable =
|
|
44
|
+
@selector = opts[:selector] || {}
|
|
45
|
+
@fields = convert_fields_for_query(opts[:fields])
|
|
46
|
+
@skip = opts[:skip] || 0
|
|
47
|
+
@limit = opts[:limit] || 0
|
|
48
|
+
@order = opts[:order]
|
|
49
|
+
@hint = opts[:hint]
|
|
50
|
+
@snapshot = opts[:snapshot]
|
|
51
|
+
@timeout = opts.fetch(:timeout, true)
|
|
52
|
+
@explain = opts[:explain]
|
|
53
|
+
@socket = opts[:socket]
|
|
54
|
+
@tailable = opts[:tailable] || false
|
|
53
55
|
@closed = false
|
|
54
56
|
@query_run = false
|
|
55
|
-
|
|
57
|
+
@transformer = opts[:transformer]
|
|
58
|
+
batch_size(opts[:batch_size] || 0)
|
|
56
59
|
|
|
57
60
|
@full_collection_name = "#{@collection.db.name}.#{@collection.name}"
|
|
58
61
|
@cache = []
|
|
@@ -86,8 +89,13 @@ module Mongo
|
|
|
86
89
|
raise OperationFailure, err
|
|
87
90
|
end
|
|
88
91
|
|
|
89
|
-
|
|
92
|
+
if @transformer.nil?
|
|
93
|
+
doc
|
|
94
|
+
else
|
|
95
|
+
@transformer.call(doc) if doc
|
|
96
|
+
end
|
|
90
97
|
end
|
|
98
|
+
alias :next :next_document
|
|
91
99
|
|
|
92
100
|
# Reset this cursor on the server. Cursor options, such as the
|
|
93
101
|
# query string and the values for skip and limit, are preserved.
|
|
@@ -307,8 +315,8 @@ module Mongo
|
|
|
307
315
|
def query_options_hash
|
|
308
316
|
{ :selector => @selector,
|
|
309
317
|
:fields => @fields,
|
|
310
|
-
:skip => @
|
|
311
|
-
:limit => @
|
|
318
|
+
:skip => @skip,
|
|
319
|
+
:limit => @limit,
|
|
312
320
|
:order => @order,
|
|
313
321
|
:hint => @hint,
|
|
314
322
|
:snapshot => @snapshot,
|
|
@@ -373,18 +381,21 @@ module Mongo
|
|
|
373
381
|
end
|
|
374
382
|
|
|
375
383
|
# Run query the first time we request an object from the wire
|
|
384
|
+
# TODO: should we be calling instrument_payload even if logging
|
|
385
|
+
# is disabled?
|
|
376
386
|
def send_initial_query
|
|
377
387
|
if @query_run
|
|
378
388
|
false
|
|
379
389
|
else
|
|
380
390
|
message = construct_query_message
|
|
381
|
-
@
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
391
|
+
@connection.instrument(:find, instrument_payload) do
|
|
392
|
+
results, @n_received, @cursor_id = @connection.receive_message(
|
|
393
|
+
Mongo::Constants::OP_QUERY, message, nil, @socket, @command)
|
|
394
|
+
@returned += @n_received
|
|
395
|
+
@cache += results
|
|
396
|
+
@query_run = true
|
|
397
|
+
close_cursor_if_query_complete
|
|
398
|
+
end
|
|
388
399
|
true
|
|
389
400
|
end
|
|
390
401
|
end
|
|
@@ -401,10 +412,13 @@ module Mongo
|
|
|
401
412
|
message
|
|
402
413
|
end
|
|
403
414
|
|
|
404
|
-
def
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
415
|
+
def instrument_payload
|
|
416
|
+
log = { :database => @db.name, :collection => @collection.name, :selector => selector }
|
|
417
|
+
log[:fields] = @fields if @fields
|
|
418
|
+
log[:skip] = @skip if @skip && (@skip > 0)
|
|
419
|
+
log[:limit] = @limit if @limit && (@limit > 0)
|
|
420
|
+
log[:order] = @order if @order
|
|
421
|
+
log
|
|
408
422
|
end
|
|
409
423
|
|
|
410
424
|
def construct_query_spec
|