use std::collections::HashMap;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
use super::super::vertex_timestamp::IdentityLatch;
use super::super::{ColumnStore, IdIndexer, LabelId, Timestamp, VertexSchema, VertexTimestamp};
use crate::encoding::EncodingSelector;
use crate::schema::{LabelVersionHistory, SchemaObjectType};
use linkrs_core::{StorageError, StorageResult};
#[derive(Debug, Clone)]
pub struct VertexTableConfig {
pub initial_capacity: usize,
pub string_overflow_threshold: usize,
pub chunk_capacity: usize,
}
impl Default for VertexTableConfig {
fn default() -> Self {
Self {
initial_capacity: 4096,
string_overflow_threshold: crate::vertex::column::overflow::DEFAULT_OVERFLOW_THRESHOLD,
chunk_capacity: crate::vertex::column::chunk::DEFAULT_CHUNK_ROWS,
}
}
}
#[derive(Debug)]
pub struct VertexTable {
pub(super) label: LabelId,
pub(super) label_name: String,
pub(super) schema: VertexSchema,
pub(super) id_indexer: IdIndexer,
pub(super) columns: ColumnStore,
pub(super) timestamps: IdentityLatch,
pub(super) is_open: AtomicBool,
pub(super) property_index_cache: HashMap<Arc<str>, usize>,
pub(super) version_history: Arc<Mutex<LabelVersionHistory>>,
pub(super) encoding_selector: EncodingSelector,
pub(super) string_overflow_threshold: usize,
pub(super) chunk_capacity: usize,
pub(super) pending_schema_change: Option<super::staged_schema::PendingVertexSchemaChange>,
pub(super) history_floor: Timestamp,
}
mod maintenance;
mod mutations;
mod reads;
mod writes;
impl VertexTable {
pub(crate) const VERSION_CHAIN_PRESSURE_WARN_LEN: usize = 1024;
pub fn with_config(
label: LabelId,
label_name: String,
schema: VertexSchema,
config: VertexTableConfig,
) -> Self {
let columns = ColumnStore::with_capacity(schema.properties.len());
for prop in &schema.properties {
columns.add_column(prop.name.to_string(), prop.data_type.clone(), prop.nullable);
if let Some(col) = columns.get_column(&prop.name) {
col.set_chunk_capacity(config.chunk_capacity);
}
if matches!(
prop.data_type,
linkrs_core::DataType::String | linkrs_core::DataType::Blob
) {
if let Some(col) = columns.get_column(&prop.name) {
col.set_overflow_threshold(config.string_overflow_threshold);
}
}
}
let mut property_index_cache = HashMap::new();
for (idx, prop) in schema.properties.iter().enumerate() {
property_index_cache.insert(prop.name.clone(), idx);
}
let version_history = Arc::new(Mutex::new(LabelVersionHistory::new(
label,
label_name.clone(),
SchemaObjectType::Vertex,
)));
Self {
label,
label_name,
schema,
id_indexer: IdIndexer::with_capacity(config.initial_capacity),
columns,
timestamps: IdentityLatch::new(VertexTimestamp::with_capacity(config.initial_capacity)),
is_open: AtomicBool::new(true),
property_index_cache,
version_history,
encoding_selector: EncodingSelector::default(),
string_overflow_threshold: config.string_overflow_threshold,
chunk_capacity: config.chunk_capacity,
pending_schema_change: None,
history_floor: 0,
}
}
pub fn schema(&self) -> &VertexSchema {
&self.schema
}
pub fn set_schema(&mut self, schema: VertexSchema) -> StorageResult<()> {
if self.pending_schema_change.is_some() {
return Err(StorageError::invalid_operation(
"set_schema rejected while a staged vertex schema change is pending".to_string(),
));
}
self.schema = schema;
self.property_index_cache.clear();
for (idx, prop) in self.schema.properties.iter().enumerate() {
self.property_index_cache.insert(prop.name.clone(), idx);
}
Ok(())
}
pub fn version_history_ref(&self) -> Arc<Mutex<LabelVersionHistory>> {
Arc::clone(&self.version_history)
}
}
#[cfg(test)]
mod tests;