use tracing::info;
use super::format::{
GRAPH_LABEL_CKPT_FORMAT_VERSION, GraphLabelCheckpointFile, GraphLabelPartition,
};
use super::paths::{GRAPH_LABEL_CKPT_STATE, graph_label_ckpt_dir, graph_label_ckpt_state_path};
use crate::data::executor::core_loop::CoreLoop;
use crate::types::Lsn;
impl CoreLoop {
pub(in crate::data::executor) fn checkpoint_graph_labels(&self) -> crate::Result<Lsn> {
let durable_through = self.watermark;
let mut partitions: Vec<GraphLabelPartition> = self
.csr
.iter()
.filter_map(|(&(db, tid), partition)| {
let mut nodes: Vec<(String, Vec<String>)> = partition
.labeled_nodes()
.into_iter()
.map(|(node, labels)| {
(
node.to_string(),
labels.into_iter().map(str::to_string).collect(),
)
})
.collect();
if nodes.is_empty() {
return None;
}
nodes.sort_by(|a, b| a.0.cmp(&b.0));
Some(GraphLabelPartition {
database_id: db.as_u64(),
tenant_id: tid.as_u64(),
nodes,
})
})
.collect();
partitions.sort_by_key(|p| (p.database_id, p.tenant_id));
let labeled_nodes: usize = partitions.iter().map(|p| p.nodes.len()).sum();
let file = GraphLabelCheckpointFile {
format_version: GRAPH_LABEL_CKPT_FORMAT_VERSION,
durable_through_lsn: durable_through.as_u64(),
partitions,
};
let bytes = zerompk::to_msgpack_vec(&file).map_err(|e| crate::Error::Serialization {
format: "msgpack".to_string(),
detail: format!("graph node-label checkpoint encode failed: {e}"),
})?;
let ckpt_dir = graph_label_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 = graph_label_ckpt_state_path(&ckpt_dir);
let tmp = ckpt_dir.join(format!("{GRAPH_LABEL_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,
partitions = file.partitions.len(),
labeled_nodes,
durable_through_lsn = durable_through.as_u64(),
"graph node-label 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: "graph".to_string(),
detail: format!(
"graph node-label checkpoint: failed to {action} at {}: {e}",
path.display()
),
}
}