use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use crate::{Result, SalamanderError};
pub(crate) const MANIFEST_FORMAT_VERSION: u32 = 3;
pub(crate) const STORAGE_FORMAT_VERSION: u32 = 2;
pub(crate) const PAYLOAD_FORMAT_VERSION: u32 = 1;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Manifest {
pub format_version: u32,
#[serde(default = "legacy_storage_format_version")]
pub storage_format_version: u32,
#[serde(default)]
pub database_id: [u8; 16],
#[serde(default = "default_payload_format_version")]
pub payload_format_version: u32,
pub active_segment_base: u64,
pub next_offset: u64,
}
fn legacy_storage_format_version() -> u32 {
1
}
fn default_payload_format_version() -> u32 {
1
}
impl Manifest {
pub fn read(dir: &Path) -> Result<Self> {
let bytes = std::fs::read(manifest_path(dir))?;
serde_json::from_slice(&bytes).map_err(|e| SalamanderError::Manifest(e.to_string()))
}
pub fn write(&self, dir: &Path) -> Result<()> {
let final_path = manifest_path(dir);
let tmp_path = dir.join("manifest.json.tmp");
let bytes = serde_json::to_vec_pretty(self)
.map_err(|e| SalamanderError::Manifest(e.to_string()))?;
{
let mut tmp = File::create(&tmp_path)?;
tmp.write_all(&bytes)?;
tmp.sync_all()?;
}
std::fs::rename(&tmp_path, &final_path)?;
super::sync_dir(dir)?;
Ok(())
}
}
fn manifest_path(dir: &Path) -> PathBuf {
dir.join("manifest.json")
}