Class: ConnectionPool

Inherits:
Object
  • Object
show all
Defined in:
lib/connection_pool.rb

Overview

Do something in the block, that always create an adapter instance or connect to a server.

Defined Under Namespace

Classes: ConnectionTimeoutError

Constant Summary collapse

VERSION =
'0.1.1'
DEFAULT_OPTIONS =
{ :size => 5, :timeout => 5 }

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}, &block) ⇒ ConnectionPool

Creates a new ConnectionPool object. spec is a ConnectionSpecification object which describes database connection information (e.g. adapter, host name, username, password, etc), as well as the maximum size for this ConnectionPool.

The default ConnectionPool maximum size is 5.

Raises:

  • (ArgumentError)


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/connection_pool.rb', line 77

def initialize(options = {}, &block)
  @options = DEFAULT_OPTIONS.merge(options)

  raise ArgumentError, "Connection pool requires a block that create a new connection!" unless block

  @connection_block = block

  # The cache of reserved connections mapped to threads
  @reserved_connections = {}

  # The mutex used to synchronize pool access
  @connection_mutex = Monitor.new
  @queue = @connection_mutex.new_cond

  # default 5 second timeout
  @timeout = @options[:timeout]

  # default max pool size to 5
  @size = @options[:size]

  @connections = []
  @checked_out = []
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



65
66
67
# File 'lib/connection_pool.rb', line 65

def options
  @options
end

Instance Method Details

#checkin(conn) ⇒ Object

Check-in a connection back into the pool, indicating that you no longer need this connection.

conn: which was obtained by earlier by calling checkout on this pool.



207
208
209
210
211
212
# File 'lib/connection_pool.rb', line 207

def checkin(conn)
  @connection_mutex.synchronize do
    @checked_out.delete conn
    @queue.signal
  end
end

#checkoutObject

Check-out a database connection from the pool, indicating that you want to use it. You should call #checkin when you no longer need this.

This is done by either returning an existing connection, or by creating a new connection. If the maximum number of connections for this pool has already been reached, but the pool is empty (i.e. they’re all being used), then this method will wait until a thread has checked in a connection. The wait time is bounded however: if no connection can be checked out within the timeout specified for this pool, then a ConnectionTimeoutError exception will be raised.

Returns: connection instance return by the connection_block



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/connection_pool.rb', line 179

def checkout
  # Checkout an available connection
  @connection_mutex.synchronize do
    loop do
      conn = if @checked_out.size < @connections.size
               checkout_existing_connection
             elsif @connections.size < @size
               checkout_new_connection
             end
      return conn if conn
      # No connections available; wait for one
      if @queue.wait(@timeout)
        next
      else
        # try looting dead threads
        clear_stale_cached_connections!
        if @size == @checked_out.size
          raise ConnectionTimeoutError, "Could not obtain a connection within #{@timeout} seconds. The max pool size is currently #{@size}; consider increasing it."
        end
      end
    end
  end
end

#clear_stale_cached_connections!Object

Return any checked-out connections back to the pool by threads that are no longer alive.



156
157
158
159
160
161
162
163
164
# File 'lib/connection_pool.rb', line 156

def clear_stale_cached_connections!
  keys = @reserved_connections.keys - Thread.list.find_all { |t|
    t.alive?
  }.map { |thread| thread.object_id }
  keys.each do |key|
    checkin @reserved_connections[key]
    @reserved_connections.delete(key)
  end
end

#connected?Boolean

Returns true if a connection has already been opened.

Returns:

  • (Boolean)


129
130
131
# File 'lib/connection_pool.rb', line 129

def connected?
  !@connections.empty?
end

#connectionObject

Retrieve the connection associated with the current thread, or call #checkout to obtain one if necessary.

#connection can be called any number of times; the connection is held in a hash keyed by the thread id.



106
107
108
# File 'lib/connection_pool.rb', line 106

def connection
  @reserved_connections[current_connection_id] ||= checkout
end

#connection_cached?Boolean

whether connection cached in the current thread

Returns:

  • (Boolean)


215
216
217
# File 'lib/connection_pool.rb', line 215

def connection_cached?
  !!@reserved_connections[current_connection_id]
end

#disconnect!Object

Disconnects all connections in the pool, and clears the pool.



134
135
136
137
138
139
140
141
142
143
# File 'lib/connection_pool.rb', line 134

def disconnect!
  @reserved_connections.each do |name,conn|
    checkin conn
  end
  @reserved_connections = {}
  @connections.each do |conn|
    conn.disconnect!
  end
  @connections = []
end

#release_connectionObject

Signal that the thread is finished with the current connection. #release_connection releases the connection-thread association and returns the connection to the pool.



113
114
115
116
# File 'lib/connection_pool.rb', line 113

def release_connection
  conn = @reserved_connections.delete(current_connection_id)
  checkin conn if conn
end

#verify_active_connections!Object

Verify active connections and remove and disconnect connections associated with stale threads.



147
148
149
150
151
152
# File 'lib/connection_pool.rb', line 147

def verify_active_connections! #:nodoc:
  clear_stale_cached_connections!
  @connections.each do |connection|
    connection.verify!
  end
end

#with_connectionObject

If a connection already exists yield it to the block. If no connection exists checkout a connection, yield it to the block, and checkin the connection when finished.



121
122
123
124
125
126
# File 'lib/connection_pool.rb', line 121

def with_connection
  fresh_connection = true unless connection_cached?
  yield connection
ensure
  release_connection if fresh_connection
end