use tracing::info;
use super::format::{SYNC_HWM_CKPT_FORMAT_VERSION, SyncHwmCheckpointFile};
use super::paths::{SYNC_HWM_CKPT_STATE, sync_hwm_ckpt_dir, sync_hwm_ckpt_state_path};
use crate::data::executor::core_loop::CoreLoop;
use crate::types::Lsn;
impl CoreLoop {
pub(in crate::data::executor) fn checkpoint_sync_hwm(&self) -> crate::Result<Lsn> {
let durable_through = self.watermark;
let mut hwm: Vec<(u64, u64, u64)> = self
.sync_hwm
.iter()
.map(|(&(producer_id, stream_id), &seq)| (producer_id, stream_id, seq))
.collect();
hwm.sort_unstable();
let mut epoch_floor: Vec<(u64, u64)> = self
.producer_epoch_floor
.iter()
.map(|(&producer_id, &epoch)| (producer_id, epoch))
.collect();
epoch_floor.sort_unstable();
let file = SyncHwmCheckpointFile {
format_version: SYNC_HWM_CKPT_FORMAT_VERSION,
durable_through_lsn: durable_through.as_u64(),
hwm,
epoch_floor,
};
let bytes = zerompk::to_msgpack_vec(&file).map_err(|e| crate::Error::Serialization {
format: "msgpack".to_string(),
detail: format!("sync HWM checkpoint encode failed: {e}"),
})?;
let ckpt_dir = sync_hwm_ckpt_dir(&self.data_dir, self.core_id);
std::fs::create_dir_all(&ckpt_dir).map_err(|e| storage_err(&ckpt_dir, "create dir", &e))?;
let path = sync_hwm_ckpt_state_path(&ckpt_dir);
let tmp = ckpt_dir.join(format!("{SYNC_HWM_CKPT_STATE}.tmp"));
nodedb_wal::segment::write_checkpoint_framed(&tmp, &path, &bytes)
.map_err(|e| storage_err(&path, "publish state", &e))?;
info!(
core = self.core_id,
streams = file.hwm.len(),
producers = file.epoch_floor.len(),
durable_through_lsn = durable_through.as_u64(),
"sync HWM checkpoint published"
);
Ok(durable_through)
}
}
fn storage_err(path: &std::path::Path, action: &str, e: &dyn std::fmt::Display) -> crate::Error {
crate::Error::Storage {
engine: "sync_hwm".to_string(),
detail: format!(
"sync HWM checkpoint: failed to {action} at {}: {e}",
path.display()
),
}
}