rust-postgres/pool.rs

157 lines
4.4 KiB
Rust
Raw Normal View History

2013-10-20 21:34:50 +00:00
//! A simple connection pool
2013-09-17 05:48:34 +00:00
extern mod extra;
use extra::arc::MutexArc;
use super::{PostgresNotificationIterator,
2013-10-21 00:54:50 +00:00
PostgresCancelData,
PostgresConnection,
2013-09-18 05:06:47 +00:00
NormalPostgresStatement,
2013-11-10 04:58:38 +00:00
PostgresTransaction,
SslMode};
2013-11-11 01:41:15 +00:00
use super::error::{PostgresConnectError, PostgresDbError};
2013-09-18 05:06:47 +00:00
use super::types::ToSql;
2013-09-17 05:48:34 +00:00
struct InnerConnectionPool {
url: ~str,
ssl: SslMode,
2013-09-17 05:48:34 +00:00
pool: ~[PostgresConnection],
}
impl InnerConnectionPool {
fn new_connection(&mut self) -> Option<PostgresConnectError> {
match PostgresConnection::try_connect(self.url, &self.ssl) {
2013-09-17 05:48:34 +00:00
Ok(conn) => {
self.pool.push(conn);
None
}
Err(err) => Some(err)
}
}
}
2013-09-30 02:47:30 +00:00
/// A simple fixed-size Postgres connection pool.
///
/// It can be shared across tasks.
2013-09-17 06:38:27 +00:00
#[deriving(Clone)]
pub struct PostgresConnectionPool {
priv pool: MutexArc<InnerConnectionPool>
}
2013-09-17 05:48:34 +00:00
impl PostgresConnectionPool {
2013-09-30 02:47:30 +00:00
/// Attempts to create a new pool with the specified number of connections.
///
/// Returns an error if the specified number of connections cannot be
/// created.
pub fn try_new(url: &str, ssl: SslMode, pool_size: uint)
2013-09-17 05:48:34 +00:00
-> Result<PostgresConnectionPool, PostgresConnectError> {
let mut pool = InnerConnectionPool {
url: url.to_owned(),
ssl: ssl,
2013-09-17 05:48:34 +00:00
pool: ~[],
};
2013-12-09 05:56:43 +00:00
for _ in range(0, pool_size) {
2013-09-17 05:48:34 +00:00
match pool.new_connection() {
None => (),
Some(err) => return Err(err)
}
}
Ok(PostgresConnectionPool {
pool: MutexArc::new(pool)
})
2013-09-17 05:48:34 +00:00
}
2013-09-30 02:47:30 +00:00
/// A convenience function wrapping `try_new`.
///
/// Fails if the pool cannot be created.
pub fn new(url: &str, ssl: SslMode, pool_size: uint)
-> PostgresConnectionPool {
match PostgresConnectionPool::try_new(url, ssl, pool_size) {
Ok(pool) => pool,
2013-10-19 17:13:39 +00:00
Err(err) => fail!("Unable to initialize pool: {}", err.to_str())
}
}
2013-09-30 02:47:30 +00:00
/// Retrieves a connection from the pool.
///
/// If all connections are in use, blocks until one becomes available.
pub fn get_connection(&self) -> PooledPostgresConnection {
2013-09-17 05:48:34 +00:00
let conn = unsafe {
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-17 05:48:34 +00:00
};
2013-09-30 02:47:30 +00:00
PooledPostgresConnection {
2013-09-18 05:06:47 +00:00
pool: self.clone(),
conn: Some(conn)
}
}
}
2013-09-30 02:47:30 +00:00
/// A Postgres connection pulled from a connection pool.
///
/// It will be returned to the pool when it falls out of scope, even due to
/// task failure.
2013-09-18 05:06:47 +00:00
pub struct PooledPostgresConnection {
priv pool: PostgresConnectionPool,
// TODO remove the Option wrapper when drop takes self by value
2013-09-18 05:06:47 +00:00
priv conn: Option<PostgresConnection>
}
impl Drop for PooledPostgresConnection {
fn drop(&mut self) {
2013-09-17 05:48:34 +00:00
unsafe {
self.pool.pool.unsafe_access(|pool| {
2013-09-18 05:06:47 +00:00
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 {
2013-09-30 02:47:30 +00:00
/// Like `PostgresConnection::try_prepare`.
2013-09-18 05:06:47 +00:00
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-30 02:47:30 +00:00
/// Like `PostgresConnection::prepare`.
2013-09-18 05:06:47 +00:00
pub fn prepare<'a>(&'a self, query: &str) -> NormalPostgresStatement<'a> {
self.conn.get_ref().prepare(query)
}
2013-09-30 02:47:30 +00:00
/// Like `PostgresConnection::try_update`.
2013-09-18 05:06:47 +00:00
pub fn try_update(&self, query: &str, params: &[&ToSql])
-> Result<uint, PostgresDbError> {
self.conn.get_ref().try_update(query, params)
}
2013-09-30 02:47:30 +00:00
/// Like `PostgresConnection::update`.
2013-09-18 05:06:47 +00:00
pub fn update(&self, query: &str, params: &[&ToSql]) -> uint {
self.conn.get_ref().update(query, params)
}
2013-10-14 01:58:31 +00:00
/// Like `PostgresConnection::transaction`.
pub fn transaction<'a>(&'a self) -> PostgresTransaction<'a> {
self.conn.get_ref().transaction()
2013-09-17 05:48:34 +00:00
}
/// Like `PostgresConnection::notifications`.
pub fn notifications<'a>(&'a self) -> PostgresNotificationIterator<'a> {
self.conn.get_ref().notifications()
}
2013-10-21 00:54:50 +00:00
/// Like `PostgresConnection::cancel_data`.
pub fn cancel_data(&self) -> PostgresCancelData {
self.conn.get_ref().cancel_data()
}
2013-09-17 05:48:34 +00:00
}