mongodb-mongo 0.12 → 0.13
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.rdoc +12 -12
- data/Rakefile +1 -1
- data/bin/bson_benchmark.rb +1 -1
- data/bin/mongo_console +3 -3
- data/bin/run_test_script +2 -2
- data/bin/standard_benchmark +3 -3
- data/examples/admin.rb +3 -3
- data/examples/benchmarks.rb +2 -2
- data/examples/blog.rb +4 -4
- data/examples/capped.rb +3 -3
- data/examples/cursor.rb +3 -3
- data/examples/gridfs.rb +4 -4
- data/examples/index_test.rb +11 -11
- data/examples/info.rb +3 -3
- data/examples/queries.rb +3 -3
- data/examples/simple.rb +3 -3
- data/examples/strict.rb +3 -3
- data/examples/types.rb +4 -9
- data/lib/mongo.rb +35 -3
- data/lib/mongo/admin.rb +56 -60
- data/lib/mongo/collection.rb +368 -320
- data/lib/mongo/connection.rb +166 -0
- data/lib/mongo/cursor.rb +206 -209
- data/lib/mongo/db.rb +478 -489
- data/lib/mongo/errors.rb +8 -9
- data/lib/mongo/gridfs/chunk.rb +66 -70
- data/lib/mongo/gridfs/grid_store.rb +406 -410
- data/lib/mongo/message/get_more_message.rb +8 -13
- data/lib/mongo/message/insert_message.rb +7 -11
- data/lib/mongo/message/kill_cursors_message.rb +7 -12
- data/lib/mongo/message/message.rb +58 -62
- data/lib/mongo/message/message_header.rb +19 -24
- data/lib/mongo/message/msg_message.rb +5 -9
- data/lib/mongo/message/opcodes.rb +10 -15
- data/lib/mongo/message/query_message.rb +42 -46
- data/lib/mongo/message/remove_message.rb +8 -12
- data/lib/mongo/message/update_message.rb +9 -13
- data/lib/mongo/query.rb +84 -88
- data/lib/mongo/types/binary.rb +13 -17
- data/lib/mongo/types/code.rb +9 -13
- data/lib/mongo/types/dbref.rb +10 -14
- data/lib/mongo/types/objectid.rb +103 -107
- data/lib/mongo/types/regexp_of_holding.rb +18 -22
- data/lib/mongo/types/undefined.rb +7 -10
- data/lib/mongo/util/bson.rb +4 -9
- data/lib/mongo/util/xml_to_ruby.rb +1 -3
- data/mongo-ruby-driver.gemspec +33 -32
- data/{tests → test}/mongo-qa/_common.rb +1 -1
- data/{tests → test}/mongo-qa/admin +1 -1
- data/{tests → test}/mongo-qa/capped +1 -1
- data/{tests → test}/mongo-qa/count1 +4 -4
- data/{tests → test}/mongo-qa/dbs +1 -1
- data/{tests → test}/mongo-qa/find +1 -1
- data/{tests → test}/mongo-qa/find1 +1 -1
- data/{tests → test}/mongo-qa/gridfs_in +2 -2
- data/{tests → test}/mongo-qa/gridfs_out +2 -2
- data/{tests → test}/mongo-qa/indices +2 -2
- data/{tests → test}/mongo-qa/remove +1 -1
- data/{tests → test}/mongo-qa/stress1 +1 -1
- data/{tests → test}/mongo-qa/test1 +1 -1
- data/{tests → test}/mongo-qa/update +1 -1
- data/{tests → test}/test_admin.rb +3 -3
- data/{tests → test}/test_bson.rb +4 -4
- data/{tests → test}/test_byte_buffer.rb +0 -0
- data/{tests → test}/test_chunk.rb +4 -4
- data/{tests → test}/test_collection.rb +42 -4
- data/{tests/test_mongo.rb → test/test_connection.rb} +35 -11
- data/test/test_cursor.rb +223 -0
- data/{tests → test}/test_db.rb +12 -12
- data/{tests → test}/test_db_api.rb +28 -33
- data/{tests → test}/test_db_connection.rb +3 -3
- data/{tests → test}/test_grid_store.rb +4 -4
- data/{tests → test}/test_message.rb +1 -1
- data/{tests → test}/test_objectid.rb +3 -3
- data/{tests → test}/test_ordered_hash.rb +0 -0
- data/{tests → test}/test_round_trip.rb +6 -2
- data/{tests → test}/test_threading.rb +3 -3
- data/test/test_xgen.rb +73 -0
- metadata +33 -32
- data/lib/mongo/mongo.rb +0 -164
- data/tests/test_cursor.rb +0 -121
@@ -0,0 +1,166 @@
|
|
1
|
+
# --
|
2
|
+
# Copyright (C) 2008-2009 10gen Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
# ++
|
16
|
+
|
17
|
+
require 'mongo/db'
|
18
|
+
|
19
|
+
module Mongo
|
20
|
+
|
21
|
+
# A connection to MongoDB.
|
22
|
+
class Connection
|
23
|
+
|
24
|
+
DEFAULT_PORT = 27017
|
25
|
+
|
26
|
+
# Create a Mongo database server instance. You specify either one or a
|
27
|
+
# pair of servers. If one, you also say if connecting to a slave is
|
28
|
+
# OK. In either case, the host default is "localhost" and port default
|
29
|
+
# is DEFAULT_PORT.
|
30
|
+
#
|
31
|
+
# If you specify a pair, pair_or_host is a hash with two keys :left
|
32
|
+
# and :right. Each key maps to either
|
33
|
+
# * a server name, in which case port is DEFAULT_PORT
|
34
|
+
# * a port number, in which case server is "localhost"
|
35
|
+
# * an array containing a server name and a port number in that order
|
36
|
+
#
|
37
|
+
# +options+ are passed on to each DB instance:
|
38
|
+
#
|
39
|
+
# :slave_ok :: Only used if one host is specified. If false, when
|
40
|
+
# connecting to that host/port a DB object will check to
|
41
|
+
# see if the server is the master. If it is not, an error
|
42
|
+
# is thrown.
|
43
|
+
#
|
44
|
+
# :auto_reconnect :: If a DB connection gets closed (for example, we
|
45
|
+
# have a server pair and saw the "not master"
|
46
|
+
# error, which closes the connection), then
|
47
|
+
# automatically try to reconnect to the master or
|
48
|
+
# to the single server we have been given. Defaults
|
49
|
+
# to +false+.
|
50
|
+
#
|
51
|
+
# Since that's so confusing, here are a few examples:
|
52
|
+
#
|
53
|
+
# Connection.new # localhost, DEFAULT_PORT, !slave
|
54
|
+
# Connection.new("localhost") # localhost, DEFAULT_PORT, !slave
|
55
|
+
# Connection.new("localhost", 3000) # localhost, 3000, slave not ok
|
56
|
+
# # localhost, 3000, slave ok
|
57
|
+
# Connection.new("localhost", 3000, :slave_ok => true)
|
58
|
+
# # localhost, DEFAULT_PORT, auto reconnect
|
59
|
+
# Connection.new(nil, nil, :auto_reconnect => true)
|
60
|
+
#
|
61
|
+
# # A pair of servers. DB will always talk to the master. On socket
|
62
|
+
# # error or "not master" error, we will auto-reconnect to the
|
63
|
+
# # current master.
|
64
|
+
# Connection.new({:left => ["db1.example.com", 3000],
|
65
|
+
# :right => "db2.example.com"}, # DEFAULT_PORT
|
66
|
+
# nil, :auto_reconnect => true)
|
67
|
+
#
|
68
|
+
# # Here, :right is localhost/DEFAULT_PORT. No auto-reconnect.
|
69
|
+
# Connection.new({:left => ["db1.example.com", 3000]})
|
70
|
+
#
|
71
|
+
# When a DB object first connects to a pair, it will find the master
|
72
|
+
# instance and connect to that one.
|
73
|
+
def initialize(pair_or_host=nil, port=nil, options={})
|
74
|
+
@pair = case pair_or_host
|
75
|
+
when String
|
76
|
+
[[pair_or_host, port ? port.to_i : DEFAULT_PORT]]
|
77
|
+
when Hash
|
78
|
+
connections = []
|
79
|
+
connections << pair_val_to_connection(pair_or_host[:left])
|
80
|
+
connections << pair_val_to_connection(pair_or_host[:right])
|
81
|
+
connections
|
82
|
+
when nil
|
83
|
+
[['localhost', DEFAULT_PORT]]
|
84
|
+
end
|
85
|
+
@options = options
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return the Mongo::DB named +db_name+. The slave_ok and
|
89
|
+
# auto_reconnect options passed in via #new may be overridden here.
|
90
|
+
# See DB#new for other options you can pass in.
|
91
|
+
def db(db_name, options={})
|
92
|
+
DB.new(db_name, @pair, @options.merge(options))
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns a hash containing database names as keys and disk space for
|
96
|
+
# each as values.
|
97
|
+
def database_info
|
98
|
+
doc = single_db_command('admin', :listDatabases => 1)
|
99
|
+
h = {}
|
100
|
+
doc['databases'].each { |db|
|
101
|
+
h[db['name']] = db['sizeOnDisk'].to_i
|
102
|
+
}
|
103
|
+
h
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns an array of database names.
|
107
|
+
def database_names
|
108
|
+
database_info.keys
|
109
|
+
end
|
110
|
+
|
111
|
+
# Not implemented.
|
112
|
+
def clone_database(from)
|
113
|
+
raise "not implemented"
|
114
|
+
end
|
115
|
+
|
116
|
+
# Not implemented.
|
117
|
+
def copy_database(from_host, from_db, to_db)
|
118
|
+
raise "not implemented"
|
119
|
+
end
|
120
|
+
|
121
|
+
# Drops the database +name+.
|
122
|
+
def drop_database(name)
|
123
|
+
single_db_command(name, :dropDatabase => 1)
|
124
|
+
end
|
125
|
+
|
126
|
+
protected
|
127
|
+
|
128
|
+
# Turns an array containing a host name string and a
|
129
|
+
# port number integer into a [host, port] pair array.
|
130
|
+
def pair_val_to_connection(a)
|
131
|
+
case a
|
132
|
+
when nil
|
133
|
+
['localhost', DEFAULT_PORT]
|
134
|
+
when String
|
135
|
+
[a, DEFAULT_PORT]
|
136
|
+
when Integer
|
137
|
+
['localhost', a]
|
138
|
+
when Array
|
139
|
+
a
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Send cmd (a hash, possibly ordered) to the admin database and return
|
144
|
+
# the answer. Raises an error unless the return is "ok" (DB#ok?
|
145
|
+
# returns +true+).
|
146
|
+
def single_db_command(db_name, cmd)
|
147
|
+
db = nil
|
148
|
+
begin
|
149
|
+
db = db(db_name)
|
150
|
+
doc = db.db_command(cmd)
|
151
|
+
raise "error retrieving database info: #{doc.inspect}" unless db.ok?(doc)
|
152
|
+
doc
|
153
|
+
ensure
|
154
|
+
db.close if db
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class Mongo < Connection
|
160
|
+
def initialize(pair_or_host=nil, port=nil, options={})
|
161
|
+
super(pair_or_host, port, options)
|
162
|
+
|
163
|
+
warn "Mongo::Mongo is deprecated and will be removed - please use Mongo::Connection"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
data/lib/mongo/cursor.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# --
|
2
1
|
# Copyright (C) 2008-2009 10gen Inc.
|
3
2
|
#
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -12,220 +11,218 @@
|
|
12
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
12
|
# See the License for the specific language governing permissions and
|
14
13
|
# limitations under the License.
|
15
|
-
# ++
|
16
14
|
|
17
15
|
require 'mongo/message'
|
18
16
|
require 'mongo/util/byte_buffer'
|
19
17
|
require 'mongo/util/bson'
|
20
18
|
|
21
|
-
module
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
#
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
def refill_via_get_more
|
195
|
-
send_query_if_needed
|
196
|
-
return if @cursor_id == 0
|
197
|
-
@db._synchronize {
|
198
|
-
@db.send_to_db(GetMoreMessage.new(@admin ? 'admin' : @db.name, @collection.name, @cursor_id))
|
199
|
-
read_all
|
200
|
-
}
|
201
|
-
end
|
202
|
-
|
203
|
-
def object_from_stream
|
204
|
-
buf = ByteBuffer.new
|
205
|
-
buf.put_array(@db.receive_full(4).unpack("C*"))
|
206
|
-
buf.rewind
|
207
|
-
size = buf.get_int
|
208
|
-
buf.put_array(@db.receive_full(size - 4).unpack("C*"), 4)
|
209
|
-
@n_remaining -= 1
|
210
|
-
buf.rewind
|
211
|
-
BSON.new.deserialize(buf)
|
212
|
-
end
|
213
|
-
|
214
|
-
def send_query_if_needed
|
215
|
-
# Run query first time we request an object from the wire
|
216
|
-
unless @query_run
|
217
|
-
@db._synchronize {
|
218
|
-
@db.send_query_message(QueryMessage.new(@admin ? 'admin' : @db.name, @collection.name, @query))
|
219
|
-
@query_run = true
|
220
|
-
read_all
|
221
|
-
}
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
def to_s
|
226
|
-
"DBResponse(flags=#@result_flags, cursor_id=#@cursor_id, start=#@starting_from, n_returned=#@n_returned)"
|
227
|
-
end
|
19
|
+
module Mongo
|
20
|
+
|
21
|
+
# A cursor over query results. Returned objects are hashes.
|
22
|
+
class Cursor
|
23
|
+
|
24
|
+
include Enumerable
|
25
|
+
|
26
|
+
RESPONSE_HEADER_SIZE = 20
|
27
|
+
|
28
|
+
attr_reader :db, :collection, :query
|
29
|
+
|
30
|
+
# Create a new cursor.
|
31
|
+
#
|
32
|
+
# Should not be called directly by application developers.
|
33
|
+
def initialize(db, collection, query, admin=false)
|
34
|
+
@db, @collection, @query, @admin = db, collection, query, admin
|
35
|
+
@num_to_return = @query.number_to_return || 0
|
36
|
+
@cache = []
|
37
|
+
@closed = false
|
38
|
+
@query_run = false
|
39
|
+
end
|
40
|
+
|
41
|
+
# Return the next object or nil if there are no more. Raises an error
|
42
|
+
# if necessary.
|
43
|
+
def next_object
|
44
|
+
refill_via_get_more if num_remaining == 0
|
45
|
+
o = @cache.shift
|
46
|
+
|
47
|
+
if o && o['$err']
|
48
|
+
err = o['$err']
|
49
|
+
|
50
|
+
# If the server has stopped being the master (e.g., it's one of a
|
51
|
+
# pair but it has died or something like that) then we close that
|
52
|
+
# connection. If the db has auto connect option and a pair of
|
53
|
+
# servers, next request will re-open on master server.
|
54
|
+
@db.close if err == "not master"
|
55
|
+
|
56
|
+
raise err
|
57
|
+
end
|
58
|
+
|
59
|
+
o
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get the size of the results set for this query.
|
63
|
+
#
|
64
|
+
# Returns the number of objects in the results set for this query. Does
|
65
|
+
# not take limit and skip into account. Raises OperationFailure on a
|
66
|
+
# database error.
|
67
|
+
def count
|
68
|
+
command = OrderedHash["count", @collection.name,
|
69
|
+
"query", @query.selector]
|
70
|
+
response = @db.db_command(command)
|
71
|
+
return response['n'].to_i if response['ok'] == 1
|
72
|
+
return 0 if response['errmsg'] == "ns missing"
|
73
|
+
raise OperationFailure, "Count failed: #{response['errmsg']}"
|
74
|
+
end
|
75
|
+
|
76
|
+
# Iterate over each document in this cursor, yielding it to the given
|
77
|
+
# block.
|
78
|
+
#
|
79
|
+
# Iterating over an entire cursor will close it.
|
80
|
+
def each
|
81
|
+
num_returned = 0
|
82
|
+
while more? && (@num_to_return <= 0 || num_returned < @num_to_return)
|
83
|
+
yield next_object()
|
84
|
+
num_returned += 1
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return all of the documents in this cursor as an array of hashes.
|
89
|
+
#
|
90
|
+
# Raises InvalidOperation if this cursor has already been used (including
|
91
|
+
# any previous calls to this method).
|
92
|
+
#
|
93
|
+
# Use of this method is discouraged - iterating over a cursor is much
|
94
|
+
# more efficient in most cases.
|
95
|
+
def to_a
|
96
|
+
raise InvalidOperation, "can't call Cursor#to_a on a used cursor" if @query_run
|
97
|
+
rows = []
|
98
|
+
num_returned = 0
|
99
|
+
while more? && (@num_to_return <= 0 || num_returned < @num_to_return)
|
100
|
+
rows << next_object()
|
101
|
+
num_returned += 1
|
102
|
+
end
|
103
|
+
rows
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns an explain plan record for this cursor.
|
107
|
+
def explain
|
108
|
+
old_val = @query.explain
|
109
|
+
@query.explain = true
|
110
|
+
|
111
|
+
c = Cursor.new(@db, @collection, @query)
|
112
|
+
explanation = c.next_object
|
113
|
+
c.close
|
114
|
+
|
115
|
+
@query.explain = old_val
|
116
|
+
explanation
|
117
|
+
end
|
118
|
+
|
119
|
+
# Close the cursor.
|
120
|
+
#
|
121
|
+
# Note: if a cursor is read until exhausted (read until OP_QUERY or
|
122
|
+
# OP_GETMORE returns zero for the cursor id), there is no need to
|
123
|
+
# close it by calling this method.
|
124
|
+
#
|
125
|
+
# Collection#find takes an optional block argument which can be used to
|
126
|
+
# ensure that your cursors get closed. See the documentation for
|
127
|
+
# Collection#find for details.
|
128
|
+
def close
|
129
|
+
@db.send_to_db(KillCursorsMessage.new(@cursor_id)) if @cursor_id
|
130
|
+
@cache = []
|
131
|
+
@cursor_id = 0
|
132
|
+
@closed = true
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns true if this cursor is closed, false otherwise.
|
136
|
+
def closed?; @closed; end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def read_all
|
141
|
+
read_message_header
|
142
|
+
read_response_header
|
143
|
+
read_objects_off_wire
|
144
|
+
end
|
145
|
+
|
146
|
+
def read_objects_off_wire
|
147
|
+
while doc = next_object_on_wire
|
148
|
+
@cache << doc
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def read_message_header
|
153
|
+
MessageHeader.new.read_header(@db)
|
154
|
+
end
|
155
|
+
|
156
|
+
def read_response_header
|
157
|
+
header_buf = ByteBuffer.new
|
158
|
+
header_buf.put_array(@db.receive_full(RESPONSE_HEADER_SIZE).unpack("C*"))
|
159
|
+
raise "Short read for DB response header; expected #{RESPONSE_HEADER_SIZE} bytes, saw #{header_buf.length}" unless header_buf.length == RESPONSE_HEADER_SIZE
|
160
|
+
header_buf.rewind
|
161
|
+
@result_flags = header_buf.get_int
|
162
|
+
@cursor_id = header_buf.get_long
|
163
|
+
@starting_from = header_buf.get_int
|
164
|
+
@n_returned = header_buf.get_int
|
165
|
+
@n_remaining = @n_returned
|
166
|
+
end
|
167
|
+
|
168
|
+
def num_remaining
|
169
|
+
refill_via_get_more if @cache.length == 0
|
170
|
+
@cache.length
|
171
|
+
end
|
172
|
+
|
173
|
+
# Internal method, not for general use. Return +true+ if there are
|
174
|
+
# more records to retrieve. We do not check @num_to_return; #each is
|
175
|
+
# responsible for doing that.
|
176
|
+
def more?
|
177
|
+
num_remaining > 0
|
178
|
+
end
|
179
|
+
|
180
|
+
def next_object_on_wire
|
181
|
+
send_query_if_needed
|
182
|
+
# if @n_remaining is 0 but we have a non-zero cursor, there are more
|
183
|
+
# to fetch, so do a GetMore operation, but don't do it here - do it
|
184
|
+
# when someone pulls an object out of the cache and it's empty
|
185
|
+
return nil if @n_remaining == 0
|
186
|
+
object_from_stream
|
187
|
+
end
|
188
|
+
|
189
|
+
def refill_via_get_more
|
190
|
+
if send_query_if_needed or @cursor_id == 0
|
191
|
+
return
|
228
192
|
end
|
193
|
+
@db._synchronize {
|
194
|
+
@db.send_to_db(GetMoreMessage.new(@admin ? 'admin' : @db.name, @collection.name, @cursor_id))
|
195
|
+
read_all
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
def object_from_stream
|
200
|
+
buf = ByteBuffer.new
|
201
|
+
buf.put_array(@db.receive_full(4).unpack("C*"))
|
202
|
+
buf.rewind
|
203
|
+
size = buf.get_int
|
204
|
+
buf.put_array(@db.receive_full(size - 4).unpack("C*"), 4)
|
205
|
+
@n_remaining -= 1
|
206
|
+
buf.rewind
|
207
|
+
BSON.new.deserialize(buf)
|
208
|
+
end
|
209
|
+
|
210
|
+
def send_query_if_needed
|
211
|
+
# Run query first time we request an object from the wire
|
212
|
+
if @query_run
|
213
|
+
false
|
214
|
+
else
|
215
|
+
@db._synchronize {
|
216
|
+
@db.send_query_message(QueryMessage.new(@admin ? 'admin' : @db.name, @collection.name, @query))
|
217
|
+
@query_run = true
|
218
|
+
read_all
|
219
|
+
}
|
220
|
+
true
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def to_s
|
225
|
+
"DBResponse(flags=#@result_flags, cursor_id=#@cursor_id, start=#@starting_from, n_returned=#@n_returned)"
|
229
226
|
end
|
230
227
|
end
|
231
228
|
end
|