Still some lifetime problem...

This commit is contained in:
Gwenael Treguier 2015-12-18 20:18:46 +01:00
parent 85fb89b280
commit 30c8910d19

View File

@ -9,12 +9,12 @@ use {Result, Connection, Statement};
#[derive(Debug)] #[derive(Debug)]
pub struct StatementCache<'conn> { pub struct StatementCache<'conn> {
conn: &'conn Connection, conn: &'conn Connection,
cache: VecDeque<Statement<'conn>>, // back = LRU cache: RefCell<VecDeque<Statement<'conn>>>, // back = LRU
} }
pub struct CachedStatement<'conn> { pub struct CachedStatement<'conn> {
stmt: Option<Statement<'conn>>, stmt: Option<Statement<'conn>>,
cache: RefCell<StatementCache<'conn>>, cache: &'conn StatementCache<'conn>,
pub cacheable: bool, pub cacheable: bool,
} }
@ -36,7 +36,7 @@ impl<'conn> Drop for CachedStatement<'conn> {
#[allow(unused_must_use)] #[allow(unused_must_use)]
fn drop(&mut self) { fn drop(&mut self) {
if self.cacheable { if self.cacheable {
self.cache.borrow_mut().release(self.stmt.take().unwrap()); self.cache.release(self.stmt.take().unwrap());
} else { } else {
self.stmt.take().unwrap().finalize(); self.stmt.take().unwrap().finalize();
} }
@ -44,9 +44,7 @@ impl<'conn> Drop for CachedStatement<'conn> {
} }
impl<'conn> CachedStatement<'conn> { impl<'conn> CachedStatement<'conn> {
fn new(stmt: Statement<'conn>, fn new(stmt: Statement<'conn>, cache: &'conn StatementCache<'conn>) -> CachedStatement<'conn> {
cache: RefCell<StatementCache<'conn>>)
-> CachedStatement<'conn> {
CachedStatement { CachedStatement {
stmt: Some(stmt), stmt: Some(stmt),
cache: cache, cache: cache,
@ -60,7 +58,7 @@ impl<'conn> StatementCache<'conn> {
pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> { pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
StatementCache { StatementCache {
conn: conn, conn: conn,
cache: VecDeque::with_capacity(capacity), cache: RefCell::new(VecDeque::with_capacity(capacity)),
} }
} }
@ -70,12 +68,12 @@ impl<'conn> StatementCache<'conn> {
/// # Failure /// # Failure
/// ///
/// Will return `Err` if no cached statement can be found and the underlying SQLite prepare call fails. /// Will return `Err` if no cached statement can be found and the underlying SQLite prepare call fails.
pub fn get(&mut self, sql: &str) -> Result<CachedStatement<'conn>> { pub fn get(&'conn self, sql: &str) -> Result<CachedStatement<'conn>> {
let stmt = match self.cache.iter().rposition(|entry| entry.eq(sql)) { let stmt = match self.cache.borrow().iter().rposition(|entry| entry.eq(sql)) {
Some(index) => Ok(self.cache.swap_remove_front(index).unwrap()), // FIXME Not LRU compliant Some(index) => Ok(self.cache.borrow_mut().swap_remove_front(index).unwrap()), // FIXME Not LRU compliant
_ => self.conn.prepare(sql), _ => self.conn.prepare(sql),
}; };
stmt.map(|stmt| CachedStatement::new(stmt, RefCell::new(self))) stmt.map(|stmt| CachedStatement::new(stmt, self))
} }
/// If `discard` is true, then the statement is deleted immediately. /// If `discard` is true, then the statement is deleted immediately.
@ -86,29 +84,29 @@ impl<'conn> StatementCache<'conn> {
/// ///
/// Will return `Err` if `stmt` (or the already cached statement implementing the same SQL) statement is `discard`ed /// Will return `Err` if `stmt` (or the already cached statement implementing the same SQL) statement is `discard`ed
/// and the underlying SQLite finalize call fails. /// and the underlying SQLite finalize call fails.
fn release(&mut self, mut stmt: Statement<'conn>) { fn release(&self, mut stmt: Statement<'conn>) {
if self.cache.capacity() == self.cache.len() { if self.cache.borrow().capacity() == self.cache.borrow().len() {
// is full // is full
self.cache.pop_back(); // LRU dropped self.cache.borrow_mut().pop_back(); // LRU dropped
} }
stmt.reset_if_needed(); stmt.reset_if_needed();
stmt.clear_bindings(); stmt.clear_bindings();
self.cache.push_front(stmt) self.cache.borrow_mut().push_front(stmt)
} }
/// Flush the prepared statement cache /// Flush the prepared statement cache
pub fn clear(&mut self) { pub fn clear(&self) {
self.cache.clear(); self.cache.borrow_mut().clear();
} }
/// Return current cache size. /// Return current cache size.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.cache.len() self.cache.borrow().len()
} }
/// Return maximum cache size. /// Return maximum cache size.
pub fn capacity(&self) -> usize { pub fn capacity(&self) -> usize {
self.cache.capacity() self.cache.borrow().capacity()
} }
} }
@ -125,22 +123,20 @@ mod test {
assert_eq!(15, cache.capacity()); assert_eq!(15, cache.capacity());
let sql = "PRAGMA schema_version"; let sql = "PRAGMA schema_version";
let mut stmt = cache.get(sql).unwrap(); {
assert_eq!(0, cache.len()); let mut stmt = cache.get(sql).unwrap();
assert_eq!(0, assert_eq!(0, cache.len());
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0)); assert_eq!(0,
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
// println!("NEW {:?}", stmt); }
cache.release(stmt);
assert_eq!(1, cache.len()); assert_eq!(1, cache.len());
stmt = cache.get(sql).unwrap(); {
assert_eq!(0, cache.len()); let mut stmt = cache.get(sql).unwrap();
assert_eq!(0, assert_eq!(0, cache.len());
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0)); assert_eq!(0,
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
// println!("CACHED {:?}", stmt); }
cache.release(stmt);
assert_eq!(1, cache.len()); assert_eq!(1, cache.len());
cache.clear(); cache.clear();