Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tidesdb"
version = "0.11.0"
version = "0.11.1"
edition = "2024"
authors = ["TidesDB <hello@tidesdb.com>"]
description = "TidesDB is a high-performance embeddable, durable, adaptive, and optionally cloud-native key-value storage engine"
Expand Down
4 changes: 4 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ fn main() {
println!("cargo:rustc-check-cfg=cfg(tidesdb_has_cancel_background_work)");
println!("cargo:rustc-check-cfg=cfg(tidesdb_has_raise_open_file_limit)");
println!("cargo:rustc-check-cfg=cfg(tidesdb_has_write_amp_stats)");
println!("cargo:rustc-check-cfg=cfg(tidesdb_has_single_writer_fencing)");

// These gates follow C API/ABI boundaries found while testing the version
// matrix. Keeping them derived from the selected C tag avoids long feature
Expand All @@ -167,6 +168,9 @@ fn main() {
if version_at_least(&version, 9, 3, 4) {
println!("cargo:rustc-cfg=tidesdb_has_write_amp_stats");
}
if version_at_least(&version, 9, 3, 8) {
println!("cargo:rustc-cfg=tidesdb_has_single_writer_fencing");
}

// tidesdb S3 connector uses POSIX-only functions (gmtime_r, fmemopen)
// that were not available on Windows until v9.0.6
Expand Down
8 changes: 8 additions & 0 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,12 @@ impl TidesDB {
compaction_count,
) = (0u64, 0u64, 0u64, 0u64, 0u64, 0u64, 0u64, 0u64);

// Single-writer fencing epochs (tidesdb >= 9.3.8; 0 on older libraries).
#[cfg(tidesdb_has_single_writer_fencing)]
let (primary_epoch, seen_epoch) = (c_stats.primary_epoch, c_stats.seen_epoch);
#[cfg(not(tidesdb_has_single_writer_fencing))]
let (primary_epoch, seen_epoch) = (0u64, 0u64);

let object_store_connector = if c_stats.object_store_connector.is_null() {
String::new()
} else {
Expand Down Expand Up @@ -663,6 +669,8 @@ impl TidesDB {
total_uploads: c_stats.total_uploads,
total_upload_failures: c_stats.total_upload_failures,
replica_mode: c_stats.replica_mode != 0,
primary_epoch,
seen_epoch,
uwal_bytes_written,
wal_bytes_written,
flush_bytes_written,
Expand Down
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub enum ErrorCode {
ReadOnly,
/// Resource is busy (another operation is in progress)
Busy,
/// A required precondition was not met
Precondition,
}

impl ErrorCode {
Expand All @@ -59,6 +61,7 @@ impl ErrorCode {
ffi::TDB_ERR_LOCKED => Some(ErrorCode::Locked),
ffi::TDB_ERR_READONLY => Some(ErrorCode::ReadOnly),
ffi::TDB_ERR_BUSY => Some(ErrorCode::Busy),
ffi::TDB_ERR_PRECONDITION => Some(ErrorCode::Precondition),
_ => Some(ErrorCode::Unknown),
}
}
Expand All @@ -81,6 +84,7 @@ impl fmt::Display for ErrorCode {
ErrorCode::Locked => write!(f, "database is locked"),
ErrorCode::ReadOnly => write!(f, "database is read-only"),
ErrorCode::Busy => write!(f, "resource is busy"),
ErrorCode::Precondition => write!(f, "precondition not met"),
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub const TDB_ERR_UNKNOWN: c_int = -11;
pub const TDB_ERR_LOCKED: c_int = -12;
pub const TDB_ERR_READONLY: c_int = -13;
pub const TDB_ERR_BUSY: c_int = -14;
pub const TDB_ERR_PRECONDITION: c_int = -15;

/// Object store backend identifiers (`tidesdb_objstore_backend_t`)
pub const TDB_BACKEND_FS: c_int = 0;
Expand Down Expand Up @@ -326,6 +327,13 @@ pub struct tidesdb_db_stats_t {
pub total_uploads: u64,
pub total_upload_failures: u64,
pub replica_mode: c_int,
// Added in TidesDB 9.3.8: single-writer fencing epochs (object-store mode).
// These sit between `replica_mode` and the write-amp counters in the C
// struct, so they must be gated and ordered to match the C layout exactly.
#[cfg(tidesdb_has_single_writer_fencing)]
pub primary_epoch: u64,
#[cfg(tidesdb_has_single_writer_fencing)]
pub seen_epoch: u64,
// Added in TidesDB 9.3.4. This struct is stack-allocated by Rust before
// passing it to C, so the tail must match C exactly to avoid overwrites.
#[cfg(tidesdb_has_write_amp_stats)]
Expand Down
16 changes: 16 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1622,10 +1622,18 @@ mod tests {
let _ = stats.total_upload_failures;
let _ = stats.replica_mode;

// Single-writer fencing epochs should be accessible. On a local
// (non-object-store) database they are 0; on libraries older than
// 9.3.8 they are reported as 0 as well.
let _ = stats.primary_epoch;
let _ = stats.seen_epoch;

// For a non-unified, non-object-store db:
assert!(!stats.unified_memtable_enabled);
assert!(!stats.object_store_enabled);
assert!(!stats.replica_mode);
assert_eq!(stats.primary_epoch, 0);
assert_eq!(stats.seen_epoch, 0);
}

#[test]
Expand Down Expand Up @@ -1934,6 +1942,14 @@ mod tests {
assert_eq!(ErrorCode::Busy.to_string(), "resource is busy");
}

#[test]
fn test_error_code_precondition() {
// Verify the Precondition error code (-15) is recognized and rendered.
let code = ErrorCode::from_code(-15);
assert_eq!(code, Some(ErrorCode::Precondition));
assert_eq!(ErrorCode::Precondition.to_string(), "precondition not met");
}

#[test]
fn test_builtin_comparator_symbols_callable() {
// The built-in comparator C functions should be linkable and behave like memcmp.
Expand Down
6 changes: 6 additions & 0 deletions src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ pub struct DbStats {
pub total_upload_failures: u64,
/// Whether running in read-only replica mode
pub replica_mode: bool,
/// Single-writer fencing: lease epoch this primary currently holds (0 when not a
/// primary / no lease). Requires tidesdb >= 9.3.8; reported as 0 on older libraries.
pub primary_epoch: u64,
/// Single-writer fencing: highest lease epoch a replica has observed.
/// Requires tidesdb >= 9.3.8; reported as 0 on older libraries.
pub seen_epoch: u64,
/// Framed bytes appended to the shared unified WAL (0 if unified mode off).
/// Requires tidesdb >= 9.3.4; reported as 0 on older libraries.
pub uwal_bytes_written: u64,
Expand Down
Loading