mongo 0.18.2 → 0.18.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/README.rdoc +37 -28
  2. data/Rakefile +19 -0
  3. data/bin/objectid_benchmark.rb +23 -0
  4. data/examples/admin.rb +7 -6
  5. data/examples/capped.rb +3 -4
  6. data/examples/cursor.rb +4 -3
  7. data/examples/gridfs.rb +3 -2
  8. data/examples/index_test.rb +10 -9
  9. data/examples/info.rb +3 -2
  10. data/examples/queries.rb +3 -2
  11. data/examples/simple.rb +3 -2
  12. data/examples/strict.rb +2 -1
  13. data/examples/types.rb +4 -3
  14. data/lib/mongo.rb +29 -12
  15. data/lib/mongo/admin.rb +17 -2
  16. data/lib/mongo/collection.rb +230 -169
  17. data/lib/mongo/connection.rb +136 -91
  18. data/lib/mongo/cursor.rb +68 -40
  19. data/lib/mongo/db.rb +247 -123
  20. data/lib/mongo/{errors.rb → exceptions.rb} +6 -5
  21. data/lib/mongo/gridfs.rb +6 -0
  22. data/lib/mongo/gridfs/grid_store.rb +142 -94
  23. data/lib/mongo/types/binary.rb +11 -1
  24. data/lib/mongo/types/code.rb +6 -1
  25. data/lib/mongo/types/dbref.rb +7 -2
  26. data/lib/mongo/types/min_max_keys.rb +58 -0
  27. data/lib/mongo/types/objectid.rb +76 -20
  28. data/lib/mongo/types/regexp_of_holding.rb +5 -0
  29. data/lib/mongo/util/bson_ruby.rb +36 -2
  30. data/lib/mongo/util/byte_buffer.rb +18 -2
  31. data/lib/mongo/util/conversions.rb +6 -5
  32. data/lib/mongo/util/ordered_hash.rb +3 -1
  33. data/lib/mongo/util/support.rb +3 -0
  34. data/lib/mongo/util/xml_to_ruby.rb +7 -0
  35. data/test/test_bson.rb +48 -0
  36. data/test/test_collection.rb +13 -0
  37. data/test/test_connection.rb +35 -0
  38. data/test/test_conversions.rb +1 -1
  39. data/test/test_cursor.rb +37 -5
  40. data/test/test_db.rb +51 -2
  41. data/test/test_db_api.rb +4 -7
  42. data/test/test_grid_store.rb +10 -0
  43. data/test/test_objectid.rb +16 -2
  44. data/test/test_ordered_hash.rb +14 -0
  45. data/test/threading/test_threading_large_pool.rb +4 -4
  46. data/test/unit/db_test.rb +43 -0
  47. metadata +5 -7
  48. data/examples/benchmarks.rb +0 -42
  49. data/examples/blog.rb +0 -76
  50. data/lib/mongo/constants.rb +0 -15
  51. data/test/mongo-qa/_common.rb +0 -8
@@ -20,11 +20,10 @@ require 'thread'
20
20
 
21
21
  module Mongo
22
22
 
23
- # A connection to MongoDB.
23
+ # Instantiates and manages connections to MongoDB.
24
24
  class Connection
25
25
 
26
- # We need to make sure that all connection abort when
27
- # a ConnectionError is raised.
26
+ # Abort connections if a ConnectionError is raised.
28
27
  Thread.abort_on_exception = true
29
28
 
30
29
  DEFAULT_PORT = 27017
@@ -33,70 +32,59 @@ module Mongo
33
32
 
34
33
  attr_reader :logger, :size, :host, :port, :nodes, :sockets, :checked_out
35
34
 
36
- def slave_ok?
37
- @slave_ok
38
- end
39
-
40
35
  # Counter for generating unique request ids.
41
36
  @@current_request_id = 0
42
37
 
43
- # Creates a connection to MongoDB. Specify either one or a pair of servers,
38
+ # Create a connection to MongoDB. Specify either one or a pair of servers,
44
39
  # along with a maximum connection pool size and timeout.
45
40
  #
46
- # == Connecting
47
41
  # If connecting to just one server, you may specify whether connection to slave is permitted.
42
+ # In all cases, the default host is "localhost" and the default port is 27017.
48
43
  #
49
- # In all cases, the default host is "localhost" and the default port, is 27017.
50
- #
51
- # When specifying a pair, pair_or_host, is a hash with two keys: :left and :right. Each key maps to either
44
+ # When specifying a pair, +pair_or_host+, is a hash with two keys: :left and :right. Each key maps to either
52
45
  # * a server name, in which case port is 27017,
53
46
  # * a port number, in which case the server is "localhost", or
54
47
  # * an array containing [server_name, port_number]
55
48
  #
56
- # === Options
57
- #
58
- # :slave_ok :: Defaults to +false+. Must be set to +true+ when connecting
59
- # to a single, slave node.
60
- #
61
- # :logger :: Optional Logger instance to which driver usage information
62
- # will be logged.
63
- #
64
- # :auto_reconnect :: DEPRECATED. See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby
65
- #
66
- # :pool_size :: The maximum number of socket connections that can be opened
67
- # that can be opened to the database.
68
- #
69
- # :timeout :: When all of the connections to the pool are checked out,
70
- # this is the number of seconds to wait for a new connection
71
- # to be released before throwing an exception.
72
- #
73
49
  # Note that there are a few issues when using connection pooling with Ruby 1.9 on Windows. These
74
50
  # should be resolved in the next release.
75
51
  #
76
- # === Examples:
52
+ # @param [String, Hash] pair_or_host See explanation above.
53
+ # @param [Integer] port specify a port number here if only one host is being specified. Leave nil if
54
+ # specifying a pair of servers in +pair_or_host+.
77
55
  #
78
- # # localhost, 27017
79
- # Connection.new
56
+ # @option options [Boolean] :slave_ok (false) Must be set to +true+ when connecting
57
+ # to a single, slave node.
58
+ # @option options [Logger, #debug] :logger (nil) Logger instance to receive driver operation log.
59
+ # @option options [Boolean] :auto_reconnect DEPRECATED. See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby
60
+ # @option options [Integer] :pool_size (1) The maximum number of socket connections that can be opened to the database.
61
+ # @option options [Float] :timeout (5.0) When all of the connections to the pool are checked out,
62
+ # this is the number of seconds to wait for a new connection to be released before throwing an exception.
80
63
  #
81
- # # localhost, 27017
82
- # Connection.new("localhost")
83
64
  #
84
- # # localhost, 3000, max 5 connections, with max 5 seconds of wait time.
85
- # Connection.new("localhost", 3000, :pool_size => 5, :timeout => 5)
65
+ # @example localhost, 27017
66
+ # Connection.new
86
67
  #
87
- # # localhost, 3000, where this node may be a slave
88
- # Connection.new("localhost", 3000, :slave_ok => true)
68
+ # @example localhost, 27017
69
+ # Connection.new("localhost")
89
70
  #
90
- # # A pair of servers. The driver will always talk to master.
91
- # # On connection errors, Mongo::ConnectionFailure will be raised.
92
- # # See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby
93
- # Connection.new({:left => ["db1.example.com", 27017],
71
+ # @example localhost, 3000, max 5 connections, with max 5 seconds of wait time.
72
+ # Connection.new("localhost", 3000, :pool_size => 5, :timeout => 5)
73
+ #
74
+ # @example localhost, 3000, where this node may be a slave
75
+ # Connection.new("localhost", 3000, :slave_ok => true)
76
+ #
77
+ # @example A pair of servers. The driver will always talk to master.
78
+ # # On connection errors, Mongo::ConnectionFailure will be raised.
79
+ # Connection.new({:left => ["db1.example.com", 27017],
94
80
  # :right => ["db2.example.com", 27017]})
95
81
  #
96
- # A pair of servers, with connection pooling. Not the nil param placeholder for port.
97
- # Connection.new({:left => ["db1.example.com", 27017],
98
- # :right => ["db2.example.com", 27017]}, nil,
99
- # :pool_size => 20, :timeout => 5)
82
+ # @example A pair of servers with connection pooling enabled. Note the nil param placeholder for port.
83
+ # Connection.new({:left => ["db1.example.com", 27017],
84
+ # :right => ["db2.example.com", 27017]}, nil,
85
+ # :pool_size => 20, :timeout => 5)
86
+ #
87
+ # @see http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby Replica pairs in Ruby
100
88
  def initialize(pair_or_host=nil, port=nil, options={})
101
89
  @nodes = format_pair(pair_or_host, port)
102
90
 
@@ -124,7 +112,7 @@ module Mongo
124
112
  warn(":auto_reconnect is deprecated. see http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby")
125
113
  end
126
114
 
127
- # Slave ok can be true only if one node is specified
115
+ # slave_ok can be true only if one node is specified
128
116
  @slave_ok = options[:slave_ok] && @nodes.length == 1
129
117
  @logger = options[:logger] || nil
130
118
  @options = options
@@ -133,8 +121,10 @@ module Mongo
133
121
  connect_to_master if should_connect
134
122
  end
135
123
 
136
- # Returns a hash with all database names and their respective sizes on
137
- # disk.
124
+ # Return a hash with all database names
125
+ # and their respective sizes on disk.
126
+ #
127
+ # @return [Hash]
138
128
  def database_info
139
129
  doc = self['admin'].command(:listDatabases => 1)
140
130
  returning({}) do |info|
@@ -142,39 +132,57 @@ module Mongo
142
132
  end
143
133
  end
144
134
 
145
- # Returns an array of database names.
135
+ # Return an array of database names.
136
+ #
137
+ # @return [Array]
146
138
  def database_names
147
139
  database_info.keys
148
140
  end
149
141
 
150
- # Returns the database named +db_name+. The slave_ok and
151
- # See DB#new for other options you can pass in.
142
+ # Return a database with the given name.
143
+ # See DB#new for valid options hash parameters.
144
+ #
145
+ # @param [String] db_name a valid database name.
146
+ #
147
+ # @return [Mongo::DB]
152
148
  def db(db_name, options={})
153
149
  DB.new(db_name, self, options.merge(:logger => @logger))
154
150
  end
155
151
 
156
- # Returns the database named +db_name+.
152
+ # Shortcut for returning a database. Use DB#db to accept options.
153
+ #
154
+ # @param [String] db_name a valid database name.
155
+ #
156
+ # @return [Mongo::DB]
157
157
  def [](db_name)
158
158
  DB.new(db_name, self, :logger => @logger)
159
159
  end
160
160
 
161
- # Drops the database +name+.
161
+ # Drop a database.
162
+ #
163
+ # @param [String] name name of an existing database.
162
164
  def drop_database(name)
163
165
  self[name].command(:dropDatabase => 1)
164
166
  end
165
167
 
166
- # Copies the database +from+ on the local server to +to+ on the specified +host+.
168
+ # Copy the database +from+ on the local server to +to+ on the specified +host+.
167
169
  # +host+ defaults to 'localhost' if no value is provided.
168
- def copy_database(from, to, host="localhost")
170
+ #
171
+ # @param [String] from name of the database to copy from.
172
+ # @param [String] to name of the database to copy to.
173
+ # @param [String] from_host host of the 'from' database.
174
+ def copy_database(from, to, from_host="localhost")
169
175
  oh = OrderedHash.new
170
176
  oh[:copydb] = 1
171
- oh[:fromhost] = host
177
+ oh[:fromhost] = from_host
172
178
  oh[:fromdb] = from
173
179
  oh[:todb] = to
174
180
  self["admin"].command(oh)
175
181
  end
176
182
 
177
- # Increments and returns the next available request id.
183
+ # Increment and return the next available request id.
184
+ #
185
+ # return [Integer]
178
186
  def get_request_id
179
187
  request_id = ''
180
188
  @id_lock.synchronize do
@@ -183,51 +191,75 @@ module Mongo
183
191
  request_id
184
192
  end
185
193
 
186
- # Returns the build information for the current connection.
194
+ # Get the build information for the current connection.
195
+ #
196
+ # @return [Hash]
187
197
  def server_info
188
198
  db("admin").command({:buildinfo => 1}, {:admin => true, :check_response => true})
189
199
  end
190
200
 
191
- # Gets the build version of the current server.
192
- # Returns a ServerVersion object for comparability.
201
+ # Get the build version of the current server.
202
+ #
203
+ # @return [Mongo::ServerVersion]
204
+ # object allowing easy comparability of version.
193
205
  def server_version
194
206
  ServerVersion.new(server_info["version"])
195
207
  end
196
208
 
209
+ # Is it okay to connect to a slave?
210
+ #
211
+ # @return [Boolean]
212
+ def slave_ok?
213
+ @slave_ok
214
+ end
215
+
197
216
 
198
217
  ## Connections and pooling ##
199
218
 
200
- # Sends a message to MongoDB.
219
+ # Send a message to MongoDB, adding the necessary headers.
201
220
  #
202
- # Takes a MongoDB opcode, +operation+, a message of class ByteBuffer,
203
- # +message+, and an optional formatted +log_message+.
204
- # Sends the message to the databse, adding the necessary headers.
221
+ # @param [Integer] operation a MongoDB opcode.
222
+ # @param [ByteBuffer] message a message to send to the database.
223
+ # @param [String] log_message text version of +message+ for logging.
224
+ #
225
+ # @return [True]
205
226
  def send_message(operation, message, log_message=nil)
206
227
  @logger.debug(" MONGODB #{log_message || message}") if @logger
207
- packed_message = add_message_headers(operation, message).to_s
208
- socket = checkout
209
- send_message_on_socket(packed_message, socket)
210
- checkin(socket)
228
+ begin
229
+ packed_message = add_message_headers(operation, message).to_s
230
+ socket = checkout
231
+ send_message_on_socket(packed_message, socket)
232
+ ensure
233
+ checkin(socket)
234
+ end
211
235
  end
212
236
 
213
237
  # Sends a message to the database, waits for a response, and raises
214
238
  # an exception if the operation has failed.
215
239
  #
216
- # Takes a MongoDB opcode, +operation+, a message of class ByteBuffer,
217
- # +message+, the +db_name+, and an optional formatted +log_message+.
218
- # Sends the message to the database, adding the necessary headers.
240
+ # @param [Integer] operation a MongoDB opcode.
241
+ # @param [ByteBuffer] message a message to send to the database.
242
+ # @param [String] db_name the name of the database. used on call to get_last_error.
243
+ # @param [String] log_message text version of +message+ for logging.
244
+ #
245
+ # @return [Array]
246
+ # An array whose indexes include [0] documents returned, [1] number of document received,
247
+ # and [3] a cursor_id.
219
248
  def send_message_with_safe_check(operation, message, db_name, log_message=nil)
220
249
  message_with_headers = add_message_headers(operation, message)
221
250
  message_with_check = last_error_message(db_name)
222
251
  @logger.debug(" MONGODB #{log_message || message}") if @logger
223
- sock = checkout
224
- packed_message = message_with_headers.append!(message_with_check).to_s
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)
252
+ begin
253
+ sock = checkout
254
+ packed_message = message_with_headers.append!(message_with_check).to_s
255
+ docs = num_received = cursor_id = ''
256
+ @safe_mutex.synchronize do
257
+ send_message_on_socket(packed_message, sock)
258
+ docs, num_received, cursor_id = receive(sock)
259
+ end
260
+ ensure
261
+ checkin(sock)
229
262
  end
230
- checkin(sock)
231
263
  if num_received == 1 && error = docs[0]['err']
232
264
  raise Mongo::OperationFailure, error
233
265
  end
@@ -236,25 +268,35 @@ module Mongo
236
268
 
237
269
  # Sends a message to the database and waits for the response.
238
270
  #
239
- # Takes a MongoDB opcode, +operation+, a message of class ByteBuffer,
240
- # +message+, and an optional formatted +log_message+. This method
241
- # also takes an options socket for internal use with #connect_to_master.
271
+ # @param [Integer] operation a MongoDB opcode.
272
+ # @param [ByteBuffer] message a message to send to the database.
273
+ # @param [String] log_message text version of +message+ for logging.
274
+ # @param [Socket] socket a socket to use in lieu of checking out a new one.
275
+ #
276
+ # @return [Array]
277
+ # An array whose indexes include [0] documents returned, [1] number of document received,
278
+ # and [3] a cursor_id.
242
279
  def receive_message(operation, message, log_message=nil, socket=nil)
243
280
  packed_message = add_message_headers(operation, message).to_s
244
281
  @logger.debug(" MONGODB #{log_message || message}") if @logger
245
- sock = socket || checkout
282
+ begin
283
+ sock = socket || checkout
246
284
 
247
- result = ''
248
- @safe_mutex.synchronize do
249
- send_message_on_socket(packed_message, sock)
250
- result = receive(sock)
285
+ result = ''
286
+ @safe_mutex.synchronize do
287
+ send_message_on_socket(packed_message, sock)
288
+ result = receive(sock)
289
+ end
290
+ ensure
291
+ checkin(sock)
251
292
  end
252
- checkin(sock)
253
293
  result
254
294
  end
255
295
 
256
- # Creates a new socket and tries to connect to master.
257
- # If successful, sets @host and @port to master and returns the socket.
296
+ # Create a new socket and attempt to connect to master.
297
+ # If successful, sets host and port to master and returns the socket.
298
+ #
299
+ # @raise [ConnectionFailure] if unable to connect to any host or port.
258
300
  def connect_to_master
259
301
  close
260
302
  @host = @port = nil
@@ -286,7 +328,7 @@ module Mongo
286
328
  end
287
329
 
288
330
  # Are we connected to MongoDB? This is determined by checking whether
289
- # @host and @port have values, since they're set to nil on calls to #close.
331
+ # host and port have values, since they're set to nil on calls to #close.
290
332
  def connected?
291
333
  @host && @port
292
334
  end
@@ -361,6 +403,9 @@ module Mongo
361
403
  return socket if socket
362
404
 
363
405
  # Otherwise, wait
406
+ if @logger
407
+ @logger.warn "Waiting for available connection; #{@checked_out.size} of #{@size} connections checked out."
408
+ end
364
409
  @queue.wait(@connection_mutex)
365
410
  end
366
411
  end
@@ -25,7 +25,10 @@ module Mongo
25
25
 
26
26
  # Create a new cursor.
27
27
  #
28
- # Should not be called directly by application developers.
28
+ # Note: cursors are created when executing queries using [Collection#find] and other
29
+ # similar methods. Application developers shouldn't have to create cursors manually.
30
+ #
31
+ # @return [Cursor]
29
32
  def initialize(collection, options={})
30
33
  @db = collection.db
31
34
  @collection = collection
@@ -49,7 +52,9 @@ module Mongo
49
52
  @query_run = false
50
53
  end
51
54
 
52
- # Return the next document or nil if there are no more.
55
+ # Get the next document specified the cursor options.
56
+ #
57
+ # @return [Hash, Nil] the next document or Nil if no documents remain.
53
58
  def next_document
54
59
  refill_via_get_more if num_remaining == 0
55
60
  doc = @cache.shift
@@ -71,6 +76,7 @@ module Mongo
71
76
  doc
72
77
  end
73
78
 
79
+ # @deprecated use Cursor#next_document instead.
74
80
  def next_object
75
81
  warn "Cursor#next_object is deprecated; please use Cursor#next_document instead."
76
82
  next_document
@@ -78,9 +84,10 @@ module Mongo
78
84
 
79
85
  # Get the size of the result set for this query.
80
86
  #
81
- # Returns the number of objects in the result set for this query. Does
82
- # not take limit and skip into account. Raises OperationFailure on a
83
- # database error.
87
+ # @return [Integer] the number of objects in the result set for this query. Does
88
+ # not take limit and skip into account.
89
+ #
90
+ # @raise [OperationFailure] on a database error.
84
91
  def count
85
92
  command = OrderedHash["count", @collection.name,
86
93
  "query", @selector,
@@ -93,15 +100,16 @@ module Mongo
93
100
 
94
101
  # Sort this cursor's results.
95
102
  #
96
- # Takes either a single key and a direction, or an array of [key,
97
- # direction] pairs. Directions should be specified as Mongo::ASCENDING / Mongo::DESCENDING
98
- # (or :ascending / :descending, :asc / :desc).
99
- #
100
- # Raises InvalidOperation if this cursor has already been used. Raises
101
- # InvalidSortValueError if the specified order is invalid.
102
- #
103
103
  # This method overrides any sort order specified in the Collection#find
104
104
  # method, and only the last sort applied has an effect.
105
+ #
106
+ # @param [Symbol, Array] key_or_list either 1) a key to sort by or 2)
107
+ # an array of [key, direction] pairs to sort by. Direction should
108
+ # be specified as Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING (or :descending / :desc)
109
+ #
110
+ # @raise [InvalidOperation] if this cursor has already been used.
111
+ #
112
+ # @raise [InvalidSortValueError] if the specified order is invalid.
105
113
  def sort(key_or_list, direction=nil)
106
114
  check_modifiable
107
115
 
@@ -115,13 +123,14 @@ module Mongo
115
123
  self
116
124
  end
117
125
 
118
- # Limits the number of results to be returned by this cursor.
119
- # Returns the current number_to_return if no parameter is given.
120
- #
121
- # Raises InvalidOperation if this cursor has already been used.
126
+ # Limit the number of results to be returned by this cursor.
122
127
  #
123
128
  # This method overrides any limit specified in the Collection#find method,
124
129
  # and only the last limit applied has an effect.
130
+ #
131
+ # @return [Integer] the current number_to_return if no parameter is given.
132
+ #
133
+ # @raise [InvalidOperation] if this cursor has already been used.
125
134
  def limit(number_to_return=nil)
126
135
  return @limit unless number_to_return
127
136
  check_modifiable
@@ -134,10 +143,12 @@ module Mongo
134
143
  # Skips the first +number_to_skip+ results of this cursor.
135
144
  # Returns the current number_to_skip if no parameter is given.
136
145
  #
137
- # Raises InvalidOperation if this cursor has already been used.
138
- #
139
146
  # This method overrides any skip specified in the Collection#find method,
140
147
  # and only the last skip applied has an effect.
148
+ #
149
+ # @return [Integer]
150
+ #
151
+ # @raise [InvalidOperation] if this cursor has already been used.
141
152
  def skip(number_to_skip=nil)
142
153
  return @skip unless number_to_skip
143
154
  check_modifiable
@@ -151,6 +162,13 @@ module Mongo
151
162
  # block.
152
163
  #
153
164
  # Iterating over an entire cursor will close it.
165
+ #
166
+ # @yield passes each document to a block for processing.
167
+ #
168
+ # @example if 'comments' represents a collection of comments:
169
+ # comments.find.each do |doc|
170
+ # puts doc['user']
171
+ # end
154
172
  def each
155
173
  num_returned = 0
156
174
  while more? && (@limit <= 0 || num_returned < @limit)
@@ -159,13 +177,15 @@ module Mongo
159
177
  end
160
178
  end
161
179
 
162
- # Return all of the documents in this cursor as an array of hashes.
180
+ # Receive all the documents from this cursor as an array of hashes.
163
181
  #
164
- # Raises InvalidOperation if this cursor has already been used or if
165
- # this methods has already been called on the cursor.
182
+ # Note: use of this method is discouraged - in most cases, it's much more
183
+ # efficient to retrieve documents as you need them by iterating over the cursor.
166
184
  #
167
- # Use of this method is discouraged - iterating over a cursor is much
168
- # more efficient in most cases.
185
+ # @return [Array] an array of documents.
186
+ #
187
+ # @raise [InvalidOperation] if this cursor has already been used or if
188
+ # this method has already been called on the cursor.
169
189
  def to_a
170
190
  raise InvalidOperation, "can't call Cursor#to_a on a used cursor" if @query_run
171
191
  rows = []
@@ -177,7 +197,9 @@ module Mongo
177
197
  rows
178
198
  end
179
199
 
180
- # Returns an explain plan document for this cursor.
200
+ # Get the explain plan for this cursor.
201
+ #
202
+ # @return [Hash] a document containing the explain plan for this cursor.
181
203
  def explain
182
204
  c = Cursor.new(@collection, query_options_hash.merge(:limit => -@limit.abs, :explain => true))
183
205
  explanation = c.next_document
@@ -186,19 +208,19 @@ module Mongo
186
208
  explanation
187
209
  end
188
210
 
189
- # Closes the cursor.
211
+ # Close the cursor.
190
212
  #
191
213
  # Note: if a cursor is read until exhausted (read until Mongo::Constants::OP_QUERY or
192
214
  # Mongo::Constants::OP_GETMORE returns zero for the cursor id), there is no need to
193
- # close it by calling this method.
215
+ # close it manually.
216
+ #
217
+ # Note also: Collection#find takes an optional block argument which can be used to
218
+ # ensure that your cursors get closed.
194
219
  #
195
- # Collection#find takes an optional block argument which can be used to
196
- # ensure that your cursors get closed. See the documentation for
197
- # Collection#find for details.
220
+ # @return [True]
198
221
  def close
199
222
  if @cursor_id
200
- message = ByteBuffer.new
201
- message.put_int(0)
223
+ message = ByteBuffer.new([0, 0, 0, 0])
202
224
  message.put_int(1)
203
225
  message.put_long(@cursor_id)
204
226
  @connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, "cursor.close()")
@@ -207,18 +229,26 @@ module Mongo
207
229
  @closed = true
208
230
  end
209
231
 
210
- # Returns true if this cursor is closed, false otherwise.
232
+ # Is this cursor closed?
233
+ #
234
+ # @return [Boolean]
211
235
  def closed?; @closed; end
212
236
 
213
237
  # Returns an integer indicating which query options have been selected.
214
- # See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
238
+ #
239
+ # @return [Integer]
240
+ #
241
+ # @see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
242
+ # The MongoDB wire protocol.
215
243
  def query_opts
216
244
  timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
217
245
  slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
218
246
  slave_ok + timeout
219
247
  end
220
248
 
221
- # Returns the query options for this Cursor.
249
+ # Get the query options for this Cursor.
250
+ #
251
+ # @return [Hash]
222
252
  def query_options_hash
223
253
  { :selector => @selector,
224
254
  :fields => @fields,
@@ -233,7 +263,7 @@ module Mongo
233
263
 
234
264
  private
235
265
 
236
- # Converts the +:fields+ parameter from a single field name or an array
266
+ # Convert the +:fields+ parameter from a single field name or an array
237
267
  # of fields names to a hash, with the field names for keys and '1' for each
238
268
  # value.
239
269
  def convert_fields_for_query(fields)
@@ -284,9 +314,7 @@ module Mongo
284
314
 
285
315
  def refill_via_get_more
286
316
  return if send_initial_query || @cursor_id.zero?
287
- message = ByteBuffer.new
288
- # Reserved.
289
- message.put_int(0)
317
+ message = ByteBuffer.new([0, 0, 0, 0])
290
318
 
291
319
  # DB name.
292
320
  db_name = @admin ? 'admin' : @db.name
@@ -328,8 +356,8 @@ module Mongo
328
356
  if query_contains_special_fields?
329
357
  selector = selector_with_special_query_fields
330
358
  end
331
- message.put_array(BSON.serialize(selector, false).unpack("C*"))
332
- message.put_array(BSON.serialize(@fields, false).unpack("C*")) if @fields
359
+ message.put_array(BSON.serialize(selector, false).to_a)
360
+ message.put_array(BSON.serialize(@fields, false).to_a) if @fields
333
361
  message
334
362
  end
335
363