RUBY-320 RUBY-284 initial cascading read API. Mapping sockets to pools.
This commit is contained in:
parent
a6ea525e3d
commit
45c40e7267
|
@ -84,6 +84,8 @@ module Mongo
|
||||||
unless pk_factory
|
unless pk_factory
|
||||||
@safe = opts.fetch(:safe, @db.safe)
|
@safe = opts.fetch(:safe, @db.safe)
|
||||||
end
|
end
|
||||||
|
read = opts.fetch(:read, @db.read_preference)
|
||||||
|
@read_preference = read.is_a?(Hash) ? read.dup : read
|
||||||
@pk_factory = pk_factory || opts[:pk] || BSON::ObjectId
|
@pk_factory = pk_factory || opts[:pk] || BSON::ObjectId
|
||||||
@hint = nil
|
@hint = nil
|
||||||
end
|
end
|
||||||
|
@ -200,6 +202,7 @@ module Mongo
|
||||||
return_key = opts.delete(:return_key)
|
return_key = opts.delete(:return_key)
|
||||||
transformer = opts.delete(:transformer)
|
transformer = opts.delete(:transformer)
|
||||||
show_disk_loc = opts.delete(:max_scan)
|
show_disk_loc = opts.delete(:max_scan)
|
||||||
|
read = opts.delete(:read) || @read_preference
|
||||||
|
|
||||||
if timeout == false && !block_given?
|
if timeout == false && !block_given?
|
||||||
raise ArgumentError, "Collection#find must be invoked with a block when timeout is disabled."
|
raise ArgumentError, "Collection#find must be invoked with a block when timeout is disabled."
|
||||||
|
@ -226,7 +229,8 @@ module Mongo
|
||||||
:transformer => transformer,
|
:transformer => transformer,
|
||||||
:max_scan => max_scan,
|
:max_scan => max_scan,
|
||||||
:show_disk_loc => show_disk_loc,
|
:show_disk_loc => show_disk_loc,
|
||||||
:return_key => return_key
|
:return_key => return_key,
|
||||||
|
:read => read
|
||||||
})
|
})
|
||||||
|
|
||||||
if block_given?
|
if block_given?
|
||||||
|
@ -681,6 +685,13 @@ module Mongo
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# The value of the read preference. This will be
|
||||||
|
# either +:primary+, +:secondary+, or an object
|
||||||
|
# representing the tags to be read from.
|
||||||
|
def read_preference
|
||||||
|
@read_preference
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def new_group(opts={})
|
def new_group(opts={})
|
||||||
|
|
|
@ -310,7 +310,7 @@ module Mongo
|
||||||
#
|
#
|
||||||
# @core databases []-instance_method
|
# @core databases []-instance_method
|
||||||
def [](db_name)
|
def [](db_name)
|
||||||
DB.new(db_name, self, :safe => @safe)
|
DB.new(db_name, self)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Drop a database.
|
# Drop a database.
|
||||||
|
@ -410,11 +410,7 @@ module Mongo
|
||||||
|
|
||||||
send_message_on_socket(packed_message, socket)
|
send_message_on_socket(packed_message, socket)
|
||||||
ensure
|
ensure
|
||||||
if connection == :writer
|
checkin(socket)
|
||||||
checkin_writer(socket)
|
|
||||||
else
|
|
||||||
checkin_reader(socket)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -446,7 +442,7 @@ module Mongo
|
||||||
docs, num_received, cursor_id = receive(sock, last_error_id)
|
docs, num_received, cursor_id = receive(sock, last_error_id)
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
checkin_writer(sock)
|
checkin(sock)
|
||||||
end
|
end
|
||||||
|
|
||||||
if num_received == 1 && (error = docs[0]['err'] || docs[0]['errmsg'])
|
if num_received == 1 && (error = docs[0]['err'] || docs[0]['errmsg'])
|
||||||
|
@ -470,16 +466,24 @@ module Mongo
|
||||||
# @return [Array]
|
# @return [Array]
|
||||||
# An array whose indexes include [0] documents returned, [1] number of document received,
|
# An array whose indexes include [0] documents returned, [1] number of document received,
|
||||||
# and [3] a cursor_id.
|
# and [3] a cursor_id.
|
||||||
def receive_message(operation, message, log_message=nil, socket=nil, command=false)
|
def receive_message(operation, message, log_message=nil, socket=nil, command=false, read=:primary)
|
||||||
request_id = add_message_headers(message, operation)
|
request_id = add_message_headers(message, operation)
|
||||||
packed_message = message.to_s
|
packed_message = message.to_s
|
||||||
begin
|
begin
|
||||||
if socket
|
if socket
|
||||||
sock = socket
|
sock = socket
|
||||||
checkin = false
|
should_checkin = false
|
||||||
else
|
else
|
||||||
sock = (command ? checkout_writer : checkout_reader)
|
if command
|
||||||
checkin = true
|
sock = checkout_writer
|
||||||
|
elsif read == :primary
|
||||||
|
sock = checkout_writer
|
||||||
|
elsif read == :secondary
|
||||||
|
sock = checkout_reader
|
||||||
|
else
|
||||||
|
sock = checkout_tagged(read)
|
||||||
|
end
|
||||||
|
should_checkin = true
|
||||||
end
|
end
|
||||||
|
|
||||||
result = ''
|
result = ''
|
||||||
|
@ -488,8 +492,8 @@ module Mongo
|
||||||
result = receive(sock, request_id)
|
result = receive(sock, request_id)
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
if checkin
|
if should_checkin
|
||||||
command ? checkin_writer(sock) : checkin_reader(sock)
|
checkin(sock)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
result
|
result
|
||||||
|
@ -559,6 +563,14 @@ module Mongo
|
||||||
end
|
end
|
||||||
alias :primary? :read_primary?
|
alias :primary? :read_primary?
|
||||||
|
|
||||||
|
# The value of the read preference. Because
|
||||||
|
# this is a single-node connection, the value
|
||||||
|
# is +:primary+, and the connection will read
|
||||||
|
# from whichever type of node it's connected to.
|
||||||
|
def read_preference
|
||||||
|
:primary
|
||||||
|
end
|
||||||
|
|
||||||
# Close the connection to the database.
|
# Close the connection to the database.
|
||||||
def close
|
def close
|
||||||
@primary_pool.close if @primary_pool
|
@primary_pool.close if @primary_pool
|
||||||
|
@ -591,14 +603,21 @@ module Mongo
|
||||||
# Checkin a socket used for reading.
|
# Checkin a socket used for reading.
|
||||||
# Note: this is overridden in ReplSetConnection.
|
# Note: this is overridden in ReplSetConnection.
|
||||||
def checkin_reader(socket)
|
def checkin_reader(socket)
|
||||||
if @primary_pool
|
warn "Connection#checkin_writer is not deprecated and will be remove " +
|
||||||
@primary_pool.checkin(socket)
|
"in driver v2.0. Use Connection#checkin instead."
|
||||||
end
|
checkin(socket)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Checkin a socket used for writing.
|
# Checkin a socket used for writing.
|
||||||
# Note: this is overridden in ReplSetConnection.
|
# Note: this is overridden in ReplSetConnection.
|
||||||
def checkin_writer(socket)
|
def checkin_writer(socket)
|
||||||
|
warn "Connection#checkin_writer is not deprecated and will be remove " +
|
||||||
|
"in driver v2.0. Use Connection#checkin instead."
|
||||||
|
checkin(socket)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check a socket back into its pool.
|
||||||
|
def checkin(socket)
|
||||||
if @primary_pool
|
if @primary_pool
|
||||||
@primary_pool.checkin(socket)
|
@primary_pool.checkin(socket)
|
||||||
end
|
end
|
||||||
|
|
|
@ -70,6 +70,8 @@ module Mongo
|
||||||
@query_run = false
|
@query_run = false
|
||||||
|
|
||||||
@transformer = opts[:transformer]
|
@transformer = opts[:transformer]
|
||||||
|
read = opts[:read] || collection.read_preference
|
||||||
|
@read_preference = read.is_a?(Hash) ? read.dup : read
|
||||||
batch_size(opts[:batch_size] || 0)
|
batch_size(opts[:batch_size] || 0)
|
||||||
|
|
||||||
@full_collection_name = "#{@collection.db.name}.#{@collection.name}"
|
@full_collection_name = "#{@collection.db.name}.#{@collection.name}"
|
||||||
|
@ -448,7 +450,7 @@ module Mongo
|
||||||
message.put_long(@cursor_id)
|
message.put_long(@cursor_id)
|
||||||
@logger.debug("MONGODB cursor.refresh() for cursor #{@cursor_id}") if @logger
|
@logger.debug("MONGODB cursor.refresh() for cursor #{@cursor_id}") if @logger
|
||||||
results, @n_received, @cursor_id = @connection.receive_message(
|
results, @n_received, @cursor_id = @connection.receive_message(
|
||||||
Mongo::Constants::OP_GET_MORE, message, nil, @socket, @command)
|
Mongo::Constants::OP_GET_MORE, message, nil, @socket, @command, @read_preference)
|
||||||
@returned += @n_received
|
@returned += @n_received
|
||||||
@cache += results
|
@cache += results
|
||||||
close_cursor_if_query_complete
|
close_cursor_if_query_complete
|
||||||
|
@ -464,7 +466,7 @@ module Mongo
|
||||||
message = construct_query_message
|
message = construct_query_message
|
||||||
@connection.instrument(:find, instrument_payload) do
|
@connection.instrument(:find, instrument_payload) do
|
||||||
results, @n_received, @cursor_id = @connection.receive_message(
|
results, @n_received, @cursor_id = @connection.receive_message(
|
||||||
Mongo::Constants::OP_QUERY, message, nil, @socket, @command)
|
Mongo::Constants::OP_QUERY, message, nil, @socket, @command, @read_preference)
|
||||||
@returned += @n_received
|
@returned += @n_received
|
||||||
@cache += results
|
@cache += results
|
||||||
@query_run = true
|
@query_run = true
|
||||||
|
|
|
@ -82,6 +82,8 @@ module Mongo
|
||||||
@strict = opts[:strict]
|
@strict = opts[:strict]
|
||||||
@pk_factory = opts[:pk]
|
@pk_factory = opts[:pk]
|
||||||
@safe = opts.fetch(:safe, @connection.safe)
|
@safe = opts.fetch(:safe, @connection.safe)
|
||||||
|
read = opts.fetch(:read, @connection.read_preference)
|
||||||
|
@read_preference = read.is_a?(Hash) ? read.dup : read
|
||||||
@cache_time = opts[:cache_time] || 300 #5 minutes.
|
@cache_time = opts[:cache_time] || 300 #5 minutes.
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -609,6 +611,13 @@ module Mongo
|
||||||
doc
|
doc
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# The value of the read preference. This will be
|
||||||
|
# either +:primary+, +:secondary+, or an object
|
||||||
|
# representing the tags to be read from.
|
||||||
|
def read_preference
|
||||||
|
@read_preference
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def system_command_collection
|
def system_command_collection
|
||||||
|
|
|
@ -48,6 +48,9 @@ module Mongo
|
||||||
# Raised on failures in connection to the database server.
|
# Raised on failures in connection to the database server.
|
||||||
class ConnectionTimeoutError < MongoRubyError; end
|
class ConnectionTimeoutError < MongoRubyError; end
|
||||||
|
|
||||||
|
# Raised when no tags in a read preference maps to a given connection.
|
||||||
|
class NodeWithTagsNotFound < MongoRubyError; end
|
||||||
|
|
||||||
# Raised when a connection operation fails.
|
# Raised when a connection operation fails.
|
||||||
class ConnectionFailure < MongoDBError; end
|
class ConnectionFailure < MongoDBError; end
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,14 @@ module Mongo
|
||||||
@refresh_interval = opts[:refresh_interval] || 90
|
@refresh_interval = opts[:refresh_interval] || 90
|
||||||
|
|
||||||
# Are we allowing reads from secondaries?
|
# Are we allowing reads from secondaries?
|
||||||
|
if opts[:read_secondary]
|
||||||
|
warn ":read_secondary options has now been deprecated and will " +
|
||||||
|
"be removed in driver v2.0. Use the :read option instead."
|
||||||
@read_secondary = opts.fetch(:read_secondary, false)
|
@read_secondary = opts.fetch(:read_secondary, false)
|
||||||
|
@read = :secondary
|
||||||
|
else
|
||||||
|
@read = opts.fetch(:read, :primary)
|
||||||
|
end
|
||||||
|
|
||||||
# Lock around changes to the global config
|
# Lock around changes to the global config
|
||||||
@connection_lock = Mutex.new
|
@connection_lock = Mutex.new
|
||||||
|
@ -121,6 +128,10 @@ module Mongo
|
||||||
# Store the refresher thread
|
# Store the refresher thread
|
||||||
@refresh_thread = nil
|
@refresh_thread = nil
|
||||||
|
|
||||||
|
# Maps
|
||||||
|
@sockets_to_pools = {}
|
||||||
|
@tags_to_pools = {}
|
||||||
|
|
||||||
# Replica set name
|
# Replica set name
|
||||||
if opts[:rs_name]
|
if opts[:rs_name]
|
||||||
warn ":rs_name option has been deprecated and will be removed in 2.0. " +
|
warn ":rs_name option has been deprecated and will be removed in 2.0. " +
|
||||||
|
@ -226,6 +237,10 @@ module Mongo
|
||||||
end
|
end
|
||||||
alias :primary? :read_primary?
|
alias :primary? :read_primary?
|
||||||
|
|
||||||
|
def read_preference
|
||||||
|
@read
|
||||||
|
end
|
||||||
|
|
||||||
# Close the connection to the database.
|
# Close the connection to the database.
|
||||||
def close
|
def close
|
||||||
super
|
super
|
||||||
|
@ -254,6 +269,8 @@ module Mongo
|
||||||
@secondaries = []
|
@secondaries = []
|
||||||
@secondary_pools = []
|
@secondary_pools = []
|
||||||
@arbiters = []
|
@arbiters = []
|
||||||
|
@tags_to_pools.clear
|
||||||
|
@sockets_to_pools.clear
|
||||||
end
|
end
|
||||||
|
|
||||||
# If a ConnectionFailure is raised, this method will be called
|
# If a ConnectionFailure is raised, this method will be called
|
||||||
|
@ -265,11 +282,15 @@ module Mongo
|
||||||
"Use ReplSetConnection#close instead."
|
"Use ReplSetConnection#close instead."
|
||||||
end
|
end
|
||||||
|
|
||||||
# Is it okay to connect to a slave?
|
# Returns +true+ if it's okay to read from a secondary node.
|
||||||
|
# Since this is a replica set, this must always be true.
|
||||||
#
|
#
|
||||||
# @return [Boolean]
|
# This method exist primarily so that Cursor objects will
|
||||||
|
# generate query messages with a slaveOkay value of +true+.
|
||||||
|
#
|
||||||
|
# @return [Boolean] +true+
|
||||||
def slave_ok?
|
def slave_ok?
|
||||||
@read_secondary
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate_pools
|
def authenticate_pools
|
||||||
|
@ -299,25 +320,29 @@ module Mongo
|
||||||
|
|
||||||
# Checkout a socket for reading (i.e., a secondary node).
|
# Checkout a socket for reading (i.e., a secondary node).
|
||||||
# Note that @read_pool might point to the primary pool
|
# Note that @read_pool might point to the primary pool
|
||||||
# if no read pool has been defined. That's okay; we don't
|
# if no read pool has been defined.
|
||||||
# want to have to check for the existence of the @read_pool
|
|
||||||
# because that introduces concurrency issues.
|
|
||||||
def checkout_reader
|
def checkout_reader
|
||||||
connect unless connected?
|
connect unless connected?
|
||||||
|
|
||||||
if @read_secondary && @read_pool
|
socket = @read_pool.checkout
|
||||||
begin
|
@sockets_to_pools[socket] = @read_pool
|
||||||
return @read_pool.checkout
|
return socket
|
||||||
rescue NoMethodError
|
end
|
||||||
warn "Read pool was not available."
|
|
||||||
|
# Checkout a socket connected to a node with one of
|
||||||
|
# the provided tags. If no such node exists, raise
|
||||||
|
# an exception.
|
||||||
|
def checkout_tagged(tags)
|
||||||
|
tags.each do |k, v|
|
||||||
|
if pool = @tags_to_pools[{k.to_s => v}]
|
||||||
|
socket = pool.checkout
|
||||||
|
@sockets_to_pools[socket] = pool
|
||||||
|
return socket
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
raise NodeWithTagsNotFound,
|
||||||
return @primary_pool.checkout
|
"Could not find a connection tagged with #{tags}."
|
||||||
rescue NoMethodError
|
|
||||||
raise ConnectionFailure, "Not connected to any nodes."
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Checkout a socket for writing (i.e., a primary node).
|
# Checkout a socket for writing (i.e., a primary node).
|
||||||
|
@ -326,7 +351,9 @@ module Mongo
|
||||||
|
|
||||||
if @primary_pool
|
if @primary_pool
|
||||||
begin
|
begin
|
||||||
return @primary_pool.checkout
|
socket = @primary_pool.checkout
|
||||||
|
@sockets_to_pools[socket] = @primary
|
||||||
|
return socket
|
||||||
rescue NoMethodError
|
rescue NoMethodError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -336,17 +363,21 @@ module Mongo
|
||||||
|
|
||||||
# Checkin a socket used for reading.
|
# Checkin a socket used for reading.
|
||||||
def checkin_reader(socket)
|
def checkin_reader(socket)
|
||||||
if @read_secondary
|
warn "ReplSetConnection#checkin_writer is not deprecated and will be remove " +
|
||||||
@read_pool.checkin(socket)
|
"in driver v2.0. Use ReplSetConnection#checkin instead."
|
||||||
else
|
checkin(socket)
|
||||||
checkin_writer(socket)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Checkin a socket used for writing.
|
# Checkin a socket used for writing.
|
||||||
def checkin_writer(socket)
|
def checkin_writer(socket)
|
||||||
if @primary_pool
|
warn "ReplSetConnection#checkin_writer is not deprecated and will be remove " +
|
||||||
@primary_pool.checkin(socket)
|
"in driver v2.0. Use ReplSetConnection#checkin instead."
|
||||||
|
checkin(socket)
|
||||||
|
end
|
||||||
|
|
||||||
|
def checkin(socket)
|
||||||
|
if pool = @sockets_to_pools[socket]
|
||||||
|
pool.checkin(socket)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,9 +5,9 @@ class CursorTest < Test::Unit::TestCase
|
||||||
setup do
|
setup do
|
||||||
@logger = mock()
|
@logger = mock()
|
||||||
@logger.stubs(:debug)
|
@logger.stubs(:debug)
|
||||||
@connection = stub(:class => Connection, :logger => @logger, :slave_ok? => false)
|
@connection = stub(:class => Connection, :logger => @logger, :slave_ok? => false, :read_preference => :primary)
|
||||||
@db = stub(:name => "testing", :slave_ok? => false, :connection => @connection)
|
@db = stub(:name => "testing", :slave_ok? => false, :connection => @connection, :read_preference => :primary)
|
||||||
@collection = stub(:db => @db, :name => "items")
|
@collection = stub(:db => @db, :name => "items", :read_preference => :primary)
|
||||||
@cursor = Cursor.new(@collection)
|
@cursor = Cursor.new(@collection)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ class CursorTest < Test::Unit::TestCase
|
||||||
@logger.stubs(:debug)
|
@logger.stubs(:debug)
|
||||||
@connection = stub(:class => Connection, :logger => @logger, :slave_ok? => false)
|
@connection = stub(:class => Connection, :logger => @logger, :slave_ok? => false)
|
||||||
@db = stub(:slave_ok? => true, :name => "testing", :connection => @connection)
|
@db = stub(:slave_ok? => true, :name => "testing", :connection => @connection)
|
||||||
@collection = stub(:db => @db, :name => "items")
|
@collection = stub(:db => @db, :name => "items", :read_preference => :primary)
|
||||||
end
|
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
|
||||||
|
|
|
@ -15,8 +15,10 @@ class DBTest < Test::Unit::TestCase
|
||||||
setup do
|
setup do
|
||||||
@conn = stub()
|
@conn = stub()
|
||||||
@conn.stubs(:safe)
|
@conn.stubs(:safe)
|
||||||
|
@conn.stubs(:read_preference)
|
||||||
@db = DB.new("testing", @conn)
|
@db = DB.new("testing", @conn)
|
||||||
@db.stubs(:safe)
|
@db.stubs(:safe)
|
||||||
|
@db.stubs(:read_preference)
|
||||||
@collection = mock()
|
@collection = mock()
|
||||||
@db.stubs(:system_command_collection).returns(@collection)
|
@db.stubs(:system_command_collection).returns(@collection)
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,7 @@ class GridTest < Test::Unit::TestCase
|
||||||
setup do
|
setup do
|
||||||
@conn = stub()
|
@conn = stub()
|
||||||
@conn.stubs(:safe)
|
@conn.stubs(:safe)
|
||||||
|
@conn.stubs(:read_preference)
|
||||||
@db = DB.new("testing", @conn)
|
@db = DB.new("testing", @conn)
|
||||||
@files = mock()
|
@files = mock()
|
||||||
@chunks = mock()
|
@chunks = mock()
|
||||||
|
@ -13,6 +14,7 @@ class GridTest < Test::Unit::TestCase
|
||||||
@db.expects(:[]).with('fs.files').returns(@files)
|
@db.expects(:[]).with('fs.files').returns(@files)
|
||||||
@db.expects(:[]).with('fs.chunks').returns(@chunks)
|
@db.expects(:[]).with('fs.chunks').returns(@chunks)
|
||||||
@db.stubs(:safe)
|
@db.stubs(:safe)
|
||||||
|
@db.stubs(:read_preference)
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Grid classe with standard connections" do
|
context "Grid classe with standard connections" do
|
||||||
|
|
|
@ -65,7 +65,7 @@ class NodeTest < Test::Unit::TestCase
|
||||||
Node.new(@connection, ['192.168.0.1', Connection::DEFAULT_PORT])
|
Node.new(@connection, ['192.168.0.1', Connection::DEFAULT_PORT])
|
||||||
end
|
end
|
||||||
|
|
||||||
should "two nodes with the same address should have the same hash" do
|
should "two nodes with the same address should have the same hash negate" do
|
||||||
assert_not_equal Node.new(@connection, '192.168.0.1').hash,
|
assert_not_equal Node.new(@connection, '192.168.0.1').hash,
|
||||||
Node.new(@connection, '1239.33.4.2393:29949').hash
|
Node.new(@connection, '1239.33.4.2393:29949').hash
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
require './test/test_helper'
|
||||||
|
|
||||||
|
class ReadTest < Test::Unit::TestCase
|
||||||
|
|
||||||
|
context "Read mode on standard connection: " do
|
||||||
|
setup do
|
||||||
|
@read_preference = :secondary
|
||||||
|
@con = Mongo::Connection.new('localhost', 27017, :read => @read_preference, :connect => false)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Read mode on connection: " do
|
||||||
|
setup do
|
||||||
|
@read_preference = :secondary
|
||||||
|
@con = Mongo::ReplSetConnection.new(['localhost', 27017], :read => @read_preference, :connect => false)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "store read preference on Connection" do
|
||||||
|
assert_equal @read_preference, @con.read_preference
|
||||||
|
end
|
||||||
|
|
||||||
|
should "propogate to DB" do
|
||||||
|
db = @con['foo']
|
||||||
|
assert_equal @read_preference, db.read_preference
|
||||||
|
|
||||||
|
db = @con.db('foo')
|
||||||
|
assert_equal @read_preference, db.read_preference
|
||||||
|
|
||||||
|
db = DB.new('foo', @con)
|
||||||
|
assert_equal @read_preference, db.read_preference
|
||||||
|
end
|
||||||
|
|
||||||
|
should "allow db override" do
|
||||||
|
db = DB.new('foo', @con, :read => :primary)
|
||||||
|
assert_equal :primary, db.read_preference
|
||||||
|
|
||||||
|
db = @con.db('foo', :read => :primary)
|
||||||
|
assert_equal :primary, db.read_preference
|
||||||
|
end
|
||||||
|
|
||||||
|
context "on DB: " do
|
||||||
|
setup do
|
||||||
|
@db = @con['foo']
|
||||||
|
end
|
||||||
|
|
||||||
|
should "propogate to collection" do
|
||||||
|
col = @db.collection('bar')
|
||||||
|
assert_equal @read_preference, col.read_preference
|
||||||
|
|
||||||
|
col = @db['bar']
|
||||||
|
assert_equal @read_preference, col.read_preference
|
||||||
|
|
||||||
|
col = Collection.new('bar', @db)
|
||||||
|
assert_equal @read_preference, col.read_preference
|
||||||
|
end
|
||||||
|
|
||||||
|
should "allow override on collection" do
|
||||||
|
col = @db.collection('bar', :read => :primary)
|
||||||
|
assert_equal :primary, col.read_preference
|
||||||
|
|
||||||
|
col = Collection.new('bar', @db, :read => :primary)
|
||||||
|
assert_equal :primary, col.read_preference
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "on read mode ops" do
|
||||||
|
setup do
|
||||||
|
@col = @con['foo']['bar']
|
||||||
|
@mock_socket = stub()
|
||||||
|
end
|
||||||
|
|
||||||
|
should "use default value on query" do
|
||||||
|
@con.expects(:receive_message).with do |o, m, l, s, c, r|
|
||||||
|
r == :secondary
|
||||||
|
end.returns([[], 0, 0])
|
||||||
|
|
||||||
|
@col.find_one({:a => 1})
|
||||||
|
end
|
||||||
|
|
||||||
|
should "allow override default value on query" do
|
||||||
|
@con.expects(:receive_message).with do |o, m, l, s, c, r|
|
||||||
|
r == :primary
|
||||||
|
end.returns([[], 0, 0])
|
||||||
|
|
||||||
|
@col.find_one({:a => 1}, :read => :primary)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "allow override alternate value on query" do
|
||||||
|
@con.expects(:receive_message).with do |o, m, l, s, c, r|
|
||||||
|
tags = {:dc => "ny"}
|
||||||
|
end.returns([[], 0, 0])
|
||||||
|
|
||||||
|
@col.find_one({:a => 1}, :read => {:dc => "ny"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue