2013-09-17 05:48:34 +00:00
|
|
|
extern mod extra;
|
|
|
|
|
|
|
|
use extra::arc::MutexArc;
|
|
|
|
|
2013-09-18 05:06:47 +00:00
|
|
|
use super::{PostgresConnection,
|
|
|
|
NormalPostgresStatement,
|
|
|
|
PostgresDbError,
|
|
|
|
PostgresConnectError,
|
|
|
|
PostgresTransaction};
|
|
|
|
use super::types::ToSql;
|
2013-09-17 05:48:34 +00:00
|
|
|
|
|
|
|
pub struct PostgresConnectionPoolConfig {
|
|
|
|
initial_size: uint,
|
|
|
|
min_size: uint,
|
|
|
|
max_size: uint
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PostgresConnectionPoolConfig {
|
|
|
|
fn validate(&self) {
|
|
|
|
assert!(self.initial_size >= self.min_size);
|
|
|
|
assert!(self.initial_size <= self.max_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub static DEFAULT_CONFIG: PostgresConnectionPoolConfig =
|
|
|
|
PostgresConnectionPoolConfig {
|
|
|
|
initial_size: 3,
|
|
|
|
min_size: 3,
|
|
|
|
max_size: 15
|
|
|
|
};
|
|
|
|
|
|
|
|
struct InnerConnectionPool {
|
|
|
|
url: ~str,
|
|
|
|
config: PostgresConnectionPoolConfig,
|
|
|
|
pool: ~[PostgresConnection],
|
|
|
|
size: uint,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InnerConnectionPool {
|
|
|
|
fn new_connection(&mut self) -> Option<PostgresConnectError> {
|
|
|
|
match PostgresConnection::try_connect(self.url) {
|
|
|
|
Ok(conn) => {
|
|
|
|
self.pool.push(conn);
|
|
|
|
self.size += 1;
|
|
|
|
None
|
|
|
|
}
|
|
|
|
Err(err) => Some(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Should be a newtype, but blocked by mozilla/rust#9155
|
2013-09-17 06:38:27 +00:00
|
|
|
#[deriving(Clone)]
|
2013-09-17 05:48:34 +00:00
|
|
|
pub struct PostgresConnectionPool {
|
|
|
|
pool: MutexArc<InnerConnectionPool>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PostgresConnectionPool {
|
|
|
|
pub fn new(url: &str, config: PostgresConnectionPoolConfig)
|
|
|
|
-> Result<PostgresConnectionPool, PostgresConnectError> {
|
|
|
|
config.validate();
|
|
|
|
|
|
|
|
let mut pool = InnerConnectionPool {
|
|
|
|
url: url.to_owned(),
|
|
|
|
config: config,
|
|
|
|
pool: ~[],
|
|
|
|
size: 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
while pool.size < pool.config.initial_size {
|
|
|
|
match pool.new_connection() {
|
|
|
|
None => (),
|
|
|
|
Some(err) => return Err(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(PostgresConnectionPool {
|
|
|
|
pool: MutexArc::new(pool)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2013-09-18 05:06:47 +00:00
|
|
|
pub fn try_get_connection(&self) -> Result<PooledPostgresConnection,
|
|
|
|
PostgresConnectError> {
|
2013-09-17 05:48:34 +00:00
|
|
|
let conn = unsafe {
|
2013-09-18 05:06:47 +00:00
|
|
|
do self.pool.unsafe_access_cond |pool, cvar| {
|
2013-09-17 05:48:34 +00:00
|
|
|
while pool.pool.is_empty() {
|
2013-09-18 05:06:47 +00:00
|
|
|
cvar.wait();
|
2013-09-17 05:48:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pool.pool.pop()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-09-18 05:06:47 +00:00
|
|
|
Ok(PooledPostgresConnection {
|
|
|
|
pool: self.clone(),
|
|
|
|
conn: Some(conn)
|
|
|
|
})
|
|
|
|
}
|
2013-09-17 05:48:34 +00:00
|
|
|
|
2013-09-18 05:06:47 +00:00
|
|
|
pub fn get_connection(&self) -> PooledPostgresConnection {
|
|
|
|
match self.try_get_connection() {
|
|
|
|
Ok(conn) => conn,
|
|
|
|
Err(err) => fail!("Unable to get connection: %s", err.to_str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Should be a newtype
|
|
|
|
pub struct PooledPostgresConnection {
|
|
|
|
priv pool: PostgresConnectionPool,
|
|
|
|
// Todo remove the Option wrapper when drop takes self by value
|
|
|
|
priv conn: Option<PostgresConnection>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for PooledPostgresConnection {
|
|
|
|
fn drop(&mut self) {
|
2013-09-17 05:48:34 +00:00
|
|
|
unsafe {
|
2013-09-18 05:06:47 +00:00
|
|
|
do self.pool.pool.unsafe_access |pool| {
|
|
|
|
pool.pool.push(self.conn.take_unwrap());
|
2013-09-17 05:48:34 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-18 05:06:47 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-17 05:48:34 +00:00
|
|
|
|
2013-09-18 05:06:47 +00:00
|
|
|
impl PooledPostgresConnection {
|
|
|
|
pub fn try_prepare<'a>(&'a self, query: &str)
|
|
|
|
-> Result<NormalPostgresStatement<'a>, PostgresDbError> {
|
|
|
|
self.conn.get_ref().try_prepare(query)
|
2013-09-17 05:48:34 +00:00
|
|
|
}
|
|
|
|
|
2013-09-18 05:06:47 +00:00
|
|
|
pub fn prepare<'a>(&'a self, query: &str) -> NormalPostgresStatement<'a> {
|
|
|
|
self.conn.get_ref().prepare(query)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn try_update(&self, query: &str, params: &[&ToSql])
|
|
|
|
-> Result<uint, PostgresDbError> {
|
|
|
|
self.conn.get_ref().try_update(query, params)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update(&self, query: &str, params: &[&ToSql]) -> uint {
|
|
|
|
self.conn.get_ref().update(query, params)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn in_transaction<T>(&self, blk: &fn(&PostgresTransaction) -> T) -> T {
|
|
|
|
self.conn.get_ref().in_transaction(blk)
|
2013-09-17 05:48:34 +00:00
|
|
|
}
|
|
|
|
}
|