mongo 1.0 → 1.1.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.
- data/LICENSE.txt +1 -13
- data/{README.rdoc → README.md} +129 -149
- data/Rakefile +94 -58
- data/bin/mongo_console +21 -0
- data/docs/1.0_UPGRADE.md +21 -0
- data/docs/CREDITS.md +123 -0
- data/docs/FAQ.md +112 -0
- data/docs/GridFS.md +158 -0
- data/docs/HISTORY.md +185 -0
- data/docs/REPLICA_SETS.md +75 -0
- data/docs/TUTORIAL.md +247 -0
- data/docs/WRITE_CONCERN.md +28 -0
- data/lib/mongo/collection.rb +225 -105
- data/lib/mongo/connection.rb +374 -315
- data/lib/mongo/cursor.rb +122 -77
- data/lib/mongo/db.rb +109 -85
- data/lib/mongo/exceptions.rb +6 -0
- data/lib/mongo/gridfs/grid.rb +19 -11
- data/lib/mongo/gridfs/grid_ext.rb +36 -9
- data/lib/mongo/gridfs/grid_file_system.rb +15 -9
- data/lib/mongo/gridfs/grid_io.rb +49 -16
- data/lib/mongo/gridfs/grid_io_fix.rb +38 -0
- data/lib/mongo/repl_set_connection.rb +290 -0
- data/lib/mongo/util/conversions.rb +3 -1
- data/lib/mongo/util/core_ext.rb +17 -4
- data/lib/mongo/util/pool.rb +125 -0
- data/lib/mongo/util/server_version.rb +2 -0
- data/lib/mongo/util/support.rb +12 -0
- data/lib/mongo/util/uri_parser.rb +71 -0
- data/lib/mongo.rb +23 -7
- data/{mongo-ruby-driver.gemspec → mongo.gemspec} +9 -7
- data/test/auxillary/1.4_features.rb +2 -2
- data/test/auxillary/authentication_test.rb +1 -1
- data/test/auxillary/autoreconnect_test.rb +1 -1
- data/test/{slave_connection_test.rb → auxillary/slave_connection_test.rb} +6 -6
- data/test/bson/binary_test.rb +15 -0
- data/test/bson/bson_test.rb +537 -0
- data/test/bson/byte_buffer_test.rb +190 -0
- data/test/bson/hash_with_indifferent_access_test.rb +38 -0
- data/test/bson/json_test.rb +17 -0
- data/test/bson/object_id_test.rb +141 -0
- data/test/bson/ordered_hash_test.rb +197 -0
- data/test/collection_test.rb +195 -15
- data/test/connection_test.rb +93 -56
- data/test/conversions_test.rb +1 -1
- data/test/cursor_fail_test.rb +75 -0
- data/test/cursor_message_test.rb +43 -0
- data/test/cursor_test.rb +93 -32
- data/test/db_api_test.rb +28 -55
- data/test/db_connection_test.rb +2 -3
- data/test/db_test.rb +45 -40
- data/test/grid_file_system_test.rb +14 -6
- data/test/grid_io_test.rb +36 -7
- data/test/grid_test.rb +54 -10
- data/test/replica_sets/connect_test.rb +84 -0
- data/test/replica_sets/count_test.rb +35 -0
- data/test/{replica → replica_sets}/insert_test.rb +17 -14
- data/test/replica_sets/pooled_insert_test.rb +55 -0
- data/test/replica_sets/query_secondaries.rb +80 -0
- data/test/replica_sets/query_test.rb +41 -0
- data/test/replica_sets/replication_ack_test.rb +64 -0
- data/test/replica_sets/rs_test_helper.rb +29 -0
- data/test/safe_test.rb +68 -0
- data/test/support/hash_with_indifferent_access.rb +199 -0
- data/test/support/keys.rb +45 -0
- data/test/support_test.rb +19 -0
- data/test/test_helper.rb +53 -15
- data/test/threading/{test_threading_large_pool.rb → threading_with_large_pool_test.rb} +2 -2
- data/test/threading_test.rb +2 -2
- data/test/tools/repl_set_manager.rb +241 -0
- data/test/tools/test.rb +13 -0
- data/test/unit/collection_test.rb +70 -7
- data/test/unit/connection_test.rb +18 -39
- data/test/unit/cursor_test.rb +7 -8
- data/test/unit/db_test.rb +14 -17
- data/test/unit/grid_test.rb +49 -0
- data/test/unit/pool_test.rb +9 -0
- data/test/unit/repl_set_connection_test.rb +82 -0
- data/test/unit/safe_test.rb +125 -0
- metadata +132 -51
- data/bin/bson_benchmark.rb +0 -59
- data/bin/fail_if_no_c.rb +0 -11
- data/examples/admin.rb +0 -43
- data/examples/capped.rb +0 -22
- data/examples/cursor.rb +0 -48
- data/examples/gridfs.rb +0 -44
- data/examples/index_test.rb +0 -126
- data/examples/info.rb +0 -31
- data/examples/queries.rb +0 -70
- data/examples/simple.rb +0 -24
- data/examples/strict.rb +0 -35
- data/examples/types.rb +0 -36
- data/test/replica/count_test.rb +0 -34
- data/test/replica/pooled_insert_test.rb +0 -54
- data/test/replica/query_test.rb +0 -39
data/lib/mongo/cursor.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
1
3
|
# Copyright (C) 2008-2010 10gen Inc.
|
|
2
4
|
#
|
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -19,7 +21,7 @@ module Mongo
|
|
|
19
21
|
include Mongo::Conversions
|
|
20
22
|
include Enumerable
|
|
21
23
|
|
|
22
|
-
attr_reader :collection, :selector, :
|
|
24
|
+
attr_reader :collection, :selector, :fields,
|
|
23
25
|
:order, :hint, :snapshot, :timeout,
|
|
24
26
|
:full_collection_name
|
|
25
27
|
|
|
@@ -35,32 +37,39 @@ module Mongo
|
|
|
35
37
|
@db = collection.db
|
|
36
38
|
@collection = collection
|
|
37
39
|
@connection = @db.connection
|
|
40
|
+
@logger = @connection.logger
|
|
38
41
|
|
|
39
|
-
@selector =
|
|
42
|
+
@selector = options[:selector] || {}
|
|
40
43
|
@fields = convert_fields_for_query(options[:fields])
|
|
41
|
-
@admin = options[:admin] || false
|
|
42
44
|
@skip = options[:skip] || 0
|
|
43
45
|
@limit = options[:limit] || 0
|
|
44
46
|
@order = options[:order]
|
|
45
47
|
@hint = options[:hint]
|
|
46
48
|
@snapshot = options[:snapshot]
|
|
47
|
-
@timeout = options[:timeout]
|
|
49
|
+
@timeout = options.has_key?(:timeout) ? options[:timeout] : true
|
|
48
50
|
@explain = options[:explain]
|
|
49
51
|
@socket = options[:socket]
|
|
50
52
|
@tailable = options[:tailable] || false
|
|
51
|
-
@
|
|
53
|
+
@closed = false
|
|
54
|
+
@query_run = false
|
|
55
|
+
batch_size(options[:batch_size] || 0)
|
|
52
56
|
|
|
53
57
|
@full_collection_name = "#{@collection.db.name}.#{@collection.name}"
|
|
54
|
-
@cache
|
|
55
|
-
@
|
|
56
|
-
|
|
58
|
+
@cache = []
|
|
59
|
+
@returned = 0
|
|
60
|
+
|
|
61
|
+
if @collection.name =~ /^\$cmd/ || @collection.name =~ /^system/
|
|
62
|
+
@command = true
|
|
63
|
+
else
|
|
64
|
+
@command = false
|
|
65
|
+
end
|
|
57
66
|
end
|
|
58
67
|
|
|
59
68
|
# Get the next document specified the cursor options.
|
|
60
69
|
#
|
|
61
70
|
# @return [Hash, Nil] the next document or Nil if no documents remain.
|
|
62
71
|
def next_document
|
|
63
|
-
|
|
72
|
+
refresh if @cache.length == 0
|
|
64
73
|
doc = @cache.shift
|
|
65
74
|
|
|
66
75
|
if doc && doc['$err']
|
|
@@ -70,8 +79,8 @@ module Mongo
|
|
|
70
79
|
# pair but it has died or something like that) then we close that
|
|
71
80
|
# connection. The next request will re-open on master server.
|
|
72
81
|
if err == "not master"
|
|
73
|
-
raise ConnectionFailure, err
|
|
74
82
|
@connection.close
|
|
83
|
+
raise ConnectionFailure, err
|
|
75
84
|
end
|
|
76
85
|
|
|
77
86
|
raise OperationFailure, err
|
|
@@ -80,6 +89,18 @@ module Mongo
|
|
|
80
89
|
doc
|
|
81
90
|
end
|
|
82
91
|
|
|
92
|
+
# Reset this cursor on the server. Cursor options, such as the
|
|
93
|
+
# query string and the values for skip and limit, are preserved.
|
|
94
|
+
def rewind!
|
|
95
|
+
close
|
|
96
|
+
@cache.clear
|
|
97
|
+
@cursor_id = nil
|
|
98
|
+
@closed = false
|
|
99
|
+
@query_run = false
|
|
100
|
+
@n_received = nil
|
|
101
|
+
true
|
|
102
|
+
end
|
|
103
|
+
|
|
83
104
|
# Determine whether this cursor has any remaining results.
|
|
84
105
|
#
|
|
85
106
|
# @return [Boolean]
|
|
@@ -89,16 +110,23 @@ module Mongo
|
|
|
89
110
|
|
|
90
111
|
# Get the size of the result set for this query.
|
|
91
112
|
#
|
|
92
|
-
# @
|
|
93
|
-
#
|
|
113
|
+
# @param [Boolean] whether of not to take notice of skip and limit
|
|
114
|
+
#
|
|
115
|
+
# @return [Integer] the number of objects in the result set for this query.
|
|
94
116
|
#
|
|
95
117
|
# @raise [OperationFailure] on a database error.
|
|
96
|
-
def count
|
|
97
|
-
command = OrderedHash["count", @collection.name,
|
|
98
|
-
|
|
99
|
-
|
|
118
|
+
def count(skip_and_limit = false)
|
|
119
|
+
command = BSON::OrderedHash["count", @collection.name, "query", @selector]
|
|
120
|
+
|
|
121
|
+
if skip_and_limit
|
|
122
|
+
command.merge!(BSON::OrderedHash["limit", @limit]) if @limit != 0
|
|
123
|
+
command.merge!(BSON::OrderedHash["skip", @skip]) if @skip != 0
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
command.merge!(BSON::OrderedHash["fields", @fields])
|
|
127
|
+
|
|
100
128
|
response = @db.command(command)
|
|
101
|
-
return response['n'].to_i if response
|
|
129
|
+
return response['n'].to_i if Mongo::Support.ok?(response)
|
|
102
130
|
return 0 if response['errmsg'] == "ns missing"
|
|
103
131
|
raise OperationFailure, "Count failed: #{response['errmsg']}"
|
|
104
132
|
end
|
|
@@ -141,7 +169,6 @@ module Mongo
|
|
|
141
169
|
def limit(number_to_return=nil)
|
|
142
170
|
return @limit unless number_to_return
|
|
143
171
|
check_modifiable
|
|
144
|
-
raise ArgumentError, "limit requires an integer" unless number_to_return.is_a? Integer
|
|
145
172
|
|
|
146
173
|
@limit = number_to_return
|
|
147
174
|
self
|
|
@@ -159,12 +186,31 @@ module Mongo
|
|
|
159
186
|
def skip(number_to_skip=nil)
|
|
160
187
|
return @skip unless number_to_skip
|
|
161
188
|
check_modifiable
|
|
162
|
-
raise ArgumentError, "skip requires an integer" unless number_to_skip.is_a? Integer
|
|
163
189
|
|
|
164
190
|
@skip = number_to_skip
|
|
165
191
|
self
|
|
166
192
|
end
|
|
167
193
|
|
|
194
|
+
# Set the batch size for server responses.
|
|
195
|
+
#
|
|
196
|
+
# Note that the batch size will take effect only on queries
|
|
197
|
+
# where the number to be returned is greater than 100.
|
|
198
|
+
#
|
|
199
|
+
# @param [Integer] size either 0 or some integer greater than 1. If 0,
|
|
200
|
+
# the server will determine the batch size.
|
|
201
|
+
#
|
|
202
|
+
# @return [Cursor]
|
|
203
|
+
def batch_size(size=0)
|
|
204
|
+
check_modifiable
|
|
205
|
+
if size < 0 || size == 1
|
|
206
|
+
raise ArgumentError, "Invalid value for batch_size #{size}; must be 0 or > 1."
|
|
207
|
+
else
|
|
208
|
+
@batch_size = size > @limit ? @limit : size
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
self
|
|
212
|
+
end
|
|
213
|
+
|
|
168
214
|
# Iterate over each document in this cursor, yielding it to the given
|
|
169
215
|
# block.
|
|
170
216
|
#
|
|
@@ -177,31 +223,28 @@ module Mongo
|
|
|
177
223
|
# puts doc['user']
|
|
178
224
|
# end
|
|
179
225
|
def each
|
|
180
|
-
num_returned = 0
|
|
181
|
-
while has_next? && (@limit <= 0 || num_returned < @limit)
|
|
182
|
-
|
|
183
|
-
|
|
226
|
+
#num_returned = 0
|
|
227
|
+
#while has_next? && (@limit <= 0 || num_returned < @limit)
|
|
228
|
+
while doc = next_document
|
|
229
|
+
yield doc #next_document
|
|
230
|
+
#num_returned += 1
|
|
184
231
|
end
|
|
185
232
|
end
|
|
186
233
|
|
|
187
234
|
# Receive all the documents from this cursor as an array of hashes.
|
|
188
235
|
#
|
|
189
|
-
#
|
|
236
|
+
# Notes:
|
|
237
|
+
#
|
|
238
|
+
# If you've already started iterating over the cursor, the array returned
|
|
239
|
+
# by this method contains only the remaining documents. See Cursor#rewind! if you
|
|
240
|
+
# need to reset the cursor.
|
|
241
|
+
#
|
|
242
|
+
# Use of this method is discouraged - in most cases, it's much more
|
|
190
243
|
# efficient to retrieve documents as you need them by iterating over the cursor.
|
|
191
244
|
#
|
|
192
245
|
# @return [Array] an array of documents.
|
|
193
|
-
#
|
|
194
|
-
# @raise [InvalidOperation] if this cursor has already been used or if
|
|
195
|
-
# this method has already been called on the cursor.
|
|
196
246
|
def to_a
|
|
197
|
-
|
|
198
|
-
rows = []
|
|
199
|
-
num_returned = 0
|
|
200
|
-
while has_next? && (@limit <= 0 || num_returned < @limit)
|
|
201
|
-
rows << next_document
|
|
202
|
-
num_returned += 1
|
|
203
|
-
end
|
|
204
|
-
rows
|
|
247
|
+
super
|
|
205
248
|
end
|
|
206
249
|
|
|
207
250
|
# Get the explain plan for this cursor.
|
|
@@ -228,11 +271,12 @@ module Mongo
|
|
|
228
271
|
#
|
|
229
272
|
# @return [True]
|
|
230
273
|
def close
|
|
231
|
-
if @cursor_id
|
|
274
|
+
if @cursor_id && @cursor_id != 0
|
|
232
275
|
message = BSON::ByteBuffer.new([0, 0, 0, 0])
|
|
233
276
|
message.put_int(1)
|
|
234
277
|
message.put_long(@cursor_id)
|
|
235
|
-
@
|
|
278
|
+
@logger.debug("MONGODB cursor.close #{@cursor_id}") if @logger
|
|
279
|
+
@connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, nil)
|
|
236
280
|
end
|
|
237
281
|
@cursor_id = 0
|
|
238
282
|
@closed = true
|
|
@@ -250,10 +294,11 @@ module Mongo
|
|
|
250
294
|
# @see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
|
|
251
295
|
# The MongoDB wire protocol.
|
|
252
296
|
def query_opts
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
297
|
+
opts = 0
|
|
298
|
+
opts |= Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT unless @timeout
|
|
299
|
+
opts |= Mongo::Constants::OP_QUERY_SLAVE_OK if @connection.slave_ok?
|
|
300
|
+
opts |= Mongo::Constants::OP_QUERY_TAILABLE if @tailable
|
|
301
|
+
opts
|
|
257
302
|
end
|
|
258
303
|
|
|
259
304
|
# Get the query options for this Cursor.
|
|
@@ -262,7 +307,6 @@ module Mongo
|
|
|
262
307
|
def query_options_hash
|
|
263
308
|
{ :selector => @selector,
|
|
264
309
|
:fields => @fields,
|
|
265
|
-
:admin => @admin,
|
|
266
310
|
:skip => @skip_num,
|
|
267
311
|
:limit => @limit_num,
|
|
268
312
|
:order => @order,
|
|
@@ -271,6 +315,12 @@ module Mongo
|
|
|
271
315
|
:timeout => @timeout }
|
|
272
316
|
end
|
|
273
317
|
|
|
318
|
+
# Clean output for inspect.
|
|
319
|
+
def inspect
|
|
320
|
+
"<Mongo::Cursor:0x#{object_id.to_s(16)} namespace='#{@db.name}.#{@collection.name}' " +
|
|
321
|
+
"@selector=#{@selector.inspect}>"
|
|
322
|
+
end
|
|
323
|
+
|
|
274
324
|
private
|
|
275
325
|
|
|
276
326
|
# Convert the +:fields+ parameter from a single field name or an array
|
|
@@ -282,50 +332,42 @@ module Mongo
|
|
|
282
332
|
{fields => 1}
|
|
283
333
|
when Array
|
|
284
334
|
return nil if fields.length.zero?
|
|
285
|
-
|
|
286
|
-
fields.each { |field| hash[field] = 1 }
|
|
287
|
-
end
|
|
335
|
+
fields.each_with_object({}) { |field, hash| hash[field] = 1 }
|
|
288
336
|
when Hash
|
|
289
337
|
return fields
|
|
290
338
|
end
|
|
291
339
|
end
|
|
292
340
|
|
|
293
|
-
#
|
|
294
|
-
# the selector will be used in a $where clause.
|
|
295
|
-
# See http://www.mongodb.org/display/DOCS/Server-side+Code+Execution
|
|
296
|
-
def convert_selector_for_query(selector)
|
|
297
|
-
case selector
|
|
298
|
-
when Hash
|
|
299
|
-
selector
|
|
300
|
-
when nil
|
|
301
|
-
{}
|
|
302
|
-
when String
|
|
303
|
-
{"$where" => Code.new(selector)}
|
|
304
|
-
when Code
|
|
305
|
-
{"$where" => selector}
|
|
306
|
-
end
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
# Return a number of documents remaining for this cursor.
|
|
341
|
+
# Return the number of documents remaining for this cursor.
|
|
310
342
|
def num_remaining
|
|
311
|
-
|
|
343
|
+
refresh if @cache.length == 0
|
|
312
344
|
@cache.length
|
|
313
345
|
end
|
|
314
346
|
|
|
315
|
-
def
|
|
347
|
+
def refresh
|
|
316
348
|
return if send_initial_query || @cursor_id.zero?
|
|
317
349
|
message = BSON::ByteBuffer.new([0, 0, 0, 0])
|
|
318
350
|
|
|
319
351
|
# DB name.
|
|
320
|
-
|
|
321
|
-
BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.#{@collection.name}")
|
|
352
|
+
BSON::BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@collection.name}")
|
|
322
353
|
|
|
323
354
|
# Number of results to return.
|
|
324
|
-
|
|
355
|
+
if @limit > 0
|
|
356
|
+
limit = @limit - @returned
|
|
357
|
+
if @batch_size > 0
|
|
358
|
+
limit = limit < @batch_size ? limit : @batch_size
|
|
359
|
+
end
|
|
360
|
+
message.put_int(limit)
|
|
361
|
+
else
|
|
362
|
+
message.put_int(@batch_size)
|
|
363
|
+
end
|
|
325
364
|
|
|
326
365
|
# Cursor id.
|
|
327
366
|
message.put_long(@cursor_id)
|
|
328
|
-
|
|
367
|
+
@logger.debug("MONGODB cursor.refresh() for cursor #{@cursor_id}") if @logger
|
|
368
|
+
results, @n_received, @cursor_id = @connection.receive_message(
|
|
369
|
+
Mongo::Constants::OP_GET_MORE, message, nil, @socket, @command)
|
|
370
|
+
@returned += @n_received
|
|
329
371
|
@cache += results
|
|
330
372
|
close_cursor_if_query_complete
|
|
331
373
|
end
|
|
@@ -336,8 +378,10 @@ module Mongo
|
|
|
336
378
|
false
|
|
337
379
|
else
|
|
338
380
|
message = construct_query_message
|
|
339
|
-
|
|
340
|
-
|
|
381
|
+
@logger.debug query_log_message if @logger
|
|
382
|
+
results, @n_received, @cursor_id = @connection.receive_message(
|
|
383
|
+
Mongo::Constants::OP_QUERY, message, nil, @socket, @command)
|
|
384
|
+
@returned += @n_received
|
|
341
385
|
@cache += results
|
|
342
386
|
@query_run = true
|
|
343
387
|
close_cursor_if_query_complete
|
|
@@ -348,25 +392,24 @@ module Mongo
|
|
|
348
392
|
def construct_query_message
|
|
349
393
|
message = BSON::ByteBuffer.new
|
|
350
394
|
message.put_int(query_opts)
|
|
351
|
-
|
|
352
|
-
BSON::BSON_RUBY.serialize_cstr(message, "#{db_name}.#{@collection.name}")
|
|
395
|
+
BSON::BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@collection.name}")
|
|
353
396
|
message.put_int(@skip)
|
|
354
397
|
message.put_int(@limit)
|
|
355
398
|
spec = query_contains_special_fields? ? construct_query_spec : @selector
|
|
356
|
-
message.
|
|
357
|
-
message.
|
|
399
|
+
message.put_binary(BSON::BSON_CODER.serialize(spec, false).to_s)
|
|
400
|
+
message.put_binary(BSON::BSON_CODER.serialize(@fields, false).to_s) if @fields
|
|
358
401
|
message
|
|
359
402
|
end
|
|
360
403
|
|
|
361
404
|
def query_log_message
|
|
362
|
-
"#{@
|
|
405
|
+
"#{@db.name}['#{@collection.name}'].find(#{@selector.inspect}, #{@fields ? @fields.inspect : '{}'})" +
|
|
363
406
|
"#{@skip != 0 ? ('.skip(' + @skip.to_s + ')') : ''}#{@limit != 0 ? ('.limit(' + @limit.to_s + ')') : ''}" +
|
|
364
407
|
"#{@order ? ('.sort(' + @order.inspect + ')') : ''}"
|
|
365
408
|
end
|
|
366
409
|
|
|
367
410
|
def construct_query_spec
|
|
368
411
|
return @selector if @selector.has_key?('$query')
|
|
369
|
-
spec = OrderedHash.new
|
|
412
|
+
spec = BSON::OrderedHash.new
|
|
370
413
|
spec['$query'] = @selector
|
|
371
414
|
spec['$orderby'] = Mongo::Support.format_order_clause(@order) if @order
|
|
372
415
|
spec['$hint'] = @hint if @hint && @hint.length > 0
|
|
@@ -385,7 +428,9 @@ module Mongo
|
|
|
385
428
|
end
|
|
386
429
|
|
|
387
430
|
def close_cursor_if_query_complete
|
|
388
|
-
|
|
431
|
+
if @limit > 0 && @returned >= @limit
|
|
432
|
+
close
|
|
433
|
+
end
|
|
389
434
|
end
|
|
390
435
|
|
|
391
436
|
def check_modifiable
|