radixdb-storage 1.1.0

Storage contracts and physical persistence engine for RadixDB
Documentation
use std::collections::BTreeSet;

use radixdb_catalog::ObjectId;
use radixdb_storage::v6::{
    ArtifactId, ArtifactKind, ArtifactRef, ArtifactSliceRef, CatalogGeneration, CatalogId,
    CatalogRef, DatabaseGeneration, DatabaseId, FormatError, IndexSectionKind, IndexSectionRef,
    ManifestGeneration, ManifestId, ManifestKind, ManifestRef, SegmentId, WalGeneration,
    WalReplayFloor, ARTIFACT_CODEC_VERSION, FORMAT_VERSION, MAX_ARTIFACT_FILE_BYTES,
    MAX_CATALOG_FILE_BYTES, MAX_MANIFEST_FILE_BYTES,
};

fn bytes(first: u8, last: u8) -> [u8; 16] {
    let mut value = [first; 16];
    value[15] = last;
    value
}

#[test]
fn durable_identity_types_are_distinct_nonzero_and_canonical() {
    let database = DatabaseId::from_bytes(bytes(0x11, 0x12)).unwrap();
    let catalog = CatalogId::from_bytes(bytes(0x21, 0x22)).unwrap();
    let manifest = ManifestId::from_bytes(bytes(0x31, 0x32)).unwrap();
    let artifact = ArtifactId::from_bytes(bytes(0x41, 0x42)).unwrap();
    let segment = SegmentId::from_bytes(bytes(0x51, 0x52)).unwrap();

    assert_eq!(database.to_string(), "11111111111111111111111111111112");
    assert_eq!(catalog.to_string(), "21212121212121212121212121212122");
    assert_eq!(manifest.to_string(), "31313131313131313131313131313132");
    assert_eq!(artifact.to_string(), "41414141414141414141414141414142");
    assert_eq!(segment.to_string(), "51515151515151515151515151515152");
    assert_eq!(
        database.to_string().parse::<DatabaseId>().unwrap(),
        database
    );
    assert_eq!(catalog.to_string().parse::<CatalogId>().unwrap(), catalog);
    assert_eq!(
        manifest.to_string().parse::<ManifestId>().unwrap(),
        manifest
    );
    assert_eq!(
        artifact.to_string().parse::<ArtifactId>().unwrap(),
        artifact
    );
    assert_eq!(segment.to_string().parse::<SegmentId>().unwrap(), segment);

    assert!(matches!(
        DatabaseId::from_bytes([0; 16]),
        Err(FormatError::ZeroIdentity { .. })
    ));
    assert!("00".parse::<ArtifactId>().is_err());

    let generated = (0..256).map(|_| ArtifactId::new()).collect::<BTreeSet<_>>();
    assert_eq!(generated.len(), 256);
    assert!(generated.iter().all(|id| id.as_bytes() != &[0; 16]));
}

#[test]
fn generation_types_are_nonzero_monotonic_and_do_not_alias() {
    let database = DatabaseGeneration::new(7).unwrap();
    let catalog = CatalogGeneration::new(11).unwrap();
    let manifest = ManifestGeneration::new(13).unwrap();
    let wal = WalGeneration::new(17).unwrap();

    assert_eq!(database.checked_next().unwrap().get(), 8);
    assert_eq!(catalog.get(), 11);
    assert_eq!(manifest.get(), 13);
    assert_eq!(wal.get(), 17);
    assert!(DatabaseGeneration::new(0).is_err());
    assert!(matches!(
        DatabaseGeneration::new(u64::MAX).unwrap().checked_next(),
        Err(FormatError::GenerationOverflow { .. })
    ));

    let floor = WalReplayFloor::new(wal, 200);
    assert_eq!(floor.generation(), wal);
    assert_eq!(floor.lsn(), 200);
    assert!(!floor.starts_after(200));
    assert!(floor.starts_after(201));
}

#[test]
fn metadata_references_bind_kind_version_length_and_hash() {
    let catalog = CatalogRef::new(
        CatalogId::from_bytes(bytes(0x21, 1)).unwrap(),
        CatalogGeneration::new(2).unwrap(),
        304,
        [0xa1; 32],
    )
    .unwrap();
    assert_eq!(catalog.format(), FORMAT_VERSION);
    assert_eq!(catalog.byte_length(), 304);
    assert_eq!(catalog.body_sha256(), &[0xa1; 32]);

    let manifest = ManifestRef::new(
        ManifestId::from_bytes(bytes(0x31, 1)).unwrap(),
        ManifestKind::Table,
        ManifestGeneration::new(3).unwrap(),
        400,
        [0xb2; 32],
    )
    .unwrap();
    assert_eq!(manifest.kind(), ManifestKind::Table);
    assert_eq!(manifest.format().major(), 6);
    assert_eq!(manifest.format().minor(), 0);

    assert!(matches!(
        CatalogRef::from_persisted(
            catalog.id(),
            catalog.generation(),
            7,
            0,
            catalog.byte_length(),
            *catalog.body_sha256(),
        ),
        Err(FormatError::UnsupportedFormatVersion { .. })
    ));
    assert!(ManifestRef::new(
        manifest.id(),
        ManifestKind::Database,
        manifest.generation(),
        303,
        *manifest.body_sha256(),
    )
    .is_err());
    assert!(CatalogRef::new(
        catalog.id(),
        catalog.generation(),
        MAX_CATALOG_FILE_BYTES + 1,
        *catalog.body_sha256(),
    )
    .is_err());
    assert!(ManifestRef::new(
        manifest.id(),
        manifest.kind(),
        manifest.generation(),
        MAX_MANIFEST_FILE_BYTES + 1,
        *manifest.body_sha256(),
    )
    .is_err());
}

#[test]
fn artifact_reference_derives_locator_without_path_identity() {
    let id = ArtifactId::from_bytes(bytes(0xab, 0xcd)).unwrap();
    let generation = DatabaseGeneration::new(9).unwrap();
    let data = ArtifactRef::new(id, ArtifactKind::Data, generation, 4096, [0x44; 32]).unwrap();
    assert_eq!(data.codec_version(), ARTIFACT_CODEC_VERSION);
    assert_eq!(data.locator().shard(), 0xab);
    assert_eq!(
        data.relative_path().to_str().unwrap(),
        "artifacts/data/ab/abababababababababababababababcd.data"
    );

    let index = ArtifactRef::new(id, ArtifactKind::Index, generation, 4096, [0x55; 32]).unwrap();
    assert_eq!(
        index.relative_path().to_str().unwrap(),
        "artifacts/index/ab/abababababababababababababababcd.idx"
    );

    assert!(ArtifactRef::from_persisted(
        id,
        ArtifactKind::Data,
        2,
        0,
        generation,
        4096,
        [0; 32],
        0xab,
        1,
    )
    .is_err());
    assert!(ArtifactRef::from_persisted(
        id,
        ArtifactKind::Data,
        1,
        1,
        generation,
        4096,
        [0; 32],
        0xab,
        1,
    )
    .is_err());
    assert!(ArtifactRef::from_persisted(
        id,
        ArtifactKind::Data,
        1,
        0,
        generation,
        4096,
        [0; 32],
        0xaa,
        1,
    )
    .is_err());
    assert!(ArtifactRef::from_persisted(
        id,
        ArtifactKind::Data,
        1,
        0,
        generation,
        4096,
        [0; 32],
        0xab,
        2,
    )
    .is_err());
    assert!(ArtifactRef::new(
        id,
        ArtifactKind::Data,
        generation,
        MAX_ARTIFACT_FILE_BYTES + 1,
        [0; 32],
    )
    .is_err());
}

#[test]
fn index_section_reference_binds_logical_and_physical_identity() {
    let artifact = ArtifactRef::new(
        ArtifactId::from_bytes(bytes(0x61, 1)).unwrap(),
        ArtifactKind::Index,
        DatabaseGeneration::new(1).unwrap(),
        8192,
        [0x66; 32],
    )
    .unwrap();
    let slice = ArtifactSliceRef::new(
        artifact,
        7,
        IndexSectionKind::ExactPages,
        1,
        4096,
        1024,
        2048,
        200,
        0x1234_5678,
    )
    .unwrap();
    let logical = ObjectId::from_user_bytes(bytes(0x71, 1)).unwrap();
    let reference = IndexSectionRef::new(logical, slice);

    assert_eq!(reference.logical_index_id(), logical);
    assert_eq!(reference.slice().artifact().id(), artifact.id());
    assert_eq!(reference.slice().section_index(), 7);
    assert_eq!(
        reference.slice().section_kind(),
        IndexSectionKind::ExactPages
    );
    assert_eq!(reference.slice().stored_length(), 1024);
    assert_eq!(reference.slice().logical_length(), 2048);
    assert_eq!(reference.slice().item_count(), 200);
    assert_eq!(reference.slice().stored_crc32(), 0x1234_5678);

    let data = ArtifactRef::new(
        ArtifactId::from_bytes(bytes(0x81, 1)).unwrap(),
        ArtifactKind::Data,
        DatabaseGeneration::new(1).unwrap(),
        8192,
        [0x77; 32],
    )
    .unwrap();
    assert!(ArtifactSliceRef::new(
        data,
        0,
        IndexSectionKind::ExactPages,
        1,
        4096,
        512,
        512,
        1,
        0,
    )
    .is_err());
    assert!(ArtifactSliceRef::new(
        artifact,
        0,
        IndexSectionKind::ExactPages,
        1,
        4097,
        512,
        512,
        1,
        0,
    )
    .is_err());
    assert!(ArtifactSliceRef::new(
        artifact,
        0,
        IndexSectionKind::ExactPages,
        1,
        7936,
        512,
        512,
        1,
        0,
    )
    .is_err());
    assert_eq!(
        IndexSectionKind::from_tag(6).unwrap(),
        IndexSectionKind::HnswAdjacency
    );
    assert!(IndexSectionKind::from_tag(7).is_err());
}