use crate::fs::Fs;
use crate::path::PathBuf;
use crate::tree::inner::TreeId;
use crate::{DescriptorTable, GlobalTableId};
use alloc::sync::Arc;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(feature = "std")]
use parking_lot::Mutex;
#[cfg(not(feature = "std"))]
use spin::Mutex;
#[derive(Clone, Copy)]
enum Kind {
Table,
BlobFile,
}
struct Output {
kind: Kind,
id: u64,
path: PathBuf,
fs: Arc<dyn Fs>,
}
#[derive(Clone, Default)]
pub struct OutputLedger(Arc<Mutex<Vec<Output>>>);
impl OutputLedger {
pub fn record_table(&self, id: crate::TableId, path: PathBuf, fs: Arc<dyn Fs>) {
self.record(Kind::Table, id, path, fs);
}
pub fn record_blob_file(&self, id: crate::vlog::BlobFileId, path: PathBuf, fs: Arc<dyn Fs>) {
self.record(Kind::BlobFile, id, path, fs);
}
fn record(&self, kind: Kind, id: u64, path: PathBuf, fs: Arc<dyn Fs>) {
self.0.lock().push(Output { kind, id, path, fs });
}
pub fn installed(&self) {
self.0.lock().clear();
}
pub fn remove_uninstalled(&self, tree_id: TreeId, descriptor_table: Option<&DescriptorTable>) {
let outputs = core::mem::take(&mut *self.0.lock());
for output in outputs {
let global_id = GlobalTableId::from((tree_id, output.id));
if let Some(descriptors) = descriptor_table {
match output.kind {
Kind::Table => descriptors.remove_for_table(&global_id),
Kind::BlobFile => descriptors.remove_for_blob_file(&global_id),
}
}
match output.fs.remove_file(&output.path) {
Ok(()) => log::debug!(
"Removed uninstalled compaction output {}",
output.path.display(),
),
Err(e) if e.kind() == crate::io::ErrorKind::NotFound => {}
Err(e) => log::warn!(
"Could not remove uninstalled compaction output {} ({e}); it stays until \
the next open's orphan sweep",
output.path.display(),
),
}
}
}
}
#[cfg(test)]
mod tests;