From 5b5588920585d7ccb2c3ed0f8d1bd3c740e5af71 Mon Sep 17 00:00:00 2001 From: meteorgan Date: Tue, 27 Aug 2024 21:37:17 +0800 Subject: [PATCH] fix(serivces/memory) blocking scan right range --- core/src/raw/path.rs | 2 +- core/src/services/memory/backend.rs | 43 +++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/core/src/raw/path.rs b/core/src/raw/path.rs index db4d047616c..fb3c4ad07ab 100644 --- a/core/src/raw/path.rs +++ b/core/src/raw/path.rs @@ -130,7 +130,7 @@ pub fn normalize_path(path: &str) -> String { /// - Add leading `/` if not starts with: `abc/` => `/abc/` /// - Add trailing `/` if not ends with: `/abc` => `/abc/` /// -/// Finally, we will got path like `/path/to/root/`. +/// Finally, we will get path like `/path/to/root/`. pub fn normalize_root(v: &str) -> String { let mut v = v .split('/') diff --git a/core/src/services/memory/backend.rs b/core/src/services/memory/backend.rs index a231bffdf2b..a9f10d779ad 100644 --- a/core/src/services/memory/backend.rs +++ b/core/src/services/memory/backend.rs @@ -125,18 +125,17 @@ impl typed_kv::Adapter for Adapter { fn blocking_scan(&self, path: &str) -> Result> { let inner = self.inner.lock().unwrap(); - let keys: Vec<_> = if path.is_empty() { - inner.keys().cloned().collect() - } else { - let right_range = if let Some(path) = path.strip_suffix('/') { - format!("{}0", path) - } else { - format!("{}{}", path, std::char::MAX) - }; - inner - .range(path.to_string()..right_range) - .map(|(k, _)| k.to_string()) - .collect() + + if path.is_empty() { + return Ok(inner.keys().cloned().collect()); + } + + let mut keys = Vec::new(); + for (key, _) in inner.range(path.to_string()..) { + if !key.starts_with(path) { + break; + } + keys.push(key.to_string()); }; Ok(keys) } @@ -144,6 +143,8 @@ impl typed_kv::Adapter for Adapter { #[cfg(test)] mod tests { + use crate::raw::adapters::typed_kv::{Adapter, Value}; + use crate::services::memory::backend; use super::*; #[test] @@ -154,4 +155,22 @@ mod tests { let b2 = MemoryBuilder::default().build().unwrap(); assert_ne!(b1.info().name(), b2.info().name()) } + + #[test] + fn test_blocking_scan() { + let adapter = backend::Adapter { inner: Arc::new(Mutex::new(BTreeMap::default())) }; + + adapter.blocking_set("aaa/bbb/", Value::new_dir()).unwrap(); + adapter.blocking_set("aab/bbb/", Value::new_dir()).unwrap(); + adapter.blocking_set("aab/ccc/", Value::new_dir()).unwrap(); + adapter.blocking_set(&format!("aab{}aaa/", std::char::MAX), Value::new_dir()).unwrap(); + adapter.blocking_set("aac/bbb/", Value::new_dir()).unwrap(); + + let data = adapter.blocking_scan("aab").unwrap(); + assert_eq!(data.len(), 3); + for path in data { + assert_eq!(path.starts_with("aab"), true); + } + } } +