1use std::path::Path;
4use std::sync::Arc;
5use std::sync::atomic::{AtomicBool, Ordering};
6
7use lace_sans_io::core::{MachineError, RetentionSweep};
8use lace_sans_io::runtime_support::compaction::DEFAULT_COMPACTION_BATCH_BYTES;
9pub use lace_sans_io::runtime_support::compaction::{ArenaRelease, CompactionReport};
10use lace_sans_io::runtime_support::native_filesystem_store::compact_filesystem_root;
11
12use crate::{Error, IntoPolicy, Result};
13
14pub async fn compact_filesystem<P: IntoPolicy>(
22 root: impl AsRef<Path>,
23 policies: impl IntoIterator<Item = P>,
24) -> Result<CompactionReport> {
25 compact_on_blocking_thread(root.as_ref(), policies, compact_filesystem_root).await
26}
27
28#[cfg(feature = "lmdb")]
37pub async fn compact_lmdb<P: IntoPolicy>(
38 root: impl AsRef<Path>,
39 policies: impl IntoIterator<Item = P>,
40) -> Result<CompactionReport> {
41 compact_on_blocking_thread(root.as_ref(), policies, |root, sweep, batch, stop| {
42 lmdb_lace::NativeLmdbStore::compact(root, sweep, batch, stop)
43 })
44 .await
45}
46
47type CompactRoot = fn(
49 &Path,
50 RetentionSweep,
51 u64,
52 &dyn Fn() -> bool,
53) -> std::result::Result<CompactionReport, MachineError>;
54
55async fn compact_on_blocking_thread<P: IntoPolicy>(
58 root: &Path,
59 policies: impl IntoIterator<Item = P>,
60 compact: CompactRoot,
61) -> Result<CompactionReport> {
62 let policies = policies
63 .into_iter()
64 .map(IntoPolicy::into_policy)
65 .collect::<Result<Vec<_>>>()?;
66 let sweep = RetentionSweep::new(&policies)?;
67 let root = root.to_path_buf();
68 let stop = StopOnDrop(Arc::new(AtomicBool::new(false)));
69 let requested = Arc::clone(&stop.0);
70 let work = tokio::task::spawn_blocking(move || {
71 compact(&root, sweep, DEFAULT_COMPACTION_BATCH_BYTES, &|| {
72 requested.load(Ordering::Relaxed)
73 })
74 });
75 match work.await {
76 Ok(result) => result.map_err(|error| Error::from_machine(error, None)),
77 Err(error) => match error.try_into_panic() {
78 Ok(panic) => std::panic::resume_unwind(panic),
79 Err(error) => Err(Error::integration(format!(
80 "compaction task failed: {error}"
81 ))),
82 },
83 }
84}
85
86struct StopOnDrop(Arc<AtomicBool>);
88
89impl Drop for StopOnDrop {
90 fn drop(&mut self) {
91 self.0.store(true, Ordering::Relaxed);
92 }
93}
94
95#[cfg(test)]
96#[path = "compaction_tests.rs"]
97mod tests;