Initial commit
This commit is contained in:
151
lib/cache/index.ts
vendored
Normal file
151
lib/cache/index.ts
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
export interface CacheOptions {
|
||||
ttl?: number; // 生存时间(毫秒)
|
||||
maxSize?: number; // 最大缓存项数
|
||||
}
|
||||
|
||||
export interface CacheEntry<T> {
|
||||
value: T;
|
||||
timestamp: number;
|
||||
ttl: number;
|
||||
}
|
||||
|
||||
class Cache {
|
||||
private cache = new Map<string, CacheEntry<unknown>>();
|
||||
private maxSize: number;
|
||||
private defaultTtl: number;
|
||||
|
||||
constructor(options: CacheOptions = {}) {
|
||||
this.maxSize = options.maxSize || 1000;
|
||||
this.defaultTtl = options.ttl || 5 * 60 * 1000; // 默认5分钟
|
||||
}
|
||||
|
||||
set<T>(key: string, value: T, ttl?: number): void {
|
||||
// 如果缓存已满,删除最旧的项
|
||||
if (this.cache.size >= this.maxSize) {
|
||||
this.evictOldest();
|
||||
}
|
||||
|
||||
const entry: CacheEntry<T> = {
|
||||
value,
|
||||
timestamp: Date.now(),
|
||||
ttl: ttl || this.defaultTtl,
|
||||
};
|
||||
|
||||
this.cache.set(key, entry);
|
||||
logger.debug("Cache set", { key, ttl: entry.ttl });
|
||||
}
|
||||
|
||||
get<T>(key: string): T | null {
|
||||
const entry = this.cache.get(key) as CacheEntry<T> | undefined;
|
||||
|
||||
if (!entry) {
|
||||
logger.debug("Cache miss", { key });
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
if (Date.now() - entry.timestamp > entry.ttl) {
|
||||
this.cache.delete(key);
|
||||
logger.debug("Cache expired", { key });
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug("Cache hit", { key });
|
||||
return entry.value;
|
||||
}
|
||||
|
||||
has(key: string): boolean {
|
||||
const entry = this.cache.get(key);
|
||||
if (!entry) return false;
|
||||
|
||||
// 检查是否过期
|
||||
if (Date.now() - entry.timestamp > entry.ttl) {
|
||||
this.cache.delete(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
delete(key: string): boolean {
|
||||
const deleted = this.cache.delete(key);
|
||||
if (deleted) {
|
||||
logger.debug("Cache deleted", { key });
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.cache.clear();
|
||||
logger.info("Cache cleared");
|
||||
}
|
||||
|
||||
size(): number {
|
||||
return this.cache.size;
|
||||
}
|
||||
|
||||
private evictOldest(): void {
|
||||
let oldestKey: string | null = null;
|
||||
let oldestTime = Date.now();
|
||||
|
||||
for (const [key, entry] of this.cache.entries()) {
|
||||
if (entry.timestamp < oldestTime) {
|
||||
oldestTime = entry.timestamp;
|
||||
oldestKey = key;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldestKey) {
|
||||
this.cache.delete(oldestKey);
|
||||
logger.debug("Cache evicted oldest", { key: oldestKey });
|
||||
}
|
||||
}
|
||||
|
||||
// 清理过期项
|
||||
cleanup(): void {
|
||||
const now = Date.now();
|
||||
let cleanedCount = 0;
|
||||
|
||||
for (const [key, entry] of this.cache.entries()) {
|
||||
if (now - entry.timestamp > entry.ttl) {
|
||||
this.cache.delete(key);
|
||||
cleanedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanedCount > 0) {
|
||||
logger.info("Cache cleanup completed", { cleanedCount });
|
||||
}
|
||||
}
|
||||
|
||||
// 获取缓存统计信息
|
||||
getStats(): {
|
||||
size: number;
|
||||
maxSize: number;
|
||||
hitRate: number;
|
||||
missRate: number;
|
||||
} {
|
||||
return {
|
||||
size: this.cache.size,
|
||||
maxSize: this.maxSize,
|
||||
hitRate: 0, // 需要实现命中率统计
|
||||
missRate: 0, // 需要实现未命中率统计
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局缓存实例
|
||||
export const cache = new Cache({
|
||||
maxSize: 1000,
|
||||
ttl: 5 * 60 * 1000, // 5分钟
|
||||
});
|
||||
|
||||
// 定期清理过期项
|
||||
if (typeof window === "undefined") {
|
||||
// 仅在服务器端运行
|
||||
setInterval(() => {
|
||||
cache.cleanup();
|
||||
}, 60 * 1000); // 每分钟清理一次
|
||||
}
|
||||
Reference in New Issue
Block a user