use std::collections::HashMap;
use std::sync::Arc;
use anyhow::Result;
use parking_lot::Mutex;
use crate::catalog::providers::{DatabaseProvider, NamespaceProvider};
use crate::key::lqe;
use crate::kvs::LockType::Optimistic;
use crate::kvs::TransactionType::Read;
use crate::kvs::{Datastore, KVKey, KVValue};
use crate::lq::event::{LiveEvent, LiveEvents};
use crate::lq::subscriber::replay_table_live_events;
use crate::val::TableName;
#[derive(Debug, Default)]
pub(crate) struct LiveQueryRouter {
cursor: Mutex<Option<u128>>,
}
impl LiveQueryRouter {
pub(crate) fn new() -> Self {
Self::default()
}
fn begin_pass(&self, safe_vs: u128) -> Option<u128> {
let mut guard = self.cursor.lock();
match *guard {
None => {
*guard = Some(safe_vs);
None
}
Some(c) => Some(c),
}
}
fn advance(&self, safe_vs: u128) {
*self.cursor.lock() = Some(safe_vs);
}
pub(crate) fn set_baseline(&self, safe_vs: u128) {
*self.cursor.lock() = Some(safe_vs);
}
}
pub(crate) async fn process(ds: &Datastore, router: &LiveQueryRouter) -> Result<()> {
let Some(broker) = ds.live_query_broker() else {
return Ok(());
};
let txn = Arc::new(ds.transaction(Read, Optimistic).await?);
let ts_impl = txn.timestamp_impl();
let safe_vs = txn.safe_timestamp().await?.as_versionstamp();
let Some(cursor) = router.begin_pass(safe_vs) else {
txn.cancel().await?;
return Ok(());
};
if safe_vs <= cursor {
txn.cancel().await?;
return Ok(());
}
let cursor_ts = ts_impl.create_from_versionstamp(cursor).unwrap_or_else(|| ts_impl.earliest());
let mut cursor_buf = [0u8; _];
let cursor_bytes = cursor_ts.encode(&mut cursor_buf);
let nss = txn.all_ns(None).await?;
for ns in nss.iter() {
let dbs = txn.all_db(ns.namespace_id, None).await?;
for db in dbs.iter() {
let beg = lqe::prefix_ts(db.namespace_id, db.database_id, cursor_bytes).encode_key()?;
let end = lqe::suffix(db.namespace_id, db.database_id).encode_key()?;
let mut per_table: HashMap<TableName, Vec<LiveEvent>> = HashMap::new();
for (k, v) in txn.scan(beg..end, u32::MAX, 0, None).await? {
let key = lqe::Lqe::decode_key(&k)?;
let vs = ts_impl.decode(key.ts.as_ref())?.as_versionstamp();
if vs <= cursor || vs > safe_vs {
continue;
}
let events = LiveEvents::kv_decode_value(&v, ())?;
per_table.entry(key.tb.into_owned()).or_default().extend(events.0);
}
for (tb, events) in per_table {
replay_table_live_events(
ds,
Arc::clone(&txn),
&ns.name,
&db.name,
&tb,
&events,
Arc::clone(&broker),
)
.await?;
}
}
}
txn.cancel().await?;
router.advance(safe_vs);
Ok(())
}