use std::path::Path;
use crate::{Error, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SsTableFormat {
Big,
Bti,
}
impl SsTableFormat {
pub fn parse(s: &str) -> Option<Self> {
match s {
"big" => Some(Self::Big),
"bti" => Some(Self::Bti),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Big => "big",
Self::Bti => "bti",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SsTableDescriptor {
pub version: String,
pub sstable_id: String,
pub format: SsTableFormat,
pub component: String,
}
impl SsTableDescriptor {
pub fn parse(path: &Path) -> Result<Self> {
let filename = path
.file_name()
.and_then(|f| f.to_str())
.ok_or_else(|| Error::InvalidPath(format!("Invalid SSTable path: {:?}", path)))?;
Self::parse_filename(filename)
}
pub fn parse_filename(filename: &str) -> Result<Self> {
let base = if let Some(b) = filename.strip_suffix(".db") {
b
} else if let Some(b) = filename.strip_suffix(".txt") {
b
} else {
filename
};
let parts: Vec<&str> = base.split('-').collect();
if parts.len() < 4 {
return Err(Error::InvalidFormat(format!(
"SSTable filename has fewer than 4 dash-separated segments: {:?}",
filename
)));
}
let version = parts[0];
if version.len() != 2 || !version.chars().all(|c| c.is_ascii_lowercase()) {
return Err(Error::InvalidFormat(format!(
"SSTable version segment must be 2 lowercase letters, got {:?} in {:?}",
version, filename
)));
}
let format_idx = parts[2..]
.iter()
.enumerate()
.rev()
.find(|(_, p)| **p == "big" || **p == "bti")
.map(|(i, _)| i + 2);
let format_idx = format_idx.ok_or_else(|| {
Error::InvalidFormat(format!(
"No 'big' or 'bti' format segment found in {:?}",
filename
))
})?;
let format = SsTableFormat::parse(parts[format_idx]).ok_or_else(|| {
Error::InvalidFormat(format!(
"Unknown format {:?} in {:?}",
parts[format_idx], filename
))
})?;
let sstable_id = parts[1..format_idx].join("-");
let component_base = parts[format_idx + 1..].join("-");
let extension = if filename.ends_with(".db") {
".db"
} else {
".txt"
};
let component = format!("{}{}", component_base, extension);
Ok(Self {
version: version.to_string(),
sstable_id,
format,
component,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BigVersionGates {
pub version: String,
pub has_commit_log_lower_bound: bool,
pub has_commit_log_intervals: bool,
pub has_accurate_min_max: bool,
pub has_legacy_min_max: bool,
pub has_originating_host_id: bool,
pub has_max_compressed_length: bool,
pub has_pending_repair: bool,
pub has_is_transient: bool,
pub has_metadata_checksum: bool,
pub has_old_bf_format: bool,
pub has_improved_min_max: bool,
pub has_partition_level_deletion_presence_marker: bool,
pub has_key_range: bool,
pub has_uint_deletion_time: bool,
pub has_token_space_coverage: bool,
}
impl BigVersionGates {
pub fn from_version(version: &str) -> Result<Self> {
if version.len() != 2 || !version.chars().all(|c| c.is_ascii_lowercase()) {
return Err(Error::InvalidFormat(format!(
"BIG version must be 2 lowercase letters, got {:?}",
version
)));
}
let v = version;
let has_accurate_min_max = {
let first = v.chars().next().unwrap();
let second = v.chars().nth(1).unwrap();
(first == 'm' && ('d'..='z').contains(&second))
|| (first == 'n' && second.is_ascii_lowercase())
};
let has_legacy_min_max = {
let first = v.chars().next().unwrap();
let second = v.chars().nth(1).unwrap();
(first == 'm' && second.is_ascii_lowercase())
|| (first == 'n' && second.is_ascii_lowercase())
};
let has_originating_host_id = {
let first = v.chars().next().unwrap();
let second = v.chars().nth(1).unwrap();
v >= "nb" || (first == 'm' && ('e'..='z').contains(&second))
};
Ok(Self {
version: version.to_string(),
has_commit_log_lower_bound: v >= "mb",
has_commit_log_intervals: v >= "mc",
has_accurate_min_max,
has_legacy_min_max,
has_originating_host_id,
has_max_compressed_length: v >= "na",
has_pending_repair: v >= "na",
has_is_transient: v >= "na",
has_metadata_checksum: v >= "na",
has_old_bf_format: v < "na",
has_improved_min_max: v >= "oa",
has_partition_level_deletion_presence_marker: v >= "oa",
has_key_range: v >= "oa",
has_uint_deletion_time: v >= "oa",
has_token_space_coverage: v >= "oa",
})
}
pub fn is_compatible(&self) -> bool {
let v = self.version.as_str();
v >= "ma" && v.chars().next().is_some_and(|c| c <= 'o')
}
pub fn is_cassandra5_compat_mode(&self) -> bool {
self.version == "nb"
}
pub fn is_cassandra5_native(&self) -> bool {
self.version == "oa"
}
pub fn nb_fallback() -> Self {
Self {
version: "nb".to_string(),
has_commit_log_lower_bound: true, has_commit_log_intervals: true, has_accurate_min_max: true, has_legacy_min_max: true, has_originating_host_id: true, has_max_compressed_length: true, has_pending_repair: true, has_is_transient: true, has_metadata_checksum: true, has_old_bf_format: false, has_improved_min_max: false,
has_partition_level_deletion_presence_marker: false,
has_key_range: false,
has_uint_deletion_time: false,
has_token_space_coverage: false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BtiVersionGates {
pub version: String,
pub has_commit_log_lower_bound: bool,
pub has_commit_log_intervals: bool,
pub has_max_compressed_length: bool,
pub has_pending_repair: bool,
pub has_is_transient: bool,
pub has_metadata_checksum: bool,
pub has_old_bf_format: bool,
pub has_originating_host_id: bool,
pub has_accurate_min_max: bool,
pub has_legacy_min_max: bool,
pub has_improved_min_max: bool,
pub has_token_space_coverage: bool,
pub has_partition_level_deletion_presence_marker: bool,
pub has_key_range: bool,
pub has_uint_deletion_time: bool,
}
impl BtiVersionGates {
pub fn from_version(version: &str) -> Result<Self> {
if version != "da" {
return Err(Error::InvalidFormat(format!(
"BTI format only supports version 'da', got {:?}",
version
)));
}
Ok(Self {
version: version.to_string(),
has_commit_log_lower_bound: true,
has_commit_log_intervals: true,
has_max_compressed_length: true,
has_pending_repair: true,
has_is_transient: true,
has_metadata_checksum: true,
has_old_bf_format: false, has_originating_host_id: true,
has_accurate_min_max: true,
has_legacy_min_max: false,
has_improved_min_max: true,
has_token_space_coverage: true,
has_partition_level_deletion_presence_marker: true,
has_key_range: true,
has_uint_deletion_time: true,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VersionGates {
Big(BigVersionGates),
Bti(BtiVersionGates),
}
impl VersionGates {
pub fn from_descriptor(desc: &SsTableDescriptor) -> Result<Self> {
match desc.format {
SsTableFormat::Big => BigVersionGates::from_version(&desc.version).map(Self::Big),
SsTableFormat::Bti => BtiVersionGates::from_version(&desc.version).map(Self::Bti),
}
}
pub fn from_path(path: &Path) -> Result<Self> {
let desc = SsTableDescriptor::parse(path)?;
Self::from_descriptor(&desc)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_descriptor_sequential_id() {
let desc = SsTableDescriptor::parse_filename("nb-1-big-Data.db").unwrap();
assert_eq!(desc.version, "nb");
assert_eq!(desc.sstable_id, "1");
assert_eq!(desc.format, SsTableFormat::Big);
assert_eq!(desc.component, "Data.db");
}
#[test]
fn test_descriptor_uuid_id_no_hyphens() {
let filename = "nb-6aa08200a25111f0a3fef1a551383fb9-big-Data.db";
let desc = SsTableDescriptor::parse_filename(filename).unwrap();
assert_eq!(desc.version, "nb");
assert_eq!(desc.sstable_id, "6aa08200a25111f0a3fef1a551383fb9");
assert_eq!(desc.format, SsTableFormat::Big);
assert_eq!(desc.component, "Data.db");
}
#[test]
fn test_descriptor_oa_version() {
let desc = SsTableDescriptor::parse_filename("oa-1-big-Data.db").unwrap();
assert_eq!(desc.version, "oa");
assert_eq!(desc.format, SsTableFormat::Big);
}
#[test]
fn test_descriptor_da_bti_version() {
let desc = SsTableDescriptor::parse_filename("da-1-bti-Partitions.db").unwrap();
assert_eq!(desc.version, "da");
assert_eq!(desc.format, SsTableFormat::Bti);
assert_eq!(desc.component, "Partitions.db");
}
#[test]
fn test_descriptor_legacy_versions() {
for version in &["ma", "mb", "mc", "md", "me", "na"] {
let filename = format!("{}-3-big-Data.db", version);
let desc = SsTableDescriptor::parse_filename(&filename).unwrap();
assert_eq!(desc.version, *version, "version mismatch for {}", filename);
assert_eq!(desc.format, SsTableFormat::Big);
}
}
#[test]
fn test_descriptor_toc_txt() {
let desc = SsTableDescriptor::parse_filename("nb-1-big-TOC.txt").unwrap();
assert_eq!(desc.version, "nb");
assert_eq!(desc.component, "TOC.txt");
}
#[test]
fn test_descriptor_compression_info() {
let desc = SsTableDescriptor::parse_filename("nb-1-big-CompressionInfo.db").unwrap();
assert_eq!(desc.component, "CompressionInfo.db");
}
#[test]
fn test_descriptor_invalid_too_few_parts() {
assert!(SsTableDescriptor::parse_filename("nb-Data.db").is_err());
assert!(SsTableDescriptor::parse_filename("Data.db").is_err());
}
#[test]
fn test_descriptor_invalid_version_not_two_letters() {
assert!(SsTableDescriptor::parse_filename("nba-1-big-Data.db").is_err());
assert!(SsTableDescriptor::parse_filename("n-1-big-Data.db").is_err());
}
#[test]
fn test_descriptor_invalid_no_format_segment() {
assert!(SsTableDescriptor::parse_filename("nb-1-xxx-Data.db").is_err());
}
#[test]
fn test_descriptor_from_path() {
let path = PathBuf::from(
"test-data/datasets/sstables/test_basic/simple_table-6aa08200/nb-1-big-Data.db",
);
let desc = SsTableDescriptor::parse(&path).unwrap();
assert_eq!(desc.version, "nb");
assert_eq!(desc.format, SsTableFormat::Big);
}
#[test]
fn test_big_nb_gates() {
let g = BigVersionGates::from_version("nb").unwrap();
assert!(g.has_commit_log_lower_bound, "nb: hasCommitLogLowerBound");
assert!(g.has_commit_log_intervals, "nb: hasCommitLogIntervals");
assert!(g.has_max_compressed_length, "nb: hasMaxCompressedLength");
assert!(g.has_pending_repair, "nb: hasPendingRepair");
assert!(g.has_is_transient, "nb: hasIsTransient");
assert!(g.has_metadata_checksum, "nb: hasMetadataChecksum");
assert!(!g.has_old_bf_format, "nb: !hasOldBfFormat");
assert!(
g.has_originating_host_id,
"nb: hasOriginatingHostId (nb >= nb)"
);
assert!(!g.has_improved_min_max, "nb: !hasImprovedMinMax (oa-only)");
assert!(
!g.has_partition_level_deletion_presence_marker,
"nb: !hasPartitionLevelDeletionPresenceMarker (oa-only)"
);
assert!(!g.has_key_range, "nb: !hasKeyRange (oa-only)");
assert!(
!g.has_uint_deletion_time,
"nb: !hasUIntDeletionTime (oa-only)"
);
assert!(
!g.has_token_space_coverage,
"nb: !hasTokenSpaceCoverage (oa-only)"
);
}
#[test]
fn test_big_oa_gates() {
let g = BigVersionGates::from_version("oa").unwrap();
assert!(g.has_commit_log_lower_bound);
assert!(g.has_commit_log_intervals);
assert!(g.has_max_compressed_length);
assert!(g.has_pending_repair);
assert!(g.has_is_transient);
assert!(g.has_metadata_checksum);
assert!(!g.has_old_bf_format);
assert!(g.has_originating_host_id, "oa >= nb");
assert!(g.has_improved_min_max, "oa: hasImprovedMinMax");
assert!(
g.has_partition_level_deletion_presence_marker,
"oa: hasPartitionLevelDeletionPresenceMarker"
);
assert!(g.has_key_range, "oa: hasKeyRange");
assert!(g.has_uint_deletion_time, "oa: hasUIntDeletionTime");
assert!(g.has_token_space_coverage, "oa: hasTokenSpaceCoverage");
assert!(
!g.has_accurate_min_max,
"oa: hasAccurateMinMax MUST be false (deprecated)"
);
assert!(
!g.has_legacy_min_max,
"oa: hasLegacyMinMax MUST be false (deprecated)"
);
}
#[test]
fn test_oa_only_gates_absent_from_nb() {
let nb = BigVersionGates::from_version("nb").unwrap();
let oa = BigVersionGates::from_version("oa").unwrap();
let oa_only_gate_names = [
(
"hasImprovedMinMax",
nb.has_improved_min_max,
oa.has_improved_min_max,
),
(
"hasPartitionLevelDeletionPresenceMarker",
nb.has_partition_level_deletion_presence_marker,
oa.has_partition_level_deletion_presence_marker,
),
("hasKeyRange", nb.has_key_range, oa.has_key_range),
(
"hasUIntDeletionTime",
nb.has_uint_deletion_time,
oa.has_uint_deletion_time,
),
(
"hasTokenSpaceCoverage",
nb.has_token_space_coverage,
oa.has_token_space_coverage,
),
];
for (name, nb_val, oa_val) in &oa_only_gate_names {
assert!(!nb_val, "nb.{} must be FALSE (oa-only gate)", name);
assert!(oa_val, "oa.{} must be TRUE", name);
}
}
#[test]
fn test_originating_host_id_straddle_gate() {
for v in &["ma", "mb", "mc", "md"] {
let g = BigVersionGates::from_version(v).unwrap();
assert!(
!g.has_originating_host_id,
"{}: hasOriginatingHostId must be FALSE",
v
);
}
for v in &["me", "mf", "mz"] {
let g = BigVersionGates::from_version(v).unwrap();
assert!(
g.has_originating_host_id,
"{}: hasOriginatingHostId must be TRUE (m[e-z] match)",
v
);
}
let na = BigVersionGates::from_version("na").unwrap();
assert!(
!na.has_originating_host_id,
"na: hasOriginatingHostId must be FALSE (na < nb, not m[e-z])"
);
for v in &["nb", "nc", "oa"] {
let g = BigVersionGates::from_version(v).unwrap();
assert!(
g.has_originating_host_id,
"{}: hasOriginatingHostId must be TRUE (>= nb)",
v
);
}
}
#[test]
fn test_big_ma_gates() {
let g = BigVersionGates::from_version("ma").unwrap();
assert!(!g.has_commit_log_lower_bound);
assert!(!g.has_commit_log_intervals);
assert!(!g.has_accurate_min_max);
assert!(g.has_legacy_min_max, "ma is in m[a-z]");
assert!(!g.has_originating_host_id);
assert!(!g.has_max_compressed_length);
assert!(g.has_old_bf_format, "ma: hasOldBfFormat");
assert!(!g.has_improved_min_max);
assert!(!g.has_key_range);
assert!(!g.has_uint_deletion_time);
assert!(!g.has_token_space_coverage);
}
#[test]
fn test_big_na_gates() {
let g = BigVersionGates::from_version("na").unwrap();
assert!(g.has_commit_log_lower_bound);
assert!(g.has_commit_log_intervals);
assert!(g.has_accurate_min_max, "na is in n[a-z]");
assert!(g.has_legacy_min_max, "na is in n[a-z]");
assert!(!g.has_originating_host_id, "na < nb");
assert!(g.has_max_compressed_length);
assert!(g.has_pending_repair);
assert!(!g.has_old_bf_format);
assert!(!g.has_improved_min_max, "oa-only");
}
#[test]
fn test_big_md_gates() {
let g = BigVersionGates::from_version("md").unwrap();
assert!(g.has_accurate_min_max, "md is m[d-z]");
assert!(g.has_legacy_min_max, "md is m[a-z]");
assert!(!g.has_originating_host_id, "md < me");
}
#[test]
fn test_big_me_gates() {
let g = BigVersionGates::from_version("me").unwrap();
assert!(g.has_accurate_min_max, "me is m[d-z]");
assert!(g.has_originating_host_id, "me matches m[e-z]");
}
#[test]
fn test_big_is_compatible() {
for v in &["ma", "mb", "mc", "md", "me", "na", "nb", "oa"] {
let g = BigVersionGates::from_version(v).unwrap();
assert!(g.is_compatible(), "{} should be compatible", v);
}
let pa = BigVersionGates::from_version("pa").unwrap();
assert!(
!pa.is_compatible(),
"pa is beyond current 'oa' major letter"
);
}
#[test]
fn test_big_is_cassandra5_mode() {
let nb = BigVersionGates::from_version("nb").unwrap();
assert!(nb.is_cassandra5_compat_mode());
assert!(!nb.is_cassandra5_native());
let oa = BigVersionGates::from_version("oa").unwrap();
assert!(!oa.is_cassandra5_compat_mode());
assert!(oa.is_cassandra5_native());
}
#[test]
fn test_nb_fallback_matches_from_version() {
let from_fn = BigVersionGates::from_version("nb").unwrap();
let fallback = BigVersionGates::nb_fallback();
assert_eq!(fallback.version, from_fn.version);
assert_eq!(
fallback.has_commit_log_lower_bound,
from_fn.has_commit_log_lower_bound
);
assert_eq!(
fallback.has_commit_log_intervals,
from_fn.has_commit_log_intervals
);
assert_eq!(fallback.has_accurate_min_max, from_fn.has_accurate_min_max);
assert_eq!(fallback.has_legacy_min_max, from_fn.has_legacy_min_max);
assert_eq!(
fallback.has_originating_host_id,
from_fn.has_originating_host_id
);
assert_eq!(
fallback.has_max_compressed_length,
from_fn.has_max_compressed_length
);
assert_eq!(fallback.has_pending_repair, from_fn.has_pending_repair);
assert_eq!(fallback.has_is_transient, from_fn.has_is_transient);
assert_eq!(
fallback.has_metadata_checksum,
from_fn.has_metadata_checksum
);
assert_eq!(fallback.has_old_bf_format, from_fn.has_old_bf_format);
assert_eq!(fallback.has_improved_min_max, from_fn.has_improved_min_max);
assert_eq!(
fallback.has_partition_level_deletion_presence_marker,
from_fn.has_partition_level_deletion_presence_marker
);
assert_eq!(fallback.has_key_range, from_fn.has_key_range);
assert_eq!(
fallback.has_uint_deletion_time,
from_fn.has_uint_deletion_time
);
assert_eq!(
fallback.has_token_space_coverage,
from_fn.has_token_space_coverage
);
}
#[test]
fn test_big_invalid_version() {
assert!(BigVersionGates::from_version("n").is_err());
assert!(BigVersionGates::from_version("nba").is_err());
assert!(BigVersionGates::from_version("NB").is_err());
assert!(BigVersionGates::from_version("").is_err());
}
#[test]
fn test_bti_da_gates() {
let g = BtiVersionGates::from_version("da").unwrap();
assert!(g.has_commit_log_lower_bound);
assert!(g.has_commit_log_intervals);
assert!(g.has_max_compressed_length);
assert!(g.has_pending_repair);
assert!(g.has_is_transient);
assert!(g.has_metadata_checksum);
assert!(!g.has_old_bf_format, "da: !hasOldBfFormat");
assert!(g.has_originating_host_id);
assert!(
g.has_accurate_min_max,
"da: hasAccurateMinMax (BtiFormat.java:363)"
);
assert!(
!g.has_legacy_min_max,
"da: !hasLegacyMinMax (BtiFormat.java:368)"
);
assert!(g.has_improved_min_max);
assert!(g.has_token_space_coverage);
assert!(g.has_partition_level_deletion_presence_marker);
assert!(g.has_key_range);
assert!(g.has_uint_deletion_time);
}
#[test]
fn test_bti_rejects_non_da() {
assert!(BtiVersionGates::from_version("nb").is_err());
assert!(BtiVersionGates::from_version("oa").is_err());
assert!(BtiVersionGates::from_version("na").is_err());
}
#[test]
fn test_version_gates_from_path_nb() {
let path = PathBuf::from("nb-1-big-Data.db");
let gates = VersionGates::from_path(&path).unwrap();
match gates {
VersionGates::Big(g) => assert_eq!(g.version, "nb"),
VersionGates::Bti(_) => panic!("Expected Big"),
}
}
#[test]
fn test_version_gates_from_path_oa() {
let path = PathBuf::from("oa-1-big-Data.db");
let gates = VersionGates::from_path(&path).unwrap();
match gates {
VersionGates::Big(g) => {
assert_eq!(g.version, "oa");
assert!(g.has_uint_deletion_time);
}
VersionGates::Bti(_) => panic!("Expected Big"),
}
}
#[test]
fn test_version_gates_from_path_da() {
let path = PathBuf::from("da-1-bti-Partitions.db");
let gates = VersionGates::from_path(&path).unwrap();
match gates {
VersionGates::Bti(g) => assert_eq!(g.version, "da"),
VersionGates::Big(_) => panic!("Expected Bti"),
}
}
#[test]
fn test_version_gates_from_corpus_filename() {
let path = PathBuf::from("nb-6aa08200a25111f0a3fef1a551383fb9-big-Data.db");
let gates = VersionGates::from_path(&path).unwrap();
match gates {
VersionGates::Big(g) => {
assert_eq!(g.version, "nb");
assert!(!g.has_improved_min_max);
assert!(!g.has_uint_deletion_time);
}
VersionGates::Bti(_) => panic!("Expected Big"),
}
}
#[test]
fn test_descriptor_docker_oa_sequential() {
let desc = SsTableDescriptor::parse_filename("oa-2-big-Data.db").unwrap();
assert_eq!(desc.version, "oa");
assert_eq!(desc.sstable_id, "2");
assert_eq!(desc.format, SsTableFormat::Big);
assert_eq!(desc.component, "Data.db");
}
#[test]
fn test_gates_docker_oa_fixture() {
let gates = VersionGates::from_path(&PathBuf::from("oa-2-big-Data.db")).unwrap();
match gates {
VersionGates::Big(g) => {
assert_eq!(g.version, "oa");
assert!(g.has_improved_min_max, "oa fixture: hasImprovedMinMax");
assert!(
g.has_partition_level_deletion_presence_marker,
"oa fixture: hasPartitionLevelDeletionPresenceMarker"
);
assert!(g.has_key_range, "oa fixture: hasKeyRange");
assert!(g.has_uint_deletion_time, "oa fixture: hasUIntDeletionTime");
assert!(
g.has_token_space_coverage,
"oa fixture: hasTokenSpaceCoverage"
);
assert!(
!g.has_accurate_min_max,
"oa fixture: hasAccurateMinMax deprecated"
);
assert!(
!g.has_legacy_min_max,
"oa fixture: hasLegacyMinMax deprecated"
);
}
VersionGates::Bti(_) => panic!("Expected Big gates for oa-2-big-Data.db"),
}
}
#[test]
fn test_descriptor_docker_da_bti() {
let desc = SsTableDescriptor::parse_filename("da-2-bti-Data.db").unwrap();
assert_eq!(desc.version, "da");
assert_eq!(desc.sstable_id, "2");
assert_eq!(desc.format, SsTableFormat::Bti);
assert_eq!(desc.component, "Data.db");
}
#[test]
fn test_descriptor_docker_da_bti_partitions() {
let desc = SsTableDescriptor::parse_filename("da-2-bti-Partitions.db").unwrap();
assert_eq!(desc.version, "da");
assert_eq!(desc.format, SsTableFormat::Bti);
assert_eq!(desc.component, "Partitions.db");
}
#[test]
fn test_gates_docker_da_fixture() {
let gates = VersionGates::from_path(&PathBuf::from("da-2-bti-Data.db")).unwrap();
match gates {
VersionGates::Bti(g) => {
assert_eq!(g.version, "da");
assert!(g.has_improved_min_max, "da: hasImprovedMinMax");
assert!(g.has_key_range, "da: hasKeyRange");
assert!(g.has_uint_deletion_time, "da: hasUIntDeletionTime");
assert!(g.has_token_space_coverage, "da: hasTokenSpaceCoverage");
assert!(
g.has_partition_level_deletion_presence_marker,
"da: hasPartitionLevelDeletionPresenceMarker"
);
assert!(!g.has_old_bf_format, "da: !hasOldBfFormat");
assert!(g.has_originating_host_id, "da: hasOriginatingHostId");
assert!(g.has_accurate_min_max, "da: hasAccurateMinMax");
assert!(!g.has_legacy_min_max, "da: !hasLegacyMinMax");
}
VersionGates::Big(_) => panic!("Expected Bti gates for da-2-bti-Data.db"),
}
}
}