diff --git a/src/lib.rs b/src/lib.rs index 2b3d4b8..a99a162 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,9 +167,47 @@ impl<'a> From<(Bound>, Bound>)> for CowStringRange<'a> } } +/// Perform a compaction of the DB. +/// +/// For use with downstream crates needing periodic +/// compactions. Returns the number of records compacted. +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 ps = db.transaction_paths(); + if db.num_txes() <= 1 || (ps.len() == 1 && ps[0].file_name().expect("filename") == "main") { + return Ok(0); + } + } + // 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)?; + + Ok(n) +} + // not part of public api #[doc(hidden)] -#[cfg(feature = "bin")] pub fn _purge_compacted_files( compacted: CreateTx, dir: &std::path::Path,