From 5d85cf384f7b6612121c7d30bfea9e1ea4c8e426 Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Wed, 16 Dec 2009 14:14:15 -0500 Subject: [PATCH 1/5] minor: free buffer on invalid doc --- ext/cbson/cbson.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/cbson/cbson.c b/ext/cbson/cbson.c index 15d002f..56e95e2 100644 --- a/ext/cbson/cbson.c +++ b/ext/cbson/cbson.c @@ -459,6 +459,7 @@ static void write_doc(buffer_t buffer, VALUE hash, VALUE check_keys) { // make sure that length doesn't exceed 4MB if (length > 4 * 1024 * 1024) { + buffer_free(buffer); rb_raise(InvalidDocument, "Document too large: BSON documents are limited to 4MB."); return; } From f8a6d1ebb960d5529fa049cee3865c445e9f1ceb Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Wed, 16 Dec 2009 14:03:15 -0500 Subject: [PATCH 2/5] minor: docs, whitespace, naming --- HISTORY | 2 +- README.rdoc | 4 +- bin/gridstore_benchmark | 7 ++- examples/cursor.rb | 8 +-- examples/types.rb | 2 +- lib/mongo.rb | 2 +- lib/mongo/admin.rb | 3 +- lib/mongo/collection.rb | 6 +-- lib/mongo/connection.rb | 48 ++++++++--------- lib/mongo/constants.rb | 6 +-- lib/mongo/cursor.rb | 87 +++++++++++++++--------------- lib/mongo/db.rb | 14 ++--- lib/mongo/gridfs/grid_store.rb | 10 ++-- lib/mongo/types/code.rb | 1 + lib/mongo/util/server_version.rb | 6 +-- mongo-extensions.gemspec | 2 +- test/replica/count_test.rb | 6 +-- test/replica/insert_test.rb | 12 ++--- test/replica/pooled_insert_test.rb | 16 +++--- test/replica/query_test.rb | 6 +-- test/test_collection.rb | 6 +-- test/test_connection.rb | 4 +- test/test_cursor.rb | 32 +++++------ test/unit/collection_test.rb | 14 ++--- test/unit/cursor_test.rb | 24 ++++----- test/unit/db_test.rb | 22 ++++---- 26 files changed, 177 insertions(+), 173 deletions(-) diff --git a/HISTORY b/HISTORY index e011afe..dc8dfb9 100644 --- a/HISTORY +++ b/HISTORY @@ -8,7 +8,7 @@ 0.18 2009-11-25 * Connections now support connection pooling. See http://api.mongodb.org/ruby/0.18/classes/Mongo/Connection.html#M000158 * Deprecated :auto_reconnect option on connection; if the driver fails to - connect, it will automatically try to reconnect on the subsequent operation. + connect, it will automatically try to reconnect on the subsequent operation. See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby * Added Collection#map_reduce helper (Christos Trochalakis) * Deprecated DB#db_command in favor of DB#command. diff --git a/README.rdoc b/README.rdoc index be4e332..fe66517 100644 --- a/README.rdoc +++ b/README.rdoc @@ -13,7 +13,7 @@ Here is a quick code sample. See the MongoDB Ruby Tutorial @coll = db.collection('test') @coll.remove - 3.times do |i| + 3.times do |i| @coll.insert({'a' => i+1}) end puts "There are #{@coll.count()} records. Here they are:" @@ -254,7 +254,7 @@ Random cursor fun facts: = Testing -If you have the source code, you can run the tests. There's a separate rake task for testing with +If you have the source code, you can run the tests. There's a separate rake task for testing with the mongo_ext c extension enabled. $ rake test:c diff --git a/bin/gridstore_benchmark b/bin/gridstore_benchmark index db424a1..120b5de 100755 --- a/bin/gridstore_benchmark +++ b/bin/gridstore_benchmark @@ -2,7 +2,7 @@ require 'rubygems' require 'mongo' require 'mongo/gridfs' -require 'benchmark' +#require 'ruby-prof' include Mongo include GridFS @@ -15,10 +15,15 @@ length = sample_data.length mb = length / 1048576.0 t1 = Time.now +#RubyProf.start GridStore.open(db, 'mongodb.pdf', 'w') do |f| f.write(sample_data) end +#result = RubyProf.stop puts "Write: #{mb / (Time.now - t1)} mb/s" +#printer = RubyProf::FlatPrinter.new(result) +#printer.print(STDOUT, 0) + t1 = Time.now GridStore.open(db, 'mongodb.pdf', 'r') do |f| diff --git a/examples/cursor.rb b/examples/cursor.rb index 8e2e1ad..fa37ae4 100644 --- a/examples/cursor.rb +++ b/examples/cursor.rb @@ -33,14 +33,14 @@ array = cursor.to_a cursor.each { |row| pp row } # You can get the next object -first_object = coll.find().next_object +first_object = coll.find().next_document -# next_object returns nil if there are no more objects that match +# next_document returns nil if there are no more objects that match cursor = coll.find() -obj = cursor.next_object +obj = cursor.next_document while obj pp obj - obj = cursor.next_object + obj = cursor.next_document end # Destroy the collection diff --git a/examples/types.rb b/examples/types.rb index 1014fa1..dfdd798 100644 --- a/examples/types.rb +++ b/examples/types.rb @@ -30,6 +30,6 @@ coll.insert('array' => [1, 2, 3], 'null' => nil, 'symbol' => :zildjian) -pp coll.find().next_object +pp coll.find().next_document coll.clear diff --git a/lib/mongo.rb b/lib/mongo.rb index 6055192..f9d37ed 100644 --- a/lib/mongo.rb +++ b/lib/mongo.rb @@ -21,7 +21,7 @@ begin warn " You can install the extension as follows:\n gem install mongo_ext\n" warn " If you continue to receive this message after installing, make sure that the" warn " mongo_ext gem is in your load path and that the mongo_ext and mongo gems are of the same version.\n" -end +end require 'mongo/types/binary' require 'mongo/types/code' diff --git a/lib/mongo/admin.rb b/lib/mongo/admin.rb index 7f9fc01..ac73072 100644 --- a/lib/mongo/admin.rb +++ b/lib/mongo/admin.rb @@ -59,8 +59,7 @@ module Mongo raise "Error with profile command: #{doc.inspect}" unless @db.ok?(doc) end - # Return an array contining current profiling information from the - # database. + # Returns an array containing current profiling information. def profiling_info Cursor.new(Collection.new(@db, DB::SYSTEM_PROFILE_COLLECTION), :selector => {}).to_a end diff --git a/lib/mongo/collection.rb b/lib/mongo/collection.rb index 96cc44e..7f1839b 100644 --- a/lib/mongo/collection.rb +++ b/lib/mongo/collection.rb @@ -158,7 +158,7 @@ module Mongo else raise TypeError, "spec_or_object_id must be an instance of ObjectID or Hash, or nil" end - find(spec, options.merge(:limit => -1)).next_object + find(spec, options.merge(:limit => -1)).next_document end # Save a document in this collection. @@ -497,7 +497,7 @@ EOS # 'create' will be the collection name. For the other possible keys # and values, see DB#create_collection. def options - @db.collections_info(@name).next_object()['options'] + @db.collections_info(@name).next_document['options'] end # Get the number of documents in this collection. @@ -526,7 +526,7 @@ EOS private - # Sends an Mongo::Constants::OP_INSERT message to the database. + # Sends a Mongo::Constants::OP_INSERT message to the database. # Takes an array of +documents+, an optional +collection_name+, and a # +check_keys+ setting. def insert_documents(documents, collection_name=@name, check_keys=true, safe=false) diff --git a/lib/mongo/connection.rb b/lib/mongo/connection.rb index b6349cf..0372c95 100644 --- a/lib/mongo/connection.rb +++ b/lib/mongo/connection.rb @@ -33,10 +33,10 @@ module Mongo attr_reader :logger, :size, :host, :port, :nodes, :sockets, :checked_out, :reserved_connections - def slave_ok? + def slave_ok? @slave_ok end - + # Counter for generating unique request ids. @@current_request_id = 0 @@ -45,7 +45,7 @@ module Mongo # # == Connecting # If connecting to just one server, you may specify whether connection to slave is permitted. - # + # # In all cases, the default host is "localhost" and the default port, is 27017. # # When specifying a pair, pair_or_host, is a hash with two keys: :left and :right. Each key maps to either @@ -69,13 +69,13 @@ module Mongo # :timeout :: When all of the connections to the pool are checked out, # this is the number of seconds to wait for a new connection # to be released before throwing an exception. - # + # # # === Examples: # # # localhost, 27017 # Connection.new - # + # # # localhost, 27017 # Connection.new("localhost") # @@ -85,9 +85,9 @@ module Mongo # # localhost, 3000, where this node may be a slave # Connection.new("localhost", 3000, :slave_ok => true) # - # # A pair of servers. The driver will always talk to master. + # # A pair of servers. The driver will always talk to master. # # On connection errors, Mongo::ConnectionFailure will be raised. - # # See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby + # # See http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby # Connection.new({:left => ["db1.example.com", 27017], # :right => ["db2.example.com", 27017]}) # @@ -100,7 +100,7 @@ module Mongo # Host and port of current master. @host = @port = nil - + # Lock for request ids. @id_lock = Mutex.new @@ -123,7 +123,7 @@ module Mongo if options[:auto_reconnect] warn(":auto_reconnect is deprecated. see http://www.mongodb.org/display/DOCS/Replica+Pairs+in+Ruby") end - + # Slave ok can be true only if one node is specified @slave_ok = options[:slave_ok] && @nodes.length == 1 @logger = options[:logger] || nil @@ -177,7 +177,7 @@ module Mongo # Increments and returns the next available request id. def get_request_id request_id = '' - @id_lock.synchronize do + @id_lock.synchronize do request_id = @@current_request_id += 1 end request_id @@ -196,7 +196,7 @@ module Mongo ## Connections and pooling ## - + # Sends a message to MongoDB. # # Takes a MongoDB opcode, +operation+, a message of class ByteBuffer, @@ -234,7 +234,7 @@ module Mongo # Sends a message to the database and waits for the response. # # Takes a MongoDB opcode, +operation+, a message of class ByteBuffer, - # +message+, and an optional formatted +log_message+. This method + # +message+, and an optional formatted +log_message+. This method # also takes an options socket for internal use with #connect_to_master. def receive_message(operation, message, log_message=nil, socket=nil) packed_message = add_message_headers(operation, message).to_s @@ -275,7 +275,7 @@ module Mongo socket.close if socket false end - end + end raise ConnectionFailure, "failed to connect to any given host:port" unless socket end @@ -291,7 +291,7 @@ module Mongo sock.close end @host = @port = nil - @sockets.clear + @sockets.clear @checked_out.clear @reserved_connections.clear end @@ -312,7 +312,7 @@ module Mongo # Return a socket to the pool. def checkin(socket) - @connection_mutex.synchronize do + @connection_mutex.synchronize do @reserved_connections.delete Thread.current.object_id @checked_out.delete(socket) @queue.signal @@ -328,7 +328,7 @@ module Mongo Thread.list.each do |thread| keys.delete(thread.object_id) if thread.alive? end - + keys.each do |key| next unless @reserved_connections.has_key?(key) checkin(@reserved_connections[key]) @@ -366,10 +366,10 @@ module Mongo # pool size has not been exceeded. Otherwise, wait for the next # available socket. def obtain_socket - @connection_mutex.synchronize do + @connection_mutex.synchronize do connect_to_master if !connected? - loop do + loop do socket = if @checked_out.size < @sockets.size checkout_existing_socket elsif @sockets.size < @size @@ -401,9 +401,9 @@ module Mongo if RUBY_VERSION >= '1.9' # Ruby 1.9's Condition Variables don't support timeouts yet; - # until they do, we'll make do with this hack. + # until they do, we'll make do with this hack. def wait - Timeout.timeout(@timeout) do + Timeout.timeout(@timeout) do @queue.wait end end @@ -424,7 +424,7 @@ module Mongo header.put_array(receive_message_on_socket(16, sock).unpack("C*")) unless header.size == STANDARD_HEADER_SIZE raise "Short read for DB response header: " + - "expected #{STANDARD_HEADER_SIZE} bytes, saw #{header.size}" + "expected #{STANDARD_HEADER_SIZE} bytes, saw #{header.size}" end header.rewind size = header.get_int @@ -473,7 +473,7 @@ module Mongo message.put_array(BSON.serialize({:getlasterror => 1}, false).unpack("C*")) add_message_headers(Mongo::Constants::OP_QUERY, message) end - + # Prepares a message for transmission to MongoDB by # constructing a valid message header. def add_message_headers(operation, message) @@ -494,7 +494,7 @@ module Mongo end # Low-level method for sending a message on a socket. - # Requires a packed message and an available socket, + # Requires a packed message and an available socket, def send_message_on_socket(packed_message, socket) begin socket.send(packed_message, 0) @@ -537,7 +537,7 @@ module Mongo [['localhost', DEFAULT_PORT]] end end - + # Turns an array containing a host name string and a # port number integer into a [host, port] pair array. def pair_val_to_connection(a) diff --git a/lib/mongo/constants.rb b/lib/mongo/constants.rb index aa47e1f..3a9bb3b 100644 --- a/lib/mongo/constants.rb +++ b/lib/mongo/constants.rb @@ -1,8 +1,8 @@ module Mongo module Constants - OP_REPLY = 1 - OP_MSG = 1000 - OP_UPDATE = 2001 + OP_REPLY = 1 + OP_MSG = 1000 + OP_UPDATE = 2001 OP_INSERT = 2002 OP_QUERY = 2004 OP_GET_MORE = 2005 diff --git a/lib/mongo/cursor.rb b/lib/mongo/cursor.rb index e35151e..ed7efd9 100644 --- a/lib/mongo/cursor.rb +++ b/lib/mongo/cursor.rb @@ -19,7 +19,7 @@ module Mongo include Mongo::Conversions include Enumerable - attr_reader :collection, :selector, :admin, :fields, + attr_reader :collection, :selector, :admin, :fields, :order, :hint, :snapshot, :timeout, :full_collection_name @@ -49,19 +49,17 @@ module Mongo @query_run = false end - # Return the next object or nil if there are no more. Raises an error - # if necessary. - def next_object + # Return the next document or nil if there are no more. + def next_document refill_via_get_more if num_remaining == 0 - o = @cache.shift + doc = @cache.shift - if o && o['$err'] - err = o['$err'] + if doc && doc['$err'] + err = doc['$err'] # If the server has stopped being the master (e.g., it's one of a # pair but it has died or something like that) then we close that - # connection. If the db has auto connect option and a pair of - # servers, next request will re-open on master server. + # connection. The next request will re-open on master server. if err == "not master" raise ConnectionFailure, err @connection.close @@ -70,12 +68,12 @@ module Mongo raise OperationFailure, err end - o + doc end - # Get the size of the results set for this query. + # Get the size of the result set for this query. # - # Returns the number of objects in the results set for this query. Does + # Returns the number of objects in the result set for this query. Does # not take limit and skip into account. Raises OperationFailure on a # database error. def count @@ -88,17 +86,17 @@ module Mongo raise OperationFailure, "Count failed: #{response['errmsg']}" end - # Sort this cursor's result + # Sort this cursor's results. # # Takes either a single key and a direction, or an array of [key, - # direction] pairs. Directions should be specified as Mongo::ASCENDING - # or Mongo::DESCENDING (or :ascending or :descending) (or :asc or :desc). + # direction] pairs. Directions should be specified as Mongo::ASCENDING / Mongo::DESCENDING + # (or :ascending / :descending, :asc / :desc). # # Raises InvalidOperation if this cursor has already been used. Raises - # InvalidSortValueError if specified order is invalid. + # InvalidSortValueError if the specified order is invalid. # # This method overrides any sort order specified in the Collection#find - # method, and only the last sort applied has an effect + # method, and only the last sort applied has an effect. def sort(key_or_list, direction=nil) check_modifiable @@ -130,7 +128,7 @@ module Mongo # Skips the first +number_to_skip+ results of this cursor. # Returns the current number_to_skip if no parameter is given. - # + # # Raises InvalidOperation if this cursor has already been used. # # This method overrides any skip specified in the Collection#find method, @@ -151,15 +149,15 @@ module Mongo def each num_returned = 0 while more? && (@limit <= 0 || num_returned < @limit) - yield next_object() + yield next_document num_returned += 1 end end # Return all of the documents in this cursor as an array of hashes. # - # Raises InvalidOperation if this cursor has already been used (including - # any previous calls to this method). + # Raises InvalidOperation if this cursor has already been used or if + # this methods has already been called on the cursor. # # Use of this method is discouraged - iterating over a cursor is much # more efficient in most cases. @@ -168,22 +166,22 @@ module Mongo rows = [] num_returned = 0 while more? && (@limit <= 0 || num_returned < @limit) - rows << next_object() + rows << next_document num_returned += 1 end rows end - # Returns an explain plan record for this cursor. + # Returns an explain plan document for this cursor. def explain c = Cursor.new(@collection, query_options_hash.merge(:limit => -@limit.abs, :explain => true)) - explanation = c.next_object + explanation = c.next_document c.close explanation end - # Close the cursor. + # Closes the cursor. # # Note: if a cursor is read until exhausted (read until Mongo::Constants::OP_QUERY or # Mongo::Constants::OP_GETMORE returns zero for the cursor id), there is no need to @@ -211,20 +209,20 @@ module Mongo # See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY def query_opts timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT - slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0 + slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0 slave_ok + timeout end - # Returns the query options set on this Cursor. + # Returns the query options for this Cursor. def query_options_hash { :selector => @selector, - :fields => @fields, - :admin => @admin, - :skip => @skip_num, - :limit => @limit_num, - :order => @order, - :hint => @hint, - :snapshot => @snapshot, + :fields => @fields, + :admin => @admin, + :skip => @skip_num, + :limit => @limit_num, + :order => @order, + :hint => @hint, + :snapshot => @snapshot, :timeout => @timeout } end @@ -245,7 +243,7 @@ module Mongo end end - # Set query selector hash. If the selector is a Code or String object, + # Set the query selector hash. If the selector is a Code or String object, # the selector will be used in a $where clause. # See http://www.mongodb.org/display/DOCS/Server-side+Code+Execution def convert_selector_for_query(selector) @@ -266,20 +264,21 @@ module Mongo @order || @explain || @hint || @snapshot end + # Return a number of documents remaining for this cursor. def num_remaining refill_via_get_more if @cache.length == 0 @cache.length end # Internal method, not for general use. Return +true+ if there are - # more records to retrieve. This methods does not check @limit; - # #each is responsible for doing that. + # more records to retrieve. This method does not check @limit; + # Cursor#each is responsible for doing that. def more? num_remaining > 0 end def refill_via_get_more - return if send_query_if_needed || @cursor_id.zero? + return if send_initial_query || @cursor_id.zero? message = ByteBuffer.new # Reserved. message.put_int(0) @@ -290,7 +289,7 @@ module Mongo # Number of results to return; db decides for now. message.put_int(0) - + # Cursor id. message.put_long(@cursor_id) results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_GET_MORE, message, "cursor.get_more()", @socket) @@ -299,13 +298,13 @@ module Mongo end # Run query the first time we request an object from the wire - def send_query_if_needed + def send_initial_query if @query_run false else message = construct_query_message - results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_QUERY, message, - (query_log_message if @connection.logger), @socket) + results, @n_received, @cursor_id = @connection.receive_message(Mongo::Constants::OP_QUERY, message, + (query_log_message if @connection.logger), @socket) @cache += results @query_run = true close_cursor_if_query_complete @@ -331,7 +330,7 @@ module Mongo def query_log_message "#{@admin ? 'admin' : @db.name}.#{@collection.name}.find(#{@selector.inspect}, #{@fields ? @fields.inspect : '{}'})" + - "#{@skip != 0 ? ('.skip(' + @skip.to_s + ')') : ''}#{@limit != 0 ? ('.limit(' + @limit.to_s + ')') : ''}" + "#{@skip != 0 ? ('.skip(' + @skip.to_s + ')') : ''}#{@limit != 0 ? ('.limit(' + @limit.to_s + ')') : ''}" end def selector_with_special_query_fields @@ -349,7 +348,7 @@ module Mongo when String, Symbol then string_as_sort_parameters(@order) when Array then array_as_sort_parameters(@order) else - raise InvalidSortValueError, "Illegal sort clause, '#{@order.class.name}'; must be of the form " + + raise InvalidSortValueError, "Illegal sort clause, '#{@order.class.name}'; must be of the form " + "[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]" end end diff --git a/lib/mongo/db.rb b/lib/mongo/db.rb index b5b3def..7a636b9 100644 --- a/lib/mongo/db.rb +++ b/lib/mongo/db.rb @@ -48,7 +48,7 @@ module Mongo # The Mongo::Connection instance connecting to the MongoDB server. attr_reader :connection - + # An array of [host, port] pairs. attr_reader :nodes @@ -316,7 +316,7 @@ module Mongo def create_index(collection_name, field_or_spec, unique=false) self.collection(collection_name).create_index(field_or_spec, unique) end - + # Return +true+ if +doc+ contains an 'ok' field with the value 1. def ok?(doc) ok = doc['ok'] @@ -334,9 +334,9 @@ module Mongo end cursor = Cursor.new(Collection.new(self, SYSTEM_COMMAND_COLLECTION), :admin => use_admin_db, :limit => -1, :selector => selector, :socket => sock) - cursor.next_object + cursor.next_document end - + # Sends a command to the database. # # :selector (required) :: An OrderedHash, or a standard Hash with just one @@ -352,12 +352,12 @@ module Mongo # any selector containing more than one key must be an OrderedHash. def command(selector, admin=false, check_response=false, sock=nil) raise MongoArgumentError, "command must be given a selector" unless selector.is_a?(Hash) && !selector.empty? - if selector.class.eql?(Hash) && selector.keys.length > 1 + if selector.class.eql?(Hash) && selector.keys.length > 1 raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys" end - result = Cursor.new(system_command_collection, :admin => admin, - :limit => -1, :selector => selector, :socket => sock).next_object + result = Cursor.new(system_command_collection, :admin => admin, + :limit => -1, :selector => selector, :socket => sock).next_document if check_response && !ok?(result) raise OperationFailure, "Database command '#{selector.keys.first}' failed." diff --git a/lib/mongo/gridfs/grid_store.rb b/lib/mongo/gridfs/grid_store.rb index 724f2b1..f7b2d85 100644 --- a/lib/mongo/gridfs/grid_store.rb +++ b/lib/mongo/gridfs/grid_store.rb @@ -73,7 +73,7 @@ module GridFS class << self def exist?(db, name, root_collection=DEFAULT_ROOT_COLLECTION) - db.collection("#{root_collection}.files").find({'filename' => name}).next_object != nil + db.collection("#{root_collection}.files").find({'filename' => name}).next_document != nil end def open(db, name, mode, options={}) @@ -94,12 +94,12 @@ module GridFS } end - # List the contains of all GridFS files stored in the given db and + # List the contents of all GridFS files stored in the given db and # root collection. # # :db :: the database to use # - # :root_collection :: the root collection to use + # :root_collection :: the root collection to use. If not specified, will use default root collection. def list(db, root_collection=DEFAULT_ROOT_COLLECTION) db.collection("#{root_collection}.files").find().map { |f| f['filename'] @@ -148,7 +148,7 @@ module GridFS @db, @filename, @mode = db, name, mode @root = options[:root] || DEFAULT_ROOT_COLLECTION - doc = collection.find({'filename' => @filename}).next_object + doc = collection.find({'filename' => @filename}).next_document if doc @files_id = doc['_id'] @content_type = doc['contentType'] @@ -495,7 +495,7 @@ module GridFS end def nth_chunk(n) - mongo_chunk = chunk_collection.find({'files_id' => @files_id, 'n' => n}).next_object + mongo_chunk = chunk_collection.find({'files_id' => @files_id, 'n' => n}).next_document Chunk.new(self, mongo_chunk || {}) end diff --git a/lib/mongo/types/code.rb b/lib/mongo/types/code.rb index 09f61f0..dd94908 100644 --- a/lib/mongo/types/code.rb +++ b/lib/mongo/types/code.rb @@ -18,6 +18,7 @@ module Mongo # JavaScript code to be evaluated by MongoDB class Code < String + # Hash mapping identifiers to their values attr_accessor :scope diff --git a/lib/mongo/util/server_version.rb b/lib/mongo/util/server_version.rb index 226c271..c2feb24 100644 --- a/lib/mongo/util/server_version.rb +++ b/lib/mongo/util/server_version.rb @@ -25,7 +25,7 @@ module Mongo # Implements comparable. def <=>(new) local, new = self.to_a, to_array(new) - for n in 0...local.size do + for n in 0...local.size do break if elements_include_mods?(local[n], new[n]) if local[n] < new[n].to_i result = -1 @@ -52,10 +52,10 @@ module Mongo # Returns true if any elements include mod symbols (-, +) def elements_include_mods?(*elements) - elements.any? { |n| n =~ /[\-\+]/ } + elements.any? { |n| n =~ /[\-\+]/ } end - # Converts argument to an array of integers, + # Converts argument to an array of integers, # appending any mods as the final element. def to_array(version) array = version.split(".").map {|n| (n =~ /^\d+$/) ? n.to_i : n } diff --git a/mongo-extensions.gemspec b/mongo-extensions.gemspec index 5019945..2479209 100644 --- a/mongo-extensions.gemspec +++ b/mongo-extensions.gemspec @@ -1,5 +1,5 @@ require 'lib/mongo' -VERSION_HEADER = File.open(File.join(File.dirname(__FILE__), 'ext', 'cbson', 'version.h'), "r") +VERSION_HEADER = File.open(File.join(File.dirname(__FILE__), 'ext', 'cbson', 'version.h'), "r") VERSION = VERSION_HEADER.read.scan(/VERSION\s+"(\d+\.\d+(\.\d+)?)\"/)[0][0] Gem::Specification.new do |s| s.name = 'mongo_ext' diff --git a/test/replica/count_test.rb b/test/replica/count_test.rb index e3eae6d..638ddca 100644 --- a/test/replica/count_test.rb +++ b/test/replica/count_test.rb @@ -6,8 +6,8 @@ require 'test/test_helper' # NOTE: this test should be run only if a replica pair is running. class ReplicaPairCountTest < Test::Unit::TestCase include Mongo - - def setup + + def setup @conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil) @db = @conn.db('mongo-ruby-test') @db.drop_collection("test-pairs") @@ -24,7 +24,7 @@ class ReplicaPairCountTest < Test::Unit::TestCase puts "Please disconnect the current master." gets - rescue_connection_failure do + rescue_connection_failure do @coll.insert({:a => 30}, :safe => true) end @coll.insert({:a => 40}, :safe => true) diff --git a/test/replica/insert_test.rb b/test/replica/insert_test.rb index 36e0a9d..8eef365 100644 --- a/test/replica/insert_test.rb +++ b/test/replica/insert_test.rb @@ -6,8 +6,8 @@ require 'test/test_helper' # NOTE: this test should be run only if a replica pair is running. class ReplicaPairInsertTest < Test::Unit::TestCase include Mongo - - def setup + + def setup @conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil) @db = @conn.db('mongo-ruby-test') @db.drop_collection("test-pairs") @@ -19,7 +19,7 @@ class ReplicaPairInsertTest < Test::Unit::TestCase puts "Please disconnect the current master." gets - rescue_connection_failure do + rescue_connection_failure do @coll.save({:a => 30}, :safe => true) end @@ -28,12 +28,12 @@ class ReplicaPairInsertTest < Test::Unit::TestCase @coll.save({:a => 60}, :safe => true) @coll.save({:a => 70}, :safe => true) - puts "Please reconnect the old master to make sure that the new master " + + puts "Please reconnect the old master to make sure that the new master " + "has synced with the previous master. Note: this may have happened already." gets results = [] - - rescue_connection_failure do + + rescue_connection_failure do @coll.find.each {|r| results << r} [20, 30, 40, 50, 60, 70].each do |a| assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}" diff --git a/test/replica/pooled_insert_test.rb b/test/replica/pooled_insert_test.rb index 3ce41e5..ed8984b 100644 --- a/test/replica/pooled_insert_test.rb +++ b/test/replica/pooled_insert_test.rb @@ -6,8 +6,8 @@ require 'test/test_helper' # NOTE: this test should be run only if a replica pair is running. class ReplicaPairPooledInsertTest < Test::Unit::TestCase include Mongo - - def setup + + def setup @conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil, :pool_size => 10, :timeout => 5) @db = @conn.db('mongo-ruby-test') @db.drop_collection("test-pairs") @@ -22,22 +22,22 @@ class ReplicaPairPooledInsertTest < Test::Unit::TestCase threads = [] 10.times do |i| - threads[i] = Thread.new do - rescue_connection_failure do + threads[i] = Thread.new do + rescue_connection_failure do @coll.save({:a => i}, :safe => true) end end end - puts "Please reconnect the old master to make sure that the new master " + - "has synced with the previous master. Note: this may have happened already." + + puts "Please reconnect the old master to make sure that the new master " + + "has synced with the previous master. Note: this may have happened already." + "Note also that when connection with multiple threads, you may need to wait a few seconds" + "after restarting the old master so that all the data has had a chance to sync." + "This is a case of eventual consistency." gets results = [] - - rescue_connection_failure do + + rescue_connection_failure do @coll.find.each {|r| results << r} expected_results.each do |a| assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}" diff --git a/test/replica/query_test.rb b/test/replica/query_test.rb index c507b61..65da640 100644 --- a/test/replica/query_test.rb +++ b/test/replica/query_test.rb @@ -6,8 +6,8 @@ require 'test/test_helper' # NOTE: this test should be run only if a replica pair is running. class ReplicaPairQueryTest < Test::Unit::TestCase include Mongo - - def setup + + def setup @conn = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil) @db = @conn.db('mongo-ruby-test') @db.drop_collection("test-pairs") @@ -28,7 +28,7 @@ class ReplicaPairQueryTest < Test::Unit::TestCase gets results = [] - rescue_connection_failure do + rescue_connection_failure do @coll.find.each {|r| results << r} [20, 30, 40].each do |a| assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}" diff --git a/test/test_collection.rb b/test/test_collection.rb index 48706cf..2ef94d2 100644 --- a/test/test_collection.rb +++ b/test/test_collection.rb @@ -359,12 +359,12 @@ class TestCollection < Test::Unit::TestCase @@test.save(:foo => i) end - assert_equal 5, @@test.find({}, :skip => 5).next_object()["foo"] - assert_equal nil, @@test.find({}, :skip => 10).next_object() + assert_equal 5, @@test.find({}, :skip => 5).next_document()["foo"] + assert_equal nil, @@test.find({}, :skip => 10).next_document() assert_equal 5, @@test.find({}, :limit => 5).to_a.length - assert_equal 3, @@test.find({}, :skip => 3, :limit => 5).next_object()["foo"] + assert_equal 3, @@test.find({}, :skip => 3, :limit => 5).next_document()["foo"] assert_equal 5, @@test.find({}, :skip => 3, :limit => 5).to_a.length end diff --git a/test/test_connection.rb b/test/test_connection.rb index 536315e..3713843 100644 --- a/test/test_connection.rb +++ b/test/test_connection.rb @@ -54,8 +54,8 @@ class TestConnection < Test::Unit::TestCase def test_copy_database @mongo.db('old').collection('copy-test').insert('a' => 1) @mongo.copy_database('old', 'new') - old_object = @mongo.db('old').collection('copy-test').find.next_object - new_object = @mongo.db('new').collection('copy-test').find.next_object + old_object = @mongo.db('old').collection('copy-test').find.next_document + new_object = @mongo.db('new').collection('copy-test').find.next_document assert_equal old_object, new_object end diff --git a/test/test_cursor.rb b/test/test_cursor.rb index 99f42a9..e34d4ff 100644 --- a/test/test_cursor.rb +++ b/test/test_cursor.rb @@ -64,27 +64,27 @@ class CursorTest < Test::Unit::TestCase assert_kind_of Cursor, @@coll.find().sort(:a, 1) - assert_equal 0, @@coll.find().sort(:a, 1).next_object["a"] - assert_equal 4, @@coll.find().sort(:a, -1).next_object["a"] - assert_equal 0, @@coll.find().sort([["a", :asc]]).next_object["a"] + assert_equal 0, @@coll.find().sort(:a, 1).next_document["a"] + assert_equal 4, @@coll.find().sort(:a, -1).next_document["a"] + assert_equal 0, @@coll.find().sort([["a", :asc]]).next_document["a"] assert_kind_of Cursor, @@coll.find().sort([[:a, -1], [:b, 1]]) - assert_equal 4, @@coll.find().sort(:a, 1).sort(:a, -1).next_object["a"] - assert_equal 0, @@coll.find().sort(:a, -1).sort(:a, 1).next_object["a"] + assert_equal 4, @@coll.find().sort(:a, 1).sort(:a, -1).next_document["a"] + assert_equal 0, @@coll.find().sort(:a, -1).sort(:a, 1).next_document["a"] cursor = @@coll.find() - cursor.next_object() + cursor.next_document assert_raise InvalidOperation do cursor.sort(["a"]) end assert_raise InvalidSortValueError do - @@coll.find().sort(:a, 25).next_object + @@coll.find().sort(:a, 25).next_document end assert_raise InvalidSortValueError do - @@coll.find().sort(25).next_object + @@coll.find().sort(25).next_document end end @@ -106,7 +106,7 @@ class CursorTest < Test::Unit::TestCase end cursor = @@coll.find() - firstResult = cursor.next_object() + firstResult = cursor.next_document assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do cursor.limit(1) end @@ -140,7 +140,7 @@ class CursorTest < Test::Unit::TestCase end cursor = @@coll.find() - firstResult = cursor.next_object() + firstResult = cursor.next_document assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do cursor.skip(1) end @@ -233,7 +233,7 @@ class CursorTest < Test::Unit::TestCase def test_close_after_query_sent begin cursor = @@coll.find('a' => 1) - cursor.next_object + cursor.next_document cursor.close assert cursor.closed? rescue => ex @@ -267,7 +267,7 @@ class CursorTest < Test::Unit::TestCase 10.times do |i| a = @@coll.find() - a.next_object() + a.next_document a.close() end @@ -277,7 +277,7 @@ class CursorTest < Test::Unit::TestCase @@db.command("cursorInfo" => 1)["byLocation_size"]) a = @@coll.find() - a.next_object() + a.next_document assert_not_equal(client_cursors, @@db.command("cursorInfo" => 1)["clientCursors_size"]) @@ -291,7 +291,7 @@ class CursorTest < Test::Unit::TestCase assert_equal(by_location, @@db.command("cursorInfo" => 1)["byLocation_size"]) - a = @@coll.find({}, :limit => 10).next_object() + a = @@coll.find({}, :limit => 10).next_document assert_equal(client_cursors, @@db.command("cursorInfo" => 1)["clientCursors_size"]) @@ -299,7 +299,7 @@ class CursorTest < Test::Unit::TestCase @@db.command("cursorInfo" => 1)["byLocation_size"]) @@coll.find() do |cursor| - cursor.next_object() + cursor.next_document end assert_equal(client_cursors, @@ -308,7 +308,7 @@ class CursorTest < Test::Unit::TestCase @@db.command("cursorInfo" => 1)["byLocation_size"]) @@coll.find() { |cursor| - cursor.next_object() + cursor.next_document } assert_equal(client_cursors, diff --git a/test/unit/collection_test.rb b/test/unit/collection_test.rb index 6ead170..98fcdc9 100644 --- a/test/unit/collection_test.rb +++ b/test/unit/collection_test.rb @@ -2,26 +2,26 @@ require 'test/test_helper' class ConnectionTest < Test::Unit::TestCase - context "Basic operations: " do - setup do + context "Basic operations: " do + setup do @logger = mock() end - should "send update message" do + should "send update message" do @conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false) @db = @conn['testing'] @coll = @db.collection('books') - @conn.expects(:send_message).with do |op, msg, log| + @conn.expects(:send_message).with do |op, msg, log| op == 2001 && log.include?("db.books.update") end @coll.update({}, {:title => 'Moby Dick'}) end - should "send insert message" do + should "send insert message" do @conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false) @db = @conn['testing'] @coll = @db.collection('books') - @conn.expects(:send_message).with do |op, msg, log| + @conn.expects(:send_message).with do |op, msg, log| op == 2002 && log.include?("db.books.insert") end @coll.insert({:title => 'Moby Dick'}) @@ -49,4 +49,4 @@ class ConnectionTest < Test::Unit::TestCase end end - + diff --git a/test/unit/cursor_test.rb b/test/unit/cursor_test.rb index cc2e489..09ab883 100644 --- a/test/unit/cursor_test.rb +++ b/test/unit/cursor_test.rb @@ -2,15 +2,15 @@ require 'test/test_helper' class TestCursor < Test::Unit::TestCase - context "Cursor options" do - setup do + context "Cursor options" do + setup do @connection = stub(:class => Connection) - @db = stub(:name => "testing", :slave_ok? => false, :connection => @connection) + @db = stub(:name => "testing", :slave_ok? => false, :connection => @connection) @collection = stub(:db => @db, :name => "items") @cursor = Cursor.new(@collection) end - should "set admin to false" do + should "set admin to false" do assert_equal false, @cursor.admin @cursor = Cursor.new(@collection, :admin => true) @@ -60,35 +60,35 @@ class TestCursor < Test::Unit::TestCase assert_equal "name", @cursor.hint end - should "cache full collection name" do + should "cache full collection name" do assert_equal "testing.items", @cursor.full_collection_name end end - context "Query fields" do - setup do + context "Query fields" do + setup do @connection = stub(:class => Collection) @db = stub(:slave_ok? => true, :name => "testing", :connection => @connection) @collection = stub(:db => @db, :name => "items") end - should "when an array should return a hash with each key" do + should "when an array should return a hash with each key" do @cursor = Cursor.new(@collection, :fields => [:name, :age]) result = @cursor.fields assert_equal result.keys.sort{|a,b| a.to_s <=> b.to_s}, [:age, :name].sort{|a,b| a.to_s <=> b.to_s} assert result.values.all? {|v| v == 1} end - should "when a string, return a hash with just the key" do + should "when a string, return a hash with just the key" do @cursor = Cursor.new(@collection, :fields => "name") - result = @cursor.fields + result = @cursor.fields assert_equal result.keys.sort, ["name"] assert result.values.all? {|v| v == 1} end - should "return nil when neither hash nor string nor symbol" do + should "return nil when neither hash nor string nor symbol" do @cursor = Cursor.new(@collection, :fields => 1234567) - assert_nil @cursor.fields + assert_nil @cursor.fields end end end diff --git a/test/unit/db_test.rb b/test/unit/db_test.rb index 7444778..b2d7728 100644 --- a/test/unit/db_test.rb +++ b/test/unit/db_test.rb @@ -11,8 +11,8 @@ class DBTest < Test::Unit::TestCase message = db.add_message_headers(Mongo::Constants::OP_INSERT, message) end - context "DB commands" do - setup do + context "DB commands" do + setup do @conn = stub() @db = DB.new("testing", @conn) @collection = mock() @@ -20,30 +20,30 @@ class DBTest < Test::Unit::TestCase end should "raise an error if given a hash with more than one key" do - assert_raise MongoArgumentError do + assert_raise MongoArgumentError do @db.command(:buildinfo => 1, :somekey => 1) end end - should "raise an error if the selector is omitted" do - assert_raise MongoArgumentError do + should "raise an error if the selector is omitted" do + assert_raise MongoArgumentError do @db.command({}, true) end end - should "create the proper cursor" do - @cursor = mock(:next_object => {"ok" => 1}) + should "create the proper cursor" do + @cursor = mock(:next_document => {"ok" => 1}) Cursor.expects(:new).with(@collection, :admin => true, :limit => -1, :selector => {:buildinfo => 1}, :socket => nil).returns(@cursor) command = {:buildinfo => 1} @db.command(command, true) end - should "raise an error when the command fails" do - @cursor = mock(:next_object => {"ok" => 0}) + should "raise an error when the command fails" do + @cursor = mock(:next_document => {"ok" => 0}) Cursor.expects(:new).with(@collection, :admin => true, :limit => -1, :selector => {:buildinfo => 1}, :socket => nil).returns(@cursor) - assert_raise OperationFailure do + assert_raise OperationFailure do command = {:buildinfo => 1} @db.command(command, true, true) end @@ -51,4 +51,4 @@ class DBTest < Test::Unit::TestCase end end - + From 3575e2162481d2d0e6781ae18606b0a3c319d8e4 Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Wed, 16 Dec 2009 14:04:47 -0500 Subject: [PATCH 3/5] minor: credits --- CREDITS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CREDITS b/CREDITS index afa28b2..66048dc 100644 --- a/CREDITS +++ b/CREDITS @@ -47,11 +47,13 @@ Les Hill, leshill on github * OrderedHash#each returns self Sean Cribbs, seancribbs on github -* Modify standard_benchmark to allow profiling +* Modified standard_benchmark to allow profiling +* c ext for faster ObjectID creation Sunny Hirai * Suggested hashcode fix for Mongo::ObjectID * Noted index ordering bug. +* GridFS performance boost Christos Trochalakis * Added map/reduce helper From 8df3e595fbbde761ae45f6e27a5972c0f21fdbe4 Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Wed, 16 Dec 2009 14:29:39 -0500 Subject: [PATCH 4/5] minor: removed autoreconnect.rb; several tests exist for this in test/replica --- bin/autoreconnect.rb | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 bin/autoreconnect.rb diff --git a/bin/autoreconnect.rb b/bin/autoreconnect.rb deleted file mode 100644 index 0ced579..0000000 --- a/bin/autoreconnect.rb +++ /dev/null @@ -1,26 +0,0 @@ -$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib') -require 'mongo' - -db = Mongo::Connection.new({:left => ["localhost", 27017], :right => ["localhost", 27018]}, nil, :auto_reconnect => true).db("ruby_test") - -db['test'].clear -10.times do |i| - db['test'].save("x" => i) -end - -while true do - begin - exit() if not db['test'].count() == 10 - - x = 0 - db['test'].find().each do |doc| - x += doc['x'] - end - exit() if not x == 45 - print "." - STDOUT.flush - sleep 1 - rescue - sleep 1 - end -end From 7655a2c42439694e95febf269217087f98443b9d Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Wed, 16 Dec 2009 18:09:48 -0500 Subject: [PATCH 5/5] deprecated Cursor#next_object for Cursor#next_document --- lib/mongo/cursor.rb | 5 +++++ test/test_cursor.rb | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/lib/mongo/cursor.rb b/lib/mongo/cursor.rb index ed7efd9..61c0ce6 100644 --- a/lib/mongo/cursor.rb +++ b/lib/mongo/cursor.rb @@ -71,6 +71,11 @@ module Mongo doc end + def next_object + warn "Cursor#next_object is deprecated; please use Cursor#next_document instead." + next_document + end + # Get the size of the result set for this query. # # Returns the number of objects in the result set for this query. Does diff --git a/test/test_cursor.rb b/test/test_cursor.rb index e34d4ff..198622e 100644 --- a/test/test_cursor.rb +++ b/test/test_cursor.rb @@ -58,6 +58,13 @@ class CursorTest < Test::Unit::TestCase assert_equal 0, @@db['acollectionthatdoesn'].count() end + def test_next_object_deprecation + @@coll.remove + @@coll.insert({"a" => 1}) + + assert_equal 1, @@coll.find().next_object["a"] + end + def test_sort @@coll.remove 5.times{|x| @@coll.insert({"a" => x}) }