use std::sync::atomic::{AtomicU64, Ordering};
use nodedb_mem::ScopedMemory;
use super::journal::CsrJournal;
use crate::GraphError;
use crate::csr::index::CsrIndex;
static NEXT_REBUILD_TOKEN: AtomicU64 = AtomicU64::new(1);
#[derive(Debug, Clone)]
pub(crate) struct NodeLabelState {
pub(crate) names: Vec<String>,
pub(crate) bits: Vec<u64>,
}
#[derive(Debug)]
pub struct CsrRebuildSeed {
token: u64,
checkpoint: Vec<u8>,
node_labels: NodeLabelState,
}
#[derive(Debug)]
pub struct CsrRebuilt {
pub(crate) token: u64,
pub(crate) checkpoint: Vec<u8>,
pub(crate) node_labels: NodeLabelState,
}
impl CsrRebuildSeed {
pub fn token(&self) -> u64 {
self.token
}
pub fn build(self, memory: ScopedMemory) -> Result<CsrRebuilt, GraphError> {
let mut copy = restore_checkpoint(&self.checkpoint, memory)?;
copy.compact()?;
let checkpoint = copy.checkpoint_to_bytes()?;
Ok(CsrRebuilt {
token: self.token,
checkpoint,
node_labels: self.node_labels,
})
}
}
impl CsrRebuilt {
pub fn token(&self) -> u64 {
self.token
}
}
impl CsrIndex {
pub fn begin_rebuild(
&mut self,
max_journal_bytes: usize,
) -> Result<CsrRebuildSeed, GraphError> {
if self.rebuild_journal.is_some() {
return Err(GraphError::RebuildInProgress);
}
let checkpoint = self.checkpoint_to_bytes()?;
let token = NEXT_REBUILD_TOKEN.fetch_add(1, Ordering::Relaxed);
self.rebuild_journal = Some(CsrJournal::new(token, max_journal_bytes));
Ok(CsrRebuildSeed {
token,
checkpoint,
node_labels: NodeLabelState {
names: self.node_label_names.clone(),
bits: self.node_label_bits.clone(),
},
})
}
pub fn rebuild_in_progress(&self) -> bool {
self.rebuild_journal.is_some()
}
pub fn abort_rebuild(&mut self, token: u64) {
if self
.rebuild_journal
.as_ref()
.is_some_and(|journal| journal.token == token)
{
self.rebuild_journal = None;
}
}
}
pub(crate) fn restore_checkpoint(
bytes: &[u8],
memory: ScopedMemory,
) -> Result<CsrIndex, GraphError> {
CsrIndex::from_checkpoint(bytes, memory)
.map_err(|e| GraphError::RebuildSnapshotInvalid {
detail: e.to_string(),
})?
.ok_or_else(|| GraphError::RebuildSnapshotInvalid {
detail: "checkpoint bytes carry no CSR header".to_string(),
})
}