diff --git a/src/block/manager.rs b/src/block/manager.rs index 41b2f02a..d1bf90d8 100644 --- a/src/block/manager.rs +++ b/src/block/manager.rs @@ -408,8 +408,8 @@ impl BlockManager { } /// Get number of items in the refcount table - pub fn rc_len(&self) -> Result { - Ok(self.rc.rc_table.len()?) + pub fn rc_approximate_len(&self) -> Result { + Ok(self.rc.rc_table.approximate_len()?) } /// Send command to start/stop/manager scrub worker @@ -427,7 +427,7 @@ impl BlockManager { /// List all resync errors pub fn list_resync_errors(&self) -> Result, Error> { - let mut blocks = Vec::with_capacity(self.resync.errors.len()?); + let mut blocks = Vec::with_capacity(self.resync.errors.approximate_len()?); for ent in self.resync.errors.iter()? { let (hash, cnt) = ent?; let cnt = ErrorCounter::decode(&cnt); diff --git a/src/block/metrics.rs b/src/block/metrics.rs index 2d41e365..c2ebb76b 100644 --- a/src/block/metrics.rs +++ b/src/block/metrics.rs @@ -50,7 +50,7 @@ impl BlockManagerMetrics { .init(), _rc_size: meter .u64_value_observer("block.rc_size", move |observer| { - if let Ok(value) = rc_tree.len() { + if let Ok(value) = rc_tree.approximate_len() { observer.observe(value as u64, &[]) } }) @@ -58,7 +58,7 @@ impl BlockManagerMetrics { .init(), _resync_queue_len: meter .u64_value_observer("block.resync_queue_length", move |observer| { - if let Ok(value) = resync_queue.len() { + if let Ok(value) = resync_queue.approximate_len() { observer.observe(value as u64, &[]); } }) @@ -68,7 +68,7 @@ impl BlockManagerMetrics { .init(), _resync_errored_blocks: meter .u64_value_observer("block.resync_errored_blocks", move |observer| { - if let Ok(value) = resync_errors.len() { + if let Ok(value) = resync_errors.approximate_len() { observer.observe(value as u64, &[]); } }) diff --git a/src/block/resync.rs b/src/block/resync.rs index b476a0b8..004f6b48 100644 --- a/src/block/resync.rs +++ b/src/block/resync.rs @@ -106,13 +106,13 @@ impl BlockResyncManager { } /// Get length of resync queue - pub fn queue_len(&self) -> Result { - Ok(self.queue.len()?) + pub fn queue_approximate_len(&self) -> Result { + Ok(self.queue.approximate_len()?) } /// Get number of blocks that have an error - pub fn errors_len(&self) -> Result { - Ok(self.errors.len()?) + pub fn errors_approximate_len(&self) -> Result { + Ok(self.errors.approximate_len()?) } /// Clear the error counter for a block and put it in queue immediately @@ -548,9 +548,11 @@ impl Worker for ResyncWorker { } WorkerStatus { - queue_length: Some(self.manager.resync.queue_len().unwrap_or(0) as u64), + queue_length: Some(self.manager.resync.queue_approximate_len().unwrap_or(0) as u64), tranquility: Some(tranquility), - persistent_errors: Some(self.manager.resync.errors_len().unwrap_or(0) as u64), + persistent_errors: Some( + self.manager.resync.errors_approximate_len().unwrap_or(0) as u64 + ), ..Default::default() } } diff --git a/src/db/fjall_adapter.rs b/src/db/fjall_adapter.rs index d91ef12f..d6a41e9e 100644 --- a/src/db/fjall_adapter.rs +++ b/src/db/fjall_adapter.rs @@ -132,10 +132,14 @@ impl IDb for FjallDb { } } - fn len(&self, tree_idx: usize) -> Result { + fn approximate_len(&self, tree_idx: usize) -> Result { + let tree = self.get_tree(tree_idx)?; + Ok(tree.approximate_len()) + } + fn is_empty(&self, tree_idx: usize) -> Result { let tree = self.get_tree(tree_idx)?; let tx = self.keyspace.read_tx(); - Ok(tx.len(&tree)?) + Ok(tx.is_empty(&tree)?) } fn insert(&self, tree_idx: usize, key: &[u8], value: &[u8]) -> Result<()> { diff --git a/src/db/lib.rs b/src/db/lib.rs index 3454c759..5ac16da8 100644 --- a/src/db/lib.rs +++ b/src/db/lib.rs @@ -154,7 +154,7 @@ impl Db { let tree_names = other.list_trees()?; for name in tree_names { let tree = self.open_tree(&name)?; - if tree.len()? > 0 { + if !tree.is_empty()? { return Err(Error(format!("tree {} already contains data", name).into())); } @@ -196,8 +196,12 @@ impl Tree { self.0.get(self.1, key.as_ref()) } #[inline] - pub fn len(&self) -> Result { - self.0.len(self.1) + pub fn approximate_len(&self) -> Result { + self.0.approximate_len(self.1) + } + #[inline] + pub fn is_empty(&self) -> Result { + self.0.is_empty(self.1) } #[inline] @@ -335,7 +339,8 @@ pub(crate) trait IDb: Send + Sync { fn snapshot(&self, path: &PathBuf) -> Result<()>; fn get(&self, tree: usize, key: &[u8]) -> Result>; - fn len(&self, tree: usize) -> Result; + fn approximate_len(&self, tree: usize) -> Result; + fn is_empty(&self, tree: usize) -> Result; fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()>; fn remove(&self, tree: usize, key: &[u8]) -> Result<()>; diff --git a/src/db/lmdb_adapter.rs b/src/db/lmdb_adapter.rs index bd85f1b4..cbbce2f8 100644 --- a/src/db/lmdb_adapter.rs +++ b/src/db/lmdb_adapter.rs @@ -126,11 +126,16 @@ impl IDb for LmdbDb { } } - fn len(&self, tree: usize) -> Result { + fn approximate_len(&self, tree: usize) -> Result { let tree = self.get_tree(tree)?; let tx = self.db.read_txn()?; Ok(tree.len(&tx)?.try_into().unwrap()) } + fn is_empty(&self, tree: usize) -> Result { + let tree = self.get_tree(tree)?; + let tx = self.db.read_txn()?; + Ok(tree.is_empty(&tx)?) + } fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> { let tree = self.get_tree(tree)?; diff --git a/src/db/sqlite_adapter.rs b/src/db/sqlite_adapter.rs index ce6412b6..eee8b15d 100644 --- a/src/db/sqlite_adapter.rs +++ b/src/db/sqlite_adapter.rs @@ -160,7 +160,7 @@ impl IDb for SqliteDb { self.internal_get(&self.db.get()?, &tree, key) } - fn len(&self, tree: usize) -> Result { + fn approximate_len(&self, tree: usize) -> Result { let tree = self.get_tree(tree)?; let db = self.db.get()?; @@ -172,6 +172,10 @@ impl IDb for SqliteDb { } } + fn is_empty(&self, tree: usize) -> Result { + Ok(self.approximate_len(tree)? == 0) + } + fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> { let tree = self.get_tree(tree)?; let db = self.db.get()?; diff --git a/src/db/test.rs b/src/db/test.rs index 08ce1dda..1e649719 100644 --- a/src/db/test.rs +++ b/src/db/test.rs @@ -14,7 +14,7 @@ fn test_suite(db: Db) { assert!(tree.insert(ka, va).is_ok()); assert_eq!(tree.get(ka).unwrap().unwrap(), va); - assert_eq!(tree.len().unwrap(), 1); + assert_eq!(tree.iter().unwrap().count(), 1); // ---- test transaction logic ---- diff --git a/src/garage/admin/mod.rs b/src/garage/admin/mod.rs index 3bbc2b86..6ae8fa88 100644 --- a/src/garage/admin/mod.rs +++ b/src/garage/admin/mod.rs @@ -219,7 +219,7 @@ impl AdminRpcHandler { // Gather block manager statistics writeln!(&mut ret, "\nBlock manager stats:").unwrap(); - let rc_len = self.garage.block_manager.rc_len()?.to_string(); + let rc_len = self.garage.block_manager.rc_approximate_len()?.to_string(); writeln!( &mut ret, @@ -230,13 +230,13 @@ impl AdminRpcHandler { writeln!( &mut ret, " resync queue length: {}", - self.garage.block_manager.resync.queue_len()? + self.garage.block_manager.resync.queue_approximate_len()? ) .unwrap(); writeln!( &mut ret, " blocks with resync errors: {}", - self.garage.block_manager.resync.errors_len()? + self.garage.block_manager.resync.errors_approximate_len()? ) .unwrap(); @@ -346,16 +346,21 @@ impl AdminRpcHandler { F: TableSchema + 'static, R: TableReplication + 'static, { - let data_len = t.data.store.len().map_err(GarageError::from)?.to_string(); - let mkl_len = t.merkle_updater.merkle_tree_len()?.to_string(); + let data_len = t + .data + .store + .approximate_len() + .map_err(GarageError::from)? + .to_string(); + let mkl_len = t.merkle_updater.merkle_tree_approximate_len()?.to_string(); Ok(format!( " {}\t{}\t{}\t{}\t{}", F::TABLE_NAME, data_len, mkl_len, - t.merkle_updater.todo_len()?, - t.data.gc_todo_len()? + t.merkle_updater.todo_approximate_len()?, + t.data.gc_todo_approximate_len()? )) } diff --git a/src/model/s3/lifecycle_worker.rs b/src/model/s3/lifecycle_worker.rs index bb10ba48..af00437e 100644 --- a/src/model/s3/lifecycle_worker.rs +++ b/src/model/s3/lifecycle_worker.rs @@ -121,13 +121,13 @@ impl Worker for LifecycleWorker { mpu_aborted, .. } => { - let n_objects = self.garage.object_table.data.store.len().ok(); + let n_objects = self.garage.object_table.data.store.approximate_len().ok(); let progress = match n_objects { - None => "...".to_string(), - Some(total) => format!( + Some(total) if total > 0 => format!( "~{:.2}%", 100. * std::cmp::min(*counter, total) as f32 / total as f32 ), + _ => "...".to_string(), }; WorkerStatus { progress: Some(progress), diff --git a/src/table/data.rs b/src/table/data.rs index 09f4e008..1d0308ce 100644 --- a/src/table/data.rs +++ b/src/table/data.rs @@ -367,7 +367,7 @@ impl TableData { } } - pub fn gc_todo_len(&self) -> Result { - Ok(self.gc_todo.len()?) + pub fn gc_todo_approximate_len(&self) -> Result { + Ok(self.gc_todo.approximate_len()?) } } diff --git a/src/table/gc.rs b/src/table/gc.rs index 28ea119d..1f30bd76 100644 --- a/src/table/gc.rs +++ b/src/table/gc.rs @@ -313,7 +313,7 @@ impl Worker for GcWorker { fn status(&self) -> WorkerStatus { WorkerStatus { - queue_length: Some(self.gc.data.gc_todo_len().unwrap_or(0) as u64), + queue_length: Some(self.gc.data.gc_todo_approximate_len().unwrap_or(0) as u64), ..Default::default() } } diff --git a/src/table/merkle.rs b/src/table/merkle.rs index 596d5805..7ba1f007 100644 --- a/src/table/merkle.rs +++ b/src/table/merkle.rs @@ -287,12 +287,12 @@ impl MerkleUpdater { MerkleNode::decode_opt(&ent) } - pub fn merkle_tree_len(&self) -> Result { - Ok(self.data.merkle_tree.len()?) + pub fn merkle_tree_approximate_len(&self) -> Result { + Ok(self.data.merkle_tree.approximate_len()?) } - pub fn todo_len(&self) -> Result { - Ok(self.data.merkle_todo.len()?) + pub fn todo_approximate_len(&self) -> Result { + Ok(self.data.merkle_todo.approximate_len()?) } } @@ -306,7 +306,7 @@ impl Worker for MerkleWorker { fn status(&self) -> WorkerStatus { WorkerStatus { - queue_length: Some(self.0.todo_len().unwrap_or(0) as u64), + queue_length: Some(self.0.todo_approximate_len().unwrap_or(0) as u64), ..Default::default() } } diff --git a/src/table/metrics.rs b/src/table/metrics.rs index 7bb0959a..78593202 100644 --- a/src/table/metrics.rs +++ b/src/table/metrics.rs @@ -34,7 +34,7 @@ impl TableMetrics { .u64_value_observer( "table.size", move |observer| { - if let Ok(value) = store.len() { + if let Ok(value) = store.approximate_len() { observer.observe( value as u64, &[KeyValue::new("table_name", table_name)], @@ -48,7 +48,7 @@ impl TableMetrics { .u64_value_observer( "table.merkle_tree_size", move |observer| { - if let Ok(value) = merkle_tree.len() { + if let Ok(value) = merkle_tree.approximate_len() { observer.observe( value as u64, &[KeyValue::new("table_name", table_name)], @@ -62,7 +62,7 @@ impl TableMetrics { .u64_value_observer( "table.merkle_updater_todo_queue_length", move |observer| { - if let Ok(v) = merkle_todo.len() { + if let Ok(v) = merkle_todo.approximate_len() { observer.observe( v as u64, &[KeyValue::new("table_name", table_name)], @@ -76,7 +76,7 @@ impl TableMetrics { .u64_value_observer( "table.gc_todo_queue_length", move |observer| { - if let Ok(value) = gc_todo.len() { + if let Ok(value) = gc_todo.approximate_len() { observer.observe( value as u64, &[KeyValue::new("table_name", table_name)], diff --git a/src/table/queue.rs b/src/table/queue.rs index ffe0a4a7..7ef1f16e 100644 --- a/src/table/queue.rs +++ b/src/table/queue.rs @@ -27,7 +27,7 @@ impl Worker for InsertQueueWorker { fn status(&self) -> WorkerStatus { WorkerStatus { - queue_length: Some(self.0.data.insert_queue.len().unwrap_or(0) as u64), + queue_length: Some(self.0.data.insert_queue.approximate_len().unwrap_or(0) as u64), ..Default::default() } }