RUBY-284 document :read API

This commit is contained in:
Kyle Banker 2011-09-06 14:58:03 -04:00
parent 5d83ab2460
commit 50c38c6c6b
8 changed files with 78 additions and 39 deletions

View File

@ -34,6 +34,11 @@ module Mongo
# for insert, update, and remove method called on this Collection instance. If no # for insert, update, and remove method called on this Collection instance. If no
# value is provided, the default value set on this instance's DB will be used. This # value is provided, the default value set on this instance's DB will be used. This
# default can be overridden for any invocation of insert, update, or remove. # default can be overridden for any invocation of insert, update, or remove.
# @option options [:primary, :secondary] :read The default read preference for queries
# initiates from this connection object. If +:secondary+ is chosen, reads will be sent
# to one of the closest available secondary nodes. If a secondary node cannot be located, the
# read will be sent to the primary. If this option is left unspecified, the value of the read
# preference for this collection's associated Mongo::DB object will be used.
# #
# @raise [InvalidNSName] # @raise [InvalidNSName]
# if collection name is empty, contains '$', or starts or ends with '.' # if collection name is empty, contains '$', or starts or ends with '.'
@ -84,8 +89,12 @@ module Mongo
@cache = Hash.new(0) @cache = Hash.new(0)
unless pk_factory unless pk_factory
@safe = opts.fetch(:safe, @db.safe) @safe = opts.fetch(:safe, @db.safe)
@read = opts.fetch(:read, @db.read_preference) if value = opts[:read]
@read_preference = @read.is_a?(Hash) ? @read.dup : @read Mongo::Support.validate_read_preference(value)
else
value = @db.read_preference
end
@read_preference = value.is_a?(Hash) ? value.dup : value
end end
@pk_factory = pk_factory || opts[:pk] || BSON::ObjectId @pk_factory = pk_factory || opts[:pk] || BSON::ObjectId
@hint = nil @hint = nil
@ -157,6 +166,11 @@ module Mongo
# you can cut down on network traffic and decoding time. If using a Hash, keys should be field # you can cut down on network traffic and decoding time. If using a Hash, keys should be field
# names and values should be either 1 or 0, depending on whether you want to include or exclude # names and values should be either 1 or 0, depending on whether you want to include or exclude
# the given field. # the given field.
# @option opts [:primary, :secondary] :read The default read preference for queries
# initiates from this connection object. If +:secondary+ is chosen, reads will be sent
# to one of the closest available secondary nodes. If a secondary node cannot be located, the
# read will be sent to the primary. If this option is left unspecified, the value of the read
# preference for this Collection object will be used.
# @option opts [Integer] :skip number of documents to skip from the beginning of the result set # @option opts [Integer] :skip number of documents to skip from the beginning of the result set
# @option opts [Integer] :limit maximum number of documents to return # @option opts [Integer] :limit maximum number of documents to return
# @option opts [Array] :sort an array of [key, direction] pairs to sort by. Direction should # @option opts [Array] :sort an array of [key, direction] pairs to sort by. Direction should

View File

@ -685,6 +685,7 @@ module Mongo
@connect_timeout = opts[:connect_timeout] || nil @connect_timeout = opts[:connect_timeout] || nil
# Mutex for synchronizing pool access # Mutex for synchronizing pool access
# TODO: remove this.
@connection_mutex = Mutex.new @connection_mutex = Mutex.new
# Global safe option. This is false by default. # Global safe option. This is false by default.

View File

@ -70,8 +70,12 @@ module Mongo
@query_run = false @query_run = false
@transformer = opts[:transformer] @transformer = opts[:transformer]
read = opts[:read] || collection.read_preference if value = opts[:read]
@read_preference = read.is_a?(Hash) ? read.dup : read Mongo::Support.validate_read_preference(value)
else
value = collection.read_preference
end
@read_preference = value.is_a?(Hash) ? value.dup : value
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}"

View File

@ -82,8 +82,12 @@ 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) if value = opts[:read]
@read_preference = read.is_a?(Hash) ? read.dup : read Mongo::Support.validate_read_preference(value)
else
value = @connection.read_preference
end
@read_preference = value.is_a?(Hash) ? value.dup : value
@cache_time = opts[:cache_time] || 300 #5 minutes. @cache_time = opts[:cache_time] || 300 #5 minutes.
end end

View File

@ -41,8 +41,10 @@ module Mongo
# propogated to DB objects instantiated off of this Connection. This # propogated to DB objects instantiated off of this Connection. This
# default can be overridden upon instantiation of any DB by explicity setting a :safe value # default can be overridden upon instantiation of any DB by explicity setting a :safe value
# on initialization. # on initialization.
# @option options [Boolean] :read_secondary(false) If true, a random secondary node will be chosen, # @option options [:primary, :secondary] :read (:primary) The default read preference for Mongo::DB
# and all reads will be directed to that node. # objects created from this connection object. If +:secondary+ is chosen, reads will be sent
# to one of the closest available secondary nodes. If a secondary node cannot be located, the
# read will be sent to the primary.
# @option options [Logger, #debug] :logger (nil) Logger instance to receive driver operation log. # @option options [Logger, #debug] :logger (nil) Logger instance to receive driver operation log.
# @option options [Integer] :pool_size (1) The maximum number of socket connections allowed per # @option options [Integer] :pool_size (1) The maximum number of socket connections allowed per
# connection pool. Note: this setting is relevant only for multi-threaded applications. # connection pool. Note: this setting is relevant only for multi-threaded applications.
@ -125,6 +127,7 @@ module Mongo
@read = :secondary @read = :secondary
else else
@read = opts.fetch(:read, :primary) @read = opts.fetch(:read, :primary)
Mongo::Support.validate_read_preference(@read)
end end
@connected = false @connected = false

View File

@ -44,7 +44,6 @@ module Mongo
Digest::MD5.hexdigest("#{username}:mongo:#{plaintext}") Digest::MD5.hexdigest("#{username}:mongo:#{plaintext}")
end end
def validate_db_name(db_name) def validate_db_name(db_name)
unless [String, Symbol].include?(db_name.class) unless [String, Symbol].include?(db_name.class)
raise TypeError, "db_name must be a string or symbol" raise TypeError, "db_name must be a string or symbol"
@ -59,6 +58,15 @@ module Mongo
db_name db_name
end end
def validate_read_preference(value)
if [:primary, :secondary, nil].include?(value)
return true
else
raise MongoArgumentError, "#{value} is not a valid read preference. " +
"Please specify either :primary or :secondary."
end
end
def format_order_clause(order) def format_order_clause(order)
case order case order
when String, Symbol then string_as_sort_parameters(order) when String, Symbol then string_as_sort_parameters(order)

View File

@ -1,41 +1,43 @@
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require './test/replica_sets/rs_test_helper' require './test/replica_sets/rs_test_helper'
# TODO: enable this once we enable reads from tags.
class ReadPreferenceTest < Test::Unit::TestCase class ReadPreferenceTest < Test::Unit::TestCase
include Mongo include Mongo
def setup #def setup
@conn = ReplSetConnection.new([RS.host, RS.ports[0], RS.host, RS.ports[1]], :read => :secondary, :pool_size => 50) # @conn = ReplSetConnection.new([RS.host, RS.ports[0], RS.host, RS.ports[1]], :read => :secondary, :pool_size => 50)
@db = @conn.db(MONGO_TEST_DB) # @db = @conn.db(MONGO_TEST_DB)
@db.drop_collection("test-sets") # @db.drop_collection("test-sets")
end #end
def test_query_tagged # TODO: enable this once we enable reads from tags.
col = @db['mongo-test'] # def test_query_tagged
# col = @db['mongo-test']
col.insert({:a => 1}, :safe => {:w => 3}) # col.insert({:a => 1}, :safe => {:w => 3})
col.find_one({}, :read => {:db => "main"}) # col.find_one({}, :read => {:db => "main"})
col.find_one({}, :read => {:dc => "ny"}) # col.find_one({}, :read => {:dc => "ny"})
col.find_one({}, :read => {:dc => "sf"}) # col.find_one({}, :read => {:dc => "sf"})
assert_raise Mongo::NodeWithTagsNotFound do # assert_raise Mongo::NodeWithTagsNotFound do
col.find_one({}, :read => {:foo => "bar"}) # col.find_one({}, :read => {:foo => "bar"})
end # end
threads = [] # threads = []
100.times do # 100.times do
threads << Thread.new do # threads << Thread.new do
col.find_one({}, :read => {:dc => "sf"}) # col.find_one({}, :read => {:dc => "sf"})
end # end
end # end
threads.each {|t| t.join } # threads.each {|t| t.join }
col.remove # col.remove
end # end
def teardown #def teardown
RS.restart_killed_nodes # RS.restart_killed_nodes
end #end
end end

View File

@ -87,11 +87,14 @@ class ReadTest < Test::Unit::TestCase
end end
should "allow override alternate value on query" do should "allow override alternate value on query" do
@con.expects(:receive_message).with do |o, m, l, s, c, r| # TODO: enable this test once we enable reading from tags.
tags = {:dc => "ny"} # @con.expects(:receive_message).with do |o, m, l, s, c, r|
end.returns([[], 0, 0]) # tags = {:dc => "ny"}
# end.returns([[], 0, 0])
@col.find_one({:a => 1}, :read => {:dc => "ny"}) assert_raise MongoArgumentError do
@col.find_one({:a => 1}, :read => {:dc => "ny"})
end
end end
end end
end end