diff --git a/src/lib.rs b/src/lib.rs index 2b3d4b8..ed82e85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,9 +167,52 @@ impl<'a> From<(Bound>, Bound>)> for CowStringRange<'a> } } +/// Perform a compaction of the DB. +/// +/// Written for use with downstream crates needing periodic +/// compactions. +pub fn compact(dir: &std::path::Path, major: bool) -> std::io::Result<()> { + use fs2::FileExt; + let lock = std::fs::File::create(dir.join(".compact"))?; + lock.try_lock_exclusive()?; + + let db = if major { + DatabaseReader::new(dir)? + } else { + DatabaseReader::without_main_db(dir)? + }; + + let mut no_transaction_paths = false; + { + let ps = db.transaction_paths(); + if ps.len() == 1 && ps[0].file_name().expect("filename") == "main" { + no_transaction_paths = true; + } + } + + if db.num_txes() <= 1 || no_transaction_paths { + println!("Compaction has nothing to do."); + } else { + println!("Processing {} .txes", db.num_txes()); + let db = std::sync::Arc::new(db); + let mut compacted = CreateTx::new(dir)?; + + // create the new transaction after opening the database reader + let reader = db.get_range(..); + let mut n = 0u64; + for record in reader { + compacted.add_record_raw(record.key(), record.format(), record.raw()).expect("Error adding record"); + n += 1; + } + _purge_compacted_files(compacted, dir, &db, major)?; + println!("Compacted {} records.", {n}); + } + + Ok(()) +} + // not part of public api #[doc(hidden)] -#[cfg(feature = "bin")] pub fn _purge_compacted_files( compacted: CreateTx, dir: &std::path::Path,