Skip to content

Commit 9d79bef

Browse files
committed
feat(slayerfs): implement trie-based path cache with unified inode cache
1 parent 4a631f0 commit 9d79bef

File tree

13 files changed

+2107
-346
lines changed

13 files changed

+2107
-346
lines changed

project/Cargo.lock

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

project/slayerfs/.env

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# AWS S3 Configuration
2-
AWS_ACCESS_KEY_ID=rustfsadmin
3-
AWS_SECRET_ACCESS_KEY=rustfsadmin
2+
AWS_ACCESS_KEY_ID=minioadmin
3+
AWS_SECRET_ACCESS_KEY=minioadmin
44
AWS_REGION=us-east-1
55
AWS_DEFAULT_REGION=us-east-1
66
AWS_ALLOW_HTTP=true

project/slayerfs/BUCK

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ rust_binary(
2424
visibility = ["PUBLIC"],
2525
deps = [
2626
"//third-party/rust/crates/anyhow/1.0.100:anyhow",
27+
"//third-party/rust/crates/async-recursion/1.1.1:async-recursion",
2728
"//third-party/rust/crates/async-trait/0.1.89:async-trait",
2829
"//third-party/rust/crates/auto_impl/1.3.0:auto_impl",
2930
"//third-party/rust/crates/aws-config/1.8.8:aws-config",
@@ -33,14 +34,14 @@ rust_binary(
3334
"//third-party/rust/crates/bytes/1.10.1:bytes",
3435
"//third-party/rust/crates/chrono/0.4.42:chrono",
3536
"//third-party/rust/crates/clap/4.5.48:clap",
37+
"//third-party/rust/crates/dashmap/6.1.0:dashmap",
3638
"//third-party/rust/crates/dirs/6.0.0:dirs",
3739
"//third-party/rust/crates/dotenv/0.15.0:dotenv",
3840
"//third-party/rust/crates/env_logger/0.10.2:env_logger",
3941
"//third-party/rust/crates/etcd-client/0.17.0:etcd-client",
4042
"//third-party/rust/crates/futures-util/0.3.31:futures-util",
4143
"//third-party/rust/crates/futures/0.3.31:futures",
4244
"//third-party/rust/crates/hex/0.4.3:hex",
43-
"//third-party/rust/crates/http/1.3.1:http",
4445
"//third-party/rust/crates/libc/0.2.177:libc",
4546
"//third-party/rust/crates/log/0.4.28:log",
4647
"//third-party/rust/crates/md5/0.7.0:md5",
@@ -68,6 +69,7 @@ rust_library(
6869
visibility = ["PUBLIC"],
6970
deps = [
7071
"//third-party/rust/crates/anyhow/1.0.100:anyhow",
72+
"//third-party/rust/crates/async-recursion/1.1.1:async-recursion",
7173
"//third-party/rust/crates/async-trait/0.1.89:async-trait",
7274
"//third-party/rust/crates/auto_impl/1.3.0:auto_impl",
7375
"//third-party/rust/crates/aws-config/1.8.8:aws-config",
@@ -77,14 +79,14 @@ rust_library(
7779
"//third-party/rust/crates/bytes/1.10.1:bytes",
7880
"//third-party/rust/crates/chrono/0.4.42:chrono",
7981
"//third-party/rust/crates/clap/4.5.48:clap",
82+
"//third-party/rust/crates/dashmap/6.1.0:dashmap",
8083
"//third-party/rust/crates/dirs/6.0.0:dirs",
8184
"//third-party/rust/crates/dotenv/0.15.0:dotenv",
8285
"//third-party/rust/crates/env_logger/0.10.2:env_logger",
8386
"//third-party/rust/crates/etcd-client/0.17.0:etcd-client",
8487
"//third-party/rust/crates/futures-util/0.3.31:futures-util",
8588
"//third-party/rust/crates/futures/0.3.31:futures",
8689
"//third-party/rust/crates/hex/0.4.3:hex",
87-
"//third-party/rust/crates/http/1.3.1:http",
8890
"//third-party/rust/crates/libc/0.2.177:libc",
8991
"//third-party/rust/crates/log/0.4.28:log",
9092
"//third-party/rust/crates/md5/0.7.0:md5",

project/slayerfs/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ repository = "https://github.com/r2cn-dev/rk8s/tree/main/project/slayerfs"
99
[dependencies]
1010
tokio = { version = "1", features = ["fs", "io-util", "macros", "rt", "time", "net"] }
1111
async-trait = "0.1"
12+
async-recursion = "1.0"
1213
aws-config = { version = "1" }
1314
aws-sdk-s3 = { version = "1", features = ["behavior-version-latest"] }
1415
base64 = "0.21"
@@ -20,6 +21,7 @@ libc = "0.2.175"
2021
bytes = "1"
2122
hex = "0.4"
2223
moka = { version = "0.12", features = ["future"] }
24+
dashmap = "6.1"
2325
dirs = "6"
2426
sha2 = "0.10"
2527
anyhow = "1.0.100"

project/slayerfs/doc/meta.md

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ database:
7373
- **依赖注入**:VFS 构造函数接受 `MetaStore` 实例,解耦具体实现
7474
- **持久化操作**:写操作(如 `mkdir_p`、`create_file`)会持久化至后端
7575
- **延迟加载**:`readdir` 按需加载目录内容
76-
- **缓存集成**:内存 `Namespace` 作为直写缓存层
7776

7877
### 工具与示例
7978

@@ -89,6 +88,47 @@ database:
8988
cargo run --example persistence_demo -- --config config.yaml
9089
```
9190

91+
### 元数据缓存实现
92+
93+
​ `MetaClient`作为元数据客户端代理,实现了一个高性能、高并发、支持 TTL/LRU 策略的元数据缓存层,旨在加速底层元数据存储(MetaStore)的访问性能。其核心设计目标是提供快速的路径解析、Inode 属性查询和目录列表读取,同时通过一套高效的缓存失效机制来保证数据的一致性。
94+
95+
#### 2. 核心架构
96+
97+
缓存系统采用分层、多策略的复合架构,主要由以下三个核心组件构成:
98+
99+
- **Inode 缓存 (InodeCache):** 负责缓存文件和目录的元数据属性(FileAttr)、父子关系及目录内容。
100+
- **路径解析缓存 (Path Cache & PathTrie):** 负责缓存从绝对路径到 Inode 编号的映射关系。
101+
- **缓存失效机制:** 一套基于前缀树和反向索引的精确、高效的缓存失效策略。
102+
103+
#### 3. 关键组件详解
104+
105+
**3.1. Inode 缓存 (InodeCache)**
106+
107+
- **双层存储模型:** 采用 `Moka Cache` 和 `DashMap` 结合的双层设计。
108+
- **Moka:** 作为生命周期管理器,负责实现基于 TTL(存活时间)和 LRU(最近最少使用)的缓存淘汰策略。
109+
- **DashMap:** 作为主存储,提供对` InodeEntry `的高并发、分片锁读写访问,允许在不影响 Moka 内部结构的情况下对缓存项进行原地修改。
110+
- **状态化目录内容 (ChildrenState):** 通过` NotLoaded`、`Partial`、`Complete` 三种状态精确追踪目录内容的缓存状态,确保了只有从后端完整加载过的目录(Complete 状态)才会被用于响应 readdir 请求,有效避免了数据不完整问题。
111+
- **数据结构:** `InodeEntry` 封装了单个 Inode 的所有缓存信息,包括属性 (attr)、父节点指针 (parent) 和子节点列表 (children),均采用 Arc<RwLock<T>> 进行并发保护。
112+
113+
**3.2. 路径解析缓存**
114+
115+
为实现高效的路径解析和失效,系统同时使用了两种数据结构:
116+
117+
- **直接路径缓存 (path_cache):** 一个基于 Moka 的 K-V 缓存,用于存储完整路径字符串到 Inode 编号的直接映射。它为已解析路径提供了 O(1) 的访问速度。
118+
- **路径前缀树 (PathTrie):** 一个专用于路径管理的前缀树.结构的核心优势在于支持**前缀匹配失效**。当一个目录被修改时(如重命名或删除),可以 O(depth) 的复杂度移除整个子树对应的所有路径缓存,相比于遍历扁平化缓存(O(N)),效率极高。
119+
120+
**3.3. 缓存失效策略**
121+
122+
缓存失效是保证数据一致性的关键。本系统设计了一套精准、高效的失效流程:
123+
124+
1. **反向索引 (inode_to_paths):** 维护一个从 Inode 到其所有路径的 DashMap 映射,可在 O(1) 时间内定位到特定 Inode 对应的所有路径。
125+
2. **级联失效:** 当目录发生写操作时,触发 `invalidate_parent_path` 函数。
126+
3. **执行流程:**
127+
a. 使用**反向索引**找到被修改目录的所有路径。
128+
b. 对每个路径,调用 **PathTrie::remove_by_prefix** 方法,原子性地移除该路径及其所有子孙路径。
129+
c. remove_by_prefix 返回所有被移除的路径-Inode 对。
130+
d. 遍历这些被移除的条目,从**直接路径缓存 (path_cache)** 和**反向索引 (inode_to_paths)** 中清理对应的数据,从而完成整个级联失效过程。
131+
92132
## TODO:
93133

94134
### 高优先级(P0)
@@ -121,21 +161,14 @@ database:
121161
cache:
122162
enabled: true
123163
124-
# Cache capacity (number of entries)
125164
capacity:
126-
attr: 10000 # File attributes cache
127-
dentry: 10000 # Directory entry cache
165+
inode: 10000 # Inode metadata cache (includes attr, children, parent)
128166
path: 5000 # Path resolution cache
129-
inode_to_path: 5000 # Reverse path cache
130-
readdir: 1000 # Directory content cache
131167
132168
# Cache TTL (in seconds, supports decimal values)
133169
ttl:
134-
attr_ttl: 10.0 # 10 seconds
135-
dentry_ttl: 8.0 # 8 seconds
136-
path_ttl: 10.0 # 10 seconds
137-
inode_to_path_ttl: 10.0
138-
readdir_ttl: 5.0 # 5 seconds (directory content cache)
170+
inode_ttl: 10.0 # 10 seconds for inode metadata
171+
path_ttl: 10.0 # 10 seconds for path resolution
139172
140173
```
141174

@@ -156,23 +189,16 @@ database:
156189
cache:
157190
enabled: true
158191
159-
# Cache capacity (number of entries)
160192
capacity:
161-
attr: 10000 # File attributes cache
162-
dentry: 10000 # Directory entry cache
193+
inode: 10000 # Inode metadata cache (includes attr, children, parent)
163194
path: 5000 # Path resolution cache
164-
inode_to_path: 5000 # Reverse path cache
165-
readdir: 1000 # Directory content cache
166195
167196
# Cache TTL (in seconds, supports decimal values)
168197
ttl:
169-
attr_ttl: 10.0 # 10 seconds
170-
dentry_ttl: 8.0 # 8 seconds
171-
path_ttl: 10.0 # 10 seconds
172-
inode_to_path_ttl: 10.0
173-
readdir_ttl: 5.0 # 5 seconds (directory content cache)
198+
inode_ttl: 10.0 # 10 seconds for inode metadata
199+
path_ttl: 10.0 # 10 seconds for path resolution
174200
```
175201

176-
目前,本地数据库模式下,在挂载后的文件夹中,可以正常操作文件夹,包括重命名,删除,读写文件之类的操作。
202+
目前,本地数据库模式下,在挂载后的文件夹中,可以正常操作文件夹,包括重命名,删除,读写文件之类的操作。
177203

178204
运行scripts/cache_demo.sh 后可以在log中看到关于缓存命中、加入、移除等信息

project/slayerfs/examples/persistence_s3_demo.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use slayerfs::meta::factory::MetaStoreFactory;
88
use slayerfs::vfs::fs::VFS;
99
use std::path::PathBuf;
1010
use tokio::signal;
11+
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
1112

1213
#[derive(Parser)]
1314
#[command(author, version, about, long_about = None)]
@@ -81,8 +82,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
8182
// 加载 .env 文件
8283
dotenv::dotenv().ok();
8384

84-
let format = tracing_subscriber::fmt::format().with_ansi(false);
85-
tracing_subscriber::fmt().event_format(format).init();
85+
let filter = tracing_subscriber::EnvFilter::try_from_default_env()
86+
.or_else(|_| tracing_subscriber::EnvFilter::try_new("info"))
87+
.unwrap();
88+
89+
tracing_subscriber::registry()
90+
.with(tracing_subscriber::fmt::layer().with_ansi(true))
91+
.with(filter)
92+
.init();
8693

8794
#[cfg(not(target_os = "linux"))]
8895
{
Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
1+
# SQLite backend with custom cache configuration
2+
13
database:
24
type: sqlite
3-
url: "sqlite://metadata.db?mode=rwc"
5+
url: "sqlite:///tmp/slayerfs/metadata.db"
46

57
cache:
68
enabled: true
79

8-
# Cache capacity (number of entries)
910
capacity:
10-
attr: 10000 # File attributes cache
11-
dentry: 10000 # Directory entry cache
11+
inode: 10000 # Inode metadata cache (includes attr, children, parent)
1212
path: 5000 # Path resolution cache
13-
inode_to_path: 5000 # Reverse path cache
14-
readdir: 1000 # Directory content cache
1513

1614
# Cache TTL (in seconds, supports decimal values)
1715
ttl:
18-
attr_ttl: 10.0 # 10 seconds
19-
dentry_ttl: 8.0 # 8 seconds
20-
path_ttl: 10.0 # 10 seconds
21-
inode_to_path_ttl: 10.0
22-
readdir_ttl: 5.0 # 5 seconds (directory content cache)
16+
inode_ttl: 10.0 # 10 seconds for inode metadata
17+
path_ttl: 10.0 # 10 seconds for path resolution
18+

0 commit comments

Comments
 (0)