Store sockets in thread-local variables when possible.
Allow connection pools to grow if needed. All this minimizes the number of locks required and reduces the waiting time for these locks.
This commit is contained in:
parent
0b33a48dd9
commit
f668678fd1
|
@ -19,10 +19,9 @@
|
||||||
require 'set'
|
require 'set'
|
||||||
require 'socket'
|
require 'socket'
|
||||||
require 'thread'
|
require 'thread'
|
||||||
|
|
||||||
module Mongo
|
module Mongo
|
||||||
|
|
||||||
# Instantiates and manages connections to MongoDB.
|
# Instantiates and manages self.connections to MongoDB.
|
||||||
class Connection
|
class Connection
|
||||||
include Mongo::Logging
|
include Mongo::Logging
|
||||||
include Mongo::Networking
|
include Mongo::Networking
|
||||||
|
@ -35,11 +34,12 @@ module Mongo
|
||||||
|
|
||||||
DEFAULT_PORT = 27017
|
DEFAULT_PORT = 27017
|
||||||
|
|
||||||
|
mongo_thread_local_accessor :connections
|
||||||
|
|
||||||
attr_reader :logger, :size, :auths, :primary, :safe, :host_to_try,
|
attr_reader :logger, :size, :auths, :primary, :safe, :host_to_try,
|
||||||
:pool_size, :connect_timeout, :pool_timeout,
|
:pool_size, :connect_timeout, :pool_timeout,
|
||||||
:primary_pool, :socket_class
|
:primary_pool, :socket_class
|
||||||
|
|
||||||
|
|
||||||
# Create a connection to single MongoDB instance.
|
# Create a connection to single MongoDB instance.
|
||||||
#
|
#
|
||||||
# You may specify whether connection to slave is permitted.
|
# You may specify whether connection to slave is permitted.
|
||||||
|
@ -63,9 +63,9 @@ module Mongo
|
||||||
# to a single, slave node.
|
# to a single, slave node.
|
||||||
# @option opts [Logger, #debug] :logger (nil) A Logger instance for debugging driver ops. Note that
|
# @option opts [Logger, #debug] :logger (nil) A Logger instance for debugging driver ops. Note that
|
||||||
# logging negatively impacts performance; therefore, it should not be used for high-performance apps.
|
# logging negatively impacts performance; therefore, it should not be used for high-performance apps.
|
||||||
# @option opts [Integer] :pool_size (1) The maximum number of socket connections allowed per
|
# @option opts [Integer] :pool_size (1) The maximum number of socket self.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.
|
||||||
# @option opts [Float] :pool_timeout (5.0) When all of the connections a pool are checked out,
|
# @option opts [Float] :pool_timeout (5.0) When all of the self.connections a pool are checked out,
|
||||||
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
||||||
# Note: this setting is relevant only for multi-threaded applications (which in Ruby are rare).
|
# Note: this setting is relevant only for multi-threaded applications (which in Ruby are rare).
|
||||||
# @option opts [Float] :op_timeout (nil) The number of seconds to wait for a read operation to time out.
|
# @option opts [Float] :op_timeout (nil) The number of seconds to wait for a read operation to time out.
|
||||||
|
@ -80,7 +80,7 @@ module Mongo
|
||||||
# @example localhost, 27017
|
# @example localhost, 27017
|
||||||
# Connection.new("localhost")
|
# Connection.new("localhost")
|
||||||
#
|
#
|
||||||
# @example localhost, 3000, max 5 connections, with max 5 seconds of wait time.
|
# @example localhost, 3000, max 5 self.connections, with max 5 seconds of wait time.
|
||||||
# Connection.new("localhost", 3000, :pool_size => 5, :timeout => 5)
|
# Connection.new("localhost", 3000, :pool_size => 5, :timeout => 5)
|
||||||
#
|
#
|
||||||
# @example localhost, 3000, where this node may be a slave
|
# @example localhost, 3000, where this node may be a slave
|
||||||
|
@ -91,7 +91,7 @@ module Mongo
|
||||||
# @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
|
# @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
|
||||||
# driver fails to connect to a replica set with that name.
|
# driver fails to connect to a replica set with that name.
|
||||||
#
|
#
|
||||||
# @core connections
|
# @core self.connections
|
||||||
def initialize(host=nil, port=nil, opts={})
|
def initialize(host=nil, port=nil, opts={})
|
||||||
@host_to_try = format_pair(host, port)
|
@host_to_try = format_pair(host, port)
|
||||||
|
|
||||||
|
@ -481,6 +481,55 @@ module Mongo
|
||||||
@max_bson_size
|
@max_bson_size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def get_local_reader
|
||||||
|
self.connections ||= {}
|
||||||
|
self.connections[self.object_id] ||= {}
|
||||||
|
self.connections[self.object_id][:reader] ||= checkout_reader
|
||||||
|
|
||||||
|
# Thread.current[:connections] ||= {}
|
||||||
|
# Thread.current[:connections][self.object_id] ||= {}
|
||||||
|
# Thread.current[:connections][self.object_id][:reader] ||= checkout_reader
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_local_writer
|
||||||
|
self.connections ||= {}
|
||||||
|
self.connections[self.object_id] ||= {}
|
||||||
|
self.connections[self.object_id][:writer] ||= checkout_writer
|
||||||
|
# Thread.current[:connections] ||= {}
|
||||||
|
# Thread.current[:connections][self.object_id] ||= {}
|
||||||
|
# Thread.current[:connections][self.object_id][:writer] ||= checkout_writer
|
||||||
|
end
|
||||||
|
|
||||||
|
# Used to close, check in, or refresh sockets held
|
||||||
|
# in thread-local variables.
|
||||||
|
def local_socket_done(socket)
|
||||||
|
#checkin(socket)
|
||||||
|
puts "Done. Threads: #{Thread.list.size}, pool_size: #{self.pool_size}"
|
||||||
|
if self.connections[self.object_id][:reader] == socket
|
||||||
|
if self.read_pool.sockets_low?
|
||||||
|
puts "***SOCKETS ARE LOW! READER****"
|
||||||
|
checkin(socket)
|
||||||
|
self.connections[self.object_id][:reader] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.connections[self.object_id][:writer] == socket
|
||||||
|
if self.primary_pool && self.primary_pool.sockets_low?
|
||||||
|
puts "***SOCKETS ARE LOW! WRITER****"
|
||||||
|
checkin(socket)
|
||||||
|
self.connections[self.object_id][:writer] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# if Thread.current[:connections][self.object_id][:reader] == socket
|
||||||
|
# Thread.current[:connections][self.object_id][:reader] = nil
|
||||||
|
# end
|
||||||
|
# if Thread.current[:connections][self.object_id][:writer] == socket
|
||||||
|
# Thread.current[:connections][self.object_id][:writer] = nil
|
||||||
|
# end
|
||||||
|
end
|
||||||
|
|
||||||
# Checkout a socket for reading (i.e., a secondary node).
|
# Checkout a socket for reading (i.e., a secondary node).
|
||||||
# Note: this is overridden in ReplSetConnection.
|
# Note: this is overridden in ReplSetConnection.
|
||||||
def checkout_reader
|
def checkout_reader
|
||||||
|
@ -525,9 +574,6 @@ module Mongo
|
||||||
# Default maximum BSON object size
|
# Default maximum BSON object size
|
||||||
@max_bson_size = Mongo::DEFAULT_MAX_BSON_SIZE
|
@max_bson_size = Mongo::DEFAULT_MAX_BSON_SIZE
|
||||||
|
|
||||||
@safe_mutex_lock = Mutex.new
|
|
||||||
@safe_mutexes = Hash.new {|hash, key| hash[key] = Mutex.new}
|
|
||||||
|
|
||||||
# Determine whether to use SSL.
|
# Determine whether to use SSL.
|
||||||
@ssl = opts.fetch(:ssl, false)
|
@ssl = opts.fetch(:ssl, false)
|
||||||
if @ssl
|
if @ssl
|
||||||
|
|
|
@ -470,9 +470,11 @@ module Mongo
|
||||||
results, @n_received, @cursor_id = @connection.receive_message(
|
results, @n_received, @cursor_id = @connection.receive_message(
|
||||||
Mongo::Constants::OP_QUERY, message, nil, sock, @command,
|
Mongo::Constants::OP_QUERY, message, nil, sock, @command,
|
||||||
nil, @options & OP_QUERY_EXHAUST != 0)
|
nil, @options & OP_QUERY_EXHAUST != 0)
|
||||||
ensure
|
rescue ConnectionFailure, OperationFailure, OperationTimeout => ex
|
||||||
checkin_socket(sock) unless @socket
|
force_checkin_socket(sock)
|
||||||
|
raise ex
|
||||||
end
|
end
|
||||||
|
checkin_socket(sock) unless @socket
|
||||||
@returned += @n_received
|
@returned += @n_received
|
||||||
@cache += results
|
@cache += results
|
||||||
@query_run = true
|
@query_run = true
|
||||||
|
@ -505,9 +507,11 @@ module Mongo
|
||||||
begin
|
begin
|
||||||
results, @n_received, @cursor_id = @connection.receive_message(
|
results, @n_received, @cursor_id = @connection.receive_message(
|
||||||
Mongo::Constants::OP_GET_MORE, message, nil, sock, @command, nil)
|
Mongo::Constants::OP_GET_MORE, message, nil, sock, @command, nil)
|
||||||
ensure
|
rescue ConnectionFailure, OperationFailure, OperationTimeout => ex
|
||||||
checkin_socket(sock) unless @socket
|
force_checkin_socket(sock)
|
||||||
|
raise ex
|
||||||
end
|
end
|
||||||
|
checkin_socket(sock) unless @socket
|
||||||
@returned += @n_received
|
@returned += @n_received
|
||||||
@cache += results
|
@cache += results
|
||||||
close_cursor_if_query_complete
|
close_cursor_if_query_complete
|
||||||
|
@ -516,10 +520,10 @@ module Mongo
|
||||||
def checkout_socket_from_connection
|
def checkout_socket_from_connection
|
||||||
@checkin_connection = true
|
@checkin_connection = true
|
||||||
if @command || @read_preference == :primary
|
if @command || @read_preference == :primary
|
||||||
@connection.checkout_writer
|
@connection.get_local_writer
|
||||||
else
|
else
|
||||||
@read_pool = @connection.read_pool
|
@read_pool = @connection.read_pool
|
||||||
@connection.checkout_reader
|
@connection.get_local_reader
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -552,6 +556,16 @@ module Mongo
|
||||||
@read_pool.checkin(sock)
|
@read_pool.checkin(sock)
|
||||||
@checkin_read_pool = false
|
@checkin_read_pool = false
|
||||||
elsif @checkin_connection
|
elsif @checkin_connection
|
||||||
|
@connection.local_socket_done(sock)
|
||||||
|
@checkin_connection = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def force_checkin_socket(sock)
|
||||||
|
if @checkin_read_pool
|
||||||
|
@read_pool.checkin(sock)
|
||||||
|
@checkin_read_pool = false
|
||||||
|
else
|
||||||
@connection.checkin(sock)
|
@connection.checkin(sock)
|
||||||
@checkin_connection = false
|
@checkin_connection = false
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,14 +30,16 @@ module Mongo
|
||||||
packed_message = message.to_s
|
packed_message = message.to_s
|
||||||
|
|
||||||
if connection == :writer
|
if connection == :writer
|
||||||
socket = checkout_writer
|
sock = get_local_writer
|
||||||
else
|
else
|
||||||
socket = checkout_reader
|
sock = get_local_reader
|
||||||
end
|
end
|
||||||
|
|
||||||
send_message_on_socket(packed_message, socket)
|
send_message_on_socket(packed_message, sock)
|
||||||
ensure
|
local_socket_done(sock)
|
||||||
checkin(socket)
|
rescue ConnectionFailure, OperationFailure, OperationTimeout => ex
|
||||||
|
checkin(sock)
|
||||||
|
raise ex
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,11 +65,13 @@ module Mongo
|
||||||
|
|
||||||
packed_message = message.append!(last_error_message).to_s
|
packed_message = message.append!(last_error_message).to_s
|
||||||
begin
|
begin
|
||||||
sock = checkout_writer
|
sock = get_local_writer
|
||||||
send_message_on_socket(packed_message, sock)
|
send_message_on_socket(packed_message, sock)
|
||||||
docs, num_received, cursor_id = receive(sock, last_error_id)
|
docs, num_received, cursor_id = receive(sock, last_error_id)
|
||||||
ensure
|
local_socket_done(sock)
|
||||||
|
rescue ConnectionFailure, OperationFailure, OperationTimeout => ex
|
||||||
checkin(sock)
|
checkin(sock)
|
||||||
|
raise ex
|
||||||
end
|
end
|
||||||
|
|
||||||
if num_received == 1 && (error = docs[0]['err'] || docs[0]['errmsg'])
|
if num_received == 1 && (error = docs[0]['err'] || docs[0]['errmsg'])
|
||||||
|
@ -103,11 +107,11 @@ module Mongo
|
||||||
should_checkin = false
|
should_checkin = false
|
||||||
else
|
else
|
||||||
if command
|
if command
|
||||||
sock = checkout_writer
|
sock = get_local_writer
|
||||||
elsif read == :primary
|
elsif read == :primary
|
||||||
sock = checkout_writer
|
sock = get_local_writer
|
||||||
elsif read == :secondary
|
elsif read == :secondary
|
||||||
sock = checkout_reader
|
sock = get_local_reader
|
||||||
else
|
else
|
||||||
sock = checkout_tagged(read)
|
sock = checkout_tagged(read)
|
||||||
end
|
end
|
||||||
|
@ -115,14 +119,12 @@ module Mongo
|
||||||
end
|
end
|
||||||
|
|
||||||
result = ''
|
result = ''
|
||||||
@safe_mutexes[sock].synchronize do
|
|
||||||
send_message_on_socket(packed_message, sock)
|
send_message_on_socket(packed_message, sock)
|
||||||
result = receive(sock, request_id, exhaust)
|
result = receive(sock, request_id, exhaust)
|
||||||
end
|
local_socket_done(sock) if should_checkin
|
||||||
ensure
|
rescue ConnectionFailure, OperationFailure, OperationTimeout => ex
|
||||||
if should_checkin
|
checkin(sock) if should_checkin
|
||||||
checkin(sock)
|
raise ex
|
||||||
end
|
|
||||||
end
|
end
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,8 @@ module Mongo
|
||||||
|
|
||||||
# Instantiates and manages connections to a MongoDB replica set.
|
# Instantiates and manages connections to a MongoDB replica set.
|
||||||
class ReplSetConnection < Connection
|
class ReplSetConnection < Connection
|
||||||
attr_reader :replica_set_name, :seeds, :refresh_interval, :refresh_mode
|
attr_reader :replica_set_name, :seeds, :refresh_interval, :refresh_mode,
|
||||||
|
:refresh_version
|
||||||
|
|
||||||
# Create a connection to a MongoDB replica set.
|
# Create a connection to a MongoDB replica set.
|
||||||
#
|
#
|
||||||
|
@ -123,6 +124,7 @@ module Mongo
|
||||||
|
|
||||||
# Store the refresher thread
|
# Store the refresher thread
|
||||||
@refresh_thread = nil
|
@refresh_thread = nil
|
||||||
|
@refresh_version = 0
|
||||||
|
|
||||||
# Maps
|
# Maps
|
||||||
@sockets_to_pools = {}
|
@sockets_to_pools = {}
|
||||||
|
@ -301,6 +303,36 @@ module Mongo
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_local_reader
|
||||||
|
Thread.current[:connections] ||= {}
|
||||||
|
Thread.current[:connections][self.object_id] ||= {}
|
||||||
|
Thread.current[:connections][self.object_id][:version] ||= self.refresh_version
|
||||||
|
Thread.current[:connections][self.object_id][:reader] ||= checkout_reader
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_local_writer
|
||||||
|
Thread.current[:connections] ||= {}
|
||||||
|
Thread.current[:connections][self.object_id] ||= {}
|
||||||
|
Thread.current[:connections][self.object_id][:version] ||= self.refresh_version
|
||||||
|
Thread.current[:connections][self.object_id][:writer] ||= checkout_writer
|
||||||
|
end
|
||||||
|
|
||||||
|
# Used to close, check in, or refresh sockets held
|
||||||
|
# in thread-local variables.
|
||||||
|
def local_socket_done
|
||||||
|
if Thread.current[:connections][self.object_id][:version] != self.refresh_version
|
||||||
|
checkin(Thread.current[:connections][self.object_id][:reader])
|
||||||
|
Thread.current[:connections][self.object_id][:reader] ||= checkout_reader
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def checkin_sockets
|
||||||
|
checkin(Thread.current[:connections][self.object_id][:reader])
|
||||||
|
checkin(Thread.current[:connections][self.object_id][:writer])
|
||||||
|
Thread.current[:connections][self.object_id][:writer] = nil
|
||||||
|
Thread.current[:connections][self.object_id][:reader] = nil
|
||||||
|
end
|
||||||
|
|
||||||
# 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.
|
# if no read pool has been defined.
|
||||||
|
@ -480,6 +512,7 @@ module Mongo
|
||||||
@manager = new_manager
|
@manager = new_manager
|
||||||
@seeds = @manager.seeds.dup
|
@seeds = @manager.seeds.dup
|
||||||
@sockets_to_pools.clear
|
@sockets_to_pools.clear
|
||||||
|
@refresh_version += 1
|
||||||
old_manager.close if old_manager
|
old_manager.close if old_manager
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -58,3 +58,28 @@ class String
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#:nodoc:
|
||||||
|
class Class
|
||||||
|
def mongo_thread_local_accessor name, options = {}
|
||||||
|
m = Module.new
|
||||||
|
m.module_eval do
|
||||||
|
class_variable_set :"@@#{name}", Hash.new {|h,k| h[k] = options[:default] }
|
||||||
|
end
|
||||||
|
m.module_eval %{
|
||||||
|
|
||||||
|
def #{name}
|
||||||
|
@@#{name}[Thread.current.object_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def #{name}=(val)
|
||||||
|
@@#{name}[Thread.current.object_id] = val
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
class_eval do
|
||||||
|
include m
|
||||||
|
extend m
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -21,7 +21,8 @@ module Mongo
|
||||||
MAX_PING_TIME = 1_000_000
|
MAX_PING_TIME = 1_000_000
|
||||||
|
|
||||||
attr_accessor :host, :port, :address,
|
attr_accessor :host, :port, :address,
|
||||||
:size, :timeout, :safe, :checked_out, :connection
|
:size, :timeout, :safe, :checked_out, :connection,
|
||||||
|
:sockets_low
|
||||||
|
|
||||||
# Create a new pool of connections.
|
# Create a new pool of connections.
|
||||||
def initialize(connection, host, port, opts={})
|
def initialize(connection, host, port, opts={})
|
||||||
|
@ -36,7 +37,7 @@ module Mongo
|
||||||
@address = "#{@host}:#{@port}"
|
@address = "#{@host}:#{@port}"
|
||||||
|
|
||||||
# Pool size and timeout.
|
# Pool size and timeout.
|
||||||
@size = opts[:size] || 10
|
@size = opts[:size] || 10000
|
||||||
@timeout = opts[:timeout] || 5.0
|
@timeout = opts[:timeout] || 5.0
|
||||||
|
|
||||||
# Mutex for synchronizing pool access
|
# Mutex for synchronizing pool access
|
||||||
|
@ -48,9 +49,11 @@ module Mongo
|
||||||
# Operations to perform on a socket
|
# Operations to perform on a socket
|
||||||
@socket_ops = Hash.new { |h, k| h[k] = [] }
|
@socket_ops = Hash.new { |h, k| h[k] = [] }
|
||||||
|
|
||||||
|
@sockets_low = true
|
||||||
@sockets = []
|
@sockets = []
|
||||||
@pids = {}
|
@pids = {}
|
||||||
@checked_out = []
|
@checked_out = []
|
||||||
|
@threads = {}
|
||||||
@ping_time = nil
|
@ping_time = nil
|
||||||
@last_ping = nil
|
@last_ping = nil
|
||||||
@closed = false
|
@closed = false
|
||||||
|
@ -76,6 +79,10 @@ module Mongo
|
||||||
@closed
|
@closed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sockets_low?
|
||||||
|
@sockets_low
|
||||||
|
end
|
||||||
|
|
||||||
def inspect
|
def inspect
|
||||||
"#<Mongo::Pool:0x#{self.object_id.to_s(16)} @host=#{@host} @port=#{port} " +
|
"#<Mongo::Pool:0x#{self.object_id.to_s(16)} @host=#{@host} @port=#{port} " +
|
||||||
"@ping_time=#{@ping_time} #{@checked_out.size}/#{@size} sockets available.>"
|
"@ping_time=#{@ping_time} #{@checked_out.size}/#{@size} sockets available.>"
|
||||||
|
@ -138,7 +145,9 @@ module Mongo
|
||||||
# Return a socket to the pool.
|
# Return a socket to the pool.
|
||||||
def checkin(socket)
|
def checkin(socket)
|
||||||
@connection_mutex.synchronize do
|
@connection_mutex.synchronize do
|
||||||
|
puts "deleting #{socket}, size: #{@checked_out.size}"
|
||||||
@checked_out.delete(socket)
|
@checked_out.delete(socket)
|
||||||
|
puts "size now: #{@checked_out.size}"
|
||||||
@queue.signal
|
@queue.signal
|
||||||
end
|
end
|
||||||
true
|
true
|
||||||
|
@ -166,6 +175,7 @@ module Mongo
|
||||||
@sockets << socket
|
@sockets << socket
|
||||||
@pids[socket] = Process.pid
|
@pids[socket] = Process.pid
|
||||||
@checked_out << socket
|
@checked_out << socket
|
||||||
|
@threads[socket] = Thread.current.object_id
|
||||||
socket
|
socket
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -211,10 +221,36 @@ module Mongo
|
||||||
checkout_new_socket
|
checkout_new_socket
|
||||||
else
|
else
|
||||||
@checked_out << socket
|
@checked_out << socket
|
||||||
|
@threads[socket] = Thread.current.object_id
|
||||||
socket
|
socket
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cleanup
|
||||||
|
return unless @sockets.size > @size
|
||||||
|
puts "-----CLEANUP*****"
|
||||||
|
alive = {}
|
||||||
|
Thread.list.each do |t|
|
||||||
|
if t.alive?
|
||||||
|
alive[t.object_id] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@checked_out.each do |socket|
|
||||||
|
if !alive[@threads[socket]]
|
||||||
|
@checked_out.delete(socket)
|
||||||
|
if @sockets.size > @size
|
||||||
|
puts "CLEANING: #{socket}"
|
||||||
|
socket.close
|
||||||
|
@sockets.delete(socket)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# Check out an existing socket or create a new socket if the maximum
|
# Check out an existing socket or create a new socket if the maximum
|
||||||
# pool size has not been exceeded. Otherwise, wait for the next
|
# pool size has not been exceeded. Otherwise, wait for the next
|
||||||
# available socket.
|
# available socket.
|
||||||
|
@ -228,15 +264,22 @@ module Mongo
|
||||||
"consider increasing the pool size or timeout."
|
"consider increasing the pool size or timeout."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
puts "CHECKING OUT"
|
||||||
|
#@sockets_low = @checked_out.size > @size / 2
|
||||||
@connection_mutex.synchronize do
|
@connection_mutex.synchronize do
|
||||||
|
if @sockets.size > 0.7 * @size
|
||||||
|
@sockets_low = true
|
||||||
|
else
|
||||||
|
@sockets_low = false
|
||||||
|
end
|
||||||
socket = if @checked_out.size < @sockets.size
|
socket = if @checked_out.size < @sockets.size
|
||||||
|
p "checkout existing from size #{@sockets.size}"
|
||||||
checkout_existing_socket
|
checkout_existing_socket
|
||||||
elsif @sockets.size < @size
|
else
|
||||||
checkout_new_socket
|
checkout_new_socket
|
||||||
end
|
end
|
||||||
|
|
||||||
if socket
|
if socket
|
||||||
|
|
||||||
# This calls all procs, in order, scoped to existing sockets.
|
# This calls all procs, in order, scoped to existing sockets.
|
||||||
# At the moment, we use this to lazily authenticate and
|
# At the moment, we use this to lazily authenticate and
|
||||||
# logout existing socket connections.
|
# logout existing socket connections.
|
||||||
|
|
|
@ -4,7 +4,7 @@ class TestThreading < Test::Unit::TestCase
|
||||||
|
|
||||||
include Mongo
|
include Mongo
|
||||||
|
|
||||||
@@db = standard_connection(:pool_size => 1, :timeout => 30).db(MONGO_TEST_DB)
|
@@db = standard_connection(:pool_size => 10, :timeout => 30).db(MONGO_TEST_DB)
|
||||||
@@coll = @@db.collection('thread-test-collection')
|
@@coll = @@db.collection('thread-test-collection')
|
||||||
|
|
||||||
def set_up_safe_data
|
def set_up_safe_data
|
||||||
|
@ -21,16 +21,23 @@ class TestThreading < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_safe_update
|
def test_safe_update
|
||||||
|
times = []
|
||||||
set_up_safe_data
|
set_up_safe_data
|
||||||
threads = []
|
threads = []
|
||||||
100.times do |i|
|
100.times do |i|
|
||||||
threads[i] = Thread.new do
|
threads[i] = Thread.new do
|
||||||
|
10.times do
|
||||||
if i % 2 == 0
|
if i % 2 == 0
|
||||||
assert_raise Mongo::OperationFailure do
|
assert_raise Mongo::OperationFailure do
|
||||||
|
t1 = Time.now
|
||||||
@unique.update({"test" => "insert"}, {"$set" => {"test" => "update"}}, :safe => true)
|
@unique.update({"test" => "insert"}, {"$set" => {"test" => "update"}}, :safe => true)
|
||||||
|
times << Time.now - t1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
t1 = Time.now
|
||||||
@duplicate.update({"test" => "insert"}, {"$set" => {"test" => "update"}}, :safe => true)
|
@duplicate.update({"test" => "insert"}, {"$set" => {"test" => "update"}}, :safe => true)
|
||||||
|
times << Time.now - t1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue