Finished removing Message classes. Made Cursor#close threadsafe.
This commit is contained in:
parent
b938765ac0
commit
de5c078cec
2
Rakefile
2
Rakefile
|
@ -18,7 +18,7 @@ gem_command = "gem1.9" if $0.match(/1\.9$/) # use gem1.9 if we used rake1.9
|
|||
desc "Test the MongoDB Ruby driver."
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.test_files = FileList['test/test*.rb']
|
||||
t.verbose = true
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc "Generate documentation"
|
||||
|
|
|
@ -6,8 +6,8 @@ require 'mongo/types/regexp_of_holding'
|
|||
require 'mongo/util/conversions'
|
||||
|
||||
require 'mongo/errors'
|
||||
require 'mongo/constants'
|
||||
require 'mongo/connection'
|
||||
require 'mongo/message'
|
||||
require 'mongo/db'
|
||||
require 'mongo/cursor'
|
||||
require 'mongo/collection'
|
||||
|
|
|
@ -229,7 +229,7 @@ module Mongo
|
|||
BSON.serialize_cstr(message, "#{@db.name}.#{@name}")
|
||||
message.put_int(0)
|
||||
message.put_array(BSON.new.serialize(selector, false).to_a)
|
||||
@db.send_message_with_operation(OP_DELETE, message)
|
||||
@db.send_message_with_operation(Mongo::Constants::OP_DELETE, message)
|
||||
end
|
||||
|
||||
# Remove all records.
|
||||
|
@ -259,7 +259,7 @@ module Mongo
|
|||
message.put_int(options[:upsert] ? 1 : 0) # 1 if a repsert operation (upsert)
|
||||
message.put_array(BSON.new.serialize(spec, false).to_a)
|
||||
message.put_array(BSON.new.serialize(document, false).to_a)
|
||||
@db.send_message_with_operation(OP_UPDATE, message)
|
||||
@db.send_message_with_operation(Mongo::Constants::OP_UPDATE, message)
|
||||
|
||||
if options[:safe] && error=@db.error
|
||||
raise OperationFailure, error
|
||||
|
@ -454,7 +454,7 @@ EOS
|
|||
|
||||
private
|
||||
|
||||
# Sends an OP_INSERT message to the database.
|
||||
# Sends an 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)
|
||||
|
@ -462,7 +462,7 @@ EOS
|
|||
message.put_int(0)
|
||||
BSON.serialize_cstr(message, "#{@db.name}.#{collection_name}")
|
||||
documents.each { |doc| message.put_array(BSON.new.serialize(doc, check_keys).to_a) }
|
||||
@db.send_message_with_operation(OP_INSERT, message)
|
||||
@db.send_message_with_operation(Mongo::Constants::OP_INSERT, message)
|
||||
documents.collect { |o| o[:_id] || o['_id'] }
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
module Mongo
|
||||
module Constants
|
||||
OP_REPLY = 1
|
||||
OP_MSG = 1000
|
||||
OP_UPDATE = 2001
|
||||
OP_INSERT = 2002
|
||||
OP_QUERY = 2004
|
||||
OP_GET_MORE = 2005
|
||||
OP_DELETE = 2006
|
||||
OP_KILL_CURSORS = 2007
|
||||
|
||||
OP_QUERY_SLAVE_OK = 4
|
||||
OP_QUERY_NO_CURSOR_TIMEOUT = 16
|
||||
end
|
||||
end
|
|
@ -12,7 +12,6 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'mongo/message'
|
||||
require 'mongo/util/byte_buffer'
|
||||
require 'mongo/util/bson'
|
||||
|
||||
|
@ -173,17 +172,23 @@ module Mongo
|
|||
|
||||
# Close the cursor.
|
||||
#
|
||||
# Note: if a cursor is read until exhausted (read until OP_QUERY or
|
||||
# OP_GETMORE returns zero for the cursor id), there is no need to
|
||||
# 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
|
||||
# close it by calling this method.
|
||||
#
|
||||
# Collection#find takes an optional block argument which can be used to
|
||||
# ensure that your cursors get closed. See the documentation for
|
||||
# Collection#find for details.
|
||||
def close
|
||||
@db.send_to_db(KillCursorsMessage.new(@cursor_id)) if @cursor_id
|
||||
if @cursor_id
|
||||
message = ByteBuffer.new
|
||||
message.put_int(0)
|
||||
message.put_int(1)
|
||||
message.put_long(@cursor_id)
|
||||
@db.send_message_with_operation(Mongo::Constants::OP_KILL_CURSORS, message)
|
||||
end
|
||||
@cursor_id = 0
|
||||
@closed = true
|
||||
@closed = true
|
||||
end
|
||||
|
||||
# Returns true if this cursor is closed, false otherwise.
|
||||
|
@ -204,7 +209,16 @@ module Mongo
|
|||
end
|
||||
|
||||
def read_message_header
|
||||
MessageHeader.new.read_header(@db)
|
||||
message = ByteBuffer.new
|
||||
message.put_array(@db.receive_full(16).unpack("C*"))
|
||||
unless message.size == 16 #HEADER_SIZE
|
||||
raise "Short read for DB response header: expected #{16} bytes, saw #{message.size}"
|
||||
end
|
||||
message.rewind
|
||||
size = message.get_int
|
||||
request_id = message.get_int
|
||||
response_to = message.get_int
|
||||
op = message.get_int
|
||||
end
|
||||
|
||||
def read_response_header
|
||||
|
@ -221,9 +235,6 @@ module Mongo
|
|||
else
|
||||
@n_received = @n_remaining
|
||||
end
|
||||
if @query.number_to_return > 0 and @n_received >= @query.number_to_return
|
||||
close()
|
||||
end
|
||||
end
|
||||
|
||||
def num_remaining
|
||||
|
@ -262,9 +273,10 @@ module Mongo
|
|||
|
||||
# Cursor id.
|
||||
message.put_long(@cursor_id)
|
||||
@db.send_message_with_operation_without_synchronize(OP_GET_MORE, message)
|
||||
@db.send_message_with_operation_without_synchronize(Mongo::Constants::OP_GET_MORE, message)
|
||||
read_all
|
||||
}
|
||||
close_cursor_if_query_complete
|
||||
end
|
||||
|
||||
def object_from_stream
|
||||
|
@ -283,12 +295,13 @@ module Mongo
|
|||
if @query_run
|
||||
false
|
||||
else
|
||||
message = construct_query_message(@query)
|
||||
@db._synchronize {
|
||||
message = construct_query_message(@query)
|
||||
@db.send_message_with_operation_without_synchronize(Mongo::Constants::OP_QUERY, message)
|
||||
@query_run = true
|
||||
@db.send_message_with_operation_without_synchronize(OP_QUERY, message)
|
||||
read_all
|
||||
}
|
||||
close_cursor_if_query_complete
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -337,6 +350,10 @@ module Mongo
|
|||
"DBResponse(flags=#@result_flags, cursor_id=#@cursor_id, start=#@starting_from)"
|
||||
end
|
||||
|
||||
def close_cursor_if_query_complete
|
||||
close if @query.number_to_return > 0 && @n_received >= @query.number_to_return
|
||||
end
|
||||
|
||||
def check_modifiable
|
||||
if @query_run || @closed
|
||||
raise InvalidOperation, "Cannot modify the query once it has been run or closed."
|
||||
|
|
|
@ -18,7 +18,6 @@ require 'socket'
|
|||
require 'digest/md5'
|
||||
require 'thread'
|
||||
require 'mongo/collection'
|
||||
require 'mongo/message'
|
||||
require 'mongo/query'
|
||||
require 'mongo/util/ordered_hash.rb'
|
||||
require 'mongo/admin'
|
||||
|
@ -358,11 +357,6 @@ module Mongo
|
|||
message
|
||||
end
|
||||
|
||||
# Send a MsgMessage to the database.
|
||||
def send_message(msg)
|
||||
send_to_db(MsgMessage.new(msg))
|
||||
end
|
||||
|
||||
# Returns a Cursor over the query results.
|
||||
#
|
||||
# Note that the query gets sent lazily; the cursor calls
|
||||
|
@ -470,16 +464,16 @@ module Mongo
|
|||
end
|
||||
|
||||
def send_message_with_operation_without_synchronize(operation, message)
|
||||
connect_to_master if !connected? && @auto_reconnect
|
||||
begin
|
||||
message_with_headers = add_message_headers(operation, message)
|
||||
@logger.debug(" MONGODB #{operation} #{message}") if @logger
|
||||
@socket.print(message_with_headers.to_s)
|
||||
@socket.flush
|
||||
rescue => ex
|
||||
close
|
||||
raise ex
|
||||
end
|
||||
connect_to_master if !connected? && @auto_reconnect
|
||||
begin
|
||||
message_with_headers = add_message_headers(operation, message)
|
||||
@logger.debug(" MONGODB #{operation} #{message}") if @logger
|
||||
@socket.print(message_with_headers.to_s)
|
||||
@socket.flush
|
||||
rescue => ex
|
||||
close
|
||||
raise ex
|
||||
end
|
||||
end
|
||||
|
||||
def receive_message_with_operation(operation, message)
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2009 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
%w(kill_cursors_message message_header
|
||||
msg_message).each { |f|
|
||||
require "mongo/message/#{f}"
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2009 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
require 'mongo/message/message'
|
||||
require 'mongo/message/opcodes'
|
||||
|
||||
module Mongo
|
||||
|
||||
class KillCursorsMessage < Message
|
||||
|
||||
def initialize(*cursors)
|
||||
super(OP_KILL_CURSORS)
|
||||
write_int(0)
|
||||
write_int(cursors.length)
|
||||
cursors.each { |c| write_long c }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,80 +0,0 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2009 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
require 'mongo/util/bson'
|
||||
require 'mongo/util/byte_buffer'
|
||||
|
||||
module Mongo
|
||||
|
||||
class Message
|
||||
|
||||
HEADER_SIZE = 16 # size, id, response_to, opcode
|
||||
|
||||
@@class_req_id = 0
|
||||
|
||||
attr_reader :buf # for testing
|
||||
|
||||
def initialize(op)
|
||||
@op = op
|
||||
@message_length = HEADER_SIZE
|
||||
@data_length = 0
|
||||
@request_id = (@@class_req_id += 1)
|
||||
@response_id = 0
|
||||
@buf = ByteBuffer.new
|
||||
|
||||
@buf.put_int(16) # holder for length
|
||||
@buf.put_int(@request_id)
|
||||
@buf.put_int(0) # response_to
|
||||
@buf.put_int(op)
|
||||
end
|
||||
|
||||
def write_int(i)
|
||||
@buf.put_int(i)
|
||||
update_message_length
|
||||
end
|
||||
|
||||
def write_long(i)
|
||||
@buf.put_long(i)
|
||||
update_message_length
|
||||
end
|
||||
|
||||
def write_string(s)
|
||||
BSON.serialize_cstr(@buf, s)
|
||||
update_message_length
|
||||
end
|
||||
|
||||
def write_doc(hash, check_keys=false)
|
||||
@buf.put_array(BSON.new.serialize(hash, check_keys).to_a)
|
||||
update_message_length
|
||||
end
|
||||
|
||||
def to_a
|
||||
@buf.to_a
|
||||
end
|
||||
|
||||
def dump
|
||||
@buf.dump
|
||||
end
|
||||
|
||||
# Do not call. Private, but kept public for testing.
|
||||
def update_message_length
|
||||
pos = @buf.position
|
||||
@buf.put_int(@buf.size, 0)
|
||||
@buf.position = pos
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,45 +0,0 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2009 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
require 'mongo/util/byte_buffer'
|
||||
|
||||
module Mongo
|
||||
|
||||
class MessageHeader
|
||||
|
||||
HEADER_SIZE = 16
|
||||
|
||||
def initialize()
|
||||
@buf = ByteBuffer.new
|
||||
end
|
||||
|
||||
def read_header(db)
|
||||
@buf.rewind
|
||||
@buf.put_array(db.receive_full(HEADER_SIZE).unpack("C*"))
|
||||
raise "Short read for DB response header: expected #{HEADER_SIZE} bytes, saw #{@buf.size}" unless @buf.size == HEADER_SIZE
|
||||
@buf.rewind
|
||||
@size = @buf.get_int
|
||||
@request_id = @buf.get_int
|
||||
@response_to = @buf.get_int
|
||||
@op = @buf.get_int
|
||||
self
|
||||
end
|
||||
|
||||
def dump
|
||||
@buf.dump
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,29 +0,0 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2009 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
require 'mongo/message/message'
|
||||
require 'mongo/message/opcodes'
|
||||
|
||||
module Mongo
|
||||
|
||||
class MsgMessage < Message
|
||||
|
||||
def initialize(msg)
|
||||
super(OP_MSG)
|
||||
write_string(msg)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2009 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
module Mongo
|
||||
OP_REPLY = 1 # reply. responseTo is set.
|
||||
OP_MSG = 1000 # generic msg command followed by a string
|
||||
OP_UPDATE = 2001 # update object
|
||||
OP_INSERT = 2002
|
||||
# GET_BY_OID = 2003
|
||||
OP_QUERY = 2004
|
||||
OP_GET_MORE = 2005
|
||||
OP_DELETE = 2006
|
||||
OP_KILL_CURSORS = 2007
|
||||
|
||||
OP_QUERY_SLAVE_OK = 4
|
||||
OP_QUERY_NO_CURSOR_TIMEOUT = 16
|
||||
end
|
|
@ -15,7 +15,6 @@
|
|||
# ++
|
||||
|
||||
require 'mongo/collection'
|
||||
require 'mongo/message'
|
||||
require 'mongo/types/code'
|
||||
|
||||
module Mongo
|
||||
|
@ -119,10 +118,10 @@ module Mongo
|
|||
end
|
||||
|
||||
# Returns an integer indicating which query options have been selected.
|
||||
# See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-OPQUERY
|
||||
# See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY
|
||||
def query_opts
|
||||
timeout = @timeout ? 0 : OP_QUERY_NO_CURSOR_TIMEOUT
|
||||
slave_ok = @slave_ok ? OP_QUERY_SLAVE_OK : 0
|
||||
timeout = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
|
||||
slave_ok = @slave_ok ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
|
||||
slave_ok + timeout
|
||||
end
|
||||
|
||||
|
|
|
@ -20,20 +20,13 @@ PACKAGE_FILES = ['README.rdoc', 'Rakefile', 'mongo-ruby-driver.gemspec',
|
|||
'lib/mongo/admin.rb',
|
||||
'lib/mongo/collection.rb',
|
||||
'lib/mongo/connection.rb',
|
||||
'lib/mongo/constants.rb',
|
||||
'lib/mongo/cursor.rb',
|
||||
'lib/mongo/db.rb',
|
||||
'lib/mongo/gridfs/chunk.rb',
|
||||
'lib/mongo/gridfs/grid_store.rb',
|
||||
'lib/mongo/gridfs.rb',
|
||||
'lib/mongo/errors.rb',
|
||||
'lib/mongo/message/get_more_message.rb',
|
||||
'lib/mongo/message/kill_cursors_message.rb',
|
||||
'lib/mongo/message/message.rb',
|
||||
'lib/mongo/message/message_header.rb',
|
||||
'lib/mongo/message/msg_message.rb',
|
||||
'lib/mongo/message/opcodes.rb',
|
||||
'lib/mongo/message/query_message.rb',
|
||||
'lib/mongo/message.rb',
|
||||
'lib/mongo/query.rb',
|
||||
'lib/mongo/types/binary.rb',
|
||||
'lib/mongo/types/code.rb',
|
||||
|
@ -72,7 +65,6 @@ TEST_FILES = ['test/mongo-qa/_common.rb',
|
|||
'test/test_db_api.rb',
|
||||
'test/test_db_connection.rb',
|
||||
'test/test_grid_store.rb',
|
||||
'test/test_message.rb',
|
||||
'test/test_objectid.rb',
|
||||
'test/test_ordered_hash.rb',
|
||||
'test/test_threading.rb',
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
|
||||
require 'mongo'
|
||||
require 'test/unit'
|
||||
|
||||
class MessageTest < Test::Unit::TestCase
|
||||
|
||||
include Mongo
|
||||
|
||||
def setup
|
||||
@msg = Message.new(42)
|
||||
end
|
||||
|
||||
def test_initial_info
|
||||
assert_equal Message::HEADER_SIZE, @msg.buf.length
|
||||
@msg.write_long(1029)
|
||||
@msg.buf.rewind
|
||||
assert_equal Message::HEADER_SIZE + 8, @msg.buf.get_int
|
||||
@msg.buf.get_int # skip message id
|
||||
assert_equal 0, @msg.buf.get_int
|
||||
assert_equal 42, @msg.buf.get_int
|
||||
assert_equal 1029, @msg.buf.get_long
|
||||
end
|
||||
|
||||
def test_update_length
|
||||
@msg.update_message_length
|
||||
@msg.buf.rewind
|
||||
assert_equal Message::HEADER_SIZE, @msg.buf.get_int
|
||||
end
|
||||
|
||||
def test_long_length
|
||||
@msg.write_long(1027)
|
||||
assert_equal Message::HEADER_SIZE + 8, @msg.buf.length
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue