oxcache 0.5.0-rc.2

A high-performance multi-level cache library for Rust with L1 (memory) and L2 (Redis) caching.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
<div align="center">

<img src="docs/assets/oxcache.png" alt="Oxcache Logo" width="200">

[![CI Status](https://github.com/Kirky-X/oxcache/actions/workflows/ci.yml/badge.svg)](https://github.com/Kirky-X/oxcache/actions/workflows/ci.yml) [![Version](https://img.shields.io/crates/v/oxcache.svg)](https://crates.io/crates/oxcache) [![Docs.rs](https://docs.rs/oxcache/badge.svg)](https://docs.rs/oxcache) [![Downloads](https://img.shields.io/crates/d/oxcache.svg)](https://crates.io/crates/oxcache) [![License](https://img.shields.io/crates/l/oxcache.svg)](LICENSE) [![Rust](https://img.shields.io/badge/rust-1.97.1%2B-orange.svg)](https://www.rust-lang.org/) [![Coverage](https://codecov.io/gh/Kirky-X/oxcache/branch/main/graph/badge.svg)](https://codecov.io/gh/Kirky-X/oxcache)

**中文** | [English](README_EN.md)

**高性能、生产级的 Rust 多后端缓存库,支持 L1(Moka/DashMap 内存缓存)+ L2(Redis / Valkey / Dragonfly / Aerospike)多层架构。**

[✨ 功能特性](#-功能特性) • [🚀 快速开始](#-快速开始) • [📚 文档](#-文档) • [💻 示例](#-示例) • [🤝 参与贡献](#-参与贡献)

</div>

---

## 📋 目录

<details open>
<summary>📑 目录(点击折叠 / 展开)</summary>

- [✨ 功能特性](#-功能特性)
- [🚀 快速开始](#-快速开始)
  - [📦 安装](#-安装)
  - [💡 基本用法](#-基本用法)
  - [🧱 Builder API](#-builder-api)
- [🎨 特性标志](#-特性标志)
- [📚 文档](#-文档)
- [💻 示例](#-示例)
- [🏗️ 架构](#️-架构)
- [🎯 使用场景](#-使用场景)
- [🔄 同步 API](#-同步-api)
- [🌸 布隆过滤器](#-布隆过滤器)
- [⏱️ TTL 行为对照表](#️-ttl-行为对照表)
- [🧪 测试](#-测试)
- [📊 性能](#-性能)
- [🔒 安全](#-安全)
- [🗺️ 开发路线图](#️-开发路线图)
- [🤝 参与贡献](#-参与贡献)
- [📋 更新日志](#-更新日志)
- [📄 许可证](#-许可证)
- [🙏 致谢](#-致谢)
- [📞 联系与支持](#-联系与支持)
- [⭐ Star 历史](#-star-历史)

</details>

---

## ✨ 功能特性

- **极致性能**: L1 纳秒级响应(P99 < 100ns),L2 毫秒级响应(P99 < 5ms)
- **零侵入式**: 通过 `#[cached]` 宏一行代码启用缓存
- **自动故障恢复**: Redis 故障时自动降级到 L1 缓存
- **批量优化**: 智能批量写入,大幅提升吞吐量
- **同步 API**: 在异步 API 之外提供同步路径 `get_sync` / `set_sync` / `get_or_sync`,在 `multi_thread` tokio 上无需运行时
- **布隆过滤器**: 可选的 `BloomFilterBackend` 装饰器以 O(1) 成本过滤负查询,跳过 inner 后端
- **全局 per-entry TTL**: 所有后端(Moka / DashMap / Redis / Valkey / Dragonfly / Aerospike / Mock / Chain / Bloom)都遵守 per-entry `set(key, value, Some(ttl))`
- **生产级可靠**: 完整的可观测性、健康检查、混沌测试验证

---

## 🚀 快速开始

### 📦 安装

在 `Cargo.toml` 中添加依赖:

```toml
[dependencies]
oxcache = "0.5.0-rc.2"
```

> **注意**:`tokio` 和 `serde` 已默认包含。如果需要最小依赖,可以使用
> `oxcache = { version = "0.5.0-rc.2", default-features = false }` 手动添加。

> **特性**:要使用 `#[cached]` 宏,需要启用 `macros` 特性:`oxcache = { version = "0.5.0-rc.2", features = ["macros"] }`

### 💡 基本用法

```rust
use oxcache::cached;
use oxcache::{Cache, CacheBuilder};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone, Debug)]
struct User {
    id: u64,
    name: String,
}

// 一行代码启用缓存
#[cached(service = "user_cache", ttl = 600)]
async fn get_user(id: u64) -> Result<User, String> {
    // 模拟耗时的数据库查询
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
    Ok(User {
        id,
        name: format!("User {}", id),
    })
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 使用 Builder 模式初始化缓存(默认:Moka L1 内存后端)
    let cache: Cache<String, User> = Cache::builder()
        .capacity(10000)
        .ttl(std::time::Duration::from_secs(600))
        .build()
        .await?;

    // 注册缓存实例供宏使用
    cache.register_for_macro("user_cache").await;

    // 第一次调用:执行函数逻辑 + 缓存结果(~100ms)
    let user = get_user(1).await?;
    println!("First call: {:?}", user);

    // 第二次调用:直接从缓存返回(~0.1ms)
    let cached_user = get_user(1).await?;
    println!("Cached call: {:?}", cached_user);

    Ok(())
}
```

### 🧱 Builder API

Oxcache 提供类型安全的构建器 API 用于配置缓存。以下是可用的构建器方法:

| 方法 | 描述 |
|--------|------|
| `Cache::builder()` | 创建新的缓存构建器 |
| `.ttl(Duration)` | 设置缓存条目的默认 TTL |
| `.tti(Duration)` | 设置缓存条目的默认 TTI(time-to-idle) |
| `.capacity(u64)` | 设置内存缓存容量 |
| `.backend_arc(Arc<dyn CacheBackend>)` | 添加预构建后端(如 `RedisBackend`、`MokaMemoryBackend`) |
| `.sync_mode(bool)` | 启用同步 API 支持(`get_sync`/`set_sync`/...) |
| `.build()` | 构建 `Cache<K, V>` 实例(异步,内部无 await) |
| `.build_sync()` | 同步构建 `Cache<K, V>` 实例(无需运行时) |

> **注意:** Redis 后端请使用 `RedisBackend::new(url).await?` 然后通过 `.backend_arc(Arc::new(backend))` 传入。
> 分层缓存(L1+L2)请使用 `ChainCache::builder().link(...).build()`。

---

## 🎨 特性标志

### 🧱 特性分层

```toml
# 完整特性(推荐)
oxcache = { version = "0.5.0-rc.2", features = ["full"] }

# 核心功能(L1 + L2 缓存)
oxcache = { version = "0.5.0-rc.2", features = ["core"] }

# 最小特性(仅 L1 缓存)
oxcache = { version = "0.5.0-rc.2", features = ["minimal"] }

# 自定义选择
oxcache = { version = "0.5.0-rc.2", features = ["core", "macros", "metrics", "bloom"] }
```

### 📦 可用特性

| 层级 | 包含特性 | 描述 |
|------|----------|------|
| **minimal** | `memory`, `tokio/time`, `metrics`, `serialization`, `chrono` | 仅 L1 缓存 |
| **core** | `minimal` + `redis` | L1 + L2 缓存 |
| **full** | `core` + `macros`, `compression`, `batch`, `lua`, `cli`, `testing`, `dragonfly`, `aerospike`, `lock` | 完整功能 |

**独立特性**:
- `memory` - L1 缓存后端(Moka + DashMap)
- `redis` - L2 分布式缓存(Redis / Valkey)
- `dragonfly` - Dragonfly 缓存后端(Redis 协议兼容)
- `aerospike` - Aerospike 缓存后端(独立协议)
- `macros` - `#[cached]` 属性宏
- `serialization` - JSON 序列化(serde + serde_json)
- `compression` - 数据压缩(flate2)
- `metrics` - 内置性能指标(延迟直方图、操作计数、JSON 导出);如需 OTLP 导出由应用层处理
- `batch` - 优化的批量写入
- `lua` - Lua 脚本执行支持
- `cli` - 命令行界面工具
- `i18n` - 错误消息国际化 + 系统语言自动检测
- `bloom` - 负查询过滤(BloomFilter + BloomFilterBackend);不在 `full` 中,需显式启用
- `kit` - trait-kit AsyncKit 集成(OxcacheModule + 健康检查 + 生命周期 + 构建观察者 + 三阶段关闭 + 装饰器);不在 `full` 中,需显式启用
- `testing` - Testing utilities

---

## 📚 文档

| 文档 | 说明 |
|------|------|
| [📖 用户指南](docs/USER_GUIDE.md) | 从安装到进阶的完整使用教程 |
| [📘 API 参考](docs/API_REFERENCE.md) | 全部公开 API 的详细说明 |
| [🏗️ 架构文档](docs/ARCHITECTURE.md) | 设计理念与内部实现 |
| [🔒 安全文档](docs/SECURITY.md) | 安全设计与最佳实践 |
| [📋 更新日志](docs/CHANGELOG.md) | 每个版本的变更记录 |
| [🤝 贡献指南](docs/CONTRIBUTING.md) | 如何参与项目开发 |
| [📦 在线 API 文档](https://docs.rs/oxcache) | docs.rs 自动生成的最新文档 |

---

## 💻 示例

`examples/` 目录(workspace 成员 `oxcache-examples`,已设为 `publish = false`)包含 37 个可运行示例:

```bash
# 运行单个示例(在 examples/ 目录下)
cd examples && cargo run --example example_basic_operations

# 列出所有可用示例
cd examples && ls src/*/*.rs
```

### 🌱 入门(`examples/src/01_basics`)

| 示例 | 说明 |
|------|------|
| `example_basic_operations` | 基本 CRUD 操作(`get`/`set`/`delete`/`exists`) |
| `example_new_api` | 现代 API 入门(`Cache::builder()` / `Cache::memory()`) |
| `example_cache_builder` | CacheBuilder 配置(`capacity` / `ttl` / `tti` / `sync_mode`) |
| `example_serialization` | JSON 序列化 |
| `example_cache_key` | 自定义缓存键(`CacheKey` trait) |
| `example_cached_macro` | `#[cached]` 宏(`service` / `ttl` / `key_prefix`) |
| `example_explicit_init` | 显式初始化(`Cache::new()` / 全局缓存) |
| `example_get_or` | 缓存未命中时计算(`get_or`,single-flight) |
| `example_sync_api` | 同步 API(`get_sync` / `set_sync` / `clear_sync` / `len_sync`) |
| `example_byte_ops` | 字节级操作(`get_bytes` / `set_bytes` / `len` / `capacity` / `shutdown`) |
| `example_comprehensive_usage` | 综合使用(全部功能概览) |

### 🚀 进阶(`examples/src/02_advanced`)

| 示例 | 说明 |
|------|------|
| `example_batch_write` | 批量操作(`set_many` / `get_many` / `delete_many`) |
| `example_chain_cache` | 链式缓存(`ChainCache` / `ChainLink`) |
| `example_invalidation` | 缓存失效策略(TTL / TTI / 手动失效) |
| `example_warmup` | 缓存预热(批量预加载) |
| `example_smart_strategy` | 缓存策略模式(Cache-Aside / Lazy Loading / TTL 分层) |
| `example_cache_promotion` | 缓存提升(L2→L1 提升 / 热点分析) |
| `example_error_handling` | 错误处理(`OxCacheError` / 重试 / 可恢复性) |
| `example_custom_backend` | 自定义后端(`CacheReader` / `CacheWriter` / `CacheConnector`) |
| `example_dashmap_backend` | DashMap 后端(`DashMapMemoryBackend`) |
| `example_moka_ttl` | Moka per-entry TTL(`Expiry` trait) |
| `example_redis_native` | Redis 原生操作(`RedisBackend`,需 Redis) |
| `example_redis_modes` | Redis 部署模式(Standalone / Cluster / Sentinel,需 Redis) |
| `example_redis_pipeline` | Pipeline 批量(`set_many_pipeline` / `get_many_pipeline`,需 Redis) |
| `example_lua_script` | Lua 脚本执行(`eval_lua` / `script_load` / `eval_sha`,需 Redis) |

### ⚙️ 配置(`examples/src/03_config`)

| 示例 | 说明 |
|------|------|
| `example_dynamic_config` | 动态配置(运行时配置变更) |
| `example_key_generator` | Key 生成器(`KeyGenerator`) |

### 🗄️ 数据库集成(`examples/src/05_database`)

| 示例 | 说明 |
|------|------|
| `example_database_integration` | 数据库集成(Cache-Aside 模式) |

### 🧩 特性展示(`examples/src/06_features`)

| 示例 | 说明 |
|------|------|
| `example_metrics` | 指标导出(`export_json_format` / `export_prometheus_format`) |
| `example_compression` | 数据压缩(`JsonSerializer::with_compression()`) |
| `example_security` | 安全脱敏(`redact_value` / `redact_connection_string`) |
| `example_security_validation` | 安全验证(`validate_redis_key` / `validate_lua_script`) |
| `example_bloom_filter` | 布隆过滤器(`BloomFilter` / `BloomFilterBackend`) |
| `example_i18n` | 国际化(`CacheI18nFormatter`) |
| `example_events` | 事件系统(`CacheEvent` / `CacheEventType`) |
| `example_cli_usage` | CLI 使用(命令行工具) |
| `example_kit_integration` | trait-kit AsyncKit 集成(OxcacheModule / 健康检查 / 生命周期 / 构建观察者 / 三阶段关闭 / 装饰器) |

> **注意**:标注"需 Redis"的示例需要运行中的 Redis 6.0+ 服务;其余示例使用内存后端,可独立运行。

---

## 🏗️ 架构

```mermaid
graph TD
    A["Application Code<br/>#[cached] Macro"] --> B["Cache&lt;K, V&gt;<br/>统一缓存接口"]

    B --> C[ChainCache<br/>分层后端]
    B --> D[MokaMemoryBackend<br/>仅 L1]
    B --> E[RedisBackend<br/>仅 L2]

    C --> F[L1 Cache<br/>Moka]
    C --> G[L2 Cache<br/>Redis]

    D --> F
    E --> G

    style A fill:#e1f5fe
    style B fill:#f3e5f5
    style C fill:#e8f5e8
    style D fill:#fff3e0
    style E fill:#fce4ec
    style F fill:#f1f8e9
    style G fill:#fdf2e9
```

**L1**: 进程内高速缓存,使用 LRU/TinyLFU 淘汰策略
**L2**: 分布式共享缓存,支持 Sentinel/Cluster 模式

**可靠性能力**:

- [x] 单次请求去重 (Single-Flight)
- [x] Redis 故障自动降级
- [x] 优雅关闭机制
- [x] 健康检查与自动恢复

更详细的设计理念、模块划分与数据流请参阅 [架构文档](docs/ARCHITECTURE.md)。

---

## 🎯 使用场景

### 👤 场景 1: 用户信息缓存

```rust
#[cached(service = "user_cache", ttl = 600)]
async fn get_user_profile(user_id: u64) -> Result<UserProfile, Error> {
    database::query_user(user_id).await
}
```

### 🌐 场景 2: API 响应缓存

```rust
#[cached(
    service = "api_cache",
    ttl = 300,
    key = "api_{endpoint}_{version}"
)]
async fn fetch_api_data(endpoint: String, version: u32) -> Result<ApiResponse, Error> {
    http_client::get(&format!("/api/{}/{}", endpoint, version)).await
}
```

### ⚡ 场景 3: 仅 L1 热数据缓存

```rust
#[cached(service = "session_cache", ttl = 60)]
async fn get_user_session(session_id: String) -> Result<Session, Error> {
    session_store::load(session_id).await
}
```

### 🛠️ 场景 4: 手动控制缓存

```rust
use oxcache::{Cache, CacheBuilder};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct MyData {
    field: String,
}

async fn advanced_caching() -> Result<(), Box<dyn std::error::Error>> {
    // 使用 Builder 模式初始化缓存(默认:Moka L1 内存后端)
    let cache: Cache<String, MyData> = Cache::builder()
        .capacity(10000)
        .build()
        .await?;

    let my_data = MyData {
        field: "value".to_string(),
    };

    // 标准操作
    cache.set(&"key".to_string(), &my_data).await?;

    let data: Option<MyData> = cache.get(&"key".to_string()).await?;
    println!("Data: {:?}", data);

    // 删除
    cache.delete(&"key".to_string()).await?;

    Ok(())
}
```

---

## 🔄 同步 API

Oxcache 0.3.0 在异步 API 之外引入了**同步 API 路径**。在 builder 上启用:

```rust
use oxcache::Cache;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
struct User { id: u64, name: String }

#[tokio::main(flavor = "multi_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // sync_mode(true) 使 Cache<K,V> 同时持有 Arc<dyn SyncCacheBackend>
    let cache: Cache<String, User> = Cache::builder().sync_mode(true).build().await?;

    // 同步操作(无 .await)
    cache.set_sync(&"user:1".to_string(), &User { id: 1, name: "Alice".into() })?;
    let cached = cache.get_sync(&"user:1".to_string())?;
    assert_eq!(cached, Some(User { id: 1, name: "Alice".into() }));

    // per-entry TTL
    cache.set_with_ttl_sync(&"temp".to_string(), &User { id: 2, name: "Temp".into() }, Some(std::time::Duration::from_secs(60)))?;

    // 单飞 get_or_sync:并发调用共享一次 fallback 执行
    let value = cache.get_or_sync(&"user:42".to_string(), || {
        Ok(User { id: 42, name: "Bob".into() })
    })?;

    // sync 与 async API 在同一 Cache<K,V> 上共存
    cache.set(&"async_key".to_string(), &User { id: 99, name: "Async".into() }).await?;
    let v = cache.get_sync(&"async_key".to_string())?;
    Ok(())
}
```

**何时使用同步 API**:
- 阻塞调用点(遗留代码、FFI、同步处理器)
- 不想在每个断言中穿过 `async` 的测试
- 调用方本身是同步的,避免运行时开销

**运行时注意事项**:
- `sync_mode(true)` 在 `multi_thread` tokio 运行时上工作。在 `current_thread` 运行时上,Moka 的 `sync_block_on` 会 panic(使用 `#[tokio::main(flavor = "multi_thread")]` 或在运行时上下文之外调用)。
- 不启用 `sync_mode(true)` 时,调用任何 `*_sync` 方法返回 `Err(OxCacheError::NotSupported)`。

**`#[cached]` 宏参数**:

| 参数 | 类型 | 描述 |
|------|------|------|
| `service` | 字符串 | 缓存服务名称(必填) |
| `ttl` | 整数 | 默认 TTL(秒) |
| `key` | 字符串 | 自定义键模式(支持 `{param}` 插值) |
| `key_prefix` | 字符串 | 键前缀命名空间 |
| `sync` | 标志 | 生成同步函数(无需 async 运行时) |
| `skip_cache_write` | 标志 | 跳过 `Ok` 结果的缓存写入 |

**`#[cached(sync)]` 宏**:

```rust
use oxcache::cached;

#[cached(service = "user_cache", ttl = 600, sync)]
fn get_user_sync(id: u64) -> Result<User, String> {
    // 同步函数体 —— 无需 async 运行时
    Ok(User { id, name: format!("User {}", id) })
}
```

---

## 🌸 布隆过滤器

自 0.3.0 起,`bloom` 特性(需显式启用;不在 `full` 中)提供负查询过滤:

```toml
[dependencies]
oxcache = { version = "0.5.0-rc.2", features = ["memory", "bloom"] }
```

```rust
use oxcache::backend::interface::{CacheReader, CacheWriter};
use oxcache::backend::MokaMemoryBackend;
use oxcache::features::bloom_filter::{BloomFilter, BloomFilterBackend};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 独立 BloomFilter 类型
    let bf = BloomFilter::new(10_000, 0.01);  // 容量、误判率
    bf.insert("existing_key");
    assert!(bf.contains("existing_key"));    // 无假阴性
    assert!(!bf.contains("missing_key"));    // 可能有假阳性

    // 2. BloomFilterBackend 装饰器:包装任何 CacheBackend
    let inner = MokaMemoryBackend::new();
    let backend = BloomFilterBackend::builder()
        .capacity(10_000)
        .false_positive_rate(0.01)
        .inner(inner)
        .build()?;

    // `get` 时:BF 说"不存在" → 完全跳过 inner。BF 说"可能存在" → 查询 inner。
    backend.set("user:1", b"Alice".to_vec(), None).await?;
    let value = backend.get("user:1").await?;       // Some(b"Alice")
    let miss  = backend.get("user:999").await?;     // None —— BF 过滤,inner 未触及

    Ok(())
}
```

**特性**:
- 无假阴性(插入的 key 总是 `contains == true`)
- `set` 更新 BF 和 inner;`delete` 只更新 inner(BF 不支持删除)
- `clear` 同时清空两者;TTL 原样透传
- 当 inner 后端实现 `SyncCacheBackend` 时,装饰器也实现

---

## ⏱️ TTL 行为对照表

自 0.3.0 起所有后端都遵守 per-entry TTL。行为汇总:

| 后端 | `set(ttl=Some)` | `ttl(key)` | `expire(key, new_ttl)` | 说明 |
|---------|-----------------|------------|------------------------|-------|
| **MokaMemoryBackend** | 通过 `moka::Expiry` 真实 per-entry TTL | 剩余 TTL | 更新 + 返回 `true` | 全局 TTL(`builder.ttl(...)`)被 per-entry TTL 覆盖 |
| **DashMapMemoryBackend** | 存储 `(value, expiry Instant)`;读取时懒过期 | 剩余 TTL(无 TTL 则 None) | 更新 + 返回 `true` | 懒过期 —— 条目在下次访问时移除;超过容量时 FIFO O(1) 淘汰最旧条目 |
| **RedisBackend** | `SET key value EX ttl` | `TTL key`(Redis 原生) | `EXPIRE key ttl` | 使用 Redis 原生 TTL |
| **Valkey**(通过 RedisBackend) | 同 Redis | 同 Redis | 同 Redis | Redis 协议兼容,使用 `ValkeyStandalone` 模式 |
| **DragonflyBackend** | 委托内部 RedisBackend | 委托内部 RedisBackend | 委托内部 RedisBackend | Redis 协议兼容,TTL 行为与 Redis 完全一致 |
| **AerospikeBackend** | `write_policy_with_ttl` → `Expiration::Seconds` | `record.time_to_live()` | `touch` + 新 `Expiration` | 使用 Aerospike 原生 TTL(秒级精度) |
| **MockBackend** | 存储 `(value, expiry Instant)`;懒过期 | 剩余 TTL | 更新 + 返回 `true` | 仅测试用;与 DashMap 语义对齐 |
| **ChainCache** | 将 `ttl` 透传到所有链接 | 返回拥有该 key 的最高分链接的 TTL | 透传到所有链接 | 所有链接接收相同 TTL |
| **BloomFilterBackend** | 将 `ttl` 透传到 inner(同时插入 key 到 BF) | 委托给 inner | 委托给 inner | BF 本身无 TTL 概念 |

**全局 vs per-entry TTL**:
- `MokaMemoryBackend::builder().ttl(Duration)` 设置应用于每个条目的全局 TTL
- `set(key, value, Some(ttl))` 覆盖该条目的全局 TTL
- `set(key, value, None)` 使用全局 TTL(若设置);否则条目永不过期

---

## 🧪 测试

测试套件按 `tests/README.md` 组织,覆盖以下分类:

| 分类 | 运行目标 | 说明 |
|------|----------|------|
| 库单元测试 | `--lib` | `src/` 内 `#[cfg(test)]` 测试(1000+) |
| 单元测试 | `--test unit` | 后端接口、CacheBuilder、序列化、指标、日志脱敏等(325) |
| 集成测试 | `--test integration` | 批量写入、链式缓存、降级与恢复、TTL、Redis Cluster/Sentinel、分布式锁等(133) |
| 端到端测试 | `--test e2e` | 基础 Cache 操作、`#[cached]` 宏、真实业务场景、高级场景(74) |
| 宏测试 | `--test macros` | `sync` / `skip_cache_write` 模式与 trybuild 编译失败用例(10) |
| Feature 门控测试 | `--test feature_test` 及 `feature_core` / `feature_minimal` | 窄特性组合验证 |
| 混沌测试 | `--test chaos` | 后端故障注入、网络故障、随机故障 |
| 安全测试 | `--test security` | 安全覆盖与安全验证 |
| 性能测试 | `--test performance` | 内存泄漏检测、Miri 内存安全、Pipeline 性能 |

### ▶️ 常用命令

```bash
# 全部测试(等价于 make test)
cargo test --all-features --no-fail-fast

# 按测试二进制运行
cargo test --features full --lib                    # 库单元测试
cargo test --features full --test integration       # 集成测试
cargo test --features full --test e2e               # 端到端测试

# 窄特性组合(与 CI 一致)
cargo test --no-default-features --features core --test feature_core
cargo test --no-default-features --features minimal --test feature_minimal

# 跳过需要 Redis 的测试
cargo test --features full -- --skip redis

# 覆盖率(CI 门禁:行覆盖 ≥ 85%)
cargo llvm-cov --features full --workspace --fail-under-lines 85
```

> **注意**:Redis 相关测试通过 testcontainers 自动拉起 Redis 容器,需要本机 Docker 环境。

---

## 📊 性能

> 测试环境: M1 Pro, 16GB RAM, macOS, Redis 7.0
>
> **注意**: 性能因硬件、网络条件和数据大小而异。

```mermaid
xychart-beta
    title "单线程延迟测试 (P99)"
    x-axis ["L1 缓存", "L2 缓存", "数据库"]
    y-axis "延迟时间" 0 --> 60
    bar [50, 3, 30]
    line [50, 3, 30]
```

```mermaid
xychart-beta
    title "吞吐量测试 (batch_size=100)"
    x-axis ["L1 操作", "L2 单次写入", "L2 批量写入"]
    y-axis "操作数/秒" 0 --> 600
    bar [7500, 75, 350]
```

**性能数据总结**:
- **L1 缓存**: 50-100ns (内存访问)
- **L2 缓存**: 1-5ms (Redis, 本地)
- **数据库**: 10-50ms (典型 SQL 查询)
- **L1 操作**: 5-10M ops/sec
- **L2 单次写入**: 50-100K ops/sec
- **L2 批量写入**: 200-500K ops/sec

Criterion 基准测试代码见 `benches/` 目录(`modern_api_benchmark`、`redis_benchmark`、`serialization_benchmark`、`dashmap_benchmark`、`dragonfly_benchmark`)。

---

## 🔒 安全

Oxcache 实现了多项安全措施以防范常见攻击,完整的安全策略与漏洞报告流程见 [安全文档](docs/SECURITY.md)。

### 🛡️ 输入验证

所有用户输入在传递给 Redis 之前都会进行验证:

- **键验证**:键不能为空、不能超过 512KB、不能包含危险字符(`\r`、`\n`、`\0`),以防止 Redis 协议注入攻击。
- **Lua 脚本验证**:脚本验证包括:
  - 最大长度 10KB
  - 最多 100 个键
  - 阻止危险命令:`FLUSHALL`、`FLUSHDB`、`KEYS`、`SHUTDOWN`、`DEBUG`、`CONFIG`、`SAVE`、`BGSAVE`、`MONITOR`
  - 阻止嵌套 `eval`/`evalsha` 调用
  - 阻止无限循环结构:`while true`、`while 1`、`repeat`、`goto`
  - 阻止 OS 命令执行:`os.execute`、`os.exec`、`io.popen`、`loadstring`、`load`
  - 注释和字符串内容预处理,防止通过注释绕过检测
- **SCAN 模式验证**:模式验证以防止 ReDoS 攻击:
  - 最大长度 256 个字符
  - 最多 10 个通配符(`*`)字符
  - count 参数限制在安全范围内(1-1000)
- **SQL/路径遍历检测**:Redis 键会扫描潜在的 SQL 注入和路径遍历模式

### 🔐 安全 API(公共函数)

对于高级用例,您可以直接使用安全验证函数:

```rust
use oxcache::{validate_redis_key, validate_lua_script, validate_scan_pattern};

// 验证 Redis 键
validate_redis_key("user:123").expect("无效的键");

// 验证 Lua 脚本
validate_lua_script("return redis.call('GET', KEYS[1])", 1).expect("无效的脚本");

// 验证 SCAN 模式
validate_scan_pattern("user:*").expect("无效的模式");
```

### ⏱️ 超时保护

长时间运行的操作有超时保护:

- **Lua 脚本**:30 秒超时,防止 Redis 阻塞
- **SCAN 操作**:30 秒超时,防止扫描挂起

### 🔑 安全锁值

分布式锁使用库自动生成的加密安全 UUID v4 值,消除锁值预测攻击的风险。

### 🙈 连接字符串脱敏

连接字符串中的密码在日志中默认脱敏,以防止凭据泄露。使用 `redact_connection_string()` 进行安全日志记录。

### ✅ 最佳实践

1. **使用库的键验证** - 不要绕过 `validate_redis_key()` 函数
2. **避免自定义 Lua 脚本** - 尽可能使用内置缓存操作
3. **设置适当的超时** - 不要禁用 30 秒默认超时
4. **轮换锁值** - 库会自动处理
5. **永远不要记录连接字符串** - 使用脱敏工具进行调试

---

## 🗺️ 开发路线图

以下为工作区《验收与 +0.1 发布方案》中记录的 oxcache 相关规划(CHANGELOG 中暂无未完成项):

- [ ] **0.5.0 正式发布**:当前版本 0.5.0-rc.2;按发布流程完成版本 bump、`cargo publish --dry-run` 验证后,推送 tag 触发 `release.yml` 自动发布到 crates.io
- [ ] **下游版本传导**:dbnexus、inklog、limiteron、sdforge 同步对 oxcache 的依赖要求至 0.5(path + version 双写)
- [ ] **Valkey 集成测试环境门控**:8 个 Valkey 集成测试依赖 Docker(testcontainers),无 Docker 环境下无法运行,为验收记录中的已知限制
- [ ] **质量审查留档项跟进**:代码质量审查(diting)留档的 3 项 Medium 建议与 2 项 Low 记录,按优先级评估处理

---

## 🤝 参与贡献

欢迎提交 Pull Request 和 Issue!参与开发请先阅读 [贡献指南](docs/CONTRIBUTING.md),其中包含:

- **开发环境准备**:Rust 1.97.1+(edition 2024)、pre-commit hooks 安装
- **TDD 工作流**:定接口 → 写测试(red)→ 写实现(green)→ 提交 → 影响分析
- **提交前检查**:`cargo fmt`、`cargo clippy --all-features -- -D warnings`、全特性与窄特性测试全部通过

---

## 📋 更新日志

完整的版本历史见 [CHANGELOG.md](docs/CHANGELOG.md)。最近版本要点:

- **0.4.3**(2026-08-06):`kit` 特性扩展 —— 构建观察者、`CacheBackend` 关闭映射到三阶段关闭协调、后端装饰器注册
- **0.4.2**(2026-08-06):死代码清理、`glob_match` 迭代化(消除多 `*` 模式下的指数级最坏情况)、安全校验函数复杂度降低
- **0.4.1**(2026-08-04):trait-kit 0.4 集成增强(`AsyncHealthCheck` / `AsyncLifecycle`),启用 workspace 继承并统一 edition 2024

---

## 📄 许可证

本项目基于 MIT + Commons Clause 许可证发布,商业使用需单独授权。详见 [LICENSE](LICENSE)。

---

## 🙏 致谢

Oxcache 构建在众多优秀的开源项目之上:

- [Moka](https://github.com/moka-rs/moka) 与 [DashMap](https://github.com/xacrimon/dashmap) —— L1 内存缓存后端
- [redis-rs](https://github.com/redis-rs/redis) —— Redis / Valkey / Dragonfly / Sentinel / Cluster 客户端
- [aerospike-client-rust](https://github.com/aerospike/aerospike-client-rust) —— Aerospike 后端
- [Tokio](https://github.com/tokio-rs/tokio) 与 [Serde](https://github.com/serde-rs/serde) —— 异步运行时与序列化生态
- [trait-kit](https://github.com/Kirky-X/trait-kit) —— AsyncKit 集成(生命周期 / 健康检查 / 关闭协调)
- [testcontainers-rs](https://github.com/testcontainers/testcontainers-rs) 与 [Criterion](https://github.com/bheisler/criterion.rs) —— 集成测试与基准测试基础设施

---

## 📞 联系与支持

- **Issue 反馈**:[GitHub Issues](https://github.com/Kirky-X/oxcache/issues)(提供 Bug 报告 / 功能建议 / 问题咨询三类模板)
- **安全漏洞**:请勿通过公开 Issue 报告安全漏洞,参见 [安全文档](docs/SECURITY.md) 中的漏洞报告流程
- **维护者**:Kirky.X

---

## ⭐ Star 历史

[![Star History Chart](https://api.star-history.com/svg?repos=Kirky-X/oxcache&type=Date)](https://star-history.com/#Kirky-X/oxcache&Date)

### 💝 支持本项目

如果这个项目对你有帮助,请考虑给它一个 ⭐️!

**Made with love by Kirky.X**