diff options
author | Alex <alex@adnab.me> | 2024-02-09 14:07:29 +0000 |
---|---|---|
committer | Alex <alex@adnab.me> | 2024-02-09 14:07:29 +0000 |
commit | fe175fa8e2b7f8d2f719642b801d4ee101cb3289 (patch) | |
tree | 653c62511ea9f26d57efd0e7dac1556cfbae8d54 /src/garage | |
parent | 3865080c354427f913de6f2bb5e5b03f6231751c (diff) | |
parent | 8da67b3aa2614326e1981ffbb215691583e058f2 (diff) | |
download | garage-fe175fa8e2b7f8d2f719642b801d4ee101cb3289.tar.gz garage-fe175fa8e2b7f8d2f719642b801d4ee101cb3289.zip |
Merge pull request '`garage block info`: find blocks by prefix (fix #682)' (#712) from block-info-short-682 into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/712
Diffstat (limited to 'src/garage')
-rw-r--r-- | src/garage/admin/block.rs | 47 |
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())) + } } |