diff --git a/Cargo.toml b/Cargo.toml index ccabe9d..3babbc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ trace = [] [dependencies] time = "~0.1.0" bitflags = "0.7" +lru-cache = "0.0.7" libc = "~0.2" clippy = {version = "~0.0.58", optional = true} chrono = { version = "~0.2", optional = true } diff --git a/src/cache.rs b/src/cache.rs index a71be9c..e9dfd1a 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,8 +1,8 @@ //! Prepared statements cache for faster execution. use std::cell::RefCell; -use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; +use lru_cache::LruCache; use {Result, Connection, Statement}; use raw_statement::RawStatement; @@ -40,9 +40,7 @@ impl Connection { /// Prepared statements LRU cache. #[derive(Debug)] -pub struct StatementCache { - cache: RefCell>, // back = LRU -} +pub struct StatementCache(RefCell>); /// Cacheable statement. /// @@ -92,7 +90,7 @@ impl<'conn> CachedStatement<'conn> { impl StatementCache { /// Create a statement cache. pub fn with_capacity(capacity: usize) -> StatementCache { - StatementCache { cache: RefCell::new(VecDeque::with_capacity(capacity)) } + StatementCache(RefCell::new(LruCache::new(capacity))) } /// Search the cache for a prepared-statement object that implements `sql`. @@ -106,27 +104,20 @@ impl StatementCache { conn: &'conn Connection, sql: &str) -> Result> { - let mut cache = self.cache.borrow_mut(); - let stmt = match cache.iter() - .rposition(|entry| entry.sql().to_bytes().eq(sql.as_bytes())) { - Some(index) => { - let raw_stmt = cache.swap_remove_front(index).unwrap(); // FIXME Not LRU compliant - Ok(Statement::new(conn, raw_stmt)) - } - _ => conn.prepare(sql), + let mut cache = self.0.borrow_mut(); + let stmt = match cache.remove(sql) { + Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)), + None => conn.prepare(sql), }; stmt.map(|stmt| CachedStatement::new(stmt, self)) } // Return a statement to the cache. fn cache_stmt(&self, stmt: RawStatement) { - let mut cache = self.cache.borrow_mut(); - if cache.capacity() == cache.len() { - // is full - cache.pop_back(); // LRU dropped - } + let mut cache = self.0.borrow_mut(); stmt.clear_bindings(); - cache.push_front(stmt) + let sql = String::from_utf8_lossy(stmt.sql().to_bytes()).to_string(); + cache.insert(sql, stmt); } } @@ -137,15 +128,15 @@ mod test { impl StatementCache { fn clear(&self) { - self.cache.borrow_mut().clear(); + self.0.borrow_mut().clear(); } fn len(&self) -> usize { - self.cache.borrow().len() + self.0.borrow().len() } fn capacity(&self) -> usize { - self.cache.borrow().capacity() + self.0.borrow().capacity() } } diff --git a/src/lib.rs b/src/lib.rs index dbebe55..eea21cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,6 +55,7 @@ extern crate libc; extern crate libsqlite3_sys as ffi; +extern crate lru_cache; #[macro_use] extern crate bitflags; #[cfg(test)]