rusqlite/src/cache.rs

122 lines
3.6 KiB
Rust
Raw Normal View History

2015-08-08 22:33:08 +08:00
//! Prepared statements cache for faster execution.
2015-08-02 18:07:49 +08:00
use std::cell::RefCell;
2015-12-18 03:02:49 +08:00
use std::collections::VecDeque;
use {Result, Connection, Statement};
2015-08-02 18:07:49 +08:00
2015-08-08 22:33:08 +08:00
/// Prepared statements cache.
2015-08-02 18:07:49 +08:00
#[derive(Debug)]
pub struct StatementCache<'conn> {
conn: &'conn Connection,
2015-12-18 03:02:49 +08:00
cache: VecDeque<Statement<'conn>>, // back = LRU
2015-08-02 18:07:49 +08:00
}
pub struct CachedStatement<'conn> {
2015-12-18 03:02:49 +08:00
stmt: Option<Statement<'conn>>,
cache: RefCell<StatementCache<'conn>>,
2015-12-18 03:02:49 +08:00
pub cacheable: bool,
}
impl<'conn> Drop for CachedStatement<'conn> {
#[allow(unused_must_use)]
fn drop(&mut self) {
if self.cacheable {
2015-12-18 03:02:49 +08:00
self.cache.borrow_mut().release(self.stmt.take().unwrap());
} else {
2015-12-18 03:02:49 +08:00
self.stmt.take().unwrap().finalize();
}
}
}
2015-08-02 18:07:49 +08:00
impl<'conn> StatementCache<'conn> {
2015-08-08 22:33:08 +08:00
/// Create a statement cache.
pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
StatementCache {
conn: conn,
2015-12-18 03:02:49 +08:00
cache: VecDeque::with_capacity(capacity),
}
2015-08-02 18:07:49 +08:00
}
/// 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.
2015-12-07 02:57:20 +08:00
///
/// # Failure
///
/// 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<Statement<'conn>> {
2015-12-18 03:02:49 +08:00
match self.cache.iter().rposition(|entry| entry.eq(sql)) {
Some(index) => Ok(self.cache.swap_remove_front(index).unwrap()), // FIXME Not LRU compliant
_ => self.conn.prepare(sql),
2015-08-02 18:07:49 +08:00
}
}
/// 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()`.
2015-12-07 02:57:20 +08:00
///
/// # Failure
///
/// 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.
2015-12-18 03:02:49 +08:00
fn release(&mut self, mut stmt: Statement<'conn>) {
if self.cache.capacity() == self.cache.len() { // is full
self.cache.pop_back(); // LRU dropped
2015-08-02 18:07:49 +08:00
}
2015-12-07 02:57:20 +08:00
stmt.reset_if_needed();
stmt.clear_bindings();
2015-12-18 03:02:49 +08:00
self.cache.push_front(stmt)
2015-08-02 18:07:49 +08:00
}
/// Flush the prepared statement cache
pub fn clear(&mut self) {
2015-08-02 18:07:49 +08:00
self.cache.clear();
}
/// Return current cache size.
pub fn len(&self) -> usize {
self.cache.len()
}
/// Return maximum cache size.
pub fn capacity(&self) -> usize {
self.cache.capacity()
2015-08-02 18:07:49 +08:00
}
}
#[cfg(test)]
mod test {
use Connection;
2015-08-02 18:07:49 +08:00
use super::StatementCache;
#[test]
2015-08-02 18:07:49 +08:00
fn test_cache() {
let db = Connection::open_in_memory().unwrap();
2015-12-18 03:02:49 +08:00
let mut cache = StatementCache::new(&db, 15);
assert_eq!(0, cache.len());
2015-12-18 03:02:49 +08:00
assert_eq!(15, cache.capacity());
2015-08-02 18:07:49 +08:00
let sql = "PRAGMA schema_version";
let mut stmt = cache.get(sql).unwrap();
assert_eq!(0, cache.len());
2015-12-18 03:02:49 +08:00
assert_eq!(0,
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
// println!("NEW {:?}", stmt);
2015-12-18 03:02:49 +08:00
cache.release(stmt);
assert_eq!(1, cache.len());
2015-08-02 18:07:49 +08:00
stmt = cache.get(sql).unwrap();
assert_eq!(0, cache.len());
2015-12-18 03:02:49 +08:00
assert_eq!(0,
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
// println!("CACHED {:?}", stmt);
2015-12-18 03:02:49 +08:00
cache.release(stmt);
assert_eq!(1, cache.len());
cache.clear();
assert_eq!(0, cache.len());
2015-12-18 03:02:49 +08:00
assert_eq!(15, cache.capacity());
2015-08-02 18:07:49 +08:00
}
}