pub(crate) mod bundled_csr;
pub(crate) mod csr_shared;
pub mod csr_trait;
pub mod csr_variant;
pub mod csr_with_properties;
pub mod edge_table;
pub mod fragmentation_stats;
pub mod immutable_csr;
pub mod mutable_csr;
pub mod node_group;
pub mod property_schema;
pub(crate) mod pure_csr;
pub mod record_form_policy;
pub mod schema;
pub mod single_mutable_csr;
pub mod slot;
pub use csr_trait::{CsrBase, MutableCsrTrait};
pub use csr_variant::{CsrRowIter, CsrVariant};
pub use csr_with_properties::CsrWithProperties;
pub use edge_table::core::UpdateEdgePropertyByKeyParams;
pub use edge_table::{EdgeIndexStatus, EdgeStore, EdgeWalRecoveryMode, IncidentDeletedEdge};
pub use fragmentation_stats::{
FragmentationStats, VertexFragmentation, GROUP_FRAGMENTATION_THRESHOLD,
};
pub use linkrs_core::types::EdgeStrategy;
use linkrs_core::types::{EdgeId, Timestamp, VertexId};
use linkrs_core::Value;
pub use mutable_csr::{EdgePosition, MutableCsr, MutableCsrIterator};
pub use node_group::{
region_id_for_local, region_local_range, regions_per_group, CsrShardSet, EdgeCheckpointKind,
FreezeBlockReason, FreezeFeasibility, GroupDirty, NodeGroupStats, RegionDirty,
RegionMergeScope, ShardCsrIterator, TableShardManifest, DEFAULT_NODE_GROUP_BITS,
GROUP_MERGE_MIN_DENSITY, LEAF_REGION_ROWS, REGION_MERGE_MIN_DENSITY,
};
pub use single_mutable_csr::{SingleMutableCsr, SingleMutableCsrIterator};
pub use bundled_csr::{decode_scalar, encode_scalar, BundledCsr};
pub use edge_table::checkpoint::snapshot::{
MappedFrozen, MappedFrozenIterator, MappedFrozenRowIter,
};
pub use immutable_csr::{FrozenRowIter, ImmutableCsr, ImmutableCsrIterator};
pub use linkrs_core::types::INVALID_EDGE_ID;
pub use pure_csr::{PureAllIter, PureRowIter, PureTopologyCsr};
pub use record_form_policy::{
bundled_ineligibility_reason, inline_form_accepts_rank, is_bundled_eligible,
is_scalar_encodable, validate_record_form_target, validate_strategy_form, RecordForm,
RecordFormPreference, BUNDLED_RANK_REQUIRES_COLUMNAR_MSG,
};
pub(crate) use record_form_policy::{
INLINE_FORM_SCHEMA_CHANGE_MSG, NO_EDGES_STORED_MSG, ROW_POSITION_CROSS_VARIANT_MSG,
SCHEMA_CHANGE_PENDING_MSG, SINGLE_REQUIRES_COLUMNAR_MSG,
};
pub use schema::{EdgeMultiplicity, EdgeRecord, EdgeSchema, IndexConsistency, StorageDirection};
pub use slot::{ColdStamps, HotNbr, Nbr};
pub type BatchInsertEntry<'a> = (u32, u32, i64, &'a [(std::sync::Arc<str>, Value)], Timestamp);
pub type EdgePut = (u32, i64, EdgeId, Timestamp);
pub type RowEdgeBatch = (u32, Vec<EdgePut>);
#[cfg(test)]
mod tests {
use super::*;
use crate::types::StoragePropertyDef;
#[test]
fn hot_half_stays_within_single_cache_line_budget() {
assert_eq!(std::mem::size_of::<HotNbr>(), 24);
assert_eq!(std::mem::size_of::<ColdStamps>(), 8);
assert_eq!(std::mem::size_of::<Nbr>(), 32);
}
#[test]
fn slot_halves_roundtrip_through_nbr() {
let nbr = Nbr::with_create_ts(7, 2, EdgeId(9), 100);
let assembled = Nbr::from_parts(nbr.hot(), nbr.cold());
assert_eq!(assembled, nbr);
assert_eq!(
Nbr::from_parts(HotNbr::dead_gap(), ColdStamps::dead_gap()),
Nbr::dead_gap()
);
}
#[test]
fn test_edge_schema_validation_both_none() {
let schema = EdgeSchema {
label_id: 0,
label_name: "invalid_edge".into(),
src_label: 0,
dst_label: 0,
properties: vec![],
oe_strategy: EdgeStrategy::None,
ie_strategy: EdgeStrategy::None,
schema_version: 1,
record_form: RecordForm::default(),
};
let result = schema.validate();
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("at least one"));
}
#[test]
fn test_edge_schema_validation_both_enabled() {
let schema = EdgeSchema {
label_id: 0,
label_name: "valid_edge".into(),
src_label: 0,
dst_label: 0,
properties: vec![],
oe_strategy: EdgeStrategy::Multiple,
ie_strategy: EdgeStrategy::Single,
schema_version: 1,
record_form: RecordForm::default(),
};
let result = schema.validate();
assert!(result.is_ok());
}
#[test]
fn pure_target_rejection_comes_from_the_shared_constant() {
use linkrs_core::DataType;
let props = vec![StoragePropertyDef {
name: "p".into(),
data_type: DataType::Double,
nullable: true,
default_value: None,
}];
let err = validate_record_form_target(
&props,
EdgeStrategy::Multiple,
EdgeStrategy::Multiple,
RecordForm::Pure,
)
.expect_err("pure target with properties must be rejected");
assert!(
err.to_string()
.contains(record_form_policy::PURE_REQUIRES_ZERO_PROPERTIES_MSG),
"unexpected wording: {}",
err
);
}
#[test]
fn test_edge_schema_validation_ie_only() {
let schema = EdgeSchema {
label_id: 0,
label_name: "valid_edge".into(),
src_label: 0,
dst_label: 0,
properties: vec![],
oe_strategy: EdgeStrategy::None,
ie_strategy: EdgeStrategy::Multiple,
schema_version: 1,
record_form: RecordForm::default(),
};
let result = schema.validate();
assert!(result.is_ok());
assert_eq!(schema.storage_direction(), StorageDirection::InOnly);
assert!(!schema.has_out());
assert!(schema.has_in());
}
}