mongo 0.18.1 → 0.18.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +3 -59
- data/Rakefile +7 -13
- data/bin/perf.rb +30 -0
- data/examples/cursor.rb +4 -4
- data/examples/types.rb +1 -1
- data/lib/mongo.rb +2 -2
- data/lib/mongo/admin.rb +1 -2
- data/lib/mongo/collection.rb +85 -45
- data/lib/mongo/connection.rb +55 -102
- data/lib/mongo/constants.rb +3 -3
- data/lib/mongo/cursor.rb +48 -44
- data/lib/mongo/db.rb +8 -8
- data/lib/mongo/errors.rb +8 -2
- data/lib/mongo/gridfs/chunk.rb +0 -1
- data/lib/mongo/gridfs/grid_store.rb +57 -14
- data/lib/mongo/types/code.rb +1 -0
- data/lib/mongo/types/objectid.rb +5 -6
- data/lib/mongo/util/bson_ruby.rb +25 -15
- data/lib/mongo/util/conversions.rb +12 -4
- data/lib/mongo/util/ordered_hash.rb +18 -0
- data/lib/mongo/util/server_version.rb +3 -3
- data/test/replica/count_test.rb +3 -3
- data/test/replica/insert_test.rb +6 -6
- data/test/replica/pooled_insert_test.rb +8 -8
- data/test/replica/query_test.rb +3 -3
- data/test/test_bson.rb +32 -0
- data/test/test_collection.rb +140 -65
- data/test/test_connection.rb +2 -2
- data/test/test_conversions.rb +3 -3
- data/test/test_cursor.rb +44 -20
- data/test/test_db_api.rb +7 -1
- data/test/test_grid_store.rb +16 -2
- data/test/test_objectid.rb +12 -0
- data/test/test_ordered_hash.rb +16 -0
- data/test/test_threading.rb +3 -3
- data/test/threading/test_threading_large_pool.rb +7 -7
- data/test/unit/collection_test.rb +7 -7
- data/test/unit/connection_test.rb +0 -79
- data/test/unit/cursor_test.rb +12 -12
- data/test/unit/db_test.rb +11 -11
- metadata +7 -5
- data/bin/autoreconnect.rb +0 -26
data/lib/mongo/connection.rb
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
|
17
17
|
require 'set'
|
18
18
|
require 'socket'
|
19
|
-
require '
|
19
|
+
require 'thread'
|
20
20
|
|
21
21
|
module Mongo
|
22
22
|
|
@@ -31,12 +31,12 @@ module Mongo
|
|
31
31
|
STANDARD_HEADER_SIZE = 16
|
32
32
|
RESPONSE_HEADER_SIZE = 20
|
33
33
|
|
34
|
-
attr_reader :logger, :size, :host, :port, :nodes, :sockets, :checked_out
|
34
|
+
attr_reader :logger, :size, :host, :port, :nodes, :sockets, :checked_out
|
35
35
|
|
36
|
-
def slave_ok?
|
36
|
+
def slave_ok?
|
37
37
|
@slave_ok
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
# Counter for generating unique request ids.
|
41
41
|
@@current_request_id = 0
|
42
42
|
|
@@ -45,7 +45,7 @@ module Mongo
|
|
45
45
|
#
|
46
46
|
# == Connecting
|
47
47
|
# If connecting to just one server, you may specify whether connection to slave is permitted.
|
48
|
-
#
|
48
|
+
#
|
49
49
|
# In all cases, the default host is "localhost" and the default port, is 27017.
|
50
50
|
#
|
51
51
|
# When specifying a pair, pair_or_host, is a hash with two keys: :left and :right. Each key maps to either
|
@@ -69,13 +69,15 @@ module Mongo
|
|
69
69
|
# :timeout :: When all of the connections to the pool are checked out,
|
70
70
|
# this is the number of seconds to wait for a new connection
|
71
71
|
# to be released before throwing an exception.
|
72
|
-
#
|
72
|
+
#
|
73
|
+
# Note that there are a few issues when using connection pooling with Ruby 1.9 on Windows. These
|
74
|
+
# should be resolved in the next release.
|
73
75
|
#
|
74
76
|
# === Examples:
|
75
77
|
#
|
76
78
|
# # localhost, 27017
|
77
79
|
# Connection.new
|
78
|
-
#
|
80
|
+
#
|
79
81
|
# # localhost, 27017
|
80
82
|
# Connection.new("localhost")
|
81
83
|
#
|
@@ -85,9 +87,9 @@ module Mongo
|
|
85
87
|
# # localhost, 3000, where this node may be a slave
|
86
88
|
# Connection.new("localhost", 3000, :slave_ok => true)
|
87
89
|
#
|
88
|
-
# # A pair of servers. The driver will always talk to master.
|
90
|
+
# # A pair of servers. The driver will always talk to master.
|
89
91
|
# # On connection errors, Mongo::ConnectionFailure will be raised.
|
90
|
-
# # See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby
|
92
|
+
# # See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby
|
91
93
|
# Connection.new({:left => ["db1.example.com", 27017],
|
92
94
|
# :right => ["db2.example.com", 27017]})
|
93
95
|
#
|
@@ -100,22 +102,20 @@ module Mongo
|
|
100
102
|
|
101
103
|
# Host and port of current master.
|
102
104
|
@host = @port = nil
|
103
|
-
|
105
|
+
|
104
106
|
# Lock for request ids.
|
105
107
|
@id_lock = Mutex.new
|
106
108
|
|
107
109
|
# Pool size and timeout.
|
108
110
|
@size = options[:pool_size] || 1
|
109
|
-
@timeout = options[:timeout] ||
|
110
|
-
|
111
|
-
# Cache of reserved sockets mapped to threads
|
112
|
-
@reserved_connections = {}
|
111
|
+
@timeout = options[:timeout] || 5.0
|
113
112
|
|
114
113
|
# Mutex for synchronizing pool access
|
115
|
-
@connection_mutex =
|
114
|
+
@connection_mutex = Mutex.new
|
115
|
+
@safe_mutex = Mutex.new
|
116
116
|
|
117
117
|
# Condition variable for signal and wait
|
118
|
-
@queue =
|
118
|
+
@queue = ConditionVariable.new
|
119
119
|
|
120
120
|
@sockets = []
|
121
121
|
@checked_out = []
|
@@ -123,7 +123,7 @@ module Mongo
|
|
123
123
|
if options[:auto_reconnect]
|
124
124
|
warn(":auto_reconnect is deprecated. see http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby")
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
# Slave ok can be true only if one node is specified
|
128
128
|
@slave_ok = options[:slave_ok] && @nodes.length == 1
|
129
129
|
@logger = options[:logger] || nil
|
@@ -177,7 +177,7 @@ module Mongo
|
|
177
177
|
# Increments and returns the next available request id.
|
178
178
|
def get_request_id
|
179
179
|
request_id = ''
|
180
|
-
@id_lock.synchronize do
|
180
|
+
@id_lock.synchronize do
|
181
181
|
request_id = @@current_request_id += 1
|
182
182
|
end
|
183
183
|
request_id
|
@@ -196,7 +196,7 @@ module Mongo
|
|
196
196
|
|
197
197
|
|
198
198
|
## Connections and pooling ##
|
199
|
-
|
199
|
+
|
200
200
|
# Sends a message to MongoDB.
|
201
201
|
#
|
202
202
|
# Takes a MongoDB opcode, +operation+, a message of class ByteBuffer,
|
@@ -211,19 +211,22 @@ module Mongo
|
|
211
211
|
end
|
212
212
|
|
213
213
|
# Sends a message to the database, waits for a response, and raises
|
214
|
-
#
|
214
|
+
# an exception if the operation has failed.
|
215
215
|
#
|
216
216
|
# Takes a MongoDB opcode, +operation+, a message of class ByteBuffer,
|
217
217
|
# +message+, the +db_name+, and an optional formatted +log_message+.
|
218
|
-
# Sends the message to the
|
218
|
+
# Sends the message to the database, adding the necessary headers.
|
219
219
|
def send_message_with_safe_check(operation, message, db_name, log_message=nil)
|
220
220
|
message_with_headers = add_message_headers(operation, message)
|
221
221
|
message_with_check = last_error_message(db_name)
|
222
222
|
@logger.debug(" MONGODB #{log_message || message}") if @logger
|
223
223
|
sock = checkout
|
224
224
|
packed_message = message_with_headers.append!(message_with_check).to_s
|
225
|
-
|
226
|
-
|
225
|
+
docs = num_received = cursor_id = ''
|
226
|
+
@safe_mutex.synchronize do
|
227
|
+
send_message_on_socket(packed_message, sock)
|
228
|
+
docs, num_received, cursor_id = receive(sock)
|
229
|
+
end
|
227
230
|
checkin(sock)
|
228
231
|
if num_received == 1 && error = docs[0]['err']
|
229
232
|
raise Mongo::OperationFailure, error
|
@@ -234,15 +237,18 @@ module Mongo
|
|
234
237
|
# Sends a message to the database and waits for the response.
|
235
238
|
#
|
236
239
|
# Takes a MongoDB opcode, +operation+, a message of class ByteBuffer,
|
237
|
-
# +message+, and an optional formatted +log_message+. This method
|
240
|
+
# +message+, and an optional formatted +log_message+. This method
|
238
241
|
# also takes an options socket for internal use with #connect_to_master.
|
239
242
|
def receive_message(operation, message, log_message=nil, socket=nil)
|
240
243
|
packed_message = add_message_headers(operation, message).to_s
|
241
244
|
@logger.debug(" MONGODB #{log_message || message}") if @logger
|
242
245
|
sock = socket || checkout
|
243
246
|
|
244
|
-
|
245
|
-
|
247
|
+
result = ''
|
248
|
+
@safe_mutex.synchronize do
|
249
|
+
send_message_on_socket(packed_message, sock)
|
250
|
+
result = receive(sock)
|
251
|
+
end
|
246
252
|
checkin(sock)
|
247
253
|
result
|
248
254
|
end
|
@@ -275,7 +281,7 @@ module Mongo
|
|
275
281
|
socket.close if socket
|
276
282
|
false
|
277
283
|
end
|
278
|
-
end
|
284
|
+
end
|
279
285
|
raise ConnectionFailure, "failed to connect to any given host:port" unless socket
|
280
286
|
end
|
281
287
|
|
@@ -291,55 +297,25 @@ module Mongo
|
|
291
297
|
sock.close
|
292
298
|
end
|
293
299
|
@host = @port = nil
|
294
|
-
@sockets.clear
|
300
|
+
@sockets.clear
|
295
301
|
@checked_out.clear
|
296
|
-
@reserved_connections.clear
|
297
302
|
end
|
298
303
|
|
299
304
|
private
|
300
305
|
|
301
|
-
# Get a socket from the pool, mapped to the current thread.
|
302
|
-
def checkout
|
303
|
-
#return @socket ||= checkout_new_socket if @size == 1
|
304
|
-
if sock = @reserved_connections[Thread.current.object_id]
|
305
|
-
sock
|
306
|
-
else
|
307
|
-
sock = obtain_socket
|
308
|
-
@reserved_connections[Thread.current.object_id] = sock
|
309
|
-
end
|
310
|
-
sock
|
311
|
-
end
|
312
|
-
|
313
306
|
# Return a socket to the pool.
|
314
307
|
def checkin(socket)
|
315
|
-
@connection_mutex.synchronize do
|
316
|
-
@reserved_connections.delete Thread.current.object_id
|
308
|
+
@connection_mutex.synchronize do
|
317
309
|
@checked_out.delete(socket)
|
318
310
|
@queue.signal
|
319
311
|
end
|
320
312
|
true
|
321
313
|
end
|
322
314
|
|
323
|
-
# Releases the connection for any dead threads.
|
324
|
-
# Called when the connection pool grows too large to free up more sockets.
|
325
|
-
def clear_stale_cached_connections!
|
326
|
-
keys = @reserved_connections.keys
|
327
|
-
|
328
|
-
Thread.list.each do |thread|
|
329
|
-
keys.delete(thread.object_id) if thread.alive?
|
330
|
-
end
|
331
|
-
|
332
|
-
keys.each do |key|
|
333
|
-
next unless @reserved_connections.has_key?(key)
|
334
|
-
checkin(@reserved_connections[key])
|
335
|
-
@reserved_connections.delete(key)
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
315
|
# Adds a new socket to the pool and checks it out.
|
340
316
|
#
|
341
|
-
# This method is called exclusively from #
|
342
|
-
# therefore, it runs within a mutex
|
317
|
+
# This method is called exclusively from #checkout;
|
318
|
+
# therefore, it runs within a mutex.
|
343
319
|
def checkout_new_socket
|
344
320
|
begin
|
345
321
|
socket = TCPSocket.new(@host, @port)
|
@@ -354,8 +330,8 @@ module Mongo
|
|
354
330
|
|
355
331
|
# Checks out the first available socket from the pool.
|
356
332
|
#
|
357
|
-
# This method is called exclusively from #
|
358
|
-
# therefore, it runs within a mutex
|
333
|
+
# This method is called exclusively from #checkout;
|
334
|
+
# therefore, it runs within a mutex.
|
359
335
|
def checkout_existing_socket
|
360
336
|
socket = (@sockets - @checked_out).first
|
361
337
|
@checked_out << socket
|
@@ -365,11 +341,17 @@ module Mongo
|
|
365
341
|
# Check out an existing socket or create a new socket if the maximum
|
366
342
|
# pool size has not been exceeded. Otherwise, wait for the next
|
367
343
|
# available socket.
|
368
|
-
def
|
369
|
-
|
370
|
-
|
344
|
+
def checkout
|
345
|
+
connect_to_master if !connected?
|
346
|
+
start_time = Time.now
|
347
|
+
loop do
|
348
|
+
if (Time.now - start_time) > @timeout
|
349
|
+
raise ConnectionTimeoutError, "could not obtain connection within " +
|
350
|
+
"#{@timeout} seconds. The max pool size is currently #{@size}; " +
|
351
|
+
"consider increasing the pool size or timeout."
|
352
|
+
end
|
371
353
|
|
372
|
-
|
354
|
+
@connection_mutex.synchronize do
|
373
355
|
socket = if @checked_out.size < @sockets.size
|
374
356
|
checkout_existing_socket
|
375
357
|
elsif @sockets.size < @size
|
@@ -378,39 +360,10 @@ module Mongo
|
|
378
360
|
|
379
361
|
return socket if socket
|
380
362
|
|
381
|
-
#
|
382
|
-
|
383
|
-
next if @checked_out.size < @sockets.size
|
384
|
-
|
385
|
-
# Otherwise, wait.
|
386
|
-
if wait
|
387
|
-
next
|
388
|
-
else
|
389
|
-
|
390
|
-
# Try to clear stale threads once more before failing.
|
391
|
-
clear_stale_cached_connections!
|
392
|
-
if @size == @sockets.size
|
393
|
-
raise ConnectionTimeoutError, "could not obtain connection within " +
|
394
|
-
"#{@timeout} seconds. The max pool size is currently #{@size}; " +
|
395
|
-
"consider increasing it."
|
396
|
-
end
|
397
|
-
end # if
|
398
|
-
end # loop
|
399
|
-
end # synchronize
|
400
|
-
end
|
401
|
-
|
402
|
-
if RUBY_VERSION >= '1.9'
|
403
|
-
# Ruby 1.9's Condition Variables don't support timeouts yet;
|
404
|
-
# until they do, we'll make do with this hack.
|
405
|
-
def wait
|
406
|
-
Timeout.timeout(@timeout) do
|
407
|
-
@queue.wait
|
363
|
+
# Otherwise, wait
|
364
|
+
@queue.wait(@connection_mutex)
|
408
365
|
end
|
409
366
|
end
|
410
|
-
else
|
411
|
-
def wait
|
412
|
-
@queue.wait(@timeout)
|
413
|
-
end
|
414
367
|
end
|
415
368
|
|
416
369
|
def receive(sock)
|
@@ -424,7 +377,7 @@ module Mongo
|
|
424
377
|
header.put_array(receive_message_on_socket(16, sock).unpack("C*"))
|
425
378
|
unless header.size == STANDARD_HEADER_SIZE
|
426
379
|
raise "Short read for DB response header: " +
|
427
|
-
"expected #{STANDARD_HEADER_SIZE} bytes, saw #{header.size}"
|
380
|
+
"expected #{STANDARD_HEADER_SIZE} bytes, saw #{header.size}"
|
428
381
|
end
|
429
382
|
header.rewind
|
430
383
|
size = header.get_int
|
@@ -473,7 +426,7 @@ module Mongo
|
|
473
426
|
message.put_array(BSON.serialize({:getlasterror => 1}, false).unpack("C*"))
|
474
427
|
add_message_headers(Mongo::Constants::OP_QUERY, message)
|
475
428
|
end
|
476
|
-
|
429
|
+
|
477
430
|
# Prepares a message for transmission to MongoDB by
|
478
431
|
# constructing a valid message header.
|
479
432
|
def add_message_headers(operation, message)
|
@@ -494,7 +447,7 @@ module Mongo
|
|
494
447
|
end
|
495
448
|
|
496
449
|
# Low-level method for sending a message on a socket.
|
497
|
-
# Requires a packed message and an available socket,
|
450
|
+
# Requires a packed message and an available socket,
|
498
451
|
def send_message_on_socket(packed_message, socket)
|
499
452
|
begin
|
500
453
|
socket.send(packed_message, 0)
|
@@ -537,7 +490,7 @@ module Mongo
|
|
537
490
|
[['localhost', DEFAULT_PORT]]
|
538
491
|
end
|
539
492
|
end
|
540
|
-
|
493
|
+
|
541
494
|
# Turns an array containing a host name string and a
|
542
495
|
# port number integer into a [host, port] pair array.
|
543
496
|
def pair_val_to_connection(a)
|
data/lib/mongo/constants.rb
CHANGED
data/lib/mongo/cursor.rb
CHANGED
@@ -19,7 +19,7 @@ module Mongo
|
|
19
19
|
include Mongo::Conversions
|
20
20
|
include Enumerable
|
21
21
|
|
22
|
-
attr_reader :collection, :selector, :admin, :fields,
|
22
|
+
attr_reader :collection, :selector, :admin, :fields,
|
23
23
|
:order, :hint, :snapshot, :timeout,
|
24
24
|
:full_collection_name
|
25
25
|
|
@@ -49,19 +49,17 @@ module Mongo
|
|
49
49
|
@query_run = false
|
50
50
|
end
|
51
51
|
|
52
|
-
# Return the next
|
53
|
-
|
54
|
-
def next_object
|
52
|
+
# Return the next document or nil if there are no more.
|
53
|
+
def next_document
|
55
54
|
refill_via_get_more if num_remaining == 0
|
56
|
-
|
55
|
+
doc = @cache.shift
|
57
56
|
|
58
|
-
if
|
59
|
-
err =
|
57
|
+
if doc && doc['$err']
|
58
|
+
err = doc['$err']
|
60
59
|
|
61
60
|
# If the server has stopped being the master (e.g., it's one of a
|
62
61
|
# pair but it has died or something like that) then we close that
|
63
|
-
# connection.
|
64
|
-
# servers, next request will re-open on master server.
|
62
|
+
# connection. The next request will re-open on master server.
|
65
63
|
if err == "not master"
|
66
64
|
raise ConnectionFailure, err
|
67
65
|
@connection.close
|
@@ -70,12 +68,17 @@ module Mongo
|
|
70
68
|
raise OperationFailure, err
|
71
69
|
end
|
72
70
|
|
73
|
-
|
71
|
+
doc
|
72
|
+
end
|
73
|
+
|
74
|
+
def next_object
|
75
|
+
warn "Cursor#next_object is deprecated; please use Cursor#next_document instead."
|
76
|
+
next_document
|
74
77
|
end
|
75
78
|
|
76
|
-
# Get the size of the
|
79
|
+
# Get the size of the result set for this query.
|
77
80
|
#
|
78
|
-
# Returns the number of objects in the
|
81
|
+
# Returns the number of objects in the result set for this query. Does
|
79
82
|
# not take limit and skip into account. Raises OperationFailure on a
|
80
83
|
# database error.
|
81
84
|
def count
|
@@ -88,17 +91,17 @@ module Mongo
|
|
88
91
|
raise OperationFailure, "Count failed: #{response['errmsg']}"
|
89
92
|
end
|
90
93
|
|
91
|
-
# Sort this cursor's
|
94
|
+
# Sort this cursor's results.
|
92
95
|
#
|
93
96
|
# Takes either a single key and a direction, or an array of [key,
|
94
|
-
# direction] pairs. Directions should be specified as Mongo::ASCENDING
|
95
|
-
#
|
97
|
+
# direction] pairs. Directions should be specified as Mongo::ASCENDING / Mongo::DESCENDING
|
98
|
+
# (or :ascending / :descending, :asc / :desc).
|
96
99
|
#
|
97
100
|
# Raises InvalidOperation if this cursor has already been used. Raises
|
98
|
-
# InvalidSortValueError if specified order is invalid.
|
101
|
+
# InvalidSortValueError if the specified order is invalid.
|
99
102
|
#
|
100
103
|
# This method overrides any sort order specified in the Collection#find
|
101
|
-
# method, and only the last sort applied has an effect
|
104
|
+
# method, and only the last sort applied has an effect.
|
102
105
|
def sort(key_or_list, direction=nil)
|
103
106
|
check_modifiable
|
104
107
|
|
@@ -130,7 +133,7 @@ module Mongo
|
|
130
133
|
|
131
134
|
# Skips the first +number_to_skip+ results of this cursor.
|
132
135
|
# Returns the current number_to_skip if no parameter is given.
|
133
|
-
#
|
136
|
+
#
|
134
137
|
# Raises InvalidOperation if this cursor has already been used.
|
135
138
|
#
|
136
139
|
# This method overrides any skip specified in the Collection#find method,
|
@@ -151,15 +154,15 @@ module Mongo
|
|
151
154
|
def each
|
152
155
|
num_returned = 0
|
153
156
|
while more? && (@limit <= 0 || num_returned < @limit)
|
154
|
-
yield
|
157
|
+
yield next_document
|
155
158
|
num_returned += 1
|
156
159
|
end
|
157
160
|
end
|
158
161
|
|
159
162
|
# Return all of the documents in this cursor as an array of hashes.
|
160
163
|
#
|
161
|
-
# Raises InvalidOperation if this cursor has already been used
|
162
|
-
#
|
164
|
+
# Raises InvalidOperation if this cursor has already been used or if
|
165
|
+
# this methods has already been called on the cursor.
|
163
166
|
#
|
164
167
|
# Use of this method is discouraged - iterating over a cursor is much
|
165
168
|
# more efficient in most cases.
|
@@ -168,22 +171,22 @@ module Mongo
|
|
168
171
|
rows = []
|
169
172
|
num_returned = 0
|
170
173
|
while more? && (@limit <= 0 || num_returned < @limit)
|
171
|
-
rows <<
|
174
|
+
rows << next_document
|
172
175
|
num_returned += 1
|
173
176
|
end
|
174
177
|
rows
|
175
178
|
end
|
176
179
|
|
177
|
-
# Returns an explain plan
|
180
|
+
# Returns an explain plan document for this cursor.
|
178
181
|
def explain
|
179
182
|
c = Cursor.new(@collection, query_options_hash.merge(:limit => -@limit.abs, :explain => true))
|
180
|
-
explanation = c.
|
183
|
+
explanation = c.next_document
|
181
184
|
c.close
|
182
185
|
|
183
186
|
explanation
|
184
187
|
end
|
185
188
|
|
186
|
-
#
|
189
|
+
# Closes the cursor.
|
187
190
|
#
|
188
191
|
# Note: if a cursor is read until exhausted (read until Mongo::Constants::OP_QUERY or
|
189
192
|
# Mongo::Constants::OP_GETMORE returns zero for the cursor id), there is no need to
|
@@ -211,20 +214,20 @@ module Mongo
|
|
211
214
|
# See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
|
212
215
|
def query_opts
|
213
216
|
timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
|
214
|
-
slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
|
217
|
+
slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
|
215
218
|
slave_ok + timeout
|
216
219
|
end
|
217
220
|
|
218
|
-
# Returns the query options
|
221
|
+
# Returns the query options for this Cursor.
|
219
222
|
def query_options_hash
|
220
223
|
{ :selector => @selector,
|
221
|
-
:fields => @fields,
|
222
|
-
:admin => @admin,
|
223
|
-
:skip => @skip_num,
|
224
|
-
:limit => @limit_num,
|
225
|
-
:order => @order,
|
226
|
-
:hint => @hint,
|
227
|
-
:snapshot => @snapshot,
|
224
|
+
:fields => @fields,
|
225
|
+
:admin => @admin,
|
226
|
+
:skip => @skip_num,
|
227
|
+
:limit => @limit_num,
|
228
|
+
:order => @order,
|
229
|
+
:hint => @hint,
|
230
|
+
:snapshot => @snapshot,
|
228
231
|
:timeout => @timeout }
|
229
232
|
end
|
230
233
|
|
@@ -245,7 +248,7 @@ module Mongo
|
|
245
248
|
end
|
246
249
|
end
|
247
250
|
|
248
|
-
# Set query selector hash. If the selector is a Code or String object,
|
251
|
+
# Set the query selector hash. If the selector is a Code or String object,
|
249
252
|
# the selector will be used in a $where clause.
|
250
253
|
# See http://www.mongodb.org/display/DOCS/Server-side+Code+Execution
|
251
254
|
def convert_selector_for_query(selector)
|
@@ -266,20 +269,21 @@ module Mongo
|
|
266
269
|
@order || @explain || @hint || @snapshot
|
267
270
|
end
|
268
271
|
|
272
|
+
# Return a number of documents remaining for this cursor.
|
269
273
|
def num_remaining
|
270
274
|
refill_via_get_more if @cache.length == 0
|
271
275
|
@cache.length
|
272
276
|
end
|
273
277
|
|
274
278
|
# Internal method, not for general use. Return +true+ if there are
|
275
|
-
# more records to retrieve. This
|
276
|
-
# #each is responsible for doing that.
|
279
|
+
# more records to retrieve. This method does not check @limit;
|
280
|
+
# Cursor#each is responsible for doing that.
|
277
281
|
def more?
|
278
282
|
num_remaining > 0
|
279
283
|
end
|
280
284
|
|
281
285
|
def refill_via_get_more
|
282
|
-
return if
|
286
|
+
return if send_initial_query || @cursor_id.zero?
|
283
287
|
message = ByteBuffer.new
|
284
288
|
# Reserved.
|
285
289
|
message.put_int(0)
|
@@ -290,7 +294,7 @@ module Mongo
|
|
290
294
|
|
291
295
|
# Number of results to return; db decides for now.
|
292
296
|
message.put_int(0)
|
293
|
-
|
297
|
+
|
294
298
|
# Cursor id.
|
295
299
|
message.put_long(@cursor_id)
|
296
300
|
results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_GET_MORE, message, "cursor.get_more()", @socket)
|
@@ -299,13 +303,13 @@ module Mongo
|
|
299
303
|
end
|
300
304
|
|
301
305
|
# Run query the first time we request an object from the wire
|
302
|
-
def
|
306
|
+
def send_initial_query
|
303
307
|
if @query_run
|
304
308
|
false
|
305
309
|
else
|
306
310
|
message = construct_query_message
|
307
|
-
results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_QUERY, message,
|
308
|
-
(query_log_message if @connection.logger), @socket)
|
311
|
+
results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_QUERY, message,
|
312
|
+
(query_log_message if @connection.logger), @socket)
|
309
313
|
@cache += results
|
310
314
|
@query_run = true
|
311
315
|
close_cursor_if_query_complete
|
@@ -331,7 +335,7 @@ module Mongo
|
|
331
335
|
|
332
336
|
def query_log_message
|
333
337
|
"#{@admin ? 'admin' : @db.name}.#{@collection.name}.find(#{@selector.inspect}, #{@fields ? @fields.inspect : '{}'})" +
|
334
|
-
"#{@skip != 0 ? ('.skip(' + @skip.to_s + ')') : ''}#{@limit != 0 ? ('.limit(' + @limit.to_s + ')') : ''}"
|
338
|
+
"#{@skip != 0 ? ('.skip(' + @skip.to_s + ')') : ''}#{@limit != 0 ? ('.limit(' + @limit.to_s + ')') : ''}"
|
335
339
|
end
|
336
340
|
|
337
341
|
def selector_with_special_query_fields
|
@@ -349,7 +353,7 @@ module Mongo
|
|
349
353
|
when String, Symbol then string_as_sort_parameters(@order)
|
350
354
|
when Array then array_as_sort_parameters(@order)
|
351
355
|
else
|
352
|
-
raise InvalidSortValueError, "Illegal sort clause, '#{@order.class.name}'; must be of the form " +
|
356
|
+
raise InvalidSortValueError, "Illegal sort clause, '#{@order.class.name}'; must be of the form " +
|
353
357
|
"[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"
|
354
358
|
end
|
355
359
|
end
|