mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-26 11:21:46 +08:00
LRU statement cache
This commit is contained in:
parent
e8967388e6
commit
25de884720
@ -14,6 +14,7 @@ name = "rusqlite"
|
||||
|
||||
[features]
|
||||
load_extension = ["libsqlite3-sys/load_extension"]
|
||||
cache = ["lru-cache"]
|
||||
|
||||
[dependencies]
|
||||
time = "~0.1.0"
|
||||
@ -26,3 +27,7 @@ tempdir = "~0.3.4"
|
||||
[dependencies.libsqlite3-sys]
|
||||
path = "libsqlite3-sys"
|
||||
version = "0.2.0"
|
||||
|
||||
[dependencies.lru-cache]
|
||||
version = "~0.0.4"
|
||||
optional = true
|
75
src/cache.rs
Normal file
75
src/cache.rs
Normal file
@ -0,0 +1,75 @@
|
||||
extern crate lru_cache;
|
||||
|
||||
use {SqliteResult, SqliteConnection, SqliteStatement};
|
||||
use self::lru_cache::LruCache;
|
||||
|
||||
/// Prepared statements are cached for faster execution.
|
||||
/// FIXME limitation: the same SQL can be cached only once...
|
||||
#[derive(Debug)]
|
||||
pub struct StatementCache<'conn> {
|
||||
pub conn: &'conn SqliteConnection,
|
||||
cache: LruCache<String, SqliteStatement<'conn>>,
|
||||
}
|
||||
|
||||
impl<'conn> StatementCache<'conn> {
|
||||
pub fn new(conn: &'conn SqliteConnection, capacity: usize) -> StatementCache<'conn> {
|
||||
StatementCache{ conn: conn, cache: LruCache::new(capacity) }
|
||||
}
|
||||
|
||||
/// Search the cache for a prepared-statement object that implements `sql`.
|
||||
// If no such prepared-statement can be found, allocate and prepare a new one.
|
||||
pub fn get(&mut self, sql: &str) -> SqliteResult<SqliteStatement<'conn>> {
|
||||
let stmt = self.cache.remove(sql);
|
||||
match stmt {
|
||||
Some(stmt) => Ok(stmt),
|
||||
_ => self.conn.prepare(sql)
|
||||
}
|
||||
}
|
||||
|
||||
/// If `discard` is true, then the statement is deleted immediately.
|
||||
/// Otherwise it is added to the LRU list and may be returned
|
||||
/// by a subsequent call to `get()`.
|
||||
pub fn release(&mut self, stmt: SqliteStatement<'conn>, discard: bool) -> SqliteResult<()> {
|
||||
if discard {
|
||||
return stmt.finalize();
|
||||
}
|
||||
// FIXME stmt.reset_if_needed();
|
||||
// clear bindings ???
|
||||
self.cache.insert(stmt.sql(), stmt).map_or(Ok(()), |stmt| stmt.finalize())
|
||||
}
|
||||
|
||||
/// Flush the prepared statement cache
|
||||
pub fn flush(&mut self) {
|
||||
self.cache.clear();
|
||||
}
|
||||
|
||||
/// Return (current, max) sizes.
|
||||
pub fn size(&self) -> (usize, usize) {
|
||||
(self.cache.len(), self.cache.capacity())
|
||||
}
|
||||
|
||||
/// Set the maximum number of cached statements.
|
||||
pub fn set_size(&mut self, capacity: usize) {
|
||||
self.cache.set_capacity(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use SqliteConnection;
|
||||
use super::StatementCache;
|
||||
|
||||
#[test]
|
||||
fn test_cache() {
|
||||
let db = SqliteConnection::open_in_memory().unwrap();
|
||||
let mut cache = StatementCache::new(&db, 10);
|
||||
let sql = "PRAGMA schema_version";
|
||||
let mut stmt = cache.get(sql).unwrap();
|
||||
//println!("NEW {:?}", stmt);
|
||||
cache.release(stmt, false).unwrap();
|
||||
stmt = cache.get(sql).unwrap();
|
||||
//println!("CACHED {:?}", stmt);
|
||||
cache.release(stmt, true).unwrap();
|
||||
cache.flush();
|
||||
}
|
||||
}
|
@ -79,6 +79,7 @@ pub use transaction::{SqliteTransactionBehavior,
|
||||
pub mod types;
|
||||
mod transaction;
|
||||
#[cfg(feature = "load_extension")] mod load_extension_guard;
|
||||
#[cfg(feature = "cache")] pub mod cache;
|
||||
|
||||
/// A typedef of the result returned by many methods.
|
||||
pub type SqliteResult<T> = Result<T, SqliteError>;
|
||||
@ -710,6 +711,14 @@ impl<'conn> SqliteStatement<'conn> {
|
||||
}
|
||||
}
|
||||
|
||||
fn sql(&self) -> String { // TODO Maybe SQL should by kept as an SqliteStatement field ?
|
||||
unsafe {
|
||||
let c_slice = CStr::from_ptr(ffi::sqlite3_sql(self.stmt)).to_bytes();
|
||||
let utf8_str = str::from_utf8(c_slice);
|
||||
utf8_str.unwrap().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn finalize_(&mut self) -> SqliteResult<()> {
|
||||
let r = unsafe { ffi::sqlite3_finalize(self.stmt) };
|
||||
self.stmt = ptr::null_mut();
|
||||
|
Loading…
Reference in New Issue
Block a user