I needed a simple mysql connection pool in Ruby supporting get/release connection from/to pool and delete a connection pool on the end.
That is the code, together with unit tests – samples of the usage, and test runner
#!/usr/bin/env ruby
require 'test/unit'
require 'thread'
require 'mysql'
module ConnectionPool
Database = {: User => 'root',
: Password => 'pass',
: Host => 'localhost',
: Database => 'tra_db',
: ConnString => 'DBI:Mysql:tra_db:localhost',
: Connections => 10,
: Timeout => 1, }
class ConnectionPoolClass
CONN_POOL_RETURN_SLEEP = 0.001
CONN_POOL_DELETE_SLEEP = 0.001
@@instance = nil
@@instance_mutex = Mutex.new
def self.get_instance(config = Database)
@@instance_mutex.synchronize {
@@instance ||= self.new(config)
}
end
def initialize(config = Database)
@config = Database.dup.update(config)
@free_connections = []
@used_connections = []
@num_busy = 0
@max_allowed = @config[:Connections]
@monitor_mutex = Mutex.new
@free_mutex = Mutex.new
@max_allowed.times do |i|
new_conn = create_connection
@free_connections.push new_conn unless (nil == new_conn)
end
raise "Errors creating connection pool, expected #{@max_allowed} conn, but created #{free_pool_size}" unless (@max_allowed == free_pool_size)
end
## return the number of free connections in the pool
public
def free_pool_size
@monitor_mutex.synchronize {
@free_connections.size
}
end
## return the number of used connections in the pool
public
def use_pool_size
@monitor_mutex.synchronize {
@used_connections.size
}
end
## get a connection from the pool
public
def get_connection
yield(connection = get_conn_from_pool)
release_connection(connection)
return connection
end
## get a connection from the pool
protected
def get_conn_from_pool
@free_mutex.synchronize do |i|
while @free_connections.empty?
sleep(CONN_POOL_RETURN_SLEEP)
end
conn = @free_connections.pop
@used_connections.push(conn)
return conn
end
end
## release a connection back to the pool to use by somebody else
public
def release_connection(connection)
@monitor_mutex.synchronize do |i|
@free_connections.push connection
conn_idx = @used_connections.index connection
@used_connections.pop conn_idx unless (nil == conn_idx)
end
end
## creates a connection and return its handler or return nil. Used by initialize() only
private
def create_connection
dbh = Mysql.init
dbh.real_connect(@config[:Host], @config[:User], @config[:Password], @config[:Database])
return dbh
rescue Mysql::Error => e
puts e.errno
puts e.error
return nil
end
## close a particular given connection. Should stay private since it is used by
## delete_connection_pool() method only
private
def close_connection (dbh)
dbh.close if dbh
rescue Mysql::Error => e
puts e.errno
puts e.error
end
## Entirely delete connection pool. Close all connections and empty all arrays
public
def delete_connection_pool
@used_connections.each do |conn|
release_connection(conn)
end
@free_connections.each do |conn|
close_connection(conn)
sleep(CONN_POOL_DELETE_SLEEP)
end
@used_connections.clear
@free_connections.clear
end
end
end
Ideas are received here
thanks for share!