From ea341e46cf316db8d5fb2781bb0157144e7ce80e Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Mon, 14 Sep 2026 20:38:28 +0800 Subject: [PATCH] =?UTF-8?q?fs:=20=E7=9B=AE=E5=BD=95=E5=88=97=E4=B8=BE?= =?UTF-8?q?=E7=BB=99=E8=A3=B8=E5=90=8D=EF=BC=9B=E7=9B=AE=E5=BD=95=20key=20?= =?UTF-8?q?=E7=9A=84=20get/get=5Fpart=20=E6=B4=BE=E7=94=9F=20index?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两处对齐 redis 后端(issue #250): 1. list 的成员前缀目录不再扁平展开 原来把 "string·" 展开为全部 "string·<成员>",父目录会列出所有后代, 递归遍历/重建(layout dump、walk_lib)再也对不上父子层级。 改为发射去 OBJ_SEP 的裸名 —— 与存储索引登记成员前缀节点的方式一致。 2. get_raw / get_part 对目录 key 派生 index XValue 目录 key 在 fs 没有落盘索引(FS 自身即索引),原先直接返回空 → head 读前缀拿到 nil。现在按需用 dir_value().encode() 再返回/切片, 与「目录 key get 返回容器 XValue」一致。 Closes #250 Co-Authored-By: Claude Code --- src/fs/kvspace.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/fs/kvspace.rs b/src/fs/kvspace.rs index 3b88964..104feab 100644 --- a/src/fs/kvspace.rs +++ b/src/fs/kvspace.rs @@ -269,11 +269,11 @@ impl FsKVSpace { // 成员目录内:obj 是完整 key,发射为 "init." children.push(fname); } else { - // 普通目录内:成员前缀目录("math.")扁平化展开为 "math.<成员>" - let sub_key = format!("{}{}/", dir_key, fname); - for sub in self.dir_children(&sub_key) { - children.push(format!("{}{}", fname, sub)); - } + // 普通目录内:成员前缀目录("string·")→ **裸成员名** "string"。 + // 对齐 redis 后端(存储索引把成员前缀节点登记为去 · 的裸名): + // 扁平展开会让父目录列出全部后代(如 "string·upper.src"), + // 递归遍历/重建(layout dump、walk_lib)就再也对不上父子层级。 + children.push(fname.trim_end_matches(OBJ_SEP).to_string()); } } else if e.path().is_dir() { children.push(format!("{}/", fname)); @@ -362,6 +362,14 @@ impl KVSpace for FsKVSpace { } fn get_raw(&mut self, key: &str) -> Vec { + // 目录 key 无落盘索引(FS 自身即索引):按需派生 index XValue 再返回, + // 对齐 redis 后端「目录 key get 返回容器 XValue」(issue #250)。 + if Self::is_dir_key(key) { + let resolved = self.resolve_path(key); + if Self::is_dir_key(&resolved) && self.fs_path(&resolved).is_dir() { + return self.dir_value(&resolved).encode(); + } + } let (mut p, l) = sep_path(key); if p != PATH_SEP { p.push_str(DIR_INDEX_SUF); @@ -382,6 +390,17 @@ impl KVSpace for FsKVSpace { } fn get_part(&mut self, key: &str, off: u32, len: u32) -> Vec { + // 目录 key:索引是派生物(FS 自身即索引),先在内存里拼出 index XValue 再切片, + // 否则 head 读前缀会拿到空(issue #250:fs 目录 key head → nil)。 + if Self::is_dir_key(key) { + let resolved = self.resolve_path(key); + if Self::is_dir_key(&resolved) && self.fs_path(&resolved).is_dir() { + let v = self.dir_value(&resolved).encode(); + let s = (off as usize).min(v.len()); + let e = (s + len as usize).min(v.len()); + return v[s..e].to_vec(); + } + } let Some(pf) = self.physical_file(key) else { return Vec::new(); };