use super::super::vint::parse_vuint;
use super::marshal_type::build_column_infos;
use super::serialization_header::{parse_serialization_header, parse_serialization_header_schema};
use super::EncodingStatsResult;
use crate::storage::sstable::version_gate::VersionGates;
use nom::{bytes::complete::take, number::complete::be_u32, IResult};
const TIMESTAMP_EPOCH: i64 = 1_442_880_000_000_000; const DELETION_TIME_EPOCH: i64 = 1_442_880_000; const TTL_EPOCH: i64 = 0;
pub(super) fn parse_minimal_encoding_stats<'a>(
input: &'a [u8],
full_input: &'a [u8],
header_offset: Option<usize>,
gates: Option<&VersionGates>,
) -> IResult<&'a [u8], EncodingStatsResult> {
let Some(offset) = header_offset else {
tracing::debug!("No HEADER TOC offset, using fallback EncodingStats parsing");
return parse_encoding_stats_fallback(input, gates);
};
if offset >= full_input.len() {
tracing::warn!(
"TOC offset 0x{:x} exceeds input length {}, using fallback",
offset,
full_input.len()
);
return parse_encoding_stats_fallback(input, gates);
}
let header_data = &full_input[offset..];
tracing::debug!(
"Parsing EncodingStats + SerializationHeader at TOC offset 0x{:x} ({} bytes available)",
offset,
header_data.len()
);
let (rest, (min_timestamp, min_deletion_time, min_ttl)) =
parse_encoding_stats_vuints(header_data, gates)?;
tracing::debug!(
"EncodingStats from HEADER: min_timestamp={}, min_deletion_time={}, min_ttl={:?}",
min_timestamp,
min_deletion_time,
min_ttl
);
let (partition_types, clustering_types, columns) = match parse_serialization_header_schema(rest)
{
Ok((_, result)) => result,
Err(e) => {
tracing::warn!(
"Schema parsing after EncodingStats failed: {:?}, falling back to marker search",
e
);
parse_serialization_header(input)?.1
}
};
let (partition_key_columns, clustering_key_columns) =
build_column_infos(&partition_types, &clustering_types);
Ok((
input,
(
min_timestamp,
min_deletion_time,
min_ttl,
partition_key_columns,
clustering_key_columns,
columns,
),
))
}
fn parse_encoding_stats_vuints<'a>(
input: &'a [u8],
_gates: Option<&VersionGates>,
) -> IResult<&'a [u8], (i64, i64, Option<i64>)> {
let (rest, min_ts_delta) = parse_vuint(input)?;
let (rest, min_ldt_delta) = parse_vuint(rest)?;
let (rest, min_ttl_delta) = parse_vuint(rest)?;
Ok((
rest,
(
min_ts_delta as i64 + TIMESTAMP_EPOCH,
min_ldt_delta as i64 + DELETION_TIME_EPOCH,
Some(min_ttl_delta as i64 + TTL_EPOCH),
),
))
}
fn parse_encoding_stats_fallback<'a>(
input: &'a [u8],
gates: Option<&VersionGates>,
) -> IResult<&'a [u8], EncodingStatsResult> {
let (rest, _metadata_type) = be_u32(input)?;
let (rest, _data_length) = parse_vuint(rest)?;
let (rest, partitioner_len) = parse_vuint(rest)?;
let (rest, _) = take(partitioner_len as usize)(rest)?;
let (rest, _metadata1) = parse_vuint(rest)?;
let (rest, _metadata2) = parse_vuint(rest)?;
let (rest, (min_timestamp, min_deletion_time, min_ttl)) =
parse_encoding_stats_vuints(rest, gates)?;
let (_, (partition_types, clustering_types, columns)) = parse_serialization_header(rest)?;
let (partition_key_columns, clustering_key_columns) =
build_column_infos(&partition_types, &clustering_types);
Ok((
input,
(
min_timestamp,
min_deletion_time,
min_ttl,
partition_key_columns,
clustering_key_columns,
columns,
),
))
}