@abtnode/db-cache 1.17.8-beta-20260109-075740-5f484e08 → 1.17.8-beta-20260113-015027-32a1cec4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -42,20 +42,20 @@ function ulid() {
42
42
  return timeStr + rand;
43
43
  }
44
44
 
45
- var __defProp$4 = Object.defineProperty;
46
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
47
- var __publicField$4 = (obj, key, value) => {
48
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
45
+ var __defProp$5 = Object.defineProperty;
46
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
47
+ var __publicField$5 = (obj, key, value) => {
48
+ __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
49
49
  return value;
50
50
  };
51
51
  const _RedisAdapter = class _RedisAdapter {
52
52
  constructor() {
53
- __publicField$4(this, "opts", null);
54
- __publicField$4(this, "defaultTtl", 1e3 * 60 * 60);
55
- __publicField$4(this, "url", "");
56
- __publicField$4(this, "prefix", "");
57
- __publicField$4(this, "prefixKey", (key) => `${this.prefix}:${key}`);
58
- __publicField$4(this, "prefixKeyGroup", (key) => `${this.prefix}:group:${key}`);
53
+ __publicField$5(this, "opts", null);
54
+ __publicField$5(this, "defaultTtl", 1e3 * 60 * 60);
55
+ __publicField$5(this, "url", "");
56
+ __publicField$5(this, "prefix", "");
57
+ __publicField$5(this, "prefixKey", (key) => `${this.prefix}:${key}`);
58
+ __publicField$5(this, "prefixKeyGroup", (key) => `${this.prefix}:group:${key}`);
59
59
  }
60
60
  clearAll() {
61
61
  throw new Error("Method not implemented.");
@@ -198,10 +198,16 @@ const _RedisAdapter = class _RedisAdapter {
198
198
  const client = this.getClient();
199
199
  await client.flushAll();
200
200
  }
201
+ /**
202
+ * 获取 LRU 缓存统计信息(Redis 不使用 LRU 缓存)
203
+ */
204
+ getLruCacheStats() {
205
+ return null;
206
+ }
201
207
  };
202
208
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
203
- __publicField$4(_RedisAdapter, "clients", /* @__PURE__ */ new Map());
204
- __publicField$4(_RedisAdapter, "initPromises", /* @__PURE__ */ new Map());
209
+ __publicField$5(_RedisAdapter, "clients", /* @__PURE__ */ new Map());
210
+ __publicField$5(_RedisAdapter, "initPromises", /* @__PURE__ */ new Map());
205
211
  let RedisAdapter = _RedisAdapter;
206
212
 
207
213
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -230,6 +236,363 @@ async function withRetry(fn, {
230
236
  }
231
237
  }
232
238
 
239
+ var __defProp$4 = Object.defineProperty;
240
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
241
+ var __publicField$4 = (obj, key, value) => {
242
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
243
+ return value;
244
+ };
245
+ const lruCacheModule = require("lru-cache");
246
+ const LRUCacheLib = lruCacheModule?.LRUCache || lruCacheModule?.default || lruCacheModule;
247
+ const isTestEnv = process.env.NODE_ENV === "test";
248
+ const eventHub = isTestEnv ? require("@arcblock/event-hub/single") : require("@arcblock/event-hub");
249
+ const LRU_CACHE_SYNC_EVENT = "db-cache:lru:sync";
250
+ const LRU_CACHE_DELETE_EVENT = "db-cache:lru:delete";
251
+ const LRU_CACHE_CLEAR_EVENT = "db-cache:lru:clear";
252
+ const shouldEnableSync = () => {
253
+ if (isTestEnv) {
254
+ return false;
255
+ }
256
+ return process.env.NODE_APP_INSTANCE !== void 0;
257
+ };
258
+ const _LruCache = class _LruCache {
259
+ constructor(options) {
260
+ __publicField$4(this, "cacheKey");
261
+ __publicField$4(this, "maxSize");
262
+ __publicField$4(this, "enableSync");
263
+ this.cacheKey = `lru:${options.prefix}`;
264
+ this.maxSize = options.maxSize ?? 1e4;
265
+ this.enableSync = (options.enableSync ?? true) && shouldEnableSync();
266
+ if (!_LruCache.caches.has(this.cacheKey)) {
267
+ _LruCache.caches.set(
268
+ this.cacheKey,
269
+ new LRUCacheLib({
270
+ max: this.maxSize,
271
+ ttl: 0
272
+ // 我们自己管理 TTL
273
+ })
274
+ );
275
+ _LruCache.groupCaches.set(this.cacheKey, /* @__PURE__ */ new Map());
276
+ if (this.enableSync && !_LruCache.listenerSetup.has(this.cacheKey)) {
277
+ this._setupSyncListener();
278
+ _LruCache.listenerSetup.set(this.cacheKey, true);
279
+ }
280
+ }
281
+ }
282
+ getCache() {
283
+ const cache = _LruCache.caches.get(this.cacheKey);
284
+ if (!cache) {
285
+ throw new Error("LRU cache not initialized");
286
+ }
287
+ return cache;
288
+ }
289
+ getGroupCaches() {
290
+ const groupCaches = _LruCache.groupCaches.get(this.cacheKey);
291
+ if (!groupCaches) {
292
+ throw new Error("LRU group cache not initialized");
293
+ }
294
+ return groupCaches;
295
+ }
296
+ getOrCreateGroupCache(key) {
297
+ const groupCaches = this.getGroupCaches();
298
+ if (!groupCaches.has(key)) {
299
+ groupCaches.set(
300
+ key,
301
+ new LRUCacheLib({
302
+ max: this.maxSize,
303
+ ttl: 0
304
+ })
305
+ );
306
+ }
307
+ return groupCaches.get(key);
308
+ }
309
+ /**
310
+ * 设置同步监听器,接收其他 worker 广播的缓存数据
311
+ */
312
+ _setupSyncListener() {
313
+ const { cacheKey, maxSize } = this;
314
+ eventHub.on(LRU_CACHE_SYNC_EVENT, (payload) => {
315
+ const { channel, key, value, expiresAt, isGroup, subKey } = payload;
316
+ if (channel !== cacheKey)
317
+ return;
318
+ const entry = { value, expiresAt };
319
+ if (isGroup && subKey !== void 0) {
320
+ const groupCaches = _LruCache.groupCaches.get(cacheKey);
321
+ if (groupCaches) {
322
+ const groupCache = groupCaches.get(key) || new LRUCacheLib({ max: maxSize, ttl: 0 });
323
+ groupCache.set(subKey, entry);
324
+ groupCaches.set(key, groupCache);
325
+ }
326
+ } else {
327
+ const cache = _LruCache.caches.get(cacheKey);
328
+ if (cache) {
329
+ cache.set(key, entry);
330
+ }
331
+ }
332
+ });
333
+ eventHub.on(LRU_CACHE_DELETE_EVENT, (payload) => {
334
+ const { channel, keys, isGroup, groupKey } = payload;
335
+ if (channel !== cacheKey)
336
+ return;
337
+ if (isGroup && groupKey !== void 0) {
338
+ const groupCaches = _LruCache.groupCaches.get(cacheKey);
339
+ if (groupCaches) {
340
+ const groupCache = groupCaches.get(groupKey);
341
+ if (groupCache) {
342
+ for (const key of keys) {
343
+ groupCache.delete(key);
344
+ }
345
+ }
346
+ }
347
+ } else {
348
+ const cache = _LruCache.caches.get(cacheKey);
349
+ if (cache) {
350
+ for (const key of keys) {
351
+ cache.delete(key);
352
+ const groupCaches = _LruCache.groupCaches.get(cacheKey);
353
+ if (groupCaches) {
354
+ groupCaches.delete(key);
355
+ }
356
+ }
357
+ }
358
+ }
359
+ });
360
+ eventHub.on(LRU_CACHE_CLEAR_EVENT, (payload) => {
361
+ const { channel } = payload;
362
+ if (channel !== cacheKey)
363
+ return;
364
+ const cache = _LruCache.caches.get(cacheKey);
365
+ if (cache) {
366
+ cache.clear();
367
+ }
368
+ const groupCaches = _LruCache.groupCaches.get(cacheKey);
369
+ if (groupCaches) {
370
+ groupCaches.clear();
371
+ }
372
+ });
373
+ }
374
+ /**
375
+ * 广播缓存数据给其他 worker
376
+ */
377
+ _broadcastSync(key, value, expiresAt, isGroup = false, subKey) {
378
+ if (this.enableSync) {
379
+ eventHub.broadcast(LRU_CACHE_SYNC_EVENT, {
380
+ channel: this.cacheKey,
381
+ key,
382
+ value,
383
+ expiresAt,
384
+ isGroup,
385
+ subKey
386
+ });
387
+ }
388
+ }
389
+ /**
390
+ * 广播删除缓存给其他 worker
391
+ */
392
+ _broadcastDelete(keys, isGroup = false, groupKey) {
393
+ if (this.enableSync && keys.length > 0) {
394
+ eventHub.broadcast(LRU_CACHE_DELETE_EVENT, {
395
+ channel: this.cacheKey,
396
+ keys,
397
+ isGroup,
398
+ groupKey
399
+ });
400
+ }
401
+ }
402
+ /**
403
+ * 广播清空缓存给其他 worker
404
+ */
405
+ _broadcastClear() {
406
+ if (this.enableSync) {
407
+ eventHub.broadcast(LRU_CACHE_CLEAR_EVENT, {
408
+ channel: this.cacheKey
409
+ });
410
+ }
411
+ }
412
+ isExpired(entry) {
413
+ if (!entry)
414
+ return true;
415
+ if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
416
+ return true;
417
+ }
418
+ return false;
419
+ }
420
+ /* ---------------------- 基础 API ---------------------- */
421
+ /**
422
+ * 设置缓存
423
+ * @param key 缓存键
424
+ * @param value 序列化后的值
425
+ * @param expiresAt 过期时间戳,null 表示永不过期
426
+ */
427
+ set(key, value, expiresAt) {
428
+ const cache = this.getCache();
429
+ const entry = { value, expiresAt };
430
+ cache.set(key, entry);
431
+ this._broadcastSync(key, value, expiresAt);
432
+ }
433
+ /**
434
+ * 获取缓存
435
+ * @param key 缓存键
436
+ * @returns 序列化的值,未命中或过期返回 null
437
+ */
438
+ get(key) {
439
+ const cache = this.getCache();
440
+ const entry = cache.get(key);
441
+ if (!entry)
442
+ return null;
443
+ if (this.isExpired(entry)) {
444
+ cache.delete(key);
445
+ return null;
446
+ }
447
+ return entry.value;
448
+ }
449
+ /**
450
+ * 检查缓存是否存在且未过期
451
+ */
452
+ has(key) {
453
+ const cache = this.getCache();
454
+ const entry = cache.get(key);
455
+ if (!entry)
456
+ return false;
457
+ if (this.isExpired(entry)) {
458
+ cache.delete(key);
459
+ return false;
460
+ }
461
+ return true;
462
+ }
463
+ /**
464
+ * 删除缓存
465
+ */
466
+ del(key) {
467
+ const cache = this.getCache();
468
+ cache.delete(key);
469
+ const groupCaches = this.getGroupCaches();
470
+ groupCaches.delete(key);
471
+ this._broadcastDelete([key]);
472
+ }
473
+ /**
474
+ * 按前缀删除缓存
475
+ * @returns 删除的数量
476
+ */
477
+ delByPrefix(prefix) {
478
+ const cache = this.getCache();
479
+ const deletedKeys = [];
480
+ for (const key of cache.keys()) {
481
+ if (key.startsWith(prefix)) {
482
+ cache.delete(key);
483
+ deletedKeys.push(key);
484
+ }
485
+ }
486
+ const groupCaches = this.getGroupCaches();
487
+ for (const key of groupCaches.keys()) {
488
+ if (key.startsWith(prefix)) {
489
+ groupCaches.delete(key);
490
+ }
491
+ }
492
+ this._broadcastDelete(deletedKeys);
493
+ return deletedKeys.length;
494
+ }
495
+ /* ---------------------- 分组 API ---------------------- */
496
+ /**
497
+ * 设置分组缓存
498
+ */
499
+ groupSet(key, subKey, value, expiresAt) {
500
+ const groupCache = this.getOrCreateGroupCache(key);
501
+ const entry = { value, expiresAt };
502
+ groupCache.set(subKey, entry);
503
+ this._broadcastSync(key, value, expiresAt, true, subKey);
504
+ }
505
+ /**
506
+ * 获取分组缓存
507
+ */
508
+ groupGet(key, subKey) {
509
+ const groupCaches = this.getGroupCaches();
510
+ const groupCache = groupCaches.get(key);
511
+ if (!groupCache)
512
+ return null;
513
+ const entry = groupCache.get(subKey);
514
+ if (!entry)
515
+ return null;
516
+ if (this.isExpired(entry)) {
517
+ groupCache.delete(subKey);
518
+ return null;
519
+ }
520
+ return entry.value;
521
+ }
522
+ /**
523
+ * 检查分组缓存是否存在
524
+ */
525
+ groupHas(key, subKey) {
526
+ const groupCaches = this.getGroupCaches();
527
+ const groupCache = groupCaches.get(key);
528
+ if (!groupCache)
529
+ return false;
530
+ const entry = groupCache.get(subKey);
531
+ if (!entry)
532
+ return false;
533
+ if (this.isExpired(entry)) {
534
+ groupCache.delete(subKey);
535
+ return false;
536
+ }
537
+ return true;
538
+ }
539
+ /**
540
+ * 删除分组缓存
541
+ */
542
+ groupDel(key, subKey) {
543
+ const groupCaches = this.getGroupCaches();
544
+ const groupCache = groupCaches.get(key);
545
+ if (groupCache) {
546
+ groupCache.delete(subKey);
547
+ this._broadcastDelete([subKey], true, key);
548
+ }
549
+ }
550
+ /* ---------------------- 管理 API ---------------------- */
551
+ /**
552
+ * 清空所有缓存
553
+ */
554
+ clear() {
555
+ const cache = this.getCache();
556
+ cache.clear();
557
+ const groupCaches = this.getGroupCaches();
558
+ groupCaches.clear();
559
+ this._broadcastClear();
560
+ }
561
+ /**
562
+ * 获取缓存统计信息
563
+ */
564
+ getStats() {
565
+ const cache = this.getCache();
566
+ const groupCaches = this.getGroupCaches();
567
+ let totalGroupSize = 0;
568
+ for (const groupCache of groupCaches.values()) {
569
+ totalGroupSize += groupCache.size;
570
+ }
571
+ return {
572
+ size: cache.size,
573
+ // 普通缓存条目数
574
+ groupCount: totalGroupSize,
575
+ // 分组缓存条目数
576
+ maxSize: this.maxSize
577
+ // 最大容量
578
+ };
579
+ }
580
+ /**
581
+ * 关闭缓存(清理资源)
582
+ *
583
+ * 注意:不会广播 close 事件给其他 worker,因为每个 worker 有独立的生命周期
584
+ */
585
+ close() {
586
+ _LruCache.caches.delete(this.cacheKey);
587
+ _LruCache.groupCaches.delete(this.cacheKey);
588
+ _LruCache.listenerSetup.delete(this.cacheKey);
589
+ }
590
+ };
591
+ __publicField$4(_LruCache, "caches", /* @__PURE__ */ new Map());
592
+ __publicField$4(_LruCache, "groupCaches", /* @__PURE__ */ new Map());
593
+ __publicField$4(_LruCache, "listenerSetup", /* @__PURE__ */ new Map());
594
+ let LruCache = _LruCache;
595
+
233
596
  var __defProp$3 = Object.defineProperty;
234
597
  var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
235
598
  var __publicField$3 = (obj, key, value) => {
@@ -295,6 +658,8 @@ const _SqliteAdapter = class _SqliteAdapter {
295
658
  __publicField$3(this, "defaultTtl", 1e3 * 60 * 60);
296
659
  __publicField$3(this, "cleanupInterval", 5 * 60 * 1e3);
297
660
  __publicField$3(this, "dbPath", "");
661
+ __publicField$3(this, "enableLruCache", false);
662
+ __publicField$3(this, "lruCache", null);
298
663
  }
299
664
  /* ------------------------------- init ------------------------------- */
300
665
  async ensure() {
@@ -304,6 +669,28 @@ const _SqliteAdapter = class _SqliteAdapter {
304
669
  this.prefix = this.opts.prefix;
305
670
  this.defaultTtl = this.opts.ttl;
306
671
  this.cleanupInterval = this.opts.cleanupInterval ?? 5 * 60 * 1e3;
672
+ this.enableLruCache = this.opts.enableLruCache ?? false;
673
+ }
674
+ if (this.enableLruCache && !this.lruCache) {
675
+ const lruCacheKey = `sqlite:${this.dbPath}:${this.prefix}`;
676
+ if (!_SqliteAdapter.lruCaches.has(lruCacheKey)) {
677
+ const requestedSize = this.opts.lruMaxSize ?? 100;
678
+ const actualSize = Math.min(requestedSize, _SqliteAdapter.MAX_LRU_CACHE_SIZE);
679
+ if (requestedSize > _SqliteAdapter.MAX_LRU_CACHE_SIZE) {
680
+ console.warn(
681
+ `[SqliteAdapter] Requested LRU cache size ${requestedSize} exceeds maximum ${_SqliteAdapter.MAX_LRU_CACHE_SIZE}, using ${actualSize} instead`
682
+ );
683
+ }
684
+ _SqliteAdapter.lruCaches.set(
685
+ lruCacheKey,
686
+ new LruCache({
687
+ prefix: lruCacheKey,
688
+ maxSize: actualSize,
689
+ enableSync: this.opts.enableSync ?? true
690
+ })
691
+ );
692
+ }
693
+ this.lruCache = _SqliteAdapter.lruCaches.get(lruCacheKey);
307
694
  }
308
695
  if (_SqliteAdapter.clients.has(this.dbPath))
309
696
  return;
@@ -366,7 +753,11 @@ const _SqliteAdapter = class _SqliteAdapter {
366
753
  const storageKey = this.prefixKey(key);
367
754
  const effectiveTtl = opts.ttl !== void 0 ? opts.ttl : this.defaultTtl;
368
755
  const expiresAt = effectiveTtl > 0 ? Date.now() + effectiveTtl : null;
756
+ const serializedValue = this.serialize(value);
369
757
  if (opts.nx) {
758
+ if (this.lruCache?.has(storageKey)) {
759
+ return false;
760
+ }
370
761
  const existing = await dbGet(
371
762
  client,
372
763
  "SELECT value FROM kvcache WHERE key = ? AND subKey = ?",
@@ -385,13 +776,22 @@ const _SqliteAdapter = class _SqliteAdapter {
385
776
  value = excluded.value,
386
777
  expiresAt = excluded.expiresAt
387
778
  `,
388
- [storageKey, "", this.serialize(value), expiresAt]
779
+ [storageKey, "", serializedValue, expiresAt]
389
780
  );
781
+ if (this.lruCache) {
782
+ this.lruCache.set(storageKey, serializedValue, expiresAt);
783
+ }
390
784
  return true;
391
785
  }
392
786
  async get(key) {
393
- const client = this.getClient();
394
787
  const storageKey = this.prefixKey(key);
788
+ if (this.lruCache) {
789
+ const cached = this.lruCache.get(storageKey);
790
+ if (cached !== null) {
791
+ return this.deserialize(cached);
792
+ }
793
+ }
794
+ const client = this.getClient();
395
795
  const row = await dbGet(
396
796
  client,
397
797
  'SELECT value, "expiresAt" FROM kvcache WHERE key = ? AND subKey = ?',
@@ -403,16 +803,25 @@ const _SqliteAdapter = class _SqliteAdapter {
403
803
  await this.del(key);
404
804
  return null;
405
805
  }
806
+ if (this.lruCache) {
807
+ this.lruCache.set(storageKey, row.value, row.expiresAt);
808
+ }
406
809
  return this.deserialize(row.value);
407
810
  }
408
811
  async del(key) {
409
- const client = this.getClient();
410
812
  const storageKey = this.prefixKey(key);
813
+ if (this.lruCache) {
814
+ this.lruCache.del(storageKey);
815
+ }
816
+ const client = this.getClient();
411
817
  await dbRun(client, "DELETE FROM kvcache WHERE key = ?", [storageKey]);
412
818
  }
413
819
  async has(key) {
414
- const client = this.getClient();
415
820
  const storageKey = this.prefixKey(key);
821
+ if (this.lruCache?.has(storageKey)) {
822
+ return true;
823
+ }
824
+ const client = this.getClient();
416
825
  const row = await dbGet(
417
826
  client,
418
827
  'SELECT "expiresAt" FROM kvcache WHERE key = ? AND subKey = ?',
@@ -432,11 +841,7 @@ const _SqliteAdapter = class _SqliteAdapter {
432
841
  const storageKey = this.prefixKey(key);
433
842
  const effectiveTtl = opts.ttl !== void 0 ? opts.ttl : this.defaultTtl;
434
843
  const expiresAt = effectiveTtl > 0 ? Date.now() + effectiveTtl : null;
435
- if (opts.nx) {
436
- const exists = await this.groupHas(key, subKey);
437
- if (exists)
438
- return;
439
- }
844
+ const serializedValue = this.serialize(value);
440
845
  await dbRun(
441
846
  client,
442
847
  `
@@ -446,12 +851,21 @@ const _SqliteAdapter = class _SqliteAdapter {
446
851
  value = excluded.value,
447
852
  expiresAt = excluded.expiresAt
448
853
  `,
449
- [storageKey, subKey, this.serialize(value), expiresAt]
854
+ [storageKey, subKey, serializedValue, expiresAt]
450
855
  );
856
+ if (this.lruCache) {
857
+ this.lruCache.groupSet(storageKey, subKey, serializedValue, expiresAt);
858
+ }
451
859
  }
452
860
  async groupGet(key, subKey) {
453
- const client = this.getClient();
454
861
  const storageKey = this.prefixKey(key);
862
+ if (this.lruCache) {
863
+ const cached = this.lruCache.groupGet(storageKey, subKey);
864
+ if (cached !== null) {
865
+ return this.deserialize(cached);
866
+ }
867
+ }
868
+ const client = this.getClient();
455
869
  const row = await dbGet(
456
870
  client,
457
871
  'SELECT value, "expiresAt" FROM kvcache WHERE key = ? AND subKey = ?',
@@ -463,11 +877,17 @@ const _SqliteAdapter = class _SqliteAdapter {
463
877
  await this.groupDel(key, subKey);
464
878
  return null;
465
879
  }
880
+ if (this.lruCache) {
881
+ this.lruCache.groupSet(storageKey, subKey, row.value, row.expiresAt);
882
+ }
466
883
  return this.deserialize(row.value);
467
884
  }
468
885
  async groupHas(key, subKey) {
469
- const client = this.getClient();
470
886
  const storageKey = this.prefixKey(key);
887
+ if (this.lruCache?.groupHas(storageKey, subKey)) {
888
+ return true;
889
+ }
890
+ const client = this.getClient();
471
891
  const row = await dbGet(
472
892
  client,
473
893
  'SELECT "expiresAt" FROM kvcache WHERE key = ? AND subKey = ?',
@@ -482,12 +902,21 @@ const _SqliteAdapter = class _SqliteAdapter {
482
902
  return true;
483
903
  }
484
904
  async groupDel(key, subKey) {
485
- const client = this.getClient();
486
905
  const storageKey = this.prefixKey(key);
906
+ if (this.lruCache) {
907
+ this.lruCache.groupDel(storageKey, subKey);
908
+ }
909
+ const client = this.getClient();
487
910
  await dbRun(client, "DELETE FROM kvcache WHERE key = ? AND subKey = ?", [storageKey, subKey]);
488
911
  }
489
912
  /* ------------------------------- misc ------------------------------- */
490
913
  async close() {
914
+ if (this.lruCache) {
915
+ this.lruCache.close();
916
+ const lruCacheKey = `sqlite:${this.dbPath}:${this.prefix}`;
917
+ _SqliteAdapter.lruCaches.delete(lruCacheKey);
918
+ this.lruCache = null;
919
+ }
491
920
  if (this.dbPath) {
492
921
  const timer = _SqliteAdapter.cleanupTimers.get(this.dbPath);
493
922
  if (timer) {
@@ -503,14 +932,29 @@ const _SqliteAdapter = class _SqliteAdapter {
503
932
  }
504
933
  }
505
934
  async flushAll() {
935
+ if (this.lruCache) {
936
+ this.lruCache.clear();
937
+ }
506
938
  const client = this.getClient();
507
939
  const run = node_util.promisify(client.run.bind(client));
508
940
  await run("DELETE FROM kvcache");
509
941
  }
942
+ /**
943
+ * 获取 LRU 缓存统计信息
944
+ */
945
+ getLruCacheStats() {
946
+ if (!this.lruCache) {
947
+ return null;
948
+ }
949
+ return this.lruCache.getStats();
950
+ }
510
951
  };
511
952
  __publicField$3(_SqliteAdapter, "clients", /* @__PURE__ */ new Map());
512
953
  __publicField$3(_SqliteAdapter, "initPromises", /* @__PURE__ */ new Map());
513
954
  __publicField$3(_SqliteAdapter, "cleanupTimers", /* @__PURE__ */ new Map());
955
+ __publicField$3(_SqliteAdapter, "lruCaches", /* @__PURE__ */ new Map());
956
+ /** LRU 缓存的最大条数上限 */
957
+ __publicField$3(_SqliteAdapter, "MAX_LRU_CACHE_SIZE", 100);
514
958
  let SqliteAdapter = _SqliteAdapter;
515
959
 
516
960
  var __defProp$2 = Object.defineProperty;
@@ -662,6 +1106,14 @@ class BaseDBCache {
662
1106
  await this.adapter.ensure();
663
1107
  return this.adapter.flushAll();
664
1108
  }
1109
+ /**
1110
+ * 获取 LRU 缓存统计信息
1111
+ * @returns 缓存统计信息,如果未启用 LRU 缓存则返回 null
1112
+ */
1113
+ getLruCacheStats() {
1114
+ this.initAdapter();
1115
+ return this.adapter.getLruCacheStats();
1116
+ }
665
1117
  }
666
1118
 
667
1119
  var __defProp$1 = Object.defineProperty;
@@ -873,5 +1325,6 @@ const getAbtNodeRedisAndSQLiteUrl = () => {
873
1325
  };
874
1326
 
875
1327
  exports.DBCache = LockDBCache;
1328
+ exports.LruCache = LruCache;
876
1329
  exports.getAbtNodeRedisAndSQLiteUrl = getAbtNodeRedisAndSQLiteUrl;
877
1330
  exports.withRetry = withRetry;