1+ ---
2+ globs: *.js
3+ description: 缓存管理和性能优化规范
4+ ---
5+
6+ # 缓存管理规范
7+
8+ ## 双层缓存架构
9+
10+ ### 1. 内存缓存 (Map对象)
11+ ```javascript
12+ // 内存缓存配置
13+ this.cache = new Map();
14+ this.cacheTimeout = 5 * 60 * 1000; // 5分钟过期
15+ this.maxCacheSize = 100; // 最大100个条目
16+ ```
17+
18+ ### 2. 文件缓存 (JSON文件)
19+ ```javascript
20+ // 文件缓存配置
21+ const CACHE_DIR = path.join(process.cwd(), 'cache');
22+ const PAPER_CACHE_DIR = path.join(CACHE_DIR, 'papers');
23+ const PAPER_CACHE_EXPIRY = 30 * 24 * 60 * 60 * 1000; // 30天过期
24+ ```
25+
26+ ## 缓存操作模式
27+
28+ ### 内存缓存操作
29+ ```javascript
30+ // 获取缓存
31+ getFromCache(key) {
32+ const cached = this.cache.get(key);
33+ if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
34+ this.cacheStats.hits++;
35+ return cached.data;
36+ }
37+ this.cacheStats.misses++;
38+ return null;
39+ }
40+
41+ // 设置缓存
42+ setCache(key, data) {
43+ // LRU淘汰策略
44+ if (this.cache.size >= this.maxCacheSize) {
45+ const oldestKey = this.cache.keys().next().value;
46+ this.cache.delete(oldestKey);
47+ this.cacheStats.evictions++;
48+ }
49+
50+ this.cache.set(key, {
51+ data,
52+ timestamp: Date.now()
53+ });
54+ this.cacheStats.sets++;
55+ }
56+ ```
57+
58+ ### 文件缓存操作
59+ ```javascript
60+ // 从文件缓存获取
61+ getPaperFromFileCache(pmid) {
62+ const cachePath = this.getPaperCachePath(pmid);
63+ if (!fs.existsSync(cachePath)) {
64+ this.cacheStats.fileMisses++;
65+ return null;
66+ }
67+
68+ const fileContent = fs.readFileSync(cachePath, 'utf8');
69+ const cachedData = JSON.parse(fileContent);
70+
71+ // 检查过期时间
72+ if (Date.now() - cachedData.timestamp > PAPER_CACHE_EXPIRY) {
73+ fs.unlinkSync(cachePath);
74+ return null;
75+ }
76+
77+ this.cacheStats.fileHits++;
78+ return cachedData.data;
79+ }
80+
81+ // 保存到文件缓存
82+ setPaperToFileCache(pmid, data) {
83+ const cachePath = this.getPaperCachePath(pmid);
84+ const cacheData = {
85+ version: CACHE_VERSION,
86+ pmid: pmid,
87+ timestamp: Date.now(),
88+ data: data
89+ };
90+
91+ fs.writeFileSync(cachePath, JSON.stringify(cacheData, null, 2));
92+ this.cacheStats.fileSets++;
93+ }
94+ ```
95+
96+ ## 缓存统计和监控
97+
98+ ### 统计数据结构
99+ ```javascript
100+ this.cacheStats = {
101+ hits: 0, // 内存缓存命中
102+ misses: 0, // 内存缓存未命中
103+ sets: 0, // 内存缓存设置
104+ evictions: 0, // 内存缓存淘汰
105+ fileHits: 0, // 文件缓存命中
106+ fileMisses: 0, // 文件缓存未命中
107+ fileSets: 0 // 文件缓存设置
108+ };
109+ ```
110+
111+ ### 缓存统计报告
112+ ```javascript
113+ getCacheStats() {
114+ const memoryHitRate = this.cacheStats.hits / (this.cacheStats.hits + this.cacheStats.misses) * 100;
115+ const fileHitRate = this.cacheStats.fileHits / (this.cacheStats.fileHits + this.cacheStats.fileMisses) * 100;
116+
117+ return {
118+ memory: {
119+ hits: this.cacheStats.hits,
120+ misses: this.cacheStats.misses,
121+ hitRate: memoryHitRate.toFixed(2) + '%',
122+ currentSize: this.cache.size,
123+ maxSize: this.maxCacheSize
124+ },
125+ file: {
126+ hits: this.cacheStats.fileHits,
127+ misses: this.cacheStats.fileMisses,
128+ hitRate: fileHitRate.toFixed(2) + '%',
129+ totalPapers: this.getFileCacheCount()
130+ }
131+ };
132+ }
133+ ```
134+
135+ ## 缓存清理策略
136+
137+ ### 过期缓存清理
138+ ```javascript
139+ // 清理过期内存缓存
140+ cleanExpiredCache() {
141+ const now = Date.now();
142+ let cleaned = 0;
143+ for (const [key, value] of this.cache.entries()) {
144+ if (now - value.timestamp >= this.cacheTimeout) {
145+ this.cache.delete(key);
146+ cleaned++;
147+ }
148+ }
149+ return cleaned;
150+ }
151+
152+ // 清理过期文件缓存
153+ cleanExpiredPaperCache() {
154+ let cleaned = 0;
155+ for (const [pmid, info] of Object.entries(indexData.papers)) {
156+ const cachePath = this.getPaperCachePath(pmid);
157+ if (fs.existsSync(cachePath)) {
158+ const fileContent = fs.readFileSync(cachePath, 'utf8');
159+ const cachedData = JSON.parse(fileContent);
160+
161+ if (Date.now() - cachedData.timestamp > PAPER_CACHE_EXPIRY) {
162+ fs.unlinkSync(cachePath);
163+ delete indexData.papers[pmid];
164+ cleaned++;
165+ }
166+ }
167+ }
168+ return cleaned;
169+ }
170+ ```
171+
172+ ## 缓存键生成策略
173+
174+ ### 搜索缓存键
175+ ```javascript
176+ getCacheKey(query, maxResults, daysBack, sortBy) {
177+ return `${query}|${maxResults}|${daysBack}|${sortBy}`;
178+ }
179+ ```
180+
181+ ### 论文缓存键
182+ ```javascript
183+ getPaperCachePath(pmid) {
184+ return path.join(PAPER_CACHE_DIR, `${pmid}.json`);
185+ }
186+ ```
187+
188+ ## 缓存性能优化
189+
190+ ### 批量缓存检查
191+ ```javascript
192+ // 批量检查文件缓存
193+ for (const id of ids) {
194+ const cachedArticle = this.getPaperFromFileCache(id);
195+ if (cachedArticle) {
196+ articles.push(cachedArticle);
197+ } else {
198+ uncachedIds.push(id);
199+ }
200+ }
201+ ```
202+
203+ ### 缓存预热
204+ ```javascript
205+ // 初始化缓存目录
206+ initCacheDirectories() {
207+ if (!fs.existsSync(CACHE_DIR)) {
208+ fs.mkdirSync(CACHE_DIR, { recursive: true });
209+ }
210+
211+ if (!fs.existsSync(PAPER_CACHE_DIR)) {
212+ fs.mkdirSync(PAPER_CACHE_DIR, { recursive: true });
213+ }
214+ }
215+ ```
0 commit comments