mongo 1.3.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +8 -7
- data/docs/HISTORY.md +19 -0
- data/lib/mongo.rb +1 -1
- data/lib/mongo/collection.rb +24 -14
- data/lib/mongo/connection.rb +27 -3
- data/lib/mongo/cursor.rb +25 -7
- data/lib/mongo/db.rb +30 -20
- data/lib/mongo/gridfs/grid.rb +2 -1
- data/lib/mongo/gridfs/grid_file_system.rb +1 -0
- data/lib/mongo/gridfs/grid_io.rb +56 -46
- data/lib/mongo/repl_set_connection.rb +1 -0
- data/test/bson/bson_test.rb +5 -0
- data/test/bson/ordered_hash_test.rb +7 -1
- data/test/db_api_test.rb +12 -0
- data/test/db_test.rb +35 -7
- data/test/grid_file_system_test.rb +16 -0
- data/test/grid_io_test.rb +18 -0
- data/test/grid_test.rb +59 -1
- data/test/replica_sets/connect_test.rb +5 -1
- data/test/replica_sets/query_secondaries.rb +15 -3
- data/test/tools/repl_set_manager.rb +3 -3
- metadata +138 -211
data/README.md
CHANGED
@@ -18,17 +18,18 @@ for much more:
|
|
18
18
|
|
19
19
|
require 'rubygems'
|
20
20
|
require 'mongo'
|
21
|
-
include Mongo
|
22
21
|
|
23
|
-
|
24
|
-
|
22
|
+
@conn = Mongo::Connection.new
|
23
|
+
@db = @conn['sample-db']
|
24
|
+
@coll = @db['test']
|
25
25
|
|
26
|
-
coll.remove
|
26
|
+
@coll.remove
|
27
27
|
3.times do |i|
|
28
|
-
coll.insert({'a' => i+1})
|
28
|
+
@coll.insert({'a' => i+1})
|
29
29
|
end
|
30
|
-
|
31
|
-
coll.
|
30
|
+
|
31
|
+
puts "There are #{@coll.count} records. Here they are:"
|
32
|
+
@coll.find.each { |doc| puts doc.inspect }
|
32
33
|
|
33
34
|
# Installation
|
34
35
|
|
data/docs/HISTORY.md
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
# MongoDB Ruby Driver History
|
2
2
|
|
3
|
+
### 1.3.1
|
4
|
+
2011-5-10
|
5
|
+
|
6
|
+
* Fix GridIO#gets infinite loop error (Ryan McGeary)
|
7
|
+
* Fix BSON::OrderedHash#reject! leaving keys with null values (rpt. by Ben Poweski)
|
8
|
+
* Minor semantic fix for OrderedHash#reject!
|
9
|
+
* Fix Mongo::DB to allow symbols in method traversing collection names (rpt. by Chris Griego)
|
10
|
+
* Support new server regex option "s" (dotall). This is folded in with \m in Ruby.
|
11
|
+
* Fix so that Cursor#close hits the right node when :read_secondary is enabled.
|
12
|
+
* Support maxScan, showDiskLoc, and returnKey cursor options.
|
13
|
+
* Make DB#validate_collection compatible with server v1.9.1.
|
14
|
+
* Fix so that GridIO#gets returns local md5 with md5 matches server md5 (Steve Tantra).
|
15
|
+
* Fix bug in BSON::OrderedHash that prevents YAML.load (Ian Warshak).
|
16
|
+
* Fix example from /examples.
|
17
|
+
* Ensure that we do not modify hash arguments by calling Hash#dup when appropriate.
|
18
|
+
* Ensure that JRuby deserializer preserves binary subtypes properly.
|
19
|
+
* Fix for streaming an empty file into GridFS (Daniël van de Burgt).
|
20
|
+
* Minor doc fixes.
|
21
|
+
|
3
22
|
### 1.3.0
|
4
23
|
2011-4-04
|
5
24
|
|
data/lib/mongo.rb
CHANGED
data/lib/mongo/collection.rb
CHANGED
@@ -91,7 +91,7 @@ module Mongo
|
|
91
91
|
# Return a sub-collection of this collection by name. If 'users' is a collection, then
|
92
92
|
# 'users.comments' is a sub-collection of users.
|
93
93
|
#
|
94
|
-
# @param [String] name
|
94
|
+
# @param [String, Symbol] name
|
95
95
|
# the collection to return
|
96
96
|
#
|
97
97
|
# @raise [Mongo::InvalidNSName]
|
@@ -101,7 +101,8 @@ module Mongo
|
|
101
101
|
# the specified sub-collection
|
102
102
|
def [](name)
|
103
103
|
name = "#{self.name}.#{name}"
|
104
|
-
return Collection.new(name, db) if !db.strict? ||
|
104
|
+
return Collection.new(name, db) if !db.strict? ||
|
105
|
+
db.collection_names.include?(name.to_s)
|
105
106
|
raise "Collection #{name} doesn't exist. Currently in strict mode."
|
106
107
|
end
|
107
108
|
|
@@ -147,16 +148,23 @@ module Mongo
|
|
147
148
|
# @option opts [Integer] :limit maximum number of documents to return
|
148
149
|
# @option opts [Array] :sort an array of [key, direction] pairs to sort by. Direction should
|
149
150
|
# be specified as Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING (or :descending / :desc)
|
150
|
-
# @option opts [String, Array, OrderedHash] :hint hint for query optimizer, usually not necessary if
|
151
|
+
# @option opts [String, Array, OrderedHash] :hint hint for query optimizer, usually not necessary if
|
152
|
+
# using MongoDB > 1.1
|
151
153
|
# @option opts [Boolean] :snapshot (false) if true, snapshot mode will be used for this query.
|
152
154
|
# Snapshot mode assures no duplicates are returned, or objects missed, which were preset at both the start and
|
153
|
-
# end of the query's execution.
|
154
|
-
#
|
155
|
-
#
|
155
|
+
# end of the query's execution.
|
156
|
+
# For details see http://www.mongodb.org/display/DOCS/How+to+do+Snapshotting+in+the+Mongo+Database
|
157
|
+
# @option opts [Boolean] :batch_size (100) the number of documents to returned by the database per
|
158
|
+
# GETMORE operation. A value of 0 will let the database server decide how many results to returns.
|
159
|
+
# This option can be ignored for most use cases.
|
156
160
|
# @option opts [Boolean] :timeout (true) when +true+, the returned cursor will be subject to
|
157
|
-
# the normal cursor timeout behavior of the mongod process. When +false+, the returned cursor will
|
158
|
-
# that disabling timeout will only work when #find is invoked with a block.
|
159
|
-
# close the cursor, as the cursor is explicitly
|
161
|
+
# the normal cursor timeout behavior of the mongod process. When +false+, the returned cursor will
|
162
|
+
# never timeout. Note that disabling timeout will only work when #find is invoked with a block.
|
163
|
+
# This is to prevent any inadvertant failure to close the cursor, as the cursor is explicitly
|
164
|
+
# closed when block code finishes.
|
165
|
+
# @option opts [Integer] :max_scan (nil) Limit the number of items to scan on both collection scans and indexed queries..
|
166
|
+
# @option opts [Boolean] :show_disk_loc (false) Return the disk location of each query result (for debugging).
|
167
|
+
# @option opts [Boolean] :return_key (false) Return the index key used to obtain the result (for debugging).
|
160
168
|
# @option opts [Block] :transformer (nil) a block for tranforming returned documents.
|
161
169
|
# This is normally used by object mappers to convert each returned document to an instance of a class.
|
162
170
|
#
|
@@ -168,6 +176,7 @@ module Mongo
|
|
168
176
|
#
|
169
177
|
# @core find find-instance_method
|
170
178
|
def find(selector={}, opts={})
|
179
|
+
opts = opts.dup
|
171
180
|
fields = opts.delete(:fields)
|
172
181
|
fields = ["_id"] if fields && fields.empty?
|
173
182
|
skip = opts.delete(:skip) || skip || 0
|
@@ -385,7 +394,7 @@ module Mongo
|
|
385
394
|
if safe
|
386
395
|
@connection.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, @db.name, nil, safe)
|
387
396
|
else
|
388
|
-
@connection.send_message(Mongo::Constants::OP_UPDATE, message
|
397
|
+
@connection.send_message(Mongo::Constants::OP_UPDATE, message)
|
389
398
|
end
|
390
399
|
end
|
391
400
|
end
|
@@ -433,8 +442,9 @@ module Mongo
|
|
433
442
|
#
|
434
443
|
# @core indexes create_index-instance_method
|
435
444
|
def create_index(spec, opts={})
|
436
|
-
opts[:dropDups] = opts
|
445
|
+
opts[:dropDups] = opts[:drop_dups] if opts[:drop_dups]
|
437
446
|
field_spec = parse_index_spec(spec)
|
447
|
+
opts = opts.dup
|
438
448
|
name = opts.delete(:name) || generate_index_name(field_spec)
|
439
449
|
name = name.to_s if name
|
440
450
|
|
@@ -462,7 +472,7 @@ module Mongo
|
|
462
472
|
now = Time.now.utc.to_i
|
463
473
|
field_spec = parse_index_spec(spec)
|
464
474
|
|
465
|
-
name = opts
|
475
|
+
name = opts[:name] || generate_index_name(field_spec)
|
466
476
|
name = name.to_s if name
|
467
477
|
|
468
478
|
if !@cache[name] || @cache[name] <= now
|
@@ -555,7 +565,7 @@ module Mongo
|
|
555
565
|
def map_reduce(map, reduce, opts={})
|
556
566
|
map = BSON::Code.new(map) unless map.is_a?(BSON::Code)
|
557
567
|
reduce = BSON::Code.new(reduce) unless reduce.is_a?(BSON::Code)
|
558
|
-
raw = opts
|
568
|
+
raw = opts[:raw]
|
559
569
|
|
560
570
|
hash = BSON::OrderedHash.new
|
561
571
|
hash['mapreduce'] = self.name
|
@@ -867,7 +877,7 @@ module Mongo
|
|
867
877
|
if safe
|
868
878
|
@connection.send_message_with_safe_check(Mongo::Constants::OP_INSERT, message, @db.name, nil, safe)
|
869
879
|
else
|
870
|
-
@connection.send_message(Mongo::Constants::OP_INSERT, message
|
880
|
+
@connection.send_message(Mongo::Constants::OP_INSERT, message)
|
871
881
|
end
|
872
882
|
end
|
873
883
|
documents.collect { |o| o[:_id] || o['_id'] }
|
data/lib/mongo/connection.rb
CHANGED
@@ -381,15 +381,36 @@ module Mongo
|
|
381
381
|
# @param [Integer] operation a MongoDB opcode.
|
382
382
|
# @param [BSON::ByteBuffer] message a message to send to the database.
|
383
383
|
#
|
384
|
+
# @option opts [Symbol] :connection (:writer) The connection to which
|
385
|
+
# this message should be sent. Valid options are :writer and :reader.
|
386
|
+
#
|
384
387
|
# @return [Integer] number of bytes sent
|
385
|
-
def send_message(operation, message,
|
388
|
+
def send_message(operation, message, opts={})
|
389
|
+
if opts.is_a?(String)
|
390
|
+
warn "Connection#send_message no longer takes a string log message. " +
|
391
|
+
"Logging is now handled within the Collection and Cursor classes."
|
392
|
+
opts = {}
|
393
|
+
end
|
394
|
+
|
395
|
+
connection = opts.fetch(:connection, :writer)
|
396
|
+
|
386
397
|
begin
|
387
398
|
add_message_headers(message, operation)
|
388
399
|
packed_message = message.to_s
|
389
|
-
|
400
|
+
|
401
|
+
if connection == :writer
|
402
|
+
socket = checkout_writer
|
403
|
+
else
|
404
|
+
socket = checkout_reader
|
405
|
+
end
|
406
|
+
|
390
407
|
send_message_on_socket(packed_message, socket)
|
391
408
|
ensure
|
392
|
-
|
409
|
+
if connection == :writer
|
410
|
+
checkin_writer(socket)
|
411
|
+
else
|
412
|
+
checkin_reader(socket)
|
413
|
+
end
|
393
414
|
end
|
394
415
|
end
|
395
416
|
|
@@ -437,7 +458,10 @@ module Mongo
|
|
437
458
|
#
|
438
459
|
# @param [Integer] operation a MongoDB opcode.
|
439
460
|
# @param [BSON::ByteBuffer] message a message to send to the database.
|
461
|
+
# @param [String] log_message this is currently a no-op and will be removed.
|
440
462
|
# @param [Socket] socket a socket to use in lieu of checking out a new one.
|
463
|
+
# @param [Boolean] command (false) indicate whether this is a command. If this is a command,
|
464
|
+
# the message will be sent to the primary node.
|
441
465
|
#
|
442
466
|
# @return [Array]
|
443
467
|
# An array whose indexes include [0] documents returned, [1] number of document received,
|
data/lib/mongo/cursor.rb
CHANGED
@@ -41,19 +41,31 @@ module Mongo
|
|
41
41
|
@connection = @db.connection
|
42
42
|
@logger = @connection.logger
|
43
43
|
|
44
|
+
# Query selector
|
44
45
|
@selector = opts[:selector] || {}
|
45
|
-
|
46
|
-
|
47
|
-
@limit = opts[:limit] || 0
|
46
|
+
|
47
|
+
# Special operators that form part of $query
|
48
48
|
@order = opts[:order]
|
49
|
+
@explain = opts[:explain]
|
49
50
|
@hint = opts[:hint]
|
50
51
|
@snapshot = opts[:snapshot]
|
52
|
+
@max_scan = opts.fetch(:max_scan, nil)
|
53
|
+
@return_key = opts.fetch(:return_key, nil)
|
54
|
+
@show_disk_loc = opts.fetch(:show_disk_loc, nil)
|
55
|
+
|
56
|
+
# Wire-protocol settings
|
57
|
+
@fields = convert_fields_for_query(opts[:fields])
|
58
|
+
@skip = opts[:skip] || 0
|
59
|
+
@limit = opts[:limit] || 0
|
60
|
+
@tailable = opts[:tailable] || false
|
51
61
|
@timeout = opts.fetch(:timeout, true)
|
52
|
-
|
62
|
+
|
63
|
+
# Use this socket for the query
|
53
64
|
@socket = opts[:socket]
|
54
|
-
|
65
|
+
|
55
66
|
@closed = false
|
56
67
|
@query_run = false
|
68
|
+
|
57
69
|
@transformer = opts[:transformer]
|
58
70
|
batch_size(opts[:batch_size] || 0)
|
59
71
|
|
@@ -284,7 +296,7 @@ module Mongo
|
|
284
296
|
message.put_int(1)
|
285
297
|
message.put_long(@cursor_id)
|
286
298
|
@logger.debug("MONGODB cursor.close #{@cursor_id}") if @logger
|
287
|
-
@connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message,
|
299
|
+
@connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, :connection => :reader)
|
288
300
|
end
|
289
301
|
@cursor_id = 0
|
290
302
|
@closed = true
|
@@ -320,7 +332,10 @@ module Mongo
|
|
320
332
|
:order => @order,
|
321
333
|
:hint => @hint,
|
322
334
|
:snapshot => @snapshot,
|
323
|
-
:timeout => @timeout
|
335
|
+
:timeout => @timeout,
|
336
|
+
:max_scan => @max_scan,
|
337
|
+
:return_key => @return_key,
|
338
|
+
:show_disk_loc => @show_disk_loc }
|
324
339
|
end
|
325
340
|
|
326
341
|
# Clean output for inspect.
|
@@ -429,6 +444,9 @@ module Mongo
|
|
429
444
|
spec['$hint'] = @hint if @hint && @hint.length > 0
|
430
445
|
spec['$explain'] = true if @explain
|
431
446
|
spec['$snapshot'] = true if @snapshot
|
447
|
+
spec['$maxscan'] = @max_scan if @max_scan
|
448
|
+
spec['$returnKey'] = true if @return_key
|
449
|
+
spec['$showDiskLoc'] = true if @show_disk_loc
|
432
450
|
spec
|
433
451
|
end
|
434
452
|
|
data/lib/mongo/db.rb
CHANGED
@@ -251,26 +251,28 @@ module Mongo
|
|
251
251
|
# new collection. If +strict+ is true, will raise an error if
|
252
252
|
# collection +name+ already exists.
|
253
253
|
#
|
254
|
-
# @param [String] name the name of the new collection.
|
254
|
+
# @param [String, Symbol] name the name of the new collection.
|
255
255
|
#
|
256
256
|
# @option opts [Boolean] :capped (False) created a capped collection.
|
257
257
|
#
|
258
|
-
# @option opts [Integer] :size (Nil) If +capped+ is +true+,
|
259
|
-
#
|
258
|
+
# @option opts [Integer] :size (Nil) If +capped+ is +true+,
|
259
|
+
# specifies the maximum number of bytes for the capped collection.
|
260
|
+
# If +false+, specifies the number of bytes allocated
|
260
261
|
# for the initial extent of the collection.
|
261
262
|
#
|
262
|
-
# @option opts [Integer] :max (Nil) If +capped+ is +true+, indicates
|
263
|
-
# in a capped collection.
|
263
|
+
# @option opts [Integer] :max (Nil) If +capped+ is +true+, indicates
|
264
|
+
# the maximum number of records in a capped collection.
|
264
265
|
#
|
265
|
-
# @raise [MongoDBError] raised under two conditions:
|
266
|
+
# @raise [MongoDBError] raised under two conditions:
|
267
|
+
# either we're in +strict+ mode and the collection
|
266
268
|
# already exists or collection creation fails on the server.
|
267
269
|
#
|
268
270
|
# @return [Mongo::Collection]
|
269
271
|
def create_collection(name, opts={})
|
270
|
-
|
271
|
-
if collection_names.include?(name)
|
272
|
+
if collection_names.include?(name.to_s)
|
272
273
|
if strict?
|
273
|
-
raise MongoDBError, "Collection #{name} already exists.
|
274
|
+
raise MongoDBError, "Collection #{name} already exists. " +
|
275
|
+
"Currently in strict mode."
|
274
276
|
else
|
275
277
|
return Collection.new(name, self, opts)
|
276
278
|
end
|
@@ -286,16 +288,19 @@ module Mongo
|
|
286
288
|
|
287
289
|
# Get a collection by name.
|
288
290
|
#
|
289
|
-
# @param [String] name the collection name.
|
291
|
+
# @param [String, Symbol] name the collection name.
|
290
292
|
# @param [Hash] opts any valid options that can be passed to Collection#new.
|
291
293
|
#
|
292
|
-
# @raise [MongoDBError] if collection does not already exist and we're in
|
294
|
+
# @raise [MongoDBError] if collection does not already exist and we're in
|
295
|
+
# +strict+ mode.
|
293
296
|
#
|
294
297
|
# @return [Mongo::Collection]
|
295
298
|
def collection(name, opts={})
|
296
|
-
if strict? && !collection_names.include?(name)
|
297
|
-
raise Mongo::MongoDBError, "Collection #{name} doesn't exist.
|
299
|
+
if strict? && !collection_names.include?(name.to_s)
|
300
|
+
raise Mongo::MongoDBError, "Collection #{name} doesn't exist. " +
|
301
|
+
"Currently in strict mode."
|
298
302
|
else
|
303
|
+
opts = opts.dup
|
299
304
|
opts[:safe] = opts.fetch(:safe, @safe)
|
300
305
|
opts.merge!(:pk => @pk_factory) unless opts[:pk]
|
301
306
|
Collection.new(name, self, opts)
|
@@ -305,11 +310,11 @@ module Mongo
|
|
305
310
|
|
306
311
|
# Drop a collection by +name+.
|
307
312
|
#
|
308
|
-
# @param [String] name
|
313
|
+
# @param [String, Symbol] name
|
309
314
|
#
|
310
315
|
# @return [Boolean] +true+ on success or +false+ if the collection name doesn't exist.
|
311
316
|
def drop_collection(name)
|
312
|
-
return true unless collection_names.include?(name)
|
317
|
+
return true unless collection_names.include?(name.to_s)
|
313
318
|
|
314
319
|
ok?(command(:drop => name))
|
315
320
|
end
|
@@ -590,11 +595,16 @@ module Mongo
|
|
590
595
|
# @raise [MongoDBError] if the command fails or there's a problem with the validation
|
591
596
|
# data, or if the collection is invalid.
|
592
597
|
def validate_collection(name)
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
+
cmd = BSON::OrderedHash.new
|
599
|
+
cmd[:validate] = name
|
600
|
+
cmd[:full] = true
|
601
|
+
doc = command(cmd, :check_response => false)
|
602
|
+
if !ok?(doc)
|
603
|
+
raise MongoDBError, "Error with validate command: #{doc.inspect}"
|
604
|
+
end
|
605
|
+
if (doc.has_key?('valid') && !doc['valid']) || (doc['result'] =~ /\b(exception|corrupt)\b/i)
|
606
|
+
raise MongoDBError, "Error: invalid collection #{name}: #{doc.inspect}"
|
607
|
+
end
|
598
608
|
doc
|
599
609
|
end
|
600
610
|
|
data/lib/mongo/gridfs/grid.rb
CHANGED
@@ -65,7 +65,8 @@ module Mongo
|
|
65
65
|
#
|
66
66
|
# @return [Mongo::ObjectId] the file's id.
|
67
67
|
def put(data, opts={})
|
68
|
-
|
68
|
+
opts = opts.dup
|
69
|
+
filename = opts[:filename]
|
69
70
|
opts.merge!(default_grid_io_opts)
|
70
71
|
file = GridIO.new(@files, @chunks, filename, 'w', opts=opts)
|
71
72
|
file.write(data)
|
data/lib/mongo/gridfs/grid_io.rb
CHANGED
@@ -55,6 +55,7 @@ module Mongo
|
|
55
55
|
@chunks = chunks
|
56
56
|
@filename = filename
|
57
57
|
@mode = mode
|
58
|
+
opts = opts.dup
|
58
59
|
@query = opts.delete(:query) || {}
|
59
60
|
@query_opts = opts.delete(:query_opts) || {}
|
60
61
|
@fs_name = opts.delete(:fs_name) || Grid::DEFAULT_FS_NAME
|
@@ -207,43 +208,9 @@ module Mongo
|
|
207
208
|
elsif separator.is_a?(Integer)
|
208
209
|
read_length(separator)
|
209
210
|
elsif separator.length > 1
|
210
|
-
|
211
|
-
len = 0
|
212
|
-
match_idx = 0
|
213
|
-
match_num = separator.length - 1
|
214
|
-
to_match = separator[match_idx].chr
|
215
|
-
if length
|
216
|
-
matcher = lambda {|idx, num| idx < num && len < length }
|
217
|
-
else
|
218
|
-
matcher = lambda {|idx, num| idx < num}
|
219
|
-
end
|
220
|
-
while matcher.call(match_idx, match_num) && char = getc
|
221
|
-
result << char
|
222
|
-
len += 1
|
223
|
-
if char == to_match
|
224
|
-
while match_idx < match_num do
|
225
|
-
match_idx += 1
|
226
|
-
to_match = separator[match_idx].chr
|
227
|
-
char = getc
|
228
|
-
result << char
|
229
|
-
if char != to_match
|
230
|
-
match_idx = 0
|
231
|
-
to_match = separator[match_idx].chr
|
232
|
-
break
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
237
|
-
result
|
211
|
+
read_to_string(separator, length)
|
238
212
|
else
|
239
|
-
|
240
|
-
len = 0
|
241
|
-
while char = getc
|
242
|
-
result << char
|
243
|
-
len += 1
|
244
|
-
break if char == separator || (length ? len >= length : false)
|
245
|
-
end
|
246
|
-
result
|
213
|
+
read_to_character(separator, length)
|
247
214
|
end
|
248
215
|
end
|
249
216
|
|
@@ -284,8 +251,9 @@ module Mongo
|
|
284
251
|
# @return [Mongo::GridIO] self
|
285
252
|
def each
|
286
253
|
return read_all unless block_given?
|
287
|
-
while chunk = read(chunk_size)
|
254
|
+
while chunk = read(chunk_size)
|
288
255
|
yield chunk
|
256
|
+
break if chunk.empty?
|
289
257
|
end
|
290
258
|
self
|
291
259
|
end
|
@@ -316,21 +284,18 @@ module Mongo
|
|
316
284
|
chunk
|
317
285
|
end
|
318
286
|
|
319
|
-
def last_chunk_number
|
320
|
-
(@file_length / @chunk_size).to_i
|
321
|
-
end
|
322
|
-
|
323
287
|
# Read a file in its entirety.
|
324
288
|
def read_all
|
325
289
|
buf = ''
|
326
290
|
if @current_chunk
|
327
291
|
buf << @current_chunk['data'].to_s
|
328
|
-
while
|
329
|
-
|
330
|
-
@current_chunk
|
292
|
+
while buf.size < @file_length
|
293
|
+
@current_chunk = get_chunk(@current_chunk['n'] + 1)
|
294
|
+
break if @current_chunk.nil?
|
295
|
+
buf << @current_chunk['data'].to_s
|
331
296
|
end
|
297
|
+
@file_position = @file_length
|
332
298
|
end
|
333
|
-
@file_position = @file_length
|
334
299
|
buf
|
335
300
|
end
|
336
301
|
|
@@ -361,6 +326,48 @@ module Mongo
|
|
361
326
|
buf
|
362
327
|
end
|
363
328
|
|
329
|
+
def read_to_character(character="\n", length=nil)
|
330
|
+
result = ''
|
331
|
+
len = 0
|
332
|
+
while char = getc
|
333
|
+
result << char
|
334
|
+
len += 1
|
335
|
+
break if char == character || (length ? len >= length : false)
|
336
|
+
end
|
337
|
+
result.length > 0 ? result : nil
|
338
|
+
end
|
339
|
+
|
340
|
+
def read_to_string(string="\n", length=nil)
|
341
|
+
result = ''
|
342
|
+
len = 0
|
343
|
+
match_idx = 0
|
344
|
+
match_num = string.length - 1
|
345
|
+
to_match = string[match_idx].chr
|
346
|
+
if length
|
347
|
+
matcher = lambda {|idx, num| idx < num && len < length }
|
348
|
+
else
|
349
|
+
matcher = lambda {|idx, num| idx < num}
|
350
|
+
end
|
351
|
+
while matcher.call(match_idx, match_num) && char = getc
|
352
|
+
result << char
|
353
|
+
len += 1
|
354
|
+
if char == to_match
|
355
|
+
while match_idx < match_num do
|
356
|
+
match_idx += 1
|
357
|
+
to_match = string[match_idx].chr
|
358
|
+
char = getc
|
359
|
+
result << char
|
360
|
+
if char != to_match
|
361
|
+
match_idx = 0
|
362
|
+
to_match = string[match_idx].chr
|
363
|
+
break
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
result.length > 0 ? result : nil
|
369
|
+
end
|
370
|
+
|
364
371
|
def cache_chunk_data
|
365
372
|
@current_chunk_data = @current_chunk['data'].to_s
|
366
373
|
if @current_chunk_data.respond_to?(:force_encoding)
|
@@ -413,6 +420,7 @@ module Mongo
|
|
413
420
|
|
414
421
|
# Initialize the class for writing a file.
|
415
422
|
def init_write(opts)
|
423
|
+
opts = opts.dup
|
416
424
|
@files_id = opts.delete(:_id) || BSON::ObjectId.new
|
417
425
|
@content_type = opts.delete(:content_type) || (defined? MIME) && get_content_type || DEFAULT_CONTENT_TYPE
|
418
426
|
@chunk_size = opts.delete(:chunk_size) || DEFAULT_CHUNK_SIZE
|
@@ -455,7 +463,9 @@ module Mongo
|
|
455
463
|
@server_md5 = @files.db.command(md5_command)['md5']
|
456
464
|
if @safe
|
457
465
|
@client_md5 = @local_md5.hexdigest
|
458
|
-
if @local_md5
|
466
|
+
if @local_md5 == @server_md5
|
467
|
+
@server_md5
|
468
|
+
else
|
459
469
|
raise GridMD5Failure, "File on server failed MD5 check"
|
460
470
|
end
|
461
471
|
else
|