pub mod layout;
pub mod reader;
pub mod writer;
use std::path::PathBuf;
use crate::format::frame::FormatError;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct SegmentId([u8; 16]);
impl SegmentId {
#[must_use]
pub fn new(timestamp_millis: u64, entropy: [u8; 10]) -> Self {
let timestamp = timestamp_millis.to_be_bytes();
let mut bytes = [0_u8; 16];
if let (Some(destination), Some(source)) = (bytes.get_mut(..6), timestamp.get(2..)) {
destination.copy_from_slice(source);
}
if let Some(destination) = bytes.get_mut(6..) {
destination.copy_from_slice(&entropy);
}
Self(bytes)
}
#[must_use]
pub const fn from_bytes(bytes: [u8; 16]) -> Self {
Self(bytes)
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8; 16] {
&self.0
}
#[must_use]
pub fn file_name(self) -> String {
let mut name = String::with_capacity(8 + 32 + 5);
name.push_str("segment-");
for byte in self.0 {
use std::fmt::Write as _;
let _ = write!(name, "{byte:02x}");
}
name.push_str(".zseg");
name
}
}
impl std::fmt::Display for SegmentId {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for byte in self.0 {
write!(formatter, "{byte:02x}")?;
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SegmentMeta {
pub id: SegmentId,
pub row_count: u32,
pub scheme: u16,
pub dims: u32,
pub file_size: u64,
pub epoch_id: Option<crate::epoch::EpochId>,
pub clustering_key_range: ClusteringKeyRange,
}
impl SegmentMeta {
pub(crate) fn same_segment_file(&self, other: &Self) -> bool {
self.id == other.id
&& self.row_count == other.row_count
&& self.scheme == other.scheme
&& self.dims == other.dims
&& self.file_size == other.file_size
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ClusteringKeyRange {
Unstamped,
Empty,
Bounded {
min_ts: i64,
max_ts: i64,
},
}
#[derive(Debug)]
pub enum SegmentError {
Io {
path: PathBuf,
source: std::io::Error,
},
Format(FormatError),
WrongObject {
artifact: String,
expected: SegmentId,
actual: SegmentId,
},
MissingRegion(layout::RegionKind),
Geometry(String),
Columns(String),
Alive(String),
MetadataSemantic {
detail: String,
provenance: MetadataDecodeProvenance,
},
Graph(crate::graph::block::GraphNodeError),
Postings(crate::fts::sealed::SealedSegmentError),
}
impl SegmentError {
pub(crate) fn io(path: impl Into<PathBuf>, source: std::io::Error) -> Self {
Self::Io {
path: path.into(),
source,
}
}
}
impl std::fmt::Display for SegmentError {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io { path, source } => {
write!(formatter, "segment I/O {}: {source}", path.display())
}
Self::Format(error) => error.fmt(formatter),
Self::WrongObject {
artifact,
expected,
actual,
} => {
write!(
formatter,
"artifact {artifact} failed object identity: expected {expected}, got {actual}"
)
}
Self::MissingRegion(kind) => write!(formatter, "segment is missing region {kind:?}"),
Self::Geometry(detail) => write!(formatter, "segment geometry is invalid: {detail}"),
Self::Columns(detail) => write!(formatter, "segment columns are invalid: {detail}"),
Self::Alive(detail) => write!(formatter, "segment alive set is invalid: {detail}"),
Self::MetadataSemantic { detail, .. } => {
write!(formatter, "segment metadata is invalid: {detail}")
}
Self::Graph(error) => write!(formatter, "segment graph region is invalid: {error}"),
Self::Postings(error) => {
write!(formatter, "segment postings region is invalid: {error}")
}
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum MetadataDecodeProvenance {
ColumnsPresenceTail {
column_id: u32,
row_count: u32,
byte_offset: u64,
observed_byte: u8,
allowed_mask: u8,
},
ColumnsDictionaryCode {
column_id: u32,
row: u32,
byte_offset: u64,
code: u32,
dictionary_cardinality: u32,
},
ColumnsRawStringLength {
column_id: u32,
row: u32,
byte_offset: u64,
declared_bytes: u32,
available_bytes: u64,
},
AliveBitmapTruncation {
row_count: u32,
byte_offset: u64,
declared_bytes: u32,
observed_bytes: u32,
},
}
impl std::error::Error for SegmentError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io { source, .. } => Some(source),
Self::Format(error) => Some(error),
Self::Graph(error) => Some(error),
Self::Postings(error) => Some(error),
Self::WrongObject { .. }
| Self::MissingRegion(_)
| Self::Geometry(_)
| Self::Columns(_)
| Self::Alive(_)
| Self::MetadataSemantic { .. } => None,
}
}
}
impl From<FormatError> for SegmentError {
fn from(error: FormatError) -> Self {
Self::Format(error)
}
}
impl From<crate::graph::block::GraphNodeError> for SegmentError {
fn from(error: crate::graph::block::GraphNodeError) -> Self {
Self::Graph(error)
}
}
impl From<crate::fts::sealed::SealedSegmentError> for SegmentError {
fn from(error: crate::fts::sealed::SealedSegmentError) -> Self {
Self::Postings(error)
}
}