Skip to content

Commit f9bae97

Browse files
committed
docs: add FileCacheEx documentation (en/cn) and fix comment style
- Add docs/FileCacheEx.md (English API documentation) - Add docs/cn/FileCacheEx.md (Chinese API documentation) - Fix include comments to follow libhv convention (add 'import' keyword)
1 parent f14db65 commit f9bae97

3 files changed

Lines changed: 256 additions & 3 deletions

File tree

docs/FileCacheEx.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# FileCacheEx — Enhanced File Cache
2+
3+
`FileCacheEx` is a drop-in replacement for `FileCache` that fixes thread-safety issues and provides runtime-configurable parameters.
4+
5+
## Header
6+
7+
```c++
8+
#include "FileCacheEx.h"
9+
```
10+
11+
## Improvements over FileCache
12+
13+
| Feature | FileCache | FileCacheEx |
14+
|---------|-----------|-------------|
15+
| HTTP header reserve | Compile-time 1024 bytes | Runtime configurable, default 4096 |
16+
| `prepend_header()` | Returns `void`, silently drops overflow | Returns `bool`, `false` on overflow |
17+
| Per-entry thread safety | No locking | Per-entry `std::mutex` |
18+
| `resize_buf()` httpbuf | May leave dangling reference | Explicitly invalidated (UAF prevention) |
19+
| File read | Single `read()`, may short-read | Loop with `EINTR` handling |
20+
| Cache insertion | Before initialization completes | Deferred until fully initialized |
21+
| Max file size | Compile-time `FILE_CACHE_MAX_SIZE` | Runtime `SetMaxFileSize()` |
22+
| DLL export | None | `HV_EXPORT` |
23+
24+
## Data Structures
25+
26+
```c++
27+
typedef struct file_cache_ex_s {
28+
mutable std::mutex mutex; // per-entry lock
29+
std::string filepath;
30+
struct stat st;
31+
time_t open_time;
32+
time_t stat_time;
33+
uint32_t stat_cnt;
34+
HBuf buf; // header_reserve + file_content
35+
hbuf_t filebuf; // points into buf: file content
36+
hbuf_t httpbuf; // points into buf: header + content
37+
char last_modified[64];
38+
char etag[64];
39+
std::string content_type;
40+
int header_reserve; // bytes reserved before content
41+
int header_used; // bytes actually used by header
42+
43+
bool is_modified(); // caller must hold mutex
44+
bool is_complete(); // caller must hold mutex
45+
void resize_buf(size_t filesize, int reserved); // caller must hold mutex
46+
void resize_buf(size_t filesize);
47+
bool prepend_header(const char* header, int len); // thread-safe
48+
49+
// Thread-safe accessors
50+
int get_header_reserve() const;
51+
int get_header_used() const;
52+
int get_header_remaining() const;
53+
bool header_fits(int len) const;
54+
} file_cache_ex_t;
55+
56+
typedef std::shared_ptr<file_cache_ex_t> file_cache_ex_ptr;
57+
```
58+
59+
## FileCacheEx Class
60+
61+
```c++
62+
class HV_EXPORT FileCacheEx : public hv::LRUCache<std::string, file_cache_ex_ptr> {
63+
public:
64+
int stat_interval; // seconds between stat() checks, default 10
65+
int expired_time; // seconds before expiry, default 60
66+
int max_header_length; // header reserve per entry, default 4096
67+
int max_file_size; // max cached file size, default 4MB
68+
69+
explicit FileCacheEx(size_t capacity = 100);
70+
71+
file_cache_ex_ptr Open(const char* filepath, OpenParam* param);
72+
bool Exists(const char* filepath) const;
73+
bool Close(const char* filepath);
74+
void RemoveExpiredFileCache();
75+
76+
int GetMaxHeaderLength() const;
77+
int GetMaxFileSize() const;
78+
int GetStatInterval() const;
79+
int GetExpiredTime() const;
80+
81+
void SetMaxHeaderLength(int len);
82+
void SetMaxFileSize(int size);
83+
};
84+
```
85+
86+
## Usage
87+
88+
```c++
89+
FileCacheEx filecache(200); // LRU capacity = 200
90+
filecache.SetMaxHeaderLength(8192); // 8K header reserve
91+
filecache.SetMaxFileSize(1 << 24); // 16MB max file
92+
filecache.stat_interval = 5;
93+
filecache.expired_time = 120;
94+
95+
FileCacheEx::OpenParam param;
96+
file_cache_ex_ptr fc = filecache.Open("/var/www/index.html", &param);
97+
if (fc) {
98+
std::string header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
99+
if (fc->prepend_header(header.c_str(), header.size())) {
100+
// send fc->httpbuf (header + content)
101+
} else {
102+
// header exceeds reserve, fall back to separate send
103+
}
104+
}
105+
```
106+
107+
## Migration from FileCache
108+
109+
1. Replace `#include "FileCache.h"` with `#include "FileCacheEx.h"`
110+
2. Change types: `FileCache` → `FileCacheEx`, `file_cache_ptr` → `file_cache_ex_ptr`
111+
3. Handle `bool` return from `prepend_header()`
112+
4. Optional: configure via `SetMaxHeaderLength()` / `SetMaxFileSize()`
113+
114+
## Thread Safety
115+
116+
- `FileCacheEx` inherits `hv::LRUCache` global mutex for LRU operations
117+
- Each `file_cache_ex_s` entry has its own `std::mutex` for entry-level protection
118+
- `prepend_header()` locks automatically; callers need no external synchronization
119+
- `is_modified()`, `is_complete()`, `resize_buf()` require caller to hold the mutex

docs/cn/FileCacheEx.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# FileCacheEx — 增强版文件缓存
2+
3+
`FileCacheEx``FileCache` 的增强替代方案,解决了原始实现中的线程安全问题,并提供运行时可配置的参数。
4+
5+
## 头文件
6+
7+
```c++
8+
#include "FileCacheEx.h"
9+
```
10+
11+
## 与 FileCache 的区别
12+
13+
| 特性 | FileCache | FileCacheEx |
14+
|------|-----------|-------------|
15+
| HTTP 头部预留空间 | 编译期固定 1024 字节 | 运行时可配置,默认 4096 字节 |
16+
| `prepend_header()` | 返回 `void`,溢出静默丢弃 | 返回 `bool`,失败返回 `false` |
17+
| 缓存条目线程安全 | 无锁保护 | 每条目 `std::mutex` |
18+
| `resize_buf()` 后 httpbuf | 可能悬空引用 | 主动置空,防止 UAF |
19+
| 文件读取 | 单次 `read()`,可能短读 | 循环读取,处理 `EINTR` |
20+
| `put()` 时机 | 初始化前放入缓存 | 完全初始化后放入缓存 |
21+
| 最大文件大小 | 编译期宏 `FILE_CACHE_MAX_SIZE` | 运行时 `SetMaxFileSize()` |
22+
| DLL 导出 || `HV_EXPORT` |
23+
24+
## 数据结构
25+
26+
```c++
27+
// 缓存条目
28+
typedef struct file_cache_ex_s {
29+
mutable std::mutex mutex; // 条目级互斥锁
30+
std::string filepath;
31+
struct stat st;
32+
time_t open_time;
33+
time_t stat_time;
34+
uint32_t stat_cnt;
35+
HBuf buf; // header_reserve + file_content
36+
hbuf_t filebuf; // 指向 buf 中文件内容区域
37+
hbuf_t httpbuf; // 指向 buf 中 header + 文件内容区域
38+
char last_modified[64];
39+
char etag[64];
40+
std::string content_type;
41+
int header_reserve; // 头部预留字节数
42+
int header_used; // 实际使用的头部字节数
43+
44+
// 方法
45+
bool is_modified(); // 检查文件是否被修改(需持锁)
46+
bool is_complete(); // 检查缓存是否完整(需持锁)
47+
void resize_buf(size_t filesize, int reserved); // 重新分配缓冲区(需持锁)
48+
void resize_buf(size_t filesize); // 使用当前 header_reserve
49+
bool prepend_header(const char* header, int len); // 线程安全:写入 HTTP 头
50+
51+
// 线程安全访问器
52+
int get_header_reserve() const;
53+
int get_header_used() const;
54+
int get_header_remaining() const;
55+
bool header_fits(int len) const;
56+
} file_cache_ex_t;
57+
58+
typedef std::shared_ptr<file_cache_ex_t> file_cache_ex_ptr;
59+
```
60+
61+
## FileCacheEx 类
62+
63+
```c++
64+
class HV_EXPORT FileCacheEx : public hv::LRUCache<std::string, file_cache_ex_ptr> {
65+
public:
66+
// 可配置参数
67+
int stat_interval; // stat() 检查间隔(秒),默认 10
68+
int expired_time; // 缓存过期时间(秒),默认 60
69+
int max_header_length; // 每条目头部预留字节,默认 4096
70+
int max_file_size; // 最大缓存文件大小,默认 4MB
71+
72+
explicit FileCacheEx(size_t capacity = 100);
73+
74+
// 打开文件并缓存
75+
file_cache_ex_ptr Open(const char* filepath, OpenParam* param);
76+
77+
// 检查文件是否在缓存中
78+
bool Exists(const char* filepath) const;
79+
80+
// 从缓存中移除文件
81+
bool Close(const char* filepath);
82+
83+
// 移除过期缓存条目
84+
void RemoveExpiredFileCache();
85+
86+
// Getter
87+
int GetMaxHeaderLength() const;
88+
int GetMaxFileSize() const;
89+
int GetStatInterval() const;
90+
int GetExpiredTime() const;
91+
92+
// Setter
93+
void SetMaxHeaderLength(int len);
94+
void SetMaxFileSize(int size);
95+
};
96+
```
97+
98+
## 使用示例
99+
100+
```c++
101+
FileCacheEx filecache(200); // 最大 200 个缓存条目
102+
filecache.SetMaxHeaderLength(8192); // 8K 头部预留
103+
filecache.SetMaxFileSize(1 << 24); // 16MB 最大缓存文件
104+
filecache.stat_interval = 5; // 每 5 秒检查文件变更
105+
filecache.expired_time = 120; // 2 分钟过期
106+
107+
FileCacheEx::OpenParam param;
108+
file_cache_ex_ptr fc = filecache.Open("/var/www/index.html", &param);
109+
if (fc) {
110+
// 写入 HTTP 响应头
111+
std::string header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
112+
if (fc->prepend_header(header.c_str(), header.size())) {
113+
// 发送 fc->httpbuf (header + content)
114+
} else {
115+
// 头部超出预留空间,回退到普通发送
116+
}
117+
}
118+
```
119+
120+
## 迁移指南
121+
122+
从 `FileCache` 迁移到 `FileCacheEx`:
123+
124+
1. 替换头文件引用:`#include "FileCache.h"` → `#include "FileCacheEx.h"`
125+
2. 替换类型:`FileCache` → `FileCacheEx`,`file_cache_ptr` → `file_cache_ex_ptr`
126+
3. 处理 `prepend_header()` 的 `bool` 返回值
127+
4. 可选:利用 `SetMaxHeaderLength()` / `SetMaxFileSize()` 配置参数
128+
129+
## 线程安全说明
130+
131+
- `FileCacheEx` 继承 `hv::LRUCache` 的全局互斥锁保护 LRU 操作
132+
- 每个 `file_cache_ex_s` 条目内置 `std::mutex` 保护条目级修改
133+
- `prepend_header()` 自动加锁,调用方无需额外同步
134+
- `is_modified()` / `is_complete()` / `resize_buf()` 需要调用方持锁

http/server/FileCacheEx.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
#include "htime.h"
66
#include "hlog.h"
77

8-
#include "httpdef.h" // http_content_type_str_by_suffix
9-
#include "http_page.h" // make_index_of_page
8+
#include "httpdef.h" // import http_content_type_str_by_suffix
9+
#include "http_page.h" // import make_index_of_page
1010

1111
#ifdef OS_WIN
12-
#include "hstring.h" // hv::utf8_to_wchar
12+
#include "hstring.h" // import hv::utf8_to_wchar
1313
#endif
1414

1515
#define ETAG_FMT "\"%zx-%zx\""

0 commit comments

Comments
 (0)