@fjell/cache 4.7.43 → 4.7.45
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/coverage_output.txt +94 -94
- package/dist/cache/layers/TwoLayerCacheMap.d.ts.map +1 -1
- package/dist/eviction/EvictionManager.d.ts.map +1 -1
- package/dist/index.js +860 -113
- package/dist/ops/retrieve.d.ts.map +1 -1
- package/dist/ops/set.d.ts.map +1 -1
- package/dist/ttl/TTLManager.d.ts.map +1 -1
- package/package.json +6 -6
- package/test_output.txt +96 -96
package/dist/index.js
CHANGED
|
@@ -94,48 +94,78 @@ var TwoLayerCacheMap = class _TwoLayerCacheMap extends CacheMap {
|
|
|
94
94
|
* Set a query result with rich metadata for two-layer architecture
|
|
95
95
|
*/
|
|
96
96
|
async setQueryResult(queryHash, itemKeys) {
|
|
97
|
+
logger.debug("QUERY_CACHE: TwoLayerCacheMap.setQueryResult() called", {
|
|
98
|
+
queryHash,
|
|
99
|
+
itemKeyCount: itemKeys.length,
|
|
100
|
+
itemKeys: itemKeys.map((k) => JSON.stringify(k))
|
|
101
|
+
});
|
|
97
102
|
await this.underlyingCache.setQueryResult(queryHash, itemKeys);
|
|
103
|
+
logger.debug("QUERY_CACHE: Stored query result in underlying cache", { queryHash });
|
|
98
104
|
const now = /* @__PURE__ */ new Date();
|
|
99
105
|
const isComplete = this.determineQueryCompleteness(queryHash, itemKeys);
|
|
100
106
|
const ttlSeconds = isComplete ? this.options.queryTTL : this.options.facetTTL;
|
|
107
|
+
const expiresAt = new Date(now.getTime() + ttlSeconds * 1e3);
|
|
101
108
|
const metadata = {
|
|
102
109
|
queryType: this.extractQueryType(queryHash),
|
|
103
110
|
isComplete,
|
|
104
111
|
createdAt: now,
|
|
105
|
-
expiresAt
|
|
112
|
+
expiresAt,
|
|
106
113
|
filter: this.extractFilter(queryHash),
|
|
107
114
|
params: this.extractParams(queryHash)
|
|
108
115
|
};
|
|
109
116
|
this.queryMetadataMap.set(queryHash, metadata);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
logger.debug("QUERY_CACHE: Set query result with metadata", {
|
|
118
|
+
queryHash,
|
|
119
|
+
itemCount: itemKeys.length,
|
|
120
|
+
isComplete,
|
|
121
|
+
ttlSeconds,
|
|
122
|
+
queryType: metadata.queryType,
|
|
123
|
+
createdAt: metadata.createdAt.toISOString(),
|
|
124
|
+
expiresAt: metadata.expiresAt.toISOString(),
|
|
125
|
+
filter: metadata.filter,
|
|
126
|
+
params: metadata.params
|
|
127
|
+
});
|
|
119
128
|
}
|
|
120
129
|
/**
|
|
121
130
|
* Get a query result with expiration checking
|
|
122
131
|
*/
|
|
123
132
|
async getQueryResult(queryHash) {
|
|
133
|
+
logger.debug("QUERY_CACHE: TwoLayerCacheMap.getQueryResult() called", { queryHash });
|
|
124
134
|
const metadata = this.queryMetadataMap.get(queryHash);
|
|
125
|
-
if (metadata
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
135
|
+
if (metadata) {
|
|
136
|
+
const now = /* @__PURE__ */ new Date();
|
|
137
|
+
const isExpired = metadata.expiresAt < now;
|
|
138
|
+
logger.debug("QUERY_CACHE: Query metadata found", {
|
|
139
|
+
queryHash,
|
|
140
|
+
isExpired,
|
|
141
|
+
expiresAt: metadata.expiresAt.toISOString(),
|
|
142
|
+
now: now.toISOString(),
|
|
143
|
+
isComplete: metadata.isComplete,
|
|
144
|
+
queryType: metadata.queryType
|
|
145
|
+
});
|
|
146
|
+
if (isExpired) {
|
|
147
|
+
logger.debug("QUERY_CACHE: Query result EXPIRED, removing", {
|
|
148
|
+
queryHash,
|
|
149
|
+
expiresAt: metadata.expiresAt.toISOString(),
|
|
150
|
+
now: now.toISOString()
|
|
151
|
+
});
|
|
152
|
+
await this.deleteQueryResult(queryHash);
|
|
153
|
+
return null;
|
|
129
154
|
}
|
|
130
|
-
|
|
155
|
+
} else {
|
|
156
|
+
logger.debug("QUERY_CACHE: No metadata found for query hash", { queryHash });
|
|
131
157
|
}
|
|
158
|
+
logger.debug("QUERY_CACHE: Fetching query result from underlying cache", { queryHash });
|
|
132
159
|
const result = await this.underlyingCache.getQueryResult(queryHash);
|
|
133
|
-
if (result
|
|
134
|
-
logger.debug("Query result cache
|
|
160
|
+
if (result) {
|
|
161
|
+
logger.debug("QUERY_CACHE: Query result retrieved from underlying cache", {
|
|
135
162
|
queryHash,
|
|
136
163
|
itemCount: result.length,
|
|
137
|
-
isComplete: metadata?.isComplete
|
|
164
|
+
isComplete: metadata?.isComplete,
|
|
165
|
+
itemKeys: result.map((k) => JSON.stringify(k))
|
|
138
166
|
});
|
|
167
|
+
} else {
|
|
168
|
+
logger.debug("QUERY_CACHE: No query result found in underlying cache", { queryHash });
|
|
139
169
|
}
|
|
140
170
|
return result;
|
|
141
171
|
}
|
|
@@ -150,25 +180,44 @@ var TwoLayerCacheMap = class _TwoLayerCacheMap extends CacheMap {
|
|
|
150
180
|
* Delete a query result and its metadata
|
|
151
181
|
*/
|
|
152
182
|
async deleteQueryResult(queryHash) {
|
|
183
|
+
logger.debug("QUERY_CACHE: TwoLayerCacheMap.deleteQueryResult() called", { queryHash });
|
|
184
|
+
const hadMetadata = this.queryMetadataMap.has(queryHash);
|
|
185
|
+
const metadata = this.queryMetadataMap.get(queryHash);
|
|
153
186
|
await this.underlyingCache.deleteQueryResult(queryHash);
|
|
154
187
|
this.queryMetadataMap.delete(queryHash);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
188
|
+
logger.debug("QUERY_CACHE: Deleted query result", {
|
|
189
|
+
queryHash,
|
|
190
|
+
hadMetadata,
|
|
191
|
+
wasComplete: metadata?.isComplete,
|
|
192
|
+
queryType: metadata?.queryType
|
|
193
|
+
});
|
|
158
194
|
}
|
|
159
195
|
// ===== QUERY INVALIDATION (CRITICAL FOR TWO-LAYER ARCHITECTURE) =====
|
|
160
196
|
/**
|
|
161
197
|
* Invalidate queries that are affected by item changes
|
|
162
198
|
*/
|
|
163
199
|
async invalidateQueriesForItem(itemKey) {
|
|
200
|
+
logger.debug("QUERY_CACHE: Invalidating queries for item change", {
|
|
201
|
+
itemKey: JSON.stringify(itemKey)
|
|
202
|
+
});
|
|
164
203
|
const affectedQueries = await this.findQueriesContainingItem(itemKey);
|
|
204
|
+
logger.debug("QUERY_CACHE: Found queries containing item", {
|
|
205
|
+
itemKey: JSON.stringify(itemKey),
|
|
206
|
+
affectedQueryCount: affectedQueries.length,
|
|
207
|
+
affectedQueries
|
|
208
|
+
});
|
|
165
209
|
for (const queryHash of affectedQueries) {
|
|
166
210
|
await this.deleteQueryResult(queryHash);
|
|
167
211
|
}
|
|
168
|
-
if (
|
|
169
|
-
logger.debug("Invalidated queries for item change", {
|
|
212
|
+
if (affectedQueries.length > 0) {
|
|
213
|
+
logger.debug("QUERY_CACHE: Invalidated queries for item change", {
|
|
170
214
|
itemKey: JSON.stringify(itemKey),
|
|
171
|
-
queriesInvalidated: affectedQueries.length
|
|
215
|
+
queriesInvalidated: affectedQueries.length,
|
|
216
|
+
queryHashes: affectedQueries
|
|
217
|
+
});
|
|
218
|
+
} else {
|
|
219
|
+
logger.debug("QUERY_CACHE: No queries found containing item", {
|
|
220
|
+
itemKey: JSON.stringify(itemKey)
|
|
172
221
|
});
|
|
173
222
|
}
|
|
174
223
|
}
|
|
@@ -307,18 +356,40 @@ var TwoLayerCacheMap = class _TwoLayerCacheMap extends CacheMap {
|
|
|
307
356
|
* Clean up expired queries
|
|
308
357
|
*/
|
|
309
358
|
async cleanup() {
|
|
359
|
+
const startTime = Date.now();
|
|
310
360
|
const now = /* @__PURE__ */ new Date();
|
|
311
361
|
const expiredQueries = [];
|
|
362
|
+
logger.debug("TWO_LAYER: Starting query cleanup", {
|
|
363
|
+
totalQueries: this.queryMetadataMap.size,
|
|
364
|
+
now: now.toISOString()
|
|
365
|
+
});
|
|
312
366
|
for (const [queryHash, metadata] of this.queryMetadataMap.entries()) {
|
|
313
367
|
if (metadata.expiresAt < now) {
|
|
314
368
|
expiredQueries.push(queryHash);
|
|
369
|
+
logger.debug("TWO_LAYER: Found expired query", {
|
|
370
|
+
queryHash,
|
|
371
|
+
queryType: metadata.queryType,
|
|
372
|
+
isComplete: metadata.isComplete,
|
|
373
|
+
expiresAt: metadata.expiresAt.toISOString(),
|
|
374
|
+
expiredByMs: now.getTime() - metadata.expiresAt.getTime()
|
|
375
|
+
});
|
|
315
376
|
}
|
|
316
377
|
}
|
|
317
378
|
for (const queryHash of expiredQueries) {
|
|
318
379
|
await this.deleteQueryResult(queryHash);
|
|
319
380
|
}
|
|
320
|
-
|
|
321
|
-
|
|
381
|
+
const duration = Date.now() - startTime;
|
|
382
|
+
if (expiredQueries.length > 0) {
|
|
383
|
+
logger.debug("TWO_LAYER: Query cleanup completed", {
|
|
384
|
+
expiredCount: expiredQueries.length,
|
|
385
|
+
totalQueries: this.queryMetadataMap.size,
|
|
386
|
+
duration
|
|
387
|
+
});
|
|
388
|
+
} else {
|
|
389
|
+
logger.debug("TWO_LAYER: Query cleanup - no expired queries", {
|
|
390
|
+
totalQueries: this.queryMetadataMap.size,
|
|
391
|
+
duration
|
|
392
|
+
});
|
|
322
393
|
}
|
|
323
394
|
return expiredQueries.length;
|
|
324
395
|
}
|
|
@@ -330,24 +401,68 @@ var TwoLayerCacheMap = class _TwoLayerCacheMap extends CacheMap {
|
|
|
330
401
|
// The types are accessible through super.types
|
|
331
402
|
// ===== MISSING ABSTRACT METHODS FROM CacheMap =====
|
|
332
403
|
async invalidateItemKeys(keys) {
|
|
404
|
+
const startTime = Date.now();
|
|
405
|
+
logger.debug("TWO_LAYER: Invalidating item keys", {
|
|
406
|
+
keyCount: keys.length,
|
|
407
|
+
keys: keys.map((k) => JSON.stringify(k))
|
|
408
|
+
});
|
|
333
409
|
if ("invalidateItemKeys" in this.underlyingCache && typeof this.underlyingCache.invalidateItemKeys === "function") {
|
|
334
410
|
await this.underlyingCache.invalidateItemKeys(keys);
|
|
335
411
|
}
|
|
412
|
+
let totalInvalidatedQueries = 0;
|
|
336
413
|
for (const key of keys) {
|
|
414
|
+
const beforeCount = this.queryMetadataMap.size;
|
|
337
415
|
await this.invalidateQueriesForItem(key);
|
|
416
|
+
const afterCount = this.queryMetadataMap.size;
|
|
417
|
+
const invalidated = beforeCount - afterCount;
|
|
418
|
+
totalInvalidatedQueries += invalidated;
|
|
419
|
+
if (invalidated > 0) {
|
|
420
|
+
logger.debug("TWO_LAYER: Invalidated queries for item", {
|
|
421
|
+
key: JSON.stringify(key),
|
|
422
|
+
queriesInvalidated: invalidated
|
|
423
|
+
});
|
|
424
|
+
}
|
|
338
425
|
}
|
|
426
|
+
const duration = Date.now() - startTime;
|
|
427
|
+
logger.debug("TWO_LAYER: Item key invalidation completed", {
|
|
428
|
+
keyCount: keys.length,
|
|
429
|
+
totalQueriesInvalidated: totalInvalidatedQueries,
|
|
430
|
+
duration
|
|
431
|
+
});
|
|
339
432
|
}
|
|
340
433
|
async invalidateLocation(locations) {
|
|
434
|
+
const startTime = Date.now();
|
|
435
|
+
const queryCountBefore = this.queryMetadataMap.size;
|
|
436
|
+
logger.debug("TWO_LAYER: Invalidating location", {
|
|
437
|
+
locations: JSON.stringify(locations),
|
|
438
|
+
queryCountBefore
|
|
439
|
+
});
|
|
341
440
|
if ("invalidateLocation" in this.underlyingCache && typeof this.underlyingCache.invalidateLocation === "function") {
|
|
342
441
|
await this.underlyingCache.invalidateLocation(locations);
|
|
343
442
|
}
|
|
344
443
|
this.queryMetadataMap.clear();
|
|
444
|
+
const duration = Date.now() - startTime;
|
|
445
|
+
logger.debug("TWO_LAYER: Location invalidation completed", {
|
|
446
|
+
locations: JSON.stringify(locations),
|
|
447
|
+
queriesCleared: queryCountBefore,
|
|
448
|
+
duration
|
|
449
|
+
});
|
|
345
450
|
}
|
|
346
451
|
async clearQueryResults() {
|
|
452
|
+
const startTime = Date.now();
|
|
453
|
+
const queryCountBefore = this.queryMetadataMap.size;
|
|
454
|
+
logger.debug("TWO_LAYER: Clearing all query results", {
|
|
455
|
+
queryCountBefore
|
|
456
|
+
});
|
|
347
457
|
if ("clearQueryResults" in this.underlyingCache && typeof this.underlyingCache.clearQueryResults === "function") {
|
|
348
458
|
await this.underlyingCache.clearQueryResults();
|
|
349
459
|
}
|
|
350
460
|
this.queryMetadataMap.clear();
|
|
461
|
+
const duration = Date.now() - startTime;
|
|
462
|
+
logger.debug("TWO_LAYER: Cleared all query results", {
|
|
463
|
+
queriesCleared: queryCountBefore,
|
|
464
|
+
duration
|
|
465
|
+
});
|
|
351
466
|
}
|
|
352
467
|
/**
|
|
353
468
|
* Check if two-layer mode is enabled
|
|
@@ -702,66 +817,159 @@ async function executeAllLogic(query, locations, context) {
|
|
|
702
817
|
}
|
|
703
818
|
}
|
|
704
819
|
const queryHash = createQueryHash(pkType, query, locations);
|
|
705
|
-
logger2.debug("Generated query hash for all", {
|
|
820
|
+
logger2.debug("QUERY_CACHE: Generated query hash for all()", {
|
|
821
|
+
queryHash,
|
|
822
|
+
query: JSON.stringify(query),
|
|
823
|
+
locations: JSON.stringify(locations),
|
|
824
|
+
pkType
|
|
825
|
+
});
|
|
826
|
+
logger2.debug("QUERY_CACHE: Checking query cache for hash", { queryHash });
|
|
706
827
|
const cachedItemKeys = await cacheMap.getQueryResult(queryHash);
|
|
707
828
|
if (cachedItemKeys) {
|
|
708
|
-
logger2.debug("
|
|
829
|
+
logger2.debug("QUERY_CACHE: Cache HIT - Found cached query result", {
|
|
830
|
+
queryHash,
|
|
831
|
+
cachedKeyCount: cachedItemKeys.length,
|
|
832
|
+
itemKeys: cachedItemKeys.map((k) => JSON.stringify(k))
|
|
833
|
+
});
|
|
709
834
|
const cachedItems = [];
|
|
710
835
|
let allItemsAvailable = true;
|
|
836
|
+
const missingKeys = [];
|
|
711
837
|
for (const itemKey of cachedItemKeys) {
|
|
712
838
|
const item = await cacheMap.get(itemKey);
|
|
713
839
|
if (item) {
|
|
714
840
|
cachedItems.push(item);
|
|
841
|
+
logger2.debug("QUERY_CACHE: Retrieved cached item", {
|
|
842
|
+
itemKey: JSON.stringify(itemKey),
|
|
843
|
+
itemKeyStr: JSON.stringify(item.key)
|
|
844
|
+
});
|
|
715
845
|
} else {
|
|
716
846
|
allItemsAvailable = false;
|
|
847
|
+
missingKeys.push(itemKey);
|
|
848
|
+
logger2.debug("QUERY_CACHE: Cached item MISSING from item cache", {
|
|
849
|
+
itemKey: JSON.stringify(itemKey),
|
|
850
|
+
queryHash
|
|
851
|
+
});
|
|
717
852
|
break;
|
|
718
853
|
}
|
|
719
854
|
}
|
|
720
855
|
if (allItemsAvailable) {
|
|
856
|
+
logger2.debug("QUERY_CACHE: All cached items available, returning from cache", {
|
|
857
|
+
queryHash,
|
|
858
|
+
itemCount: cachedItems.length
|
|
859
|
+
});
|
|
721
860
|
return cachedItems;
|
|
722
861
|
} else {
|
|
723
|
-
logger2.debug("Some cached items missing, invalidating query cache"
|
|
862
|
+
logger2.debug("QUERY_CACHE: Some cached items missing, invalidating query cache", {
|
|
863
|
+
queryHash,
|
|
864
|
+
missingKeys: missingKeys.map((k) => JSON.stringify(k)),
|
|
865
|
+
foundCount: cachedItems.length,
|
|
866
|
+
expectedCount: cachedItemKeys.length
|
|
867
|
+
});
|
|
724
868
|
cacheMap.deleteQueryResult(queryHash);
|
|
725
869
|
}
|
|
870
|
+
} else {
|
|
871
|
+
logger2.debug("QUERY_CACHE: Cache MISS - No cached query result found", { queryHash });
|
|
726
872
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
873
|
+
const isEmptyQuery = Object.keys(query).length === 0 || (Object.keys(query).length === 1 && "limit" in query || "offset" in query);
|
|
874
|
+
if (!isEmptyQuery) {
|
|
875
|
+
logger2.debug("QUERY_CACHE: Attempting direct cache query using queryIn() for filtered query", {
|
|
876
|
+
queryHash,
|
|
877
|
+
query: JSON.stringify(query),
|
|
878
|
+
locations: JSON.stringify(locations)
|
|
879
|
+
});
|
|
880
|
+
try {
|
|
881
|
+
const directCachedItems = await cacheMap.queryIn(query, locations);
|
|
882
|
+
if (directCachedItems && directCachedItems.length > 0) {
|
|
883
|
+
logger2.debug("QUERY_CACHE: Direct cache query SUCCESS - Found items in item cache", {
|
|
884
|
+
queryHash,
|
|
885
|
+
itemCount: directCachedItems.length,
|
|
886
|
+
itemKeys: directCachedItems.map((item) => JSON.stringify(item.key))
|
|
887
|
+
});
|
|
888
|
+
const itemKeys = directCachedItems.map((item) => item.key);
|
|
889
|
+
await cacheMap.setQueryResult(queryHash, itemKeys);
|
|
890
|
+
logger2.debug("QUERY_CACHE: Stored query result from direct cache hit", {
|
|
891
|
+
queryHash,
|
|
892
|
+
itemKeyCount: itemKeys.length,
|
|
893
|
+
itemKeys: itemKeys.map((k) => JSON.stringify(k))
|
|
894
|
+
});
|
|
895
|
+
return directCachedItems;
|
|
896
|
+
} else {
|
|
897
|
+
logger2.debug("QUERY_CACHE: Direct cache query returned no items", { queryHash });
|
|
898
|
+
}
|
|
899
|
+
} catch (error) {
|
|
900
|
+
logger2.debug("QUERY_CACHE: Error querying cache directly, proceeding to API", {
|
|
901
|
+
queryHash,
|
|
902
|
+
error: error instanceof Error ? error.message : String(error)
|
|
903
|
+
});
|
|
735
904
|
}
|
|
736
|
-
}
|
|
737
|
-
logger2.debug("
|
|
905
|
+
} else {
|
|
906
|
+
logger2.debug("QUERY_CACHE: Skipping direct cache query for empty/all query - cannot trust completeness", {
|
|
907
|
+
queryHash,
|
|
908
|
+
query: JSON.stringify(query)
|
|
909
|
+
});
|
|
738
910
|
}
|
|
911
|
+
logger2.debug("QUERY_CACHE: Fetching from API (cache miss or invalid)", {
|
|
912
|
+
queryHash,
|
|
913
|
+
query: JSON.stringify(query),
|
|
914
|
+
locations: JSON.stringify(locations)
|
|
915
|
+
});
|
|
739
916
|
let ret = [];
|
|
740
917
|
try {
|
|
741
918
|
ret = await api.all(query, locations);
|
|
919
|
+
logger2.debug("QUERY_CACHE: API response received", {
|
|
920
|
+
queryHash,
|
|
921
|
+
itemCount: ret.length,
|
|
922
|
+
itemKeys: ret.map((item) => JSON.stringify(item.key))
|
|
923
|
+
});
|
|
924
|
+
logger2.debug("QUERY_CACHE: Storing items in item cache", {
|
|
925
|
+
queryHash,
|
|
926
|
+
itemCount: ret.length
|
|
927
|
+
});
|
|
742
928
|
for (const v of ret) {
|
|
743
929
|
await cacheMap.set(v.key, v);
|
|
930
|
+
logger2.debug("QUERY_CACHE: Stored item in cache", {
|
|
931
|
+
itemKey: JSON.stringify(v.key),
|
|
932
|
+
queryHash
|
|
933
|
+
});
|
|
744
934
|
const keyStr = JSON.stringify(v.key);
|
|
745
935
|
ttlManager.onItemAdded(keyStr, cacheMap);
|
|
746
936
|
const evictedKeys = await context.evictionManager.onItemAdded(keyStr, v, cacheMap);
|
|
747
937
|
for (const evictedKey of evictedKeys) {
|
|
748
938
|
const parsedKey = JSON.parse(evictedKey);
|
|
749
939
|
await cacheMap.delete(parsedKey);
|
|
940
|
+
logger2.debug("QUERY_CACHE: Evicted item due to cache limits", {
|
|
941
|
+
evictedKey,
|
|
942
|
+
queryHash
|
|
943
|
+
});
|
|
750
944
|
}
|
|
751
945
|
}
|
|
752
946
|
const itemKeys = ret.map((item) => item.key);
|
|
753
|
-
cacheMap.setQueryResult(queryHash, itemKeys);
|
|
754
|
-
logger2.debug("
|
|
947
|
+
await cacheMap.setQueryResult(queryHash, itemKeys);
|
|
948
|
+
logger2.debug("QUERY_CACHE: Stored query result in query cache", {
|
|
949
|
+
queryHash,
|
|
950
|
+
itemKeyCount: itemKeys.length,
|
|
951
|
+
itemKeys: itemKeys.map((k) => JSON.stringify(k))
|
|
952
|
+
});
|
|
755
953
|
const event = CacheEventFactory.createQueryEvent(query, locations, ret);
|
|
756
954
|
context.eventEmitter.emit(event);
|
|
955
|
+
logger2.debug("QUERY_CACHE: Emitted query event", { queryHash });
|
|
757
956
|
} catch (e) {
|
|
758
957
|
if (e instanceof NotFoundError) {
|
|
759
|
-
|
|
760
|
-
|
|
958
|
+
logger2.debug("QUERY_CACHE: API returned NotFoundError, caching empty result", { queryHash });
|
|
959
|
+
await cacheMap.setQueryResult(queryHash, []);
|
|
960
|
+
logger2.debug("QUERY_CACHE: Cached empty query result for not found", { queryHash });
|
|
761
961
|
} else {
|
|
962
|
+
logger2.debug("QUERY_CACHE: API error occurred", {
|
|
963
|
+
queryHash,
|
|
964
|
+
error: e instanceof Error ? e.message : String(e)
|
|
965
|
+
});
|
|
762
966
|
throw e;
|
|
763
967
|
}
|
|
764
968
|
}
|
|
969
|
+
logger2.debug("QUERY_CACHE: all() operation completed", {
|
|
970
|
+
queryHash,
|
|
971
|
+
resultCount: ret.length
|
|
972
|
+
});
|
|
765
973
|
return ret;
|
|
766
974
|
}
|
|
767
975
|
|
|
@@ -964,37 +1172,93 @@ async function executeOneLogic(query, locations, context) {
|
|
|
964
1172
|
}
|
|
965
1173
|
}
|
|
966
1174
|
const queryHash = createQueryHash(pkType, query, locations);
|
|
967
|
-
logger3.debug("Generated query hash for one", {
|
|
1175
|
+
logger3.debug("QUERY_CACHE: Generated query hash for one()", {
|
|
1176
|
+
queryHash,
|
|
1177
|
+
query: JSON.stringify(query),
|
|
1178
|
+
locations: JSON.stringify(locations),
|
|
1179
|
+
pkType
|
|
1180
|
+
});
|
|
1181
|
+
logger3.debug("QUERY_CACHE: Checking query cache for hash", { queryHash });
|
|
968
1182
|
const cachedItemKeys = await cacheMap.getQueryResult(queryHash);
|
|
969
1183
|
if (cachedItemKeys) {
|
|
970
|
-
logger3.debug("
|
|
1184
|
+
logger3.debug("QUERY_CACHE: Cache HIT - Found cached query result", {
|
|
1185
|
+
queryHash,
|
|
1186
|
+
cachedKeyCount: cachedItemKeys.length,
|
|
1187
|
+
itemKeys: cachedItemKeys.map((k) => JSON.stringify(k))
|
|
1188
|
+
});
|
|
971
1189
|
if (cachedItemKeys.length === 0) {
|
|
1190
|
+
logger3.debug("QUERY_CACHE: Cached empty result (not found)", { queryHash });
|
|
972
1191
|
return null;
|
|
973
1192
|
}
|
|
974
|
-
const
|
|
1193
|
+
const itemKey = cachedItemKeys[0];
|
|
1194
|
+
logger3.debug("QUERY_CACHE: Retrieving first cached item", {
|
|
1195
|
+
queryHash,
|
|
1196
|
+
itemKey: JSON.stringify(itemKey)
|
|
1197
|
+
});
|
|
1198
|
+
const item = await cacheMap.get(itemKey);
|
|
975
1199
|
if (item) {
|
|
1200
|
+
logger3.debug("QUERY_CACHE: Retrieved cached item successfully", {
|
|
1201
|
+
queryHash,
|
|
1202
|
+
itemKey: JSON.stringify(itemKey),
|
|
1203
|
+
itemKeyStr: JSON.stringify(item.key)
|
|
1204
|
+
});
|
|
976
1205
|
return item;
|
|
977
1206
|
} else {
|
|
978
|
-
logger3.debug("Cached item
|
|
1207
|
+
logger3.debug("QUERY_CACHE: Cached item MISSING from item cache, invalidating query cache", {
|
|
1208
|
+
queryHash,
|
|
1209
|
+
itemKey: JSON.stringify(itemKey)
|
|
1210
|
+
});
|
|
979
1211
|
cacheMap.deleteQueryResult(queryHash);
|
|
980
1212
|
}
|
|
1213
|
+
} else {
|
|
1214
|
+
logger3.debug("QUERY_CACHE: Cache MISS - No cached query result found", { queryHash });
|
|
981
1215
|
}
|
|
1216
|
+
logger3.debug("QUERY_CACHE: Attempting direct cache query using queryIn()", {
|
|
1217
|
+
queryHash,
|
|
1218
|
+
query: JSON.stringify(query),
|
|
1219
|
+
locations: JSON.stringify(locations)
|
|
1220
|
+
});
|
|
982
1221
|
try {
|
|
983
1222
|
const directCachedItems = await cacheMap.queryIn(query, locations);
|
|
984
1223
|
if (directCachedItems && directCachedItems.length > 0) {
|
|
985
|
-
logger3.debug("Found item
|
|
1224
|
+
logger3.debug("QUERY_CACHE: Direct cache query SUCCESS - Found item in item cache", {
|
|
1225
|
+
queryHash,
|
|
1226
|
+
itemCount: directCachedItems.length,
|
|
1227
|
+
itemKeys: directCachedItems.map((item) => JSON.stringify(item.key))
|
|
1228
|
+
});
|
|
986
1229
|
const foundItem = directCachedItems[0];
|
|
987
1230
|
await cacheMap.setQueryResult(queryHash, [foundItem.key]);
|
|
988
|
-
logger3.debug("
|
|
1231
|
+
logger3.debug("QUERY_CACHE: Stored query result from direct cache hit", {
|
|
1232
|
+
queryHash,
|
|
1233
|
+
itemKey: JSON.stringify(foundItem.key)
|
|
1234
|
+
});
|
|
989
1235
|
return foundItem;
|
|
1236
|
+
} else {
|
|
1237
|
+
logger3.debug("QUERY_CACHE: Direct cache query returned no items", { queryHash });
|
|
990
1238
|
}
|
|
991
1239
|
} catch (error) {
|
|
992
|
-
logger3.debug("Error querying cache directly, proceeding to API", {
|
|
1240
|
+
logger3.debug("QUERY_CACHE: Error querying cache directly, proceeding to API", {
|
|
1241
|
+
queryHash,
|
|
1242
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1243
|
+
});
|
|
993
1244
|
}
|
|
1245
|
+
logger3.debug("QUERY_CACHE: Fetching from API (cache miss or invalid)", {
|
|
1246
|
+
queryHash,
|
|
1247
|
+
query: JSON.stringify(query),
|
|
1248
|
+
locations: JSON.stringify(locations)
|
|
1249
|
+
});
|
|
994
1250
|
let retItem = null;
|
|
995
1251
|
try {
|
|
996
1252
|
retItem = await api.one(query, locations);
|
|
997
1253
|
if (retItem) {
|
|
1254
|
+
logger3.debug("QUERY_CACHE: API response received", {
|
|
1255
|
+
queryHash,
|
|
1256
|
+
itemKey: JSON.stringify(retItem.key)
|
|
1257
|
+
});
|
|
1258
|
+
logger3.debug("QUERY_CACHE: Storing item in item cache", {
|
|
1259
|
+
queryHash,
|
|
1260
|
+
itemKey: JSON.stringify(retItem.key)
|
|
1261
|
+
});
|
|
998
1262
|
await cacheMap.set(retItem.key, retItem);
|
|
999
1263
|
const keyStr = JSON.stringify(retItem.key);
|
|
1000
1264
|
const metadata = await cacheMap.getMetadata(keyStr);
|
|
@@ -1014,21 +1278,38 @@ async function executeOneLogic(query, locations, context) {
|
|
|
1014
1278
|
for (const evictedKey of evictedKeys) {
|
|
1015
1279
|
const parsedKey = JSON.parse(evictedKey);
|
|
1016
1280
|
await cacheMap.delete(parsedKey);
|
|
1281
|
+
logger3.debug("QUERY_CACHE: Evicted item due to cache limits", {
|
|
1282
|
+
evictedKey,
|
|
1283
|
+
queryHash
|
|
1284
|
+
});
|
|
1017
1285
|
}
|
|
1018
1286
|
await cacheMap.setQueryResult(queryHash, [retItem.key]);
|
|
1019
|
-
logger3.debug("
|
|
1287
|
+
logger3.debug("QUERY_CACHE: Stored query result in query cache", {
|
|
1288
|
+
queryHash,
|
|
1289
|
+
itemKey: JSON.stringify(retItem.key)
|
|
1290
|
+
});
|
|
1020
1291
|
} else {
|
|
1292
|
+
logger3.debug("QUERY_CACHE: API returned null, caching empty result", { queryHash });
|
|
1021
1293
|
await cacheMap.setQueryResult(queryHash, []);
|
|
1022
|
-
logger3.debug("Cached empty query result", { queryHash });
|
|
1294
|
+
logger3.debug("QUERY_CACHE: Cached empty query result", { queryHash });
|
|
1023
1295
|
}
|
|
1024
1296
|
} catch (e) {
|
|
1025
1297
|
if (e instanceof NotFoundError2) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1298
|
+
logger3.debug("QUERY_CACHE: API returned NotFoundError, caching empty result", { queryHash });
|
|
1299
|
+
await cacheMap.setQueryResult(queryHash, []);
|
|
1300
|
+
logger3.debug("QUERY_CACHE: Cached empty query result for not found", { queryHash });
|
|
1028
1301
|
} else {
|
|
1302
|
+
logger3.debug("QUERY_CACHE: API error occurred", {
|
|
1303
|
+
queryHash,
|
|
1304
|
+
error: e instanceof Error ? e.message : String(e)
|
|
1305
|
+
});
|
|
1029
1306
|
throw e;
|
|
1030
1307
|
}
|
|
1031
1308
|
}
|
|
1309
|
+
logger3.debug("QUERY_CACHE: one() operation completed", {
|
|
1310
|
+
queryHash,
|
|
1311
|
+
result: retItem ? JSON.stringify(retItem.key) : null
|
|
1312
|
+
});
|
|
1032
1313
|
return retItem || null;
|
|
1033
1314
|
}
|
|
1034
1315
|
|
|
@@ -1110,68 +1391,128 @@ var get = async (key, context) => {
|
|
|
1110
1391
|
return [context, result];
|
|
1111
1392
|
};
|
|
1112
1393
|
async function executeGetLogic(key, context) {
|
|
1394
|
+
const startTime = Date.now();
|
|
1113
1395
|
const { api, cacheMap, pkType, ttlManager, statsManager } = context;
|
|
1396
|
+
const keyStr = JSON.stringify(key);
|
|
1397
|
+
logger5.debug("CACHE_OP: get() started", {
|
|
1398
|
+
key: keyStr,
|
|
1399
|
+
ttlEnabled: ttlManager.isTTLEnabled(),
|
|
1400
|
+
defaultTTL: ttlManager.getDefaultTTL(),
|
|
1401
|
+
cacheType: cacheMap.implementationType
|
|
1402
|
+
});
|
|
1114
1403
|
statsManager.incrementRequests();
|
|
1115
1404
|
if (!isValidItemKey(key)) {
|
|
1116
|
-
logger5.error("
|
|
1405
|
+
logger5.error("CACHE_OP: Invalid key for get", { key: keyStr });
|
|
1117
1406
|
throw new Error("Key for Get is not a valid ItemKey");
|
|
1118
1407
|
}
|
|
1119
1408
|
if (context.options?.bypassCache) {
|
|
1120
|
-
logger5.debug("Cache bypass enabled, fetching directly from API", { key });
|
|
1409
|
+
logger5.debug("CACHE_OP: Cache bypass enabled, fetching directly from API", { key: keyStr });
|
|
1121
1410
|
statsManager.incrementMisses();
|
|
1122
1411
|
try {
|
|
1412
|
+
const apiStartTime = Date.now();
|
|
1123
1413
|
const ret2 = await api.get(key);
|
|
1414
|
+
const apiDuration = Date.now() - apiStartTime;
|
|
1124
1415
|
if (ret2) {
|
|
1125
|
-
logger5.debug("API response received (not cached
|
|
1416
|
+
logger5.debug("CACHE_OP: API response received (bypass mode, not cached)", {
|
|
1417
|
+
key: keyStr,
|
|
1418
|
+
apiDuration,
|
|
1419
|
+
totalDuration: Date.now() - startTime
|
|
1420
|
+
});
|
|
1126
1421
|
return ret2;
|
|
1127
1422
|
} else {
|
|
1128
|
-
logger5.debug("API returned null", {
|
|
1423
|
+
logger5.debug("CACHE_OP: API returned null (bypass mode)", {
|
|
1424
|
+
key: keyStr,
|
|
1425
|
+
apiDuration
|
|
1426
|
+
});
|
|
1129
1427
|
return null;
|
|
1130
1428
|
}
|
|
1131
1429
|
} catch (error) {
|
|
1132
|
-
logger5.error("API request failed", {
|
|
1430
|
+
logger5.error("CACHE_OP: API request failed in bypass mode", {
|
|
1431
|
+
key: keyStr,
|
|
1432
|
+
duration: Date.now() - startTime,
|
|
1433
|
+
error
|
|
1434
|
+
});
|
|
1133
1435
|
throw error;
|
|
1134
1436
|
}
|
|
1135
1437
|
}
|
|
1136
1438
|
if (ttlManager.isTTLEnabled()) {
|
|
1137
|
-
const
|
|
1439
|
+
const cacheCheckStart = Date.now();
|
|
1138
1440
|
const cachedItem = await cacheMap.get(key);
|
|
1441
|
+
const cacheCheckDuration = Date.now() - cacheCheckStart;
|
|
1139
1442
|
if (cachedItem) {
|
|
1140
|
-
|
|
1443
|
+
logger5.debug("CACHE_OP: Item found in cache, checking TTL validity", {
|
|
1444
|
+
key: keyStr,
|
|
1445
|
+
cacheCheckDuration,
|
|
1446
|
+
defaultTTL: ttlManager.getDefaultTTL()
|
|
1447
|
+
});
|
|
1448
|
+
const ttlCheckStart = Date.now();
|
|
1449
|
+
const isValid = await ttlManager.validateItem(keyStr, cacheMap);
|
|
1450
|
+
const ttlCheckDuration = Date.now() - ttlCheckStart;
|
|
1141
1451
|
if (isValid) {
|
|
1142
|
-
|
|
1452
|
+
const totalDuration = Date.now() - startTime;
|
|
1453
|
+
logger5.debug("CACHE_OP: Cache HIT with valid TTL", {
|
|
1454
|
+
key: keyStr,
|
|
1455
|
+
cacheCheckDuration,
|
|
1456
|
+
ttlCheckDuration,
|
|
1457
|
+
totalDuration,
|
|
1458
|
+
defaultTTL: ttlManager.getDefaultTTL()
|
|
1459
|
+
});
|
|
1143
1460
|
statsManager.incrementHits();
|
|
1144
1461
|
return cachedItem;
|
|
1145
1462
|
} else {
|
|
1146
|
-
logger5.debug("Cache item
|
|
1463
|
+
logger5.debug("CACHE_OP: Cache item EXPIRED, removing from cache", {
|
|
1464
|
+
key: keyStr,
|
|
1465
|
+
cacheCheckDuration,
|
|
1466
|
+
ttlCheckDuration
|
|
1467
|
+
});
|
|
1147
1468
|
cacheMap.delete(key);
|
|
1148
1469
|
statsManager.incrementMisses();
|
|
1149
1470
|
}
|
|
1150
1471
|
} else {
|
|
1472
|
+
logger5.debug("CACHE_OP: Cache MISS (no item found)", {
|
|
1473
|
+
key: keyStr,
|
|
1474
|
+
cacheCheckDuration
|
|
1475
|
+
});
|
|
1151
1476
|
statsManager.incrementMisses();
|
|
1152
1477
|
}
|
|
1153
|
-
logger5.debug("
|
|
1478
|
+
logger5.debug("CACHE_OP: Proceeding to API fetch (TTL-enabled cache miss or expired)", {
|
|
1479
|
+
key: keyStr,
|
|
1480
|
+
defaultTTL: ttlManager.getDefaultTTL()
|
|
1481
|
+
});
|
|
1154
1482
|
} else {
|
|
1483
|
+
const cacheCheckStart = Date.now();
|
|
1155
1484
|
const cachedItem = await cacheMap.get(key);
|
|
1485
|
+
const cacheCheckDuration = Date.now() - cacheCheckStart;
|
|
1156
1486
|
if (cachedItem) {
|
|
1157
|
-
|
|
1487
|
+
const totalDuration = Date.now() - startTime;
|
|
1488
|
+
logger5.debug("CACHE_OP: Cache HIT (TTL disabled)", {
|
|
1489
|
+
key: keyStr,
|
|
1490
|
+
cacheCheckDuration,
|
|
1491
|
+
totalDuration
|
|
1492
|
+
});
|
|
1158
1493
|
statsManager.incrementHits();
|
|
1159
1494
|
return cachedItem;
|
|
1160
1495
|
} else {
|
|
1496
|
+
logger5.debug("CACHE_OP: Cache MISS (TTL disabled)", {
|
|
1497
|
+
key: keyStr,
|
|
1498
|
+
cacheCheckDuration
|
|
1499
|
+
});
|
|
1161
1500
|
statsManager.incrementMisses();
|
|
1162
1501
|
}
|
|
1163
1502
|
}
|
|
1164
1503
|
let ret;
|
|
1165
|
-
const
|
|
1504
|
+
const requestKeyStr = keyToString(key);
|
|
1166
1505
|
try {
|
|
1167
|
-
const requestEntry = inFlightRequests.get(
|
|
1506
|
+
const requestEntry = inFlightRequests.get(requestKeyStr);
|
|
1168
1507
|
let apiRequest;
|
|
1508
|
+
const apiStartTime = Date.now();
|
|
1169
1509
|
if (!requestEntry) {
|
|
1510
|
+
logger5.debug("CACHE_OP: Creating new API request", { key: keyStr });
|
|
1170
1511
|
apiRequest = api.get(key);
|
|
1171
1512
|
if (apiRequest && typeof apiRequest.then === "function") {
|
|
1172
1513
|
const timestamp = Date.now();
|
|
1173
|
-
inFlightRequests.set(
|
|
1174
|
-
const cleanup = () => inFlightRequests.delete(
|
|
1514
|
+
inFlightRequests.set(requestKeyStr, { promise: apiRequest, timestamp });
|
|
1515
|
+
const cleanup = () => inFlightRequests.delete(requestKeyStr);
|
|
1175
1516
|
if (typeof apiRequest.finally === "function") {
|
|
1176
1517
|
apiRequest.finally(cleanup);
|
|
1177
1518
|
} else {
|
|
@@ -1179,37 +1520,90 @@ async function executeGetLogic(key, context) {
|
|
|
1179
1520
|
}
|
|
1180
1521
|
}
|
|
1181
1522
|
} else {
|
|
1182
|
-
logger5.debug("Using in-flight request
|
|
1523
|
+
logger5.debug("CACHE_OP: Using existing in-flight request", {
|
|
1524
|
+
key: keyStr,
|
|
1525
|
+
requestAge: Date.now() - requestEntry.timestamp
|
|
1526
|
+
});
|
|
1183
1527
|
apiRequest = requestEntry.promise;
|
|
1184
1528
|
}
|
|
1185
1529
|
ret = await apiRequest;
|
|
1530
|
+
const apiDuration = Date.now() - apiStartTime;
|
|
1186
1531
|
if (ret) {
|
|
1532
|
+
logger5.debug("CACHE_OP: API request successful, caching result", {
|
|
1533
|
+
key: keyStr,
|
|
1534
|
+
apiDuration,
|
|
1535
|
+
itemKeyMatches: JSON.stringify(ret.key) === keyStr
|
|
1536
|
+
});
|
|
1537
|
+
const cacheSetStart = Date.now();
|
|
1187
1538
|
await cacheMap.set(ret.key, ret);
|
|
1188
|
-
const
|
|
1189
|
-
const
|
|
1539
|
+
const cacheSetDuration = Date.now() - cacheSetStart;
|
|
1540
|
+
const itemKeyStr = JSON.stringify(ret.key);
|
|
1541
|
+
const metadataStart = Date.now();
|
|
1542
|
+
const metadata = await cacheMap.getMetadata(itemKeyStr);
|
|
1190
1543
|
if (!metadata) {
|
|
1191
1544
|
const now = Date.now();
|
|
1545
|
+
const estimatedSize = estimateValueSize(ret);
|
|
1192
1546
|
const baseMetadata = {
|
|
1193
|
-
key:
|
|
1547
|
+
key: itemKeyStr,
|
|
1194
1548
|
addedAt: now,
|
|
1195
1549
|
lastAccessedAt: now,
|
|
1196
1550
|
accessCount: 1,
|
|
1197
|
-
estimatedSize
|
|
1551
|
+
estimatedSize
|
|
1198
1552
|
};
|
|
1199
|
-
await cacheMap.setMetadata(
|
|
1553
|
+
await cacheMap.setMetadata(itemKeyStr, baseMetadata);
|
|
1554
|
+
logger5.debug("CACHE_OP: Created base metadata for cached item", {
|
|
1555
|
+
key: itemKeyStr,
|
|
1556
|
+
estimatedSize
|
|
1557
|
+
});
|
|
1200
1558
|
}
|
|
1201
|
-
const
|
|
1202
|
-
|
|
1559
|
+
const metadataDuration = Date.now() - metadataStart;
|
|
1560
|
+
const evictionStart = Date.now();
|
|
1561
|
+
const evictedKeys = await context.evictionManager.onItemAdded(itemKeyStr, ret, cacheMap);
|
|
1562
|
+
const evictionDuration = Date.now() - evictionStart;
|
|
1563
|
+
if (evictedKeys.length > 0) {
|
|
1564
|
+
logger5.debug("CACHE_OP: Eviction triggered by new item", {
|
|
1565
|
+
key: itemKeyStr,
|
|
1566
|
+
evictedCount: evictedKeys.length,
|
|
1567
|
+
evictedKeys
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
const ttlStart = Date.now();
|
|
1571
|
+
await ttlManager.onItemAdded(itemKeyStr, cacheMap);
|
|
1572
|
+
const ttlDuration = Date.now() - ttlStart;
|
|
1203
1573
|
for (const evictedKey of evictedKeys) {
|
|
1204
1574
|
const parsedKey = JSON.parse(evictedKey);
|
|
1205
1575
|
await cacheMap.delete(parsedKey);
|
|
1576
|
+
logger5.debug("CACHE_OP: Removed evicted item", { evictedKey });
|
|
1206
1577
|
}
|
|
1207
1578
|
const event = CacheEventFactory.itemRetrieved(ret.key, ret, "api");
|
|
1208
1579
|
context.eventEmitter.emit(event);
|
|
1580
|
+
const totalDuration = Date.now() - startTime;
|
|
1581
|
+
logger5.debug("CACHE_OP: get() completed successfully (cache miss)", {
|
|
1582
|
+
key: keyStr,
|
|
1583
|
+
apiDuration,
|
|
1584
|
+
cacheSetDuration,
|
|
1585
|
+
metadataDuration,
|
|
1586
|
+
evictionDuration,
|
|
1587
|
+
ttlDuration,
|
|
1588
|
+
totalDuration,
|
|
1589
|
+
evictedCount: evictedKeys.length
|
|
1590
|
+
});
|
|
1591
|
+
} else {
|
|
1592
|
+
logger5.debug("CACHE_OP: API returned null", {
|
|
1593
|
+
key: keyStr,
|
|
1594
|
+
apiDuration,
|
|
1595
|
+
totalDuration: Date.now() - startTime
|
|
1596
|
+
});
|
|
1209
1597
|
}
|
|
1210
1598
|
} catch (e) {
|
|
1211
|
-
inFlightRequests.delete(
|
|
1212
|
-
|
|
1599
|
+
inFlightRequests.delete(requestKeyStr);
|
|
1600
|
+
const duration = Date.now() - startTime;
|
|
1601
|
+
logger5.error("CACHE_OP: Error in get() operation", {
|
|
1602
|
+
key: keyStr,
|
|
1603
|
+
duration,
|
|
1604
|
+
message: e.message,
|
|
1605
|
+
stack: e.stack
|
|
1606
|
+
});
|
|
1213
1607
|
throw e;
|
|
1214
1608
|
}
|
|
1215
1609
|
return ret || null;
|
|
@@ -1221,43 +1615,88 @@ import {
|
|
|
1221
1615
|
} from "@fjell/core";
|
|
1222
1616
|
var logger6 = logger_default.get("retrieve");
|
|
1223
1617
|
var retrieve = async (key, context) => {
|
|
1618
|
+
const startTime = Date.now();
|
|
1224
1619
|
const { cacheMap, pkType, statsManager } = context;
|
|
1620
|
+
const keyStr = JSON.stringify(key);
|
|
1225
1621
|
logger6.default("retrieve", { key });
|
|
1622
|
+
logger6.debug("CACHE_OP: retrieve() started", {
|
|
1623
|
+
key: keyStr,
|
|
1624
|
+
cacheType: cacheMap.implementationType,
|
|
1625
|
+
bypassEnabled: !!context.options?.bypassCache
|
|
1626
|
+
});
|
|
1226
1627
|
statsManager.incrementRequests();
|
|
1227
1628
|
if (!isValidItemKey2(key)) {
|
|
1228
|
-
logger6.error("
|
|
1629
|
+
logger6.error("CACHE_OP: Invalid key for retrieve", { key: keyStr });
|
|
1229
1630
|
throw new Error("Key for Retrieve is not a valid ItemKey");
|
|
1230
1631
|
}
|
|
1231
1632
|
if (context.options?.bypassCache) {
|
|
1232
|
-
logger6.debug("Cache bypass enabled, fetching directly from API", { key });
|
|
1633
|
+
logger6.debug("CACHE_OP: Cache bypass enabled, fetching directly from API", { key: keyStr });
|
|
1233
1634
|
statsManager.incrementMisses();
|
|
1234
1635
|
try {
|
|
1636
|
+
const apiStartTime = Date.now();
|
|
1235
1637
|
const { api } = context;
|
|
1236
1638
|
const retrieved2 = await api.get(key);
|
|
1639
|
+
const apiDuration = Date.now() - apiStartTime;
|
|
1237
1640
|
if (retrieved2) {
|
|
1238
|
-
logger6.debug("API response received (
|
|
1641
|
+
logger6.debug("CACHE_OP: API response received (bypass mode)", {
|
|
1642
|
+
key: keyStr,
|
|
1643
|
+
apiDuration,
|
|
1644
|
+
hasValue: true
|
|
1645
|
+
});
|
|
1239
1646
|
return [null, retrieved2];
|
|
1240
1647
|
} else {
|
|
1241
|
-
logger6.debug("API returned null", {
|
|
1648
|
+
logger6.debug("CACHE_OP: API returned null (bypass mode)", {
|
|
1649
|
+
key: keyStr,
|
|
1650
|
+
apiDuration
|
|
1651
|
+
});
|
|
1242
1652
|
return [null, null];
|
|
1243
1653
|
}
|
|
1244
1654
|
} catch (error) {
|
|
1245
|
-
|
|
1655
|
+
const duration = Date.now() - startTime;
|
|
1656
|
+
logger6.error("CACHE_OP: API request failed in bypass mode", {
|
|
1657
|
+
key: keyStr,
|
|
1658
|
+
duration,
|
|
1659
|
+
error
|
|
1660
|
+
});
|
|
1246
1661
|
throw error;
|
|
1247
1662
|
}
|
|
1248
1663
|
}
|
|
1249
1664
|
const containsItemKey = await cacheMap.includesKey(key);
|
|
1665
|
+
logger6.debug("CACHE_OP: Cache key check completed", {
|
|
1666
|
+
key: keyStr,
|
|
1667
|
+
exists: containsItemKey
|
|
1668
|
+
});
|
|
1250
1669
|
let retrieved;
|
|
1251
1670
|
let contextToReturn;
|
|
1252
1671
|
if (containsItemKey) {
|
|
1253
1672
|
logger6.default("Looking for Object in Cache", key);
|
|
1673
|
+
logger6.debug("CACHE_OP: Cache HIT - retrieving from cache", { key: keyStr });
|
|
1674
|
+
const getStartTime = Date.now();
|
|
1254
1675
|
retrieved = await cacheMap.get(key);
|
|
1676
|
+
const getDuration = Date.now() - getStartTime;
|
|
1255
1677
|
contextToReturn = null;
|
|
1256
1678
|
statsManager.incrementHits();
|
|
1679
|
+
const totalDuration = Date.now() - startTime;
|
|
1680
|
+
logger6.debug("CACHE_OP: retrieve() completed (cache hit)", {
|
|
1681
|
+
key: keyStr,
|
|
1682
|
+
getDuration,
|
|
1683
|
+
totalDuration,
|
|
1684
|
+
hasValue: !!retrieved
|
|
1685
|
+
});
|
|
1257
1686
|
} else {
|
|
1258
1687
|
logger6.default("Object Not Found in Cache, Retrieving from Server API", { key });
|
|
1688
|
+
logger6.debug("CACHE_OP: Cache MISS - fetching from API", { key: keyStr });
|
|
1259
1689
|
statsManager.incrementMisses();
|
|
1690
|
+
const apiStartTime = Date.now();
|
|
1260
1691
|
[contextToReturn, retrieved] = await get(key, context);
|
|
1692
|
+
const apiDuration = Date.now() - apiStartTime;
|
|
1693
|
+
const totalDuration = Date.now() - startTime;
|
|
1694
|
+
logger6.debug("CACHE_OP: retrieve() completed (cache miss)", {
|
|
1695
|
+
key: keyStr,
|
|
1696
|
+
apiDuration,
|
|
1697
|
+
totalDuration,
|
|
1698
|
+
hasValue: !!retrieved
|
|
1699
|
+
});
|
|
1261
1700
|
}
|
|
1262
1701
|
const retValue = [
|
|
1263
1702
|
contextToReturn,
|
|
@@ -1752,44 +2191,107 @@ async function executeFindLogic(finder, params, locations, context) {
|
|
|
1752
2191
|
}
|
|
1753
2192
|
}
|
|
1754
2193
|
const queryHash = createFinderHash(finder, params, locations);
|
|
1755
|
-
logger14.debug("Generated query hash for find", {
|
|
2194
|
+
logger14.debug("QUERY_CACHE: Generated query hash for find()", {
|
|
2195
|
+
queryHash,
|
|
2196
|
+
finder,
|
|
2197
|
+
params: JSON.stringify(params),
|
|
2198
|
+
locations: JSON.stringify(locations)
|
|
2199
|
+
});
|
|
2200
|
+
logger14.debug("QUERY_CACHE: Checking query cache for hash", { queryHash });
|
|
1756
2201
|
const cachedItemKeys = await cacheMap.getQueryResult(queryHash);
|
|
1757
2202
|
if (cachedItemKeys) {
|
|
1758
|
-
logger14.debug("
|
|
2203
|
+
logger14.debug("QUERY_CACHE: Cache HIT - Found cached query result", {
|
|
2204
|
+
queryHash,
|
|
2205
|
+
cachedKeyCount: cachedItemKeys.length,
|
|
2206
|
+
itemKeys: cachedItemKeys.map((k) => JSON.stringify(k))
|
|
2207
|
+
});
|
|
1759
2208
|
const cachedItems = [];
|
|
1760
2209
|
let allItemsAvailable = true;
|
|
2210
|
+
const missingKeys = [];
|
|
1761
2211
|
for (const itemKey of cachedItemKeys) {
|
|
1762
2212
|
const item = await cacheMap.get(itemKey);
|
|
1763
2213
|
if (item) {
|
|
1764
2214
|
cachedItems.push(item);
|
|
2215
|
+
logger14.debug("QUERY_CACHE: Retrieved cached item", {
|
|
2216
|
+
itemKey: JSON.stringify(itemKey),
|
|
2217
|
+
itemKeyStr: JSON.stringify(item.key)
|
|
2218
|
+
});
|
|
1765
2219
|
} else {
|
|
1766
2220
|
allItemsAvailable = false;
|
|
2221
|
+
missingKeys.push(itemKey);
|
|
2222
|
+
logger14.debug("QUERY_CACHE: Cached item MISSING from item cache", {
|
|
2223
|
+
itemKey: JSON.stringify(itemKey),
|
|
2224
|
+
queryHash
|
|
2225
|
+
});
|
|
1767
2226
|
break;
|
|
1768
2227
|
}
|
|
1769
2228
|
}
|
|
1770
2229
|
if (allItemsAvailable) {
|
|
2230
|
+
logger14.debug("QUERY_CACHE: All cached items available, returning from cache", {
|
|
2231
|
+
queryHash,
|
|
2232
|
+
itemCount: cachedItems.length
|
|
2233
|
+
});
|
|
1771
2234
|
return cachedItems;
|
|
1772
2235
|
} else {
|
|
1773
|
-
logger14.debug("Some cached items missing, invalidating query cache"
|
|
2236
|
+
logger14.debug("QUERY_CACHE: Some cached items missing, invalidating query cache", {
|
|
2237
|
+
queryHash,
|
|
2238
|
+
missingKeys: missingKeys.map((k) => JSON.stringify(k)),
|
|
2239
|
+
foundCount: cachedItems.length,
|
|
2240
|
+
expectedCount: cachedItemKeys.length
|
|
2241
|
+
});
|
|
1774
2242
|
cacheMap.deleteQueryResult(queryHash);
|
|
1775
2243
|
}
|
|
2244
|
+
} else {
|
|
2245
|
+
logger14.debug("QUERY_CACHE: Cache MISS - No cached query result found", { queryHash });
|
|
1776
2246
|
}
|
|
2247
|
+
logger14.debug("QUERY_CACHE: Fetching from API (cache miss or invalid)", {
|
|
2248
|
+
queryHash,
|
|
2249
|
+
finder,
|
|
2250
|
+
params: JSON.stringify(params),
|
|
2251
|
+
locations: JSON.stringify(locations)
|
|
2252
|
+
});
|
|
1777
2253
|
const ret = await api.find(finder, params, locations);
|
|
2254
|
+
logger14.debug("QUERY_CACHE: API response received", {
|
|
2255
|
+
queryHash,
|
|
2256
|
+
itemCount: ret.length,
|
|
2257
|
+
itemKeys: ret.map((item) => JSON.stringify(item.key))
|
|
2258
|
+
});
|
|
2259
|
+
logger14.debug("QUERY_CACHE: Storing items in item cache", {
|
|
2260
|
+
queryHash,
|
|
2261
|
+
itemCount: ret.length
|
|
2262
|
+
});
|
|
1778
2263
|
for (const v of ret) {
|
|
1779
2264
|
await cacheMap.set(v.key, v);
|
|
2265
|
+
logger14.debug("QUERY_CACHE: Stored item in cache", {
|
|
2266
|
+
itemKey: JSON.stringify(v.key),
|
|
2267
|
+
queryHash
|
|
2268
|
+
});
|
|
1780
2269
|
const keyStr = JSON.stringify(v.key);
|
|
1781
2270
|
ttlManager.onItemAdded(keyStr, cacheMap);
|
|
1782
2271
|
const evictedKeys = await context.evictionManager.onItemAdded(keyStr, v, cacheMap);
|
|
1783
2272
|
for (const evictedKey of evictedKeys) {
|
|
1784
2273
|
const parsedKey = JSON.parse(evictedKey);
|
|
1785
2274
|
await cacheMap.delete(parsedKey);
|
|
2275
|
+
logger14.debug("QUERY_CACHE: Evicted item due to cache limits", {
|
|
2276
|
+
evictedKey,
|
|
2277
|
+
queryHash
|
|
2278
|
+
});
|
|
1786
2279
|
}
|
|
1787
2280
|
}
|
|
1788
2281
|
const itemKeys = ret.map((item) => item.key);
|
|
1789
|
-
cacheMap.setQueryResult(queryHash, itemKeys);
|
|
1790
|
-
logger14.debug("
|
|
2282
|
+
await cacheMap.setQueryResult(queryHash, itemKeys);
|
|
2283
|
+
logger14.debug("QUERY_CACHE: Stored query result in query cache", {
|
|
2284
|
+
queryHash,
|
|
2285
|
+
itemKeyCount: itemKeys.length,
|
|
2286
|
+
itemKeys: itemKeys.map((k) => JSON.stringify(k))
|
|
2287
|
+
});
|
|
1791
2288
|
const event = CacheEventFactory.createQueryEvent(params, locations, ret);
|
|
1792
2289
|
eventEmitter.emit(event);
|
|
2290
|
+
logger14.debug("QUERY_CACHE: Emitted query event", { queryHash });
|
|
2291
|
+
logger14.debug("QUERY_CACHE: find() operation completed", {
|
|
2292
|
+
queryHash,
|
|
2293
|
+
resultCount: ret.length
|
|
2294
|
+
});
|
|
1793
2295
|
return ret;
|
|
1794
2296
|
}
|
|
1795
2297
|
|
|
@@ -1827,34 +2329,86 @@ async function executeFindOneLogic(finder, finderParams, locations, context) {
|
|
|
1827
2329
|
}
|
|
1828
2330
|
}
|
|
1829
2331
|
const queryHash = createFinderHash(finder, finderParams, locations);
|
|
1830
|
-
logger15.debug("Generated query hash for findOne", {
|
|
2332
|
+
logger15.debug("QUERY_CACHE: Generated query hash for findOne()", {
|
|
2333
|
+
queryHash,
|
|
2334
|
+
finder,
|
|
2335
|
+
finderParams: JSON.stringify(finderParams),
|
|
2336
|
+
locations: JSON.stringify(locations)
|
|
2337
|
+
});
|
|
2338
|
+
logger15.debug("QUERY_CACHE: Checking query cache for hash", { queryHash });
|
|
1831
2339
|
const cachedItemKeys = await cacheMap.getQueryResult(queryHash);
|
|
1832
2340
|
if (cachedItemKeys && cachedItemKeys.length > 0) {
|
|
1833
|
-
logger15.debug("
|
|
1834
|
-
|
|
2341
|
+
logger15.debug("QUERY_CACHE: Cache HIT - Found cached query result", {
|
|
2342
|
+
queryHash,
|
|
2343
|
+
cachedKeyCount: cachedItemKeys.length,
|
|
2344
|
+
itemKeys: cachedItemKeys.map((k) => JSON.stringify(k))
|
|
2345
|
+
});
|
|
2346
|
+
const itemKey = cachedItemKeys[0];
|
|
2347
|
+
logger15.debug("QUERY_CACHE: Retrieving first cached item", {
|
|
2348
|
+
queryHash,
|
|
2349
|
+
itemKey: JSON.stringify(itemKey)
|
|
2350
|
+
});
|
|
2351
|
+
const item = await cacheMap.get(itemKey);
|
|
1835
2352
|
if (item) {
|
|
2353
|
+
logger15.debug("QUERY_CACHE: Retrieved cached item successfully", {
|
|
2354
|
+
queryHash,
|
|
2355
|
+
itemKey: JSON.stringify(itemKey),
|
|
2356
|
+
itemKeyStr: JSON.stringify(item.key)
|
|
2357
|
+
});
|
|
1836
2358
|
return item;
|
|
1837
2359
|
} else {
|
|
1838
|
-
logger15.debug("Cached item
|
|
2360
|
+
logger15.debug("QUERY_CACHE: Cached item MISSING from item cache, invalidating query cache", {
|
|
2361
|
+
queryHash,
|
|
2362
|
+
itemKey: JSON.stringify(itemKey)
|
|
2363
|
+
});
|
|
1839
2364
|
cacheMap.deleteQueryResult(queryHash);
|
|
1840
2365
|
}
|
|
2366
|
+
} else {
|
|
2367
|
+
logger15.debug("QUERY_CACHE: Cache MISS - No cached query result found", { queryHash });
|
|
1841
2368
|
}
|
|
2369
|
+
logger15.debug("QUERY_CACHE: Fetching from API (cache miss or invalid)", {
|
|
2370
|
+
queryHash,
|
|
2371
|
+
finder,
|
|
2372
|
+
finderParams: JSON.stringify(finderParams),
|
|
2373
|
+
locations: JSON.stringify(locations)
|
|
2374
|
+
});
|
|
1842
2375
|
const ret = await api.findOne(finder, finderParams, locations);
|
|
1843
2376
|
if (ret === null) {
|
|
2377
|
+
logger15.debug("QUERY_CACHE: API returned null, throwing error", { queryHash, finder });
|
|
1844
2378
|
throw new Error(`findOne returned null for finder: ${finder}`);
|
|
1845
2379
|
}
|
|
1846
|
-
|
|
2380
|
+
logger15.debug("QUERY_CACHE: API response received", {
|
|
2381
|
+
queryHash,
|
|
2382
|
+
itemKey: JSON.stringify(ret.key)
|
|
2383
|
+
});
|
|
2384
|
+
logger15.debug("QUERY_CACHE: Storing item in item cache", {
|
|
2385
|
+
queryHash,
|
|
2386
|
+
itemKey: JSON.stringify(ret.key)
|
|
2387
|
+
});
|
|
2388
|
+
await cacheMap.set(ret.key, ret);
|
|
1847
2389
|
const keyStr = JSON.stringify(ret.key);
|
|
1848
2390
|
ttlManager.onItemAdded(keyStr, cacheMap);
|
|
1849
2391
|
const evictedKeys = await context.evictionManager.onItemAdded(keyStr, ret, cacheMap);
|
|
1850
2392
|
for (const evictedKey of evictedKeys) {
|
|
1851
2393
|
const parsedKey = JSON.parse(evictedKey);
|
|
1852
2394
|
await cacheMap.delete(parsedKey);
|
|
2395
|
+
logger15.debug("QUERY_CACHE: Evicted item due to cache limits", {
|
|
2396
|
+
evictedKey,
|
|
2397
|
+
queryHash
|
|
2398
|
+
});
|
|
1853
2399
|
}
|
|
1854
|
-
cacheMap.setQueryResult(queryHash, [ret.key]);
|
|
1855
|
-
logger15.debug("
|
|
2400
|
+
await cacheMap.setQueryResult(queryHash, [ret.key]);
|
|
2401
|
+
logger15.debug("QUERY_CACHE: Stored query result in query cache", {
|
|
2402
|
+
queryHash,
|
|
2403
|
+
itemKey: JSON.stringify(ret.key)
|
|
2404
|
+
});
|
|
1856
2405
|
const event = CacheEventFactory.createQueryEvent(finderParams, locations, [ret]);
|
|
1857
2406
|
eventEmitter.emit(event);
|
|
2407
|
+
logger15.debug("QUERY_CACHE: Emitted query event", { queryHash });
|
|
2408
|
+
logger15.debug("QUERY_CACHE: findOne() operation completed", {
|
|
2409
|
+
queryHash,
|
|
2410
|
+
itemKey: JSON.stringify(ret.key)
|
|
2411
|
+
});
|
|
1858
2412
|
return ret;
|
|
1859
2413
|
}
|
|
1860
2414
|
|
|
@@ -1912,39 +2466,93 @@ var normalizeKey = (key) => {
|
|
|
1912
2466
|
return key;
|
|
1913
2467
|
};
|
|
1914
2468
|
var set = async (key, v, context) => {
|
|
2469
|
+
const startTime = Date.now();
|
|
1915
2470
|
const { cacheMap, pkType, ttlManager, evictionManager, eventEmitter } = context;
|
|
2471
|
+
const keyStr = JSON.stringify(key);
|
|
1916
2472
|
logger16.default("set", { key, v });
|
|
2473
|
+
logger16.debug("CACHE_OP: set() started", {
|
|
2474
|
+
key: keyStr,
|
|
2475
|
+
cacheType: cacheMap.implementationType
|
|
2476
|
+
});
|
|
1917
2477
|
if (!isValidItemKey6(key)) {
|
|
1918
|
-
logger16.error("
|
|
2478
|
+
logger16.error("CACHE_OP: Invalid key for set", { key: keyStr });
|
|
1919
2479
|
throw new Error("Key for Set is not a valid ItemKey");
|
|
1920
2480
|
}
|
|
1921
2481
|
if (!isItemKeyEqualNormalized(key, v.key)) {
|
|
1922
|
-
logger16.error("Key
|
|
2482
|
+
logger16.error("CACHE_OP: Key mismatch in set", {
|
|
2483
|
+
providedKey: keyStr,
|
|
2484
|
+
itemKey: JSON.stringify(v.key)
|
|
2485
|
+
});
|
|
1923
2486
|
throw new Error("Key does not match item key");
|
|
1924
2487
|
}
|
|
2488
|
+
const checkStartTime = Date.now();
|
|
1925
2489
|
const previousItem = await cacheMap.get(key);
|
|
2490
|
+
const checkDuration = Date.now() - checkStartTime;
|
|
2491
|
+
logger16.debug("CACHE_OP: Previous item check", {
|
|
2492
|
+
key: keyStr,
|
|
2493
|
+
hadPreviousItem: !!previousItem,
|
|
2494
|
+
checkDuration
|
|
2495
|
+
});
|
|
2496
|
+
const setStartTime = Date.now();
|
|
1926
2497
|
await cacheMap.set(key, v);
|
|
1927
|
-
const
|
|
2498
|
+
const setDuration = Date.now() - setStartTime;
|
|
2499
|
+
const metadataStartTime = Date.now();
|
|
1928
2500
|
const metadata = await cacheMap.getMetadata(keyStr);
|
|
1929
2501
|
if (!metadata) {
|
|
1930
2502
|
const now = Date.now();
|
|
2503
|
+
const estimatedSize = estimateValueSize(v);
|
|
1931
2504
|
const baseMetadata = {
|
|
1932
2505
|
key: keyStr,
|
|
1933
2506
|
addedAt: now,
|
|
1934
2507
|
lastAccessedAt: now,
|
|
1935
2508
|
accessCount: 1,
|
|
1936
|
-
estimatedSize
|
|
2509
|
+
estimatedSize
|
|
1937
2510
|
};
|
|
1938
2511
|
await cacheMap.setMetadata(keyStr, baseMetadata);
|
|
2512
|
+
logger16.debug("CACHE_OP: Created base metadata", {
|
|
2513
|
+
key: keyStr,
|
|
2514
|
+
estimatedSize
|
|
2515
|
+
});
|
|
2516
|
+
} else {
|
|
2517
|
+
logger16.debug("CACHE_OP: Metadata already exists", {
|
|
2518
|
+
key: keyStr,
|
|
2519
|
+
addedAt: new Date(metadata.addedAt).toISOString(),
|
|
2520
|
+
accessCount: metadata.accessCount
|
|
2521
|
+
});
|
|
1939
2522
|
}
|
|
2523
|
+
const metadataDuration = Date.now() - metadataStartTime;
|
|
2524
|
+
const ttlStartTime = Date.now();
|
|
1940
2525
|
await ttlManager.onItemAdded(keyStr, cacheMap);
|
|
2526
|
+
const ttlDuration = Date.now() - ttlStartTime;
|
|
2527
|
+
const evictionStartTime = Date.now();
|
|
1941
2528
|
const evictedKeys = await evictionManager.onItemAdded(keyStr, v, cacheMap);
|
|
2529
|
+
const evictionDuration = Date.now() - evictionStartTime;
|
|
2530
|
+
if (evictedKeys.length > 0) {
|
|
2531
|
+
logger16.debug("CACHE_OP: Eviction triggered by set", {
|
|
2532
|
+
key: keyStr,
|
|
2533
|
+
evictedCount: evictedKeys.length,
|
|
2534
|
+
evictedKeys
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
1942
2537
|
for (const evictedKey of evictedKeys) {
|
|
1943
2538
|
const parsedKey = JSON.parse(evictedKey);
|
|
1944
2539
|
await cacheMap.delete(parsedKey);
|
|
2540
|
+
logger16.debug("CACHE_OP: Removed evicted item", { evictedKey });
|
|
1945
2541
|
}
|
|
1946
2542
|
const event = CacheEventFactory.itemSet(key, v, previousItem);
|
|
1947
2543
|
eventEmitter.emit(event);
|
|
2544
|
+
const totalDuration = Date.now() - startTime;
|
|
2545
|
+
logger16.debug("CACHE_OP: set() completed", {
|
|
2546
|
+
key: keyStr,
|
|
2547
|
+
checkDuration,
|
|
2548
|
+
setDuration,
|
|
2549
|
+
metadataDuration,
|
|
2550
|
+
ttlDuration,
|
|
2551
|
+
evictionDuration,
|
|
2552
|
+
totalDuration,
|
|
2553
|
+
evictedCount: evictedKeys.length,
|
|
2554
|
+
wasUpdate: !!previousItem
|
|
2555
|
+
});
|
|
1948
2556
|
return [context, v];
|
|
1949
2557
|
};
|
|
1950
2558
|
|
|
@@ -5122,9 +5730,17 @@ var EvictionManager = class {
|
|
|
5122
5730
|
return;
|
|
5123
5731
|
}
|
|
5124
5732
|
try {
|
|
5733
|
+
logger24.debug("EVICTION: Item accessed, updating metadata", {
|
|
5734
|
+
key,
|
|
5735
|
+
strategy: this.evictionStrategy.getStrategyName()
|
|
5736
|
+
});
|
|
5125
5737
|
await this.evictionStrategy.onItemAccessed(key, metadataProvider);
|
|
5126
5738
|
} catch (error) {
|
|
5127
|
-
logger24.error("Error in eviction strategy onItemAccessed", {
|
|
5739
|
+
logger24.error("EVICTION: Error in eviction strategy onItemAccessed", {
|
|
5740
|
+
key,
|
|
5741
|
+
error,
|
|
5742
|
+
strategy: this.evictionStrategy?.getStrategyName()
|
|
5743
|
+
});
|
|
5128
5744
|
}
|
|
5129
5745
|
}
|
|
5130
5746
|
/**
|
|
@@ -5135,28 +5751,81 @@ var EvictionManager = class {
|
|
|
5135
5751
|
* @returns Array of keys that were evicted
|
|
5136
5752
|
*/
|
|
5137
5753
|
async onItemAdded(key, value, metadataProvider) {
|
|
5754
|
+
const startTime = Date.now();
|
|
5138
5755
|
const evictedKeys = [];
|
|
5139
5756
|
if (!this.evictionStrategy) {
|
|
5757
|
+
logger24.debug("EVICTION: No eviction strategy configured", { key });
|
|
5140
5758
|
return evictedKeys;
|
|
5141
5759
|
}
|
|
5142
5760
|
try {
|
|
5143
5761
|
const estimatedSize = estimateValueSize(value);
|
|
5762
|
+
logger24.debug("EVICTION: Item addition started", {
|
|
5763
|
+
key,
|
|
5764
|
+
estimatedSize,
|
|
5765
|
+
strategy: this.evictionStrategy.getStrategyName()
|
|
5766
|
+
});
|
|
5767
|
+
const contextStartTime = Date.now();
|
|
5144
5768
|
const context = await this.createEvictionContext(metadataProvider, estimatedSize);
|
|
5769
|
+
const contextDuration = Date.now() - contextStartTime;
|
|
5770
|
+
logger24.debug("EVICTION: Current cache state", {
|
|
5771
|
+
key,
|
|
5772
|
+
currentItemCount: context.currentSize.itemCount,
|
|
5773
|
+
currentSizeBytes: context.currentSize.sizeBytes,
|
|
5774
|
+
maxItems: context.limits.maxItems,
|
|
5775
|
+
maxSizeBytes: context.limits.maxSizeBytes,
|
|
5776
|
+
newItemSize: estimatedSize,
|
|
5777
|
+
contextDuration
|
|
5778
|
+
});
|
|
5779
|
+
const selectionStartTime = Date.now();
|
|
5145
5780
|
const keysToEvict = await this.evictionStrategy.selectForEviction(metadataProvider, context);
|
|
5781
|
+
const selectionDuration = Date.now() - selectionStartTime;
|
|
5782
|
+
if (keysToEvict.length > 0) {
|
|
5783
|
+
logger24.debug("EVICTION: Items selected for eviction", {
|
|
5784
|
+
key,
|
|
5785
|
+
evictCount: keysToEvict.length,
|
|
5786
|
+
keysToEvict,
|
|
5787
|
+
selectionDuration,
|
|
5788
|
+
strategy: this.evictionStrategy.getStrategyName()
|
|
5789
|
+
});
|
|
5790
|
+
}
|
|
5791
|
+
const removalStartTime = Date.now();
|
|
5146
5792
|
for (const evictKey of keysToEvict) {
|
|
5147
5793
|
await this.evictionStrategy.onItemRemoved(evictKey, metadataProvider);
|
|
5148
5794
|
evictedKeys.push(evictKey);
|
|
5795
|
+
logger24.debug("EVICTION: Marked item for eviction", {
|
|
5796
|
+
evictedKey: evictKey,
|
|
5797
|
+
newKey: key
|
|
5798
|
+
});
|
|
5149
5799
|
}
|
|
5800
|
+
const removalDuration = Date.now() - removalStartTime;
|
|
5801
|
+
const addMetadataStart = Date.now();
|
|
5150
5802
|
await this.evictionStrategy.onItemAdded(key, estimatedSize, metadataProvider);
|
|
5803
|
+
const addMetadataDuration = Date.now() - addMetadataStart;
|
|
5804
|
+
const totalDuration = Date.now() - startTime;
|
|
5151
5805
|
if (evictedKeys.length > 0) {
|
|
5152
|
-
logger24.debug("
|
|
5806
|
+
logger24.debug("EVICTION: Eviction completed", {
|
|
5153
5807
|
newKey: key,
|
|
5808
|
+
evictedCount: evictedKeys.length,
|
|
5154
5809
|
evictedKeys,
|
|
5155
|
-
strategy: this.evictionStrategy.getStrategyName()
|
|
5810
|
+
strategy: this.evictionStrategy.getStrategyName(),
|
|
5811
|
+
selectionDuration,
|
|
5812
|
+
removalDuration,
|
|
5813
|
+
addMetadataDuration,
|
|
5814
|
+
totalDuration
|
|
5815
|
+
});
|
|
5816
|
+
} else {
|
|
5817
|
+
logger24.debug("EVICTION: No eviction needed", {
|
|
5818
|
+
newKey: key,
|
|
5819
|
+
estimatedSize,
|
|
5820
|
+
totalDuration
|
|
5156
5821
|
});
|
|
5157
5822
|
}
|
|
5158
5823
|
} catch (error) {
|
|
5159
|
-
logger24.error("Error in eviction strategy onItemAdded", {
|
|
5824
|
+
logger24.error("EVICTION: Error in eviction strategy onItemAdded", {
|
|
5825
|
+
key,
|
|
5826
|
+
error,
|
|
5827
|
+
strategy: this.evictionStrategy?.getStrategyName()
|
|
5828
|
+
});
|
|
5160
5829
|
}
|
|
5161
5830
|
return evictedKeys;
|
|
5162
5831
|
}
|
|
@@ -5181,25 +5850,47 @@ var EvictionManager = class {
|
|
|
5181
5850
|
* @returns Array of keys that were evicted
|
|
5182
5851
|
*/
|
|
5183
5852
|
async performEviction(metadataProvider) {
|
|
5853
|
+
const startTime = Date.now();
|
|
5184
5854
|
const evictedKeys = [];
|
|
5185
5855
|
if (!this.evictionStrategy) {
|
|
5856
|
+
logger24.debug("EVICTION: No eviction strategy configured for manual eviction");
|
|
5186
5857
|
return evictedKeys;
|
|
5187
5858
|
}
|
|
5188
5859
|
try {
|
|
5860
|
+
logger24.debug("EVICTION: Manual eviction started", {
|
|
5861
|
+
strategy: this.evictionStrategy.getStrategyName()
|
|
5862
|
+
});
|
|
5189
5863
|
const context = await this.createEvictionContext(metadataProvider);
|
|
5864
|
+
logger24.debug("EVICTION: Manual eviction - current cache state", {
|
|
5865
|
+
currentItemCount: context.currentSize.itemCount,
|
|
5866
|
+
currentSizeBytes: context.currentSize.sizeBytes,
|
|
5867
|
+
maxItems: context.limits.maxItems,
|
|
5868
|
+
maxSizeBytes: context.limits.maxSizeBytes
|
|
5869
|
+
});
|
|
5190
5870
|
const keysToEvict = await this.evictionStrategy.selectForEviction(metadataProvider, context);
|
|
5191
5871
|
for (const evictKey of keysToEvict) {
|
|
5192
5872
|
await this.evictionStrategy.onItemRemoved(evictKey, metadataProvider);
|
|
5193
5873
|
evictedKeys.push(evictKey);
|
|
5194
5874
|
}
|
|
5875
|
+
const duration = Date.now() - startTime;
|
|
5195
5876
|
if (evictedKeys.length > 0) {
|
|
5196
|
-
logger24.debug("Manual eviction
|
|
5877
|
+
logger24.debug("EVICTION: Manual eviction completed", {
|
|
5878
|
+
evictedCount: evictedKeys.length,
|
|
5197
5879
|
evictedKeys,
|
|
5198
|
-
strategy: this.evictionStrategy.getStrategyName()
|
|
5880
|
+
strategy: this.evictionStrategy.getStrategyName(),
|
|
5881
|
+
duration
|
|
5882
|
+
});
|
|
5883
|
+
} else {
|
|
5884
|
+
logger24.debug("EVICTION: Manual eviction - no items to evict", {
|
|
5885
|
+
strategy: this.evictionStrategy.getStrategyName(),
|
|
5886
|
+
duration
|
|
5199
5887
|
});
|
|
5200
5888
|
}
|
|
5201
5889
|
} catch (error) {
|
|
5202
|
-
logger24.error("Error in manual eviction", {
|
|
5890
|
+
logger24.error("EVICTION: Error in manual eviction", {
|
|
5891
|
+
error,
|
|
5892
|
+
strategy: this.evictionStrategy?.getStrategyName()
|
|
5893
|
+
});
|
|
5203
5894
|
}
|
|
5204
5895
|
return evictedKeys;
|
|
5205
5896
|
}
|
|
@@ -6628,7 +7319,7 @@ var TTLManager = class {
|
|
|
6628
7319
|
metadata
|
|
6629
7320
|
});
|
|
6630
7321
|
if (!metadata) {
|
|
6631
|
-
logger25.
|
|
7322
|
+
logger25.debug("TTL_DEBUG: No metadata found for item when setting TTL", {
|
|
6632
7323
|
key,
|
|
6633
7324
|
metadataProviderType: metadataProvider?.constructor?.name,
|
|
6634
7325
|
metadataProviderMethods: metadataProvider ? Object.getOwnPropertyNames(Object.getPrototypeOf(metadataProvider)) : null
|
|
@@ -6668,12 +7359,28 @@ var TTLManager = class {
|
|
|
6668
7359
|
async isExpired(key, metadataProvider) {
|
|
6669
7360
|
const metadata = await metadataProvider.getMetadata(key);
|
|
6670
7361
|
if (!metadata || !metadata.expiresAt) {
|
|
7362
|
+
logger25.debug("TTL_CHECK: No TTL set for item", { key, hasMetadata: !!metadata });
|
|
6671
7363
|
return false;
|
|
6672
7364
|
}
|
|
6673
7365
|
const now = Date.now();
|
|
6674
7366
|
const expired = now >= metadata.expiresAt;
|
|
7367
|
+
const remainingMs = metadata.expiresAt - now;
|
|
6675
7368
|
if (expired) {
|
|
6676
|
-
logger25.
|
|
7369
|
+
logger25.debug("TTL_CHECK: Item EXPIRED", {
|
|
7370
|
+
key,
|
|
7371
|
+
expiresAt: new Date(metadata.expiresAt).toISOString(),
|
|
7372
|
+
now: new Date(now).toISOString(),
|
|
7373
|
+
expiredByMs: now - metadata.expiresAt,
|
|
7374
|
+
ttl: metadata.ttl
|
|
7375
|
+
});
|
|
7376
|
+
} else {
|
|
7377
|
+
logger25.debug("TTL_CHECK: Item still valid", {
|
|
7378
|
+
key,
|
|
7379
|
+
expiresAt: new Date(metadata.expiresAt).toISOString(),
|
|
7380
|
+
remainingMs,
|
|
7381
|
+
remainingSec: Math.floor(remainingMs / 1e3),
|
|
7382
|
+
ttl: metadata.ttl
|
|
7383
|
+
});
|
|
6677
7384
|
}
|
|
6678
7385
|
return expired;
|
|
6679
7386
|
}
|
|
@@ -6683,9 +7390,22 @@ var TTLManager = class {
|
|
|
6683
7390
|
*/
|
|
6684
7391
|
async validateItem(key, metadataProvider) {
|
|
6685
7392
|
if (!this.config.validateOnAccess) {
|
|
7393
|
+
logger25.debug("TTL_VALIDATE: Validation disabled, skipping check", { key });
|
|
6686
7394
|
return true;
|
|
6687
7395
|
}
|
|
6688
|
-
|
|
7396
|
+
logger25.debug("TTL_VALIDATE: Validating item", {
|
|
7397
|
+
key,
|
|
7398
|
+
ttlEnabled: this.isTTLEnabled(),
|
|
7399
|
+
defaultTTL: this.config.defaultTTL
|
|
7400
|
+
});
|
|
7401
|
+
const isExpired = await this.isExpired(key, metadataProvider);
|
|
7402
|
+
const isValid = !isExpired;
|
|
7403
|
+
logger25.debug("TTL_VALIDATE: Validation result", {
|
|
7404
|
+
key,
|
|
7405
|
+
isValid,
|
|
7406
|
+
isExpired
|
|
7407
|
+
});
|
|
7408
|
+
return isValid;
|
|
6689
7409
|
}
|
|
6690
7410
|
/**
|
|
6691
7411
|
* Get TTL information for an item
|
|
@@ -6710,17 +7430,44 @@ var TTLManager = class {
|
|
|
6710
7430
|
* Find all expired items
|
|
6711
7431
|
*/
|
|
6712
7432
|
async findExpiredItems(metadataProvider) {
|
|
7433
|
+
const startTime = Date.now();
|
|
6713
7434
|
const expiredKeys = [];
|
|
6714
7435
|
const allMetadata = await metadataProvider.getAllMetadata();
|
|
6715
7436
|
const now = Date.now();
|
|
7437
|
+
logger25.debug("TTL_CLEANUP: Scanning for expired items", {
|
|
7438
|
+
totalItems: allMetadata.size,
|
|
7439
|
+
now: new Date(now).toISOString()
|
|
7440
|
+
});
|
|
7441
|
+
let itemsWithTTL = 0;
|
|
6716
7442
|
for (const [key, metadata] of allMetadata) {
|
|
6717
7443
|
const ttlMetadata = metadata;
|
|
6718
|
-
if (ttlMetadata.expiresAt
|
|
6719
|
-
|
|
7444
|
+
if (ttlMetadata.expiresAt) {
|
|
7445
|
+
itemsWithTTL++;
|
|
7446
|
+
if (now >= ttlMetadata.expiresAt) {
|
|
7447
|
+
expiredKeys.push(key);
|
|
7448
|
+
logger25.debug("TTL_CLEANUP: Found expired item", {
|
|
7449
|
+
key,
|
|
7450
|
+
expiresAt: new Date(ttlMetadata.expiresAt).toISOString(),
|
|
7451
|
+
expiredByMs: now - ttlMetadata.expiresAt
|
|
7452
|
+
});
|
|
7453
|
+
}
|
|
6720
7454
|
}
|
|
6721
7455
|
}
|
|
7456
|
+
const duration = Date.now() - startTime;
|
|
6722
7457
|
if (expiredKeys.length > 0) {
|
|
6723
|
-
logger25.debug("
|
|
7458
|
+
logger25.debug("TTL_CLEANUP: Expired items found", {
|
|
7459
|
+
expiredCount: expiredKeys.length,
|
|
7460
|
+
totalItems: allMetadata.size,
|
|
7461
|
+
itemsWithTTL,
|
|
7462
|
+
keys: expiredKeys,
|
|
7463
|
+
duration
|
|
7464
|
+
});
|
|
7465
|
+
} else {
|
|
7466
|
+
logger25.debug("TTL_CLEANUP: No expired items found", {
|
|
7467
|
+
totalItems: allMetadata.size,
|
|
7468
|
+
itemsWithTTL,
|
|
7469
|
+
duration
|
|
7470
|
+
});
|
|
6724
7471
|
}
|
|
6725
7472
|
return expiredKeys;
|
|
6726
7473
|
}
|