use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; use std::path::Path; use std::sync::Arc; use anyhow::{Context, Result}; use parking_lot::{Mutex, MutexGuard}; use serde::{Deserialize, Serialize}; use serde_json::Deserializer; use crate::compact::CompactionTask; pub struct Manifest { file: Arc>, } #[derive(Serialize, Deserialize)] pub enum ManifestRecord { Flush(usize), NewMemtable(usize), Compaction(CompactionTask, Vec), } impl Manifest { pub fn create(path: impl AsRef) -> Result { Ok(Self { file: Arc::new(Mutex::new( OpenOptions::new() .read(true) .create_new(true) .write(true) .open(path) .context("failed to create manifest")?, )), }) } pub fn recover(path: impl AsRef) -> Result<(Self, Vec)> { let mut file = OpenOptions::new() .read(true) .append(true) .open(path) .context("failed to recover manifest")?; let mut buf = Vec::new(); file.read_to_end(&mut buf)?; let stream = Deserializer::from_slice(&buf).into_iter::(); let mut records = Vec::new(); for x in stream { records.push(x?); } Ok(( Self { file: Arc::new(Mutex::new(file)), }, records, )) } pub fn add_record( &self, _state_lock_observer: &MutexGuard<()>, record: ManifestRecord, ) -> Result<()> { self.add_record_when_init(record) } pub fn add_record_when_init(&self, record: ManifestRecord) -> Result<()> { let mut file = self.file.lock(); let buf = serde_json::to_vec(&record)?; file.write_all(&buf)?; file.sync_all()?; Ok(()) } }