Skip to content

Commit ecec362

Browse files
committed
feat(storage): add sync count, db size introspection, and Backpressure error
- Add `StorageEngineSync::count_sync` to count entries without async - Add `RedbStorage::db_size_bytes` for measuring encoded payload size across all tables; used by benchmarks to compute compression ratios - Cap scan pre-allocation at 1024 entries to avoid unbounded buffer growth when callers pass a large open-ended limit - Add `LiteError::Backpressure` variant for emit back-pressure signals
1 parent 065a7e1 commit ecec362

3 files changed

Lines changed: 36 additions & 1 deletion

File tree

nodedb-lite/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub enum LiteError {
2929

3030
#[error("Arrow type conversion: expected {expected}, got {got}")]
3131
ArrowTypeConversion { expected: String, got: String },
32+
33+
#[error("backpressure: {detail}")]
34+
Backpressure { detail: String },
3235
}
3336

3437
impl From<redb::Error> for LiteError {

nodedb-lite/src/storage/engine.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ pub trait StorageEngineSync: StorageEngine {
9797
start: &[u8],
9898
limit: usize,
9999
) -> Result<Vec<KvPair>, LiteError>;
100+
101+
/// Sync count: return the number of entries in a namespace.
102+
fn count_sync(&self, ns: Namespace) -> Result<u64, LiteError>;
100103
}
101104

102105
#[cfg(test)]

nodedb-lite/src/storage/redb_storage.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,29 @@ impl RedbStorage {
112112
}
113113
}
114114

115+
/// Total user-data bytes resident in the database (sum of key + value
116+
/// lengths across all tables). Excludes B-tree metadata and free pages.
117+
///
118+
/// Works for both file-backed and in-memory databases. Used by the
119+
/// benchmark suite to compute compression ratios — both the array
120+
/// engine and the document engine push their encoded payloads through
121+
/// the same redb mutator, so this number is the apples-to-apples
122+
/// "bytes the engine actually wrote" measurement.
123+
pub fn db_size_bytes(&self) -> Result<u64, LiteError> {
124+
let db = self.db.lock().map_err(|_| LiteError::LockPoisoned)?;
125+
// `stats()` lives on `WriteTransaction` in redb 2.x. We never commit
126+
// — the transaction is dropped (rolled back) immediately after the
127+
// read.
128+
let txn = db.begin_write().map_err(|e| LiteError::Storage {
129+
detail: format!("size write txn failed: {e}"),
130+
})?;
131+
let stats = txn.stats().map_err(|e| LiteError::Storage {
132+
detail: format!("stats failed: {e}"),
133+
})?;
134+
drop(txn);
135+
Ok(stats.stored_bytes())
136+
}
137+
115138
/// Build the composite key: `[namespace_u8, ...key_bytes]`.
116139
fn make_key(ns: Namespace, key: &[u8]) -> Vec<u8> {
117140
let mut k = Vec::with_capacity(1 + key.len());
@@ -375,7 +398,9 @@ impl RedbStorage {
375398
}
376399
};
377400

378-
let mut results = Vec::with_capacity(limit);
401+
// Cap pre-allocation at 1024 entries to avoid unbounded buffer growth
402+
// when callers pass a very large `limit` for an open-ended scan.
403+
let mut results = Vec::with_capacity(limit.min(1024));
379404
let range = table
380405
.range(start_key.as_slice()..)
381406
.map_err(|e| LiteError::Storage {
@@ -530,6 +555,10 @@ impl crate::storage::engine::StorageEngineSync for RedbStorage {
530555
) -> Result<Vec<super::engine::KvPair>, LiteError> {
531556
Self::scan_range_inner(&self.db, ns, start, limit)
532557
}
558+
559+
fn count_sync(&self, ns: Namespace) -> Result<u64, LiteError> {
560+
Self::count_inner(&self.db, ns)
561+
}
533562
}
534563

535564
#[cfg(test)]

0 commit comments

Comments
 (0)