pub mod copy;
pub mod ddl;
pub mod dml;
pub mod fts_estimate;
pub mod plan_cache;
pub mod query;
pub mod standalone_call;
pub mod substitute;
pub mod transaction;
pub mod utils;
use crate::database::Database;
use crate::prepared_statement::PreparedStatement;
use plan_cache::{CachedPlan, PlanCache};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
const PLAN_CACHE_CAPACITY: usize = 100;
pub(crate) struct TxnResources {
pub local_storage: akar_storage::LocalStorage,
pub local_wal: akar_storage::LocalWAL,
pub shadow_file: akar_storage::ShadowFile,
}
pub struct Connection {
pub(crate) database: Arc<Database>,
pub(crate) statement_cache: Mutex<HashMap<String, PreparedStatement>>,
pub(crate) plan_cache: Mutex<PlanCache<CachedPlan>>,
pub(crate) txn_resources: Mutex<HashMap<u64, TxnResources>>,
pub(crate) explicit_txn_active: std::sync::atomic::AtomicBool,
processor_handlers: std::sync::OnceLock<Arc<crate::connection::query::ProcessorHandlers>>,
}
impl Connection {
pub fn new(database: &Arc<Database>) -> Self {
Self {
database: database.clone(),
statement_cache: Mutex::new(HashMap::new()),
plan_cache: Mutex::new(PlanCache::new(PLAN_CACHE_CAPACITY)),
txn_resources: Mutex::new(HashMap::new()),
explicit_txn_active: std::sync::atomic::AtomicBool::new(false),
processor_handlers: std::sync::OnceLock::new(),
}
}
pub fn clear_cache(&self) {
if let Ok(mut cache) = self.statement_cache.lock() {
cache.clear();
}
if let Ok(mut cache) = self.plan_cache.lock() {
cache.clear();
}
}
pub fn cache_size(&self) -> usize {
self.statement_cache.lock().map(|c| c.len()).unwrap_or(0)
}
pub fn plan_cache_size(&self) -> usize {
self.plan_cache.lock().map(|c| c.len()).unwrap_or(0)
}
}
impl Drop for Connection {
fn drop(&mut self) {
let txn_ids: Vec<u64> = self
.txn_resources
.lock()
.map(|map| map.keys().copied().collect())
.unwrap_or_default();
if txn_ids.is_empty() {
return;
}
let tm = &self.database.transaction_manager;
let txns: Vec<akar_transaction::Transaction> = tm
.active_snapshot()
.ok()
.map(|mut active| txn_ids.iter().filter_map(|id| active.remove(id)).collect())
.unwrap_or_default();
for mut txn in txns {
let id = txn.transaction_id;
match self.rollback_write_txn(&mut txn) {
Ok(_) => tracing::info!("Rolled back abandoned txn#{id} on connection drop"),
Err(e) => tracing::warn!("Failed to roll back abandoned txn#{id} on connection drop: {e}"),
}
}
}
}