pub const MAX_FILE_SIZE: usize = (1 << 30) - (1 << 24);
pub const MAX_USER_KEY_SIZE: usize = crate::internal::MAX_INTERNAL_KEY_SIZE - 16;
pub const MAX_USER_VALUE_SIZE: usize = crate::internal::MAX_INTERNAL_VALUE_SIZE - 64;
pub(crate) const ROW_WIDTH: usize = crate::internal::ROW_WIDTH;
pub(crate) const INITIAL_DATA_FILE_ORDINAL: u64 = 0x00bd_38a0_2a35_1cdf;
use crate::internal::MIN_INITIAL_ROWS;
use std::time::Duration;
#[derive(Debug, Clone, Copy)]
pub struct Config {
pub hash_key: (u64, u64),
pub mlock_index: bool,
pub remap_scaler: u8,
pub initial_capacity: usize,
pub max_data_file_size: u32,
pub compaction_min_threshold: u32,
pub max_concurrency: usize,
pub port_to_current_format: bool,
pub reset_on_invalid_data: bool,
pub compaction_throughput_bytes_per_sec: usize,
pub checkpoint_interval: Option<Duration>,
pub checkpoint_delta_bytes: Option<usize>,
}
impl Default for Config {
fn default() -> Self {
Self {
hash_key: (0x7c2b_23a8_12c2_005f, 0x1f6a_4035_386e_c891),
mlock_index: false,
remap_scaler: 1,
initial_capacity: MIN_INITIAL_ROWS * ROW_WIDTH,
max_data_file_size: 64 * 1024 * 1024,
compaction_min_threshold: 24 * 1024 * 1024,
max_concurrency: (2 * num_cpus::get()).clamp(16, 64),
port_to_current_format: true,
reset_on_invalid_data: false,
compaction_throughput_bytes_per_sec: 4 * 1024 * 1024,
checkpoint_interval: Some(Duration::from_secs(5)),
checkpoint_delta_bytes: Some(128 * 1024),
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("IO error: {0}")]
IOError(std::io::Error),
#[error("Missing data file: {0}")]
MissingDataFile(u16),
#[error("Data file {0} reached size limit")]
RotateDataFile(u16),
#[error("Row needs splitting at split level {0}")]
SplitRow(u64),
#[error("Maximum split level {0} reached")]
MaxSplitLevel(u64),
#[error("Too many data files")]
TooManyDataFiles,
#[error("Lockfile {0} is taken by {1}")]
LockfileTaken(std::path::PathBuf, String),
#[error("Payload {0} too large")]
PayloadTooLarge(usize),
#[error("Checkpoint shutdown: {0}")]
CheckpointShutdown(String),
#[error("Postcard error: {0}")]
PostcardError(postcard::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ReplaceStatus {
PrevValue(Vec<u8>),
WrongValue(Vec<u8>),
DoesNotExist,
}
impl ReplaceStatus {
pub fn was_replaced(&self) -> bool {
matches!(self, Self::PrevValue(_))
}
pub fn failed(&self) -> bool {
!self.was_replaced()
}
pub fn is_key_missing(&self) -> bool {
matches!(self, Self::DoesNotExist)
}
pub fn is_wrong_value(&self) -> bool {
matches!(self, Self::WrongValue(_))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SetStatus {
PrevValue(Vec<u8>),
CreatedNew,
}
impl SetStatus {
pub fn was_created(&self) -> bool {
matches!(self, Self::CreatedNew)
}
pub fn was_replaced(&self) -> bool {
matches!(self, Self::PrevValue(_))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GetOrCreateStatus {
ExistingValue(Vec<u8>),
CreatedNew(Vec<u8>),
}
impl GetOrCreateStatus {
pub fn was_created(&self) -> bool {
matches!(self, Self::CreatedNew(_))
}
pub fn already_exists(&self) -> bool {
matches!(self, Self::ExistingValue(_))
}
pub fn value(self) -> Vec<u8> {
match self {
Self::ExistingValue(value) | Self::CreatedNew(value) => value,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ListCompactionParams {
pub min_length: u64,
pub min_holes_ratio: f64,
}
impl Default for ListCompactionParams {
fn default() -> Self {
Self {
min_length: 100,
min_holes_ratio: 0.25,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Stats {
pub num_rows: u64,
pub num_items: u64,
pub num_data_files: u64,
pub index_size_bytes: u64,
pub last_remap_dur: Duration,
pub checkpoint_generation: u64,
pub checkpoint_epoch: u64,
pub uncheckpointed_bytes: u64,
pub last_checkpoint_dur: Duration,
pub num_compactions: u64,
pub checkpoint_errors: u64,
pub last_compaction_dur: Duration,
pub last_compaction_reclaimed_bytes: u32,
pub last_compaction_moved_bytes: u32,
pub num_inserted: u64,
pub num_removed: u64,
pub num_updated: u64,
pub num_positive_lookups: u64,
pub num_negative_lookups: u64,
pub num_collisions: u64,
pub num_read_ops: u64,
pub num_read_bytes: u64,
pub num_write_ops: u64,
pub num_write_bytes: u64,
pub num_rebuilt_entries: u64,
pub num_rebuild_purged_bytes: u64,
pub total_bytes: u64,
pub waste_bytes: u64,
pub entries_under_64: u64,
pub entries_under_256: u64,
pub entries_under_1024: u64,
pub entries_under_4096: u64,
pub entries_under_16384: u64,
pub entries_over_16384: u64,
}
impl Stats {
pub fn index_capacity(&self) -> u64 {
self.num_rows.saturating_mul(ROW_WIDTH as u64)
}
pub fn data_bytes(&self) -> u64 {
self.total_bytes.saturating_sub(self.waste_bytes)
}
}