aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2024-02-09 14:35:53 +0100
committerAlex Auvolat <alex@adnab.me>2024-02-09 14:35:53 +0100
commit8da67b3aa2614326e1981ffbb215691583e058f2 (patch)
treefcdd782509db15fe52156763f1bb912e9795bc6d /src
parent0c7ce001c907791518f93fd9d2db01eebc517c51 (diff)
downloadgarage-block-info-short-682.tar.gz
garage-block-info-short-682.zip
[block-info-short-682] `garage block info`: find blocks by prefix (fix #682)block-info-short-682
Diffstat (limited to 'src')
-rw-r--r--src/garage/admin/block.rs47
1 files changed, 45 insertions, 2 deletions
diff --git a/src/garage/admin/block.rs b/src/garage/admin/block.rs
index c4a45738..edeb88c0 100644
--- a/src/garage/admin/block.rs
+++ b/src/garage/admin/block.rs
@@ -25,8 +25,7 @@ impl AdminRpcHandler {
}
async fn handle_block_info(&self, hash: &String) -> Result<AdminRpc, Error> {
- let hash = hex::decode(hash).ok_or_bad_request("invalid hash")?;
- let hash = Hash::try_from(&hash).ok_or_bad_request("invalid hash")?;
+ let hash = self.find_block_hash_by_prefix(hash)?;
let refcount = self.garage.block_manager.get_block_rc(&hash)?;
let block_refs = self
.garage
@@ -189,4 +188,48 @@ impl AdminRpcHandler {
Ok(())
}
+
+ // ---- helper function ----
+ fn find_block_hash_by_prefix(&self, prefix: &str) -> Result<Hash, Error> {
+ if prefix.len() < 4 {
+ return Err(Error::BadRequest(
+ "Please specify at least 4 characters of the block hash".into(),
+ ));
+ }
+
+ let prefix_bin =
+ hex::decode(&prefix[..prefix.len() & !1]).ok_or_bad_request("invalid hash")?;
+
+ let iter = self
+ .garage
+ .block_ref_table
+ .data
+ .store
+ .range(&prefix_bin[..]..)
+ .map_err(GarageError::from)?;
+ let mut found = None;
+ for item in iter {
+ let (k, _v) = item.map_err(GarageError::from)?;
+ let hash = Hash::try_from(&k[..32]).unwrap();
+ if &hash.as_slice()[..prefix_bin.len()] != prefix_bin {
+ break;
+ }
+ if hex::encode(hash.as_slice()).starts_with(prefix) {
+ match &found {
+ Some(x) if *x == hash => (),
+ Some(_) => {
+ return Err(Error::BadRequest(format!(
+ "Several blocks match prefix `{}`",
+ prefix
+ )));
+ }
+ None => {
+ found = Some(hash);
+ }
+ }
+ }
+ }
+
+ found.ok_or_else(|| Error::BadRequest("No matching block found".into()))
+ }
}