use std::collections::HashMap;
use linkrs_core::types::Timestamp;
use crate::types::{ResourceId, TransactionId, WriteSet};
pub(super) struct SsiTracker {
read_locks: parking_lot::RwLock<HashMap<ResourceId, Vec<(TransactionId, Timestamp)>>>,
}
impl SsiTracker {
pub(super) fn new() -> Self {
Self {
read_locks: parking_lot::RwLock::new(HashMap::new()),
}
}
fn register_read(&self, txn_id: TransactionId, resource: ResourceId, start_ts: Timestamp) {
self.read_locks
.write()
.entry(resource)
.or_default()
.push((txn_id, start_ts));
}
pub(super) fn register_txn_reads(
&self,
txn_id: TransactionId,
start_ts: Timestamp,
read_set: &WriteSet,
) {
for vid in read_set.vertices.iter() {
self.register_read(txn_id, ResourceId::Vertex(*vid), start_ts);
}
for edge in read_set.edges.iter() {
self.register_read(txn_id, ResourceId::Edge(*edge), start_ts);
}
for resource in read_set.schema_resources.iter() {
self.register_read(txn_id, ResourceId::Schema(resource.clone()), start_ts);
}
for resource in read_set.index_resources.iter() {
self.register_read(txn_id, ResourceId::Index(resource.clone()), start_ts);
}
}
pub(super) fn readers(&self, resource: &ResourceId) -> Vec<(TransactionId, Timestamp)> {
self.read_locks
.read()
.get(resource)
.cloned()
.unwrap_or_default()
}
pub(super) fn unregister_reads(&self, txn_id: TransactionId) {
let mut locks = self.read_locks.write();
locks.retain(|_, entries| {
entries.retain(|(id, _)| *id != txn_id);
!entries.is_empty()
});
}
pub(super) fn prune(&self, oldest_active_ts: Timestamp) {
let mut locks = self.read_locks.write();
locks.retain(|_, entries| {
entries.retain(|(_, ts)| *ts > oldest_active_ts);
!entries.is_empty()
});
}
}