use std::path::{Path, PathBuf};
use std::sync::Arc;
use arc_swap::ArcSwap;
use parking_lot::RwLock;
use rustc_hash::{FxHashMap, FxHashSet};
use crate::instrumentation;
use crate::timestamp::get_fast_timestamp;
use crate::traits::Index;
use radixdb_core::SmartString;
use radixdb_core::{Error, Result, Row, Value};
use super::writer::{ColumnMapping, FrozenVolume};
mod access;
mod lookup;
mod publication;
mod rows;
mod table;
mod topology;
mod transactions;
mod visibility;
#[cfg(test)]
mod tests;
pub use table::{CompactionToken, SegmentLevel, SegmentMeta, SegmentRegistration, TableManifest};
use table::ReplacementExpectation;
use visibility::{compute_visibility_bitmaps, selected_ranges_are_isolated};
#[derive(Clone)]
pub struct ColdSegment {
pub volume: Arc<FrozenVolume>,
pub mapping: super::writer::ColumnMapping,
pub schema_version: u64,
pub visible: Option<Arc<Vec<u64>>>,
}
impl ColdSegment {
pub fn new(
volume: Arc<FrozenVolume>,
mapping: ColumnMapping,
schema_version: u64,
visible: Option<Arc<Vec<u64>>>,
) -> Result<Self> {
if let Some(bits) = visible.as_ref() {
let expected_words = volume.meta.row_count.div_ceil(64);
if bits.len() != expected_words {
return Err(Error::internal(format!(
"visibility bitmap has {} words for {} rows; expected {}",
bits.len(),
volume.meta.row_count,
expected_words
)));
}
let trailing = volume.meta.row_count % 64;
if trailing != 0
&& bits
.last()
.is_some_and(|word| word & (!0u64 << trailing) != 0)
{
return Err(Error::internal(
"visibility bitmap has nonzero bits beyond row count",
));
}
}
if volume.artifact_source().is_none() {
#[cfg(any(test, feature = "test-hooks"))]
if volume.columns.is_eager() {
return Ok(Self {
volume,
mapping,
schema_version,
visible,
});
}
return Err(Error::internal(
"cannot register cold segment without an artifact source",
));
}
Ok(Self {
volume,
mapping,
schema_version,
visible,
})
}
pub fn new_identity_mapping(
volume: Arc<FrozenVolume>,
schema_version: u64,
visible: Option<Arc<Vec<u64>>>,
) -> Result<Self> {
let mapping = ColumnMapping::identity(&volume);
Self::new(volume, mapping, schema_version, visible)
}
#[inline]
pub fn is_visible(&self, idx: usize) -> bool {
match &self.visible {
None => true,
Some(bits) => bits
.get(idx >> 6)
.is_some_and(|word| (word >> (idx & 63)) & 1 == 1),
}
}
}
pub struct ColdSnapshot {
pub seg_ids: smallvec::SmallVec<[u64; 4]>,
pub segs: Arc<FxHashMap<u64, ColdSegment>>,
pub ts: Arc<FxHashMap<i64, u64>>,
}
#[derive(Clone)]
pub(crate) struct TombstonePublicationSnapshot {
generation: u64,
tombstones: Arc<FxHashMap<i64, u64>>,
}
impl TombstonePublicationSnapshot {
pub(crate) const fn generation(&self) -> u64 {
self.generation
}
pub(crate) fn tombstones(&self) -> &FxHashMap<i64, u64> {
self.tombstones.as_ref()
}
}
pub struct SegmentManager {
table_name: RwLock<SmartString>,
manifest: RwLock<TableManifest>,
segments: ArcSwap<FxHashMap<u64, ColdSegment>>,
segments_update: parking_lot::Mutex<()>,
volume_dir: Option<PathBuf>,
has_segments_flag: std::sync::atomic::AtomicBool,
pub current_eviction_epoch: std::sync::atomic::AtomicU64,
tombstones: ArcSwap<FxHashMap<i64, u64>>,
tombstones_update: parking_lot::Mutex<()>,
tombstone_generation: std::sync::atomic::AtomicU64,
durable_tombstone_generation: std::sync::atomic::AtomicU64,
pending_txn_tombstones: RwLock<FxHashMap<i64, PendingTxnTombstones>>,
pending_txn_index_removals: parking_lot::Mutex<FxHashMap<i64, Vec<PendingColdIndexRemoval>>>,
cold_populated_indexes: RwLock<FxHashSet<SmartString>>,
cached_deduped_count: std::sync::atomic::AtomicU64,
cached_deduped_generation: std::sync::atomic::AtomicU64,
topology_generation: std::sync::atomic::AtomicU64,
segment_generation: std::sync::atomic::AtomicU64,
seal_fence: RwLock<()>,
visibility_seen: parking_lot::Mutex<rustc_hash::FxHashSet<i64>>,
seal_generation: std::sync::atomic::AtomicU64,
txn_seal_gens: parking_lot::Mutex<rustc_hash::FxHashMap<i64, u64>>,
seal_overlap_count: std::sync::atomic::AtomicUsize,
}
#[derive(Clone, Copy, Debug, Default, serde::Serialize)]
pub struct SegmentRuntimeOwnerSnapshot {
pub segments: u64,
pub unleveled_segments: u64,
pub l0_segments: u64,
pub l1_segments: u64,
pub l0_debt_physical_bytes: u64,
pub rows: u64,
pub resident_bytes: u64,
pub metadata_bytes: u64,
pub row_id_bytes: u64,
pub exact_index_bytes: u64,
pub ordered_index_bytes: u64,
pub descriptor_bytes: u64,
pub column_payload_bytes: u64,
pub tombstones: u64,
pub level_metadata_busy: bool,
pub truncated: bool,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct L0DebtSnapshot {
pub segments: u64,
pub physical_bytes: u64,
}
#[derive(Default)]
struct PendingTxnTombstones {
ids: FxHashSet<i64>,
journal: Vec<(i64, i64)>,
}
struct PendingColdIndexRemoval {
index: Arc<dyn Index>,
values: Vec<Value>,
row_id: i64,
removed_at: i64,
}