commonware-storage 2026.10.0

Persist and retrieve data from an abstract store.
Documentation
use commonware_allocator::mimalloc;
use commonware_runtime::{
    BLOB_PAGE_SIZE,
    buffer::paged::{CacheRef, page_size},
    tokio::Context,
};
use commonware_storage::journal::contiguous::{
    Mutable,
    fixed::{Config as FixedConfig, Journal as FixedJournal},
    variable::{Config as VariableConfig, Journal as VariableJournal},
};
use commonware_utils::{NZU64, NZUsize, sequence::FixedBytes, test_rng};
use criterion::criterion_main;
use rand::Rng;
use std::num::{NonZeroU16, NonZeroU64, NonZeroUsize};

mod append_sync;
mod fixed_append;
mod fixed_append_buffered;
mod fixed_read_random;
mod fixed_read_sequential;
mod fixed_replay;
mod segmented_variable_append_buffered;
mod variable_prepare_append;
mod variable_read_compressed;
mod variable_read_random;
mod variable_replay;

#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc::new(mimalloc::Config::DEFAULT);

criterion_main!(
    append_sync::benches,
    fixed_append::benches,
    fixed_append_buffered::benches,
    fixed_read_random::benches,
    fixed_read_sequential::benches,
    fixed_replay::benches,
    segmented_variable_append_buffered::benches,
    variable_prepare_append::benches,
    variable_read_compressed::benches,
    variable_read_random::benches,
    variable_replay::benches,
);

/// The size of the write buffer used by the journal.
const WRITE_BUFFER: NonZeroUsize = NZUsize!(1_024 * 1024); // 1MB

/// The size of the buffer used to replay the journal.
const REPLAY_BUFFER: NonZeroUsize = NZUsize!(1_024 * 1024); // 1MB

/// Use a "prod sized" page size to test the performance of the journal.
const PAGE_SIZE: NonZeroU16 = page_size(BLOB_PAGE_SIZE);

/// The number of pages to cache in the page cache. Make it big enough to be
/// fast, but not so big we avoid any page faults for the larger benchmarks.
const PAGE_CACHE_SIZE: NonZeroUsize = NZUsize!(10_000);

/// Value of items_per_blob to use in the journal config.
const ITEMS_PER_BLOB: NonZeroU64 = NZU64!(100_000);

/// Size of each journal item in bytes.
const ITEM_SIZE: usize = 32;

/// Open and return a temp fixed journal with the given config parameters and items of size ITEM_SIZE.
async fn get_fixed_journal<const ITEM_SIZE: usize>(
    context: Context,
    partition_name: &str,
    items_per_blob: NonZeroU64,
) -> FixedJournal<Context, FixedBytes<ITEM_SIZE>> {
    // Initialize the journal at the given partition.
    let journal_config = FixedConfig {
        partition: partition_name.into(),
        items_per_blob,
        write_buffer: WRITE_BUFFER,
        replay_buffer: REPLAY_BUFFER,
        page_cache: CacheRef::new(PAGE_SIZE, PAGE_CACHE_SIZE),
    };
    FixedJournal::init(context, journal_config).await.unwrap()
}

/// Append `items_to_write` random items to the given fixed journal, syncing the changes before returning.
async fn append_fixed_random_data<C, const ITEM_SIZE: usize>(
    mut journal: C,
    items_to_write: u64,
) -> C
where
    C: Mutable<Item = FixedBytes<ITEM_SIZE>>,
{
    // Append `items_to_write` random items to the journal.
    let mut rng = test_rng();
    let mut arr = [0; ITEM_SIZE];
    for _ in 0..items_to_write {
        rng.fill_bytes(&mut arr);
        (journal, _) = journal
            .append(&FixedBytes::new(arr))
            .await
            .expect("failed to append data");
    }

    // Sync the journal to ensure all data is written to disk.
    journal.sync().await.expect("failed to sync journal")
}

/// Open and return a temp variable journal with the given config parameters.
async fn get_variable_journal<const ITEM_SIZE: usize>(
    context: Context,
    partition_name: &str,
    items_per_section: NonZeroU64,
) -> VariableJournal<Context, FixedBytes<ITEM_SIZE>> {
    // Initialize the journal at the given partition.
    let journal_config = VariableConfig {
        partition: partition_name.into(),
        items_per_section,
        compression: None,
        codec_config: (),
        page_cache: CacheRef::new(PAGE_SIZE, PAGE_CACHE_SIZE),
        write_buffer: WRITE_BUFFER,
        replay_buffer: REPLAY_BUFFER,
    };
    VariableJournal::init(context, journal_config)
        .await
        .unwrap()
}