use super::*;
pub(super) fn load_column_sidecars(
dir: &std::path::Path,
graph: &mut crate::graph::dir_graph::DirGraph,
) -> io::Result<()> {
use rayon::prelude::*;
let columns_dir = dir.join("columns");
if !columns_dir.exists() {
return Ok(());
}
struct Job {
type_name: String,
col_file: std::path::PathBuf,
schema: Arc<crate::graph::schema::TypeSchema>,
type_meta: std::collections::HashMap<String, String>,
}
let mut jobs: Vec<Job> = Vec::new();
for entry in std::fs::read_dir(&columns_dir)? {
let entry = entry?;
if !entry.file_type()?.is_dir() {
continue;
}
let type_name = entry.file_name().to_string_lossy().to_string();
if graph.column_store(&type_name).is_some() {
continue;
}
let col_file = entry.path().join("columns.zst");
if !col_file.exists() {
continue;
}
let schema = graph
.type_schemas
.get(&type_name)
.cloned()
.unwrap_or_else(|| std::sync::Arc::new(crate::graph::schema::TypeSchema::new()));
let type_meta = graph
.node_type_metadata
.get(&type_name)
.cloned()
.unwrap_or_default();
jobs.push(Job {
type_name,
col_file,
schema,
type_meta,
});
}
let interner = &graph.interner;
let results: Vec<io::Result<(String, crate::graph::storage::column_store::ColumnStore)>> = jobs
.into_par_iter()
.map(
|job| -> io::Result<(String, crate::graph::storage::column_store::ColumnStore)> {
let compressed = std::fs::read(&job.col_file)?;
let decoded = zstd_decompress(&compressed)?;
if decoded.len() < 12 || &decoded[..8] != b"KGLCOLv2" {
return Err(pre_014_bincode_error("KGLCOLv1/raw column sidecar"));
}
let packed_slice = &decoded[12..];
let row_count = u32::from_le_bytes(decoded[8..12].try_into().unwrap());
let codec = serde_codec::CodecVersion::PostcardV1;
let store =
crate::graph::storage::column_store::ColumnStore::load_packed_with_codec(
job.schema,
&job.type_meta,
interner,
packed_slice,
row_count,
None,
codec,
)?;
Ok((job.type_name, store))
},
)
.collect();
for r in results {
let (type_name, store) = r?;
graph.install_column_store(&type_name, Arc::new(store));
}
Ok(())
}
pub(super) fn attach_portable_column_stores(dir_graph: &mut DirGraph) {
let types: Vec<(String, bool)> = dir_graph
.column_stores_by_name()
.into_iter()
.map(|(name, store)| (name.to_string(), store.has_id_title_columns()))
.collect();
for (type_name, has_id_title) in types {
let type_name = type_name.as_str();
let Some(indices) = dir_graph.type_indices.get(type_name) else {
continue;
};
for (row_id, node_idx) in indices.iter().enumerate() {
let Some(node) = dir_graph.graph.node_weight_mut(node_idx) else {
continue;
};
node.properties = PropertyStorage::Columnar(ColumnarRow::new(row_id as u32));
if has_id_title {
node.id = Value::Null;
node.title = Value::Null;
}
}
}
dir_graph.rebuild_indices_from_keys();
}