use std::time::Duration;
use anyhow::Result;
use chrono::{DateTime, Utc};
use crate::catalog::providers::{DatabaseProvider, NamespaceProvider, TableProvider};
use crate::catalog::{DatabaseId, NamespaceId};
use crate::key::change;
use crate::key::debug::Sprintable;
use crate::kvs::tasklease::LeaseHandler;
use crate::kvs::{BoxTimeStamp, BoxTimeStampImpl, KVKey, Transaction};
#[instrument(level = "trace", target = "surrealdb::core::cfs", skip_all)]
pub async fn gc_all_at(lh: &LeaseHandler, tx: &Transaction) -> Result<()> {
let nss = tx.all_ns(None).await?;
let ts_impl = tx.timestamp_impl();
for ns in nss.as_ref() {
trace!("Performing garbage collection on {}", ns.name);
let dbs = tx.all_db(ns.namespace_id, None).await?;
for db in dbs.as_ref() {
trace!("Performing garbage collection on {}:{}", ns.name, db.name);
let tbs = tx.all_tb(db.namespace_id, db.database_id, None).await?;
let db_cf_expiry = db.changefeed.map(|v| v.expiry).unwrap_or_default();
let tb_cf_expiry = tbs
.as_ref()
.iter()
.filter_map(|tb| tb.changefeed.as_ref())
.map(|cf| cf.expiry)
.filter(|&dur| !dur.is_zero())
.max()
.unwrap_or(Duration::ZERO);
let cf_expiry = db_cf_expiry.max(tb_cf_expiry);
if cf_expiry.is_zero() {
continue;
}
let ts = tx.timestamp().await?;
let watermark_ts = ts.sub_checked(cf_expiry).unwrap_or_else(|| ts_impl.earliest());
gc_range(tx, db.namespace_id, db.database_id, &watermark_ts, &ts_impl).await?;
lh.try_maintain_lease().await?;
yield_now!();
}
lh.try_maintain_lease().await?;
yield_now!();
}
Ok(())
}
#[instrument(level = "trace", target = "surrealdb::core::cfs", skip_all, fields(ns = %ns, db = %db))]
pub async fn gc_range(
tx: &Transaction,
ns: NamespaceId,
db: DatabaseId,
ts: &BoxTimeStamp,
ts_impl: &BoxTimeStampImpl,
) -> Result<()> {
let mut buf = [0u8; _];
let beg_ts = ts_impl.earliest().encode(&mut buf);
let mut buf = [0u8; _];
let end_ts = ts.encode(&mut buf);
let beg = change::prefix_ts(ns, db, beg_ts).encode_key()?;
let end = change::prefix_ts(ns, db, end_ts).encode_key()?;
trace!(
"Performing garbage collection on {ns}:{db} for watermark time {}, between {} and {}",
ts.as_datetime().unwrap_or(DateTime::<Utc>::MIN_UTC),
beg.sprint(),
end.sprint()
);
tx.delr(beg..end).await?;
Ok(())
}