lib/mongo/server/connection_pool.rb
# Checks a connection out of the pool.
#
# If there are active connections in the pool, the most recently used
# connection is returned. Otherwise if the connection pool size is less
# than the max size, creates a new connection and returns it. Otherwise
# waits up to the wait timeout and raises Timeout::Error if there are
# still no active connections and the pool is at max size.
#
# The returned connection counts toward the pool's max size. When the
# caller is finished using the connection, the connection should be
# checked back in via the check_in method.
#
# @return [ Mongo::Server::Connection ] The checked out connection.
# @raise [ Error::PoolClosedError ] If the pool has been closed.
# @raise [ Timeout::Error ] If the connection pool is at maximum size
#   and remains so for longer than the wait timeout.
#
# @since 2.9.0
Checks a connection out of the pool.
If there are active connections in the pool, the most recently used
connection is returned. Otherwise if the connection pool size is less
than the max size, creates a new connection and returns it. Otherwise
waits up to the wait timeout and raises Timeout::Error if there are
still no active connections and the pool is at max size.

The returned connection counts toward the pool's max size. When the
caller is finished using the connection, the connection should be
checked back in via the check_in method.
Checks a connection out of the pool . If there are active connections in the pool the most recently used connection is returned . Otherwise if the connection pool size is less than the max size creates a new connection and returns it . Otherwise waits up to the wait timeout and raises Timeout :: Error if there are still no active connections and the pool is at max size . The returned connection counts toward the pool ' s max size . When the caller is finished using the connection the connection should be checked back in via the check_in method .
def check_out(service_id: nil)
        check_invariants
        publish_cmap_event(
          Monitoring::Event::Cmap::ConnectionCheckOutStarted.new(@server.address)
        )
        if closed?
          publish_cmap_event(
            Monitoring::Event::Cmap::ConnectionCheckOutFailed.new(
              @server.address,
              Monitoring::Event::Cmap::ConnectionCheckOutFailed::POOL_CLOSED
            ),
          )
          raise Error::PoolClosedError.new(@server.address, self)
        end
        deadline = Utils.monotonic_time + wait_timeout
        pid = Process.pid
        connection = nil
        catch(:done) do
          loop do
            @lock.synchronize do
              until @available_connections.empty?
                connection = next_available_connection(service_id: service_id)
                break unless connection
                if connection.pid != pid
                  log_warn("Detected PID change - Mongo client should have been reconnected (old pid {connection.pid}, new pid {pid}")
                  connection.disconnect!(reason: :stale)
                  @populate_semaphore.signal
                  next
                end
                if connection.generation != generation(service_id: connection.service_id)
                  connection.disconnect!(reason: :stale)
                  @populate_semaphore.signal
                  next
                end
                if max_idle_time && connection.last_checkin &&
                  Time.now - connection.last_checkin > max_idle_time
                then
                  connection.disconnect!(reason: :idle)
                  @populate_semaphore.signal
                  next
                end
                @pending_connections << connection
                throw(:done)
              end
              if service_id
              else
                 Ruby does not allow a thread to lock a mutex which it already
                 holds.
                if unsynchronized_size < max_size
                  connection = create_connection
                  @pending_connections << connection
                  throw(:done)
                end
              end
            end
            wait = deadline - Utils.monotonic_time
            if wait <= 0
              publish_cmap_event(
                Monitoring::Event::Cmap::ConnectionCheckOutFailed.new(
                  @server.address,
                  Monitoring::Event::Cmap::ConnectionCheckOutFailed::TIMEOUT,
                ),
              )
              msg = @lock.synchronize do
                service_id_msg = if service_id
                  " for service {service_id}"
                else
                  ''
                end
                "Timed out attempting to check out a connection " +
                  "from pool for {@server.address}{service_id_msg} after {wait_timeout} sec. " +
                  "Connections in pool: {@available_connections.length} available, " +
                  "{@checked_out_connections.length} checked out, " +
                  "{@pending_connections.length} pending " +
                  "(max size: {max_size})"
              end
              raise Error::ConnectionCheckOutTimeout.new(msg, address: @server.address)
            end
            @available_semaphore.wait(wait)
          end
        end
        begin
          connect_connection(connection)
        rescue Exception
           Handshake or authentication failed
          @lock.synchronize do
            @pending_connections.delete(connection)
          end
          @populate_semaphore.signal
          publish_cmap_event(
            Monitoring::Event::Cmap::ConnectionCheckOutFailed.new(
              @server.address,
              Monitoring::Event::Cmap::ConnectionCheckOutFailed::CONNECTION_ERROR
            ),
          )
          raise
        end
        @lock.synchronize do
          @checked_out_connections << connection
          @pending_connections.delete(connection)
        end
        publish_cmap_event(
          Monitoring::Event::Cmap::ConnectionCheckedOut.new(@server.address, connection.id, self),
        )
        if Lint.enabled?
          unless connection.connected?
            raise Error::LintError, "Connection pool for {address} checked out a disconnected connection {connection.generation}:{connection.id}"
          end
        end
        connection
      ensure
        check_invariants
      end
def check_out ( service_id : nil ) check_invariants publish_cmap_event ( Monitoring :: Event :: Cmap :: ConnectionCheckOutStarted . new ( @server . address ) ) if closed? publish_cmap_event ( Monitoring :: Event :: Cmap :: ConnectionCheckOutFailed . new ( @server . address , Monitoring :: Event :: Cmap :: ConnectionCheckOutFailed :: POOL_CLOSED ) , ) raise Error :: PoolClosedError . new ( @server . address , self ) end deadline = Utils . monotonic_time + wait_timeout pid = Process . pid connection = nil catch ( :done ) do loop do @lock . synchronize do until @available_connections . empty? connection = next_available_connection ( service_id : service_id ) break unless connection if connection . pid != pid log_warn ( "Detected PID change - Mongo client should have been reconnected (old pid #{connection.pid}, new pid #{pid}" ) connection . disconnect! ( reason : :stale ) @populate_semaphore . signal next end if connection . generation != generation ( service_id : connection . service_id ) connection . disconnect! ( reason : :stale ) @populate_semaphore . signal next end if max_idle_time && connection . last_checkin && Time . now - connection . last_checkin > max_idle_time then connection . disconnect! ( reason : :idle ) @populate_semaphore . signal next end @pending_connections << connection throw ( :done ) end if service_id else if unsynchronized_size < max_size connection = create_connection @pending_connections << connection throw ( :done ) end end end wait = deadline - Utils . monotonic_time if wait <= 0 publish_cmap_event ( Monitoring :: Event :: Cmap :: ConnectionCheckOutFailed . new ( @server . address , Monitoring :: Event :: Cmap :: ConnectionCheckOutFailed :: TIMEOUT , ) , ) msg = @lock . synchronize do service_id_msg = if service_id " for service #{service_id}" else '' end "Timed out attempting to check out a connection " + "from pool for #{@server.address}#{service_id_msg} after #{wait_timeout} sec. " + "Connections in pool: #{@available_connections.length} available, " + "#{@checked_out_connections.length} checked out, " + "#{@pending_connections.length} pending " + "(max size: #{max_size})" end raise Error :: ConnectionCheckOutTimeout . new ( msg , address : @server . address ) end @available_semaphore . wait ( wait ) end end begin connect_connection ( connection ) rescue Exception @lock . synchronize do @pending_connections . delete ( connection ) end @populate_semaphore . signal publish_cmap_event ( Monitoring :: Event :: Cmap :: ConnectionCheckOutFailed . new ( @server . address , Monitoring :: Event :: Cmap :: ConnectionCheckOutFailed :: CONNECTION_ERROR ) , ) raise end @lock . synchronize do @checked_out_connections << connection @pending_connections . delete ( connection ) end publish_cmap_event ( Monitoring :: Event :: Cmap :: ConnectionCheckedOut . new ( @server . address , connection . id , self ) , ) if Lint . enabled? unless connection . connected? raise Error :: LintError , "Connection pool for #{address} checked out a disconnected connection #{connection.generation}:#{connection.id}" end end connection ensure check_invariants end
Checks a connection out of the pool.
Checks a connection out of the pool .
# It seems that synchronize sets up its own loop, thus a simple break # is insufficient to break the outer loop # Lock must be taken on each iteration, rather for the method # overall, otherwise other threads will not be able to check in # a connection while this thread is waiting for one. # If service_id is not nil, connection may be nil here # even if there are available connections in the pool # (they could be to other services). # Stale connections should be disconnected in the clear # method, but if any don't, check again here # If we need a connection to a particular service, we can't # create one if we don't already have one, but we can wait # for an in-progress operation to return such a connection # to the pool, or for the populator to create a suitable # connection. # If we are below pool capacity, create a new connection. # # Ruby does not allow a thread to lock a mutex which it already # holds. # Handshake or authentication failed
The checked out connection.
The checked out connection .
 Mongo::Server::Connection 
[ Error::PoolClosedError ] If the pool has been closed.
[ Error :: PoolClosedError ] If the pool has been closed .
[ Timeout::Error ] If the connection pool is at maximum size and remains so for longer than the wait timeout.
[ Timeout :: Error ] If the connection pool is at maximum size and remains so for longer than the wait timeout .
service_id
since
None