@fjell/cache 4.7.42 → 4.7.44
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 +848 -106
- 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
|
}
|
|
@@ -191,6 +240,9 @@ var TwoLayerCacheMap = class _TwoLayerCacheMap extends CacheMap {
|
|
|
191
240
|
* Determine if a query result is complete or partial based on query hash
|
|
192
241
|
*/
|
|
193
242
|
determineQueryCompleteness(queryHash, itemKeys) {
|
|
243
|
+
if (queryHash.includes('"query":{}') || queryHash.includes('"query": {}')) {
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
194
246
|
if (queryHash.includes("facet:") || queryHash.includes("filter:")) {
|
|
195
247
|
return false;
|
|
196
248
|
}
|
|
@@ -304,18 +356,40 @@ var TwoLayerCacheMap = class _TwoLayerCacheMap extends CacheMap {
|
|
|
304
356
|
* Clean up expired queries
|
|
305
357
|
*/
|
|
306
358
|
async cleanup() {
|
|
359
|
+
const startTime = Date.now();
|
|
307
360
|
const now = /* @__PURE__ */ new Date();
|
|
308
361
|
const expiredQueries = [];
|
|
362
|
+
logger.debug("TWO_LAYER: Starting query cleanup", {
|
|
363
|
+
totalQueries: this.queryMetadataMap.size,
|
|
364
|
+
now: now.toISOString()
|
|
365
|
+
});
|
|
309
366
|
for (const [queryHash, metadata] of this.queryMetadataMap.entries()) {
|
|
310
367
|
if (metadata.expiresAt < now) {
|
|
311
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
|
+
});
|
|
312
376
|
}
|
|
313
377
|
}
|
|
314
378
|
for (const queryHash of expiredQueries) {
|
|
315
379
|
await this.deleteQueryResult(queryHash);
|
|
316
380
|
}
|
|
317
|
-
|
|
318
|
-
|
|
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
|
+
});
|
|
319
393
|
}
|
|
320
394
|
return expiredQueries.length;
|
|
321
395
|
}
|
|
@@ -327,24 +401,68 @@ var TwoLayerCacheMap = class _TwoLayerCacheMap extends CacheMap {
|
|
|
327
401
|
// The types are accessible through super.types
|
|
328
402
|
// ===== MISSING ABSTRACT METHODS FROM CacheMap =====
|
|
329
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
|
+
});
|
|
330
409
|
if ("invalidateItemKeys" in this.underlyingCache && typeof this.underlyingCache.invalidateItemKeys === "function") {
|
|
331
410
|
await this.underlyingCache.invalidateItemKeys(keys);
|
|
332
411
|
}
|
|
412
|
+
let totalInvalidatedQueries = 0;
|
|
333
413
|
for (const key of keys) {
|
|
414
|
+
const beforeCount = this.queryMetadataMap.size;
|
|
334
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
|
+
}
|
|
335
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
|
+
});
|
|
336
432
|
}
|
|
337
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
|
+
});
|
|
338
440
|
if ("invalidateLocation" in this.underlyingCache && typeof this.underlyingCache.invalidateLocation === "function") {
|
|
339
441
|
await this.underlyingCache.invalidateLocation(locations);
|
|
340
442
|
}
|
|
341
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
|
+
});
|
|
342
450
|
}
|
|
343
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
|
+
});
|
|
344
457
|
if ("clearQueryResults" in this.underlyingCache && typeof this.underlyingCache.clearQueryResults === "function") {
|
|
345
458
|
await this.underlyingCache.clearQueryResults();
|
|
346
459
|
}
|
|
347
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
|
+
});
|
|
348
466
|
}
|
|
349
467
|
/**
|
|
350
468
|
* Check if two-layer mode is enabled
|
|
@@ -699,66 +817,151 @@ async function executeAllLogic(query, locations, context) {
|
|
|
699
817
|
}
|
|
700
818
|
}
|
|
701
819
|
const queryHash = createQueryHash(pkType, query, locations);
|
|
702
|
-
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 });
|
|
703
827
|
const cachedItemKeys = await cacheMap.getQueryResult(queryHash);
|
|
704
828
|
if (cachedItemKeys) {
|
|
705
|
-
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
|
+
});
|
|
706
834
|
const cachedItems = [];
|
|
707
835
|
let allItemsAvailable = true;
|
|
836
|
+
const missingKeys = [];
|
|
708
837
|
for (const itemKey of cachedItemKeys) {
|
|
709
838
|
const item = await cacheMap.get(itemKey);
|
|
710
839
|
if (item) {
|
|
711
840
|
cachedItems.push(item);
|
|
841
|
+
logger2.debug("QUERY_CACHE: Retrieved cached item", {
|
|
842
|
+
itemKey: JSON.stringify(itemKey),
|
|
843
|
+
itemKeyStr: JSON.stringify(item.key)
|
|
844
|
+
});
|
|
712
845
|
} else {
|
|
713
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
|
+
});
|
|
714
852
|
break;
|
|
715
853
|
}
|
|
716
854
|
}
|
|
717
855
|
if (allItemsAvailable) {
|
|
856
|
+
logger2.debug("QUERY_CACHE: All cached items available, returning from cache", {
|
|
857
|
+
queryHash,
|
|
858
|
+
itemCount: cachedItems.length
|
|
859
|
+
});
|
|
718
860
|
return cachedItems;
|
|
719
861
|
} else {
|
|
720
|
-
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
|
+
});
|
|
721
868
|
cacheMap.deleteQueryResult(queryHash);
|
|
722
869
|
}
|
|
870
|
+
} else {
|
|
871
|
+
logger2.debug("QUERY_CACHE: Cache MISS - No cached query result found", { queryHash });
|
|
723
872
|
}
|
|
873
|
+
logger2.debug("QUERY_CACHE: Attempting direct cache query using queryIn()", {
|
|
874
|
+
queryHash,
|
|
875
|
+
query: JSON.stringify(query),
|
|
876
|
+
locations: JSON.stringify(locations)
|
|
877
|
+
});
|
|
724
878
|
try {
|
|
725
879
|
const directCachedItems = await cacheMap.queryIn(query, locations);
|
|
726
880
|
if (directCachedItems && directCachedItems.length > 0) {
|
|
727
|
-
logger2.debug("Found items
|
|
881
|
+
logger2.debug("QUERY_CACHE: Direct cache query SUCCESS - Found items in item cache", {
|
|
882
|
+
queryHash,
|
|
883
|
+
itemCount: directCachedItems.length,
|
|
884
|
+
itemKeys: directCachedItems.map((item) => JSON.stringify(item.key))
|
|
885
|
+
});
|
|
728
886
|
const itemKeys = directCachedItems.map((item) => item.key);
|
|
729
887
|
await cacheMap.setQueryResult(queryHash, itemKeys);
|
|
730
|
-
logger2.debug("
|
|
888
|
+
logger2.debug("QUERY_CACHE: Stored query result from direct cache hit", {
|
|
889
|
+
queryHash,
|
|
890
|
+
itemKeyCount: itemKeys.length,
|
|
891
|
+
itemKeys: itemKeys.map((k) => JSON.stringify(k))
|
|
892
|
+
});
|
|
731
893
|
return directCachedItems;
|
|
894
|
+
} else {
|
|
895
|
+
logger2.debug("QUERY_CACHE: Direct cache query returned no items", { queryHash });
|
|
732
896
|
}
|
|
733
897
|
} catch (error) {
|
|
734
|
-
logger2.debug("Error querying cache directly, proceeding to API", {
|
|
898
|
+
logger2.debug("QUERY_CACHE: Error querying cache directly, proceeding to API", {
|
|
899
|
+
queryHash,
|
|
900
|
+
error: error instanceof Error ? error.message : String(error)
|
|
901
|
+
});
|
|
735
902
|
}
|
|
903
|
+
logger2.debug("QUERY_CACHE: Fetching from API (cache miss or invalid)", {
|
|
904
|
+
queryHash,
|
|
905
|
+
query: JSON.stringify(query),
|
|
906
|
+
locations: JSON.stringify(locations)
|
|
907
|
+
});
|
|
736
908
|
let ret = [];
|
|
737
909
|
try {
|
|
738
910
|
ret = await api.all(query, locations);
|
|
911
|
+
logger2.debug("QUERY_CACHE: API response received", {
|
|
912
|
+
queryHash,
|
|
913
|
+
itemCount: ret.length,
|
|
914
|
+
itemKeys: ret.map((item) => JSON.stringify(item.key))
|
|
915
|
+
});
|
|
916
|
+
logger2.debug("QUERY_CACHE: Storing items in item cache", {
|
|
917
|
+
queryHash,
|
|
918
|
+
itemCount: ret.length
|
|
919
|
+
});
|
|
739
920
|
for (const v of ret) {
|
|
740
921
|
await cacheMap.set(v.key, v);
|
|
922
|
+
logger2.debug("QUERY_CACHE: Stored item in cache", {
|
|
923
|
+
itemKey: JSON.stringify(v.key),
|
|
924
|
+
queryHash
|
|
925
|
+
});
|
|
741
926
|
const keyStr = JSON.stringify(v.key);
|
|
742
927
|
ttlManager.onItemAdded(keyStr, cacheMap);
|
|
743
928
|
const evictedKeys = await context.evictionManager.onItemAdded(keyStr, v, cacheMap);
|
|
744
929
|
for (const evictedKey of evictedKeys) {
|
|
745
930
|
const parsedKey = JSON.parse(evictedKey);
|
|
746
931
|
await cacheMap.delete(parsedKey);
|
|
932
|
+
logger2.debug("QUERY_CACHE: Evicted item due to cache limits", {
|
|
933
|
+
evictedKey,
|
|
934
|
+
queryHash
|
|
935
|
+
});
|
|
747
936
|
}
|
|
748
937
|
}
|
|
749
938
|
const itemKeys = ret.map((item) => item.key);
|
|
750
|
-
cacheMap.setQueryResult(queryHash, itemKeys);
|
|
751
|
-
logger2.debug("
|
|
939
|
+
await cacheMap.setQueryResult(queryHash, itemKeys);
|
|
940
|
+
logger2.debug("QUERY_CACHE: Stored query result in query cache", {
|
|
941
|
+
queryHash,
|
|
942
|
+
itemKeyCount: itemKeys.length,
|
|
943
|
+
itemKeys: itemKeys.map((k) => JSON.stringify(k))
|
|
944
|
+
});
|
|
752
945
|
const event = CacheEventFactory.createQueryEvent(query, locations, ret);
|
|
753
946
|
context.eventEmitter.emit(event);
|
|
947
|
+
logger2.debug("QUERY_CACHE: Emitted query event", { queryHash });
|
|
754
948
|
} catch (e) {
|
|
755
949
|
if (e instanceof NotFoundError) {
|
|
756
|
-
|
|
757
|
-
|
|
950
|
+
logger2.debug("QUERY_CACHE: API returned NotFoundError, caching empty result", { queryHash });
|
|
951
|
+
await cacheMap.setQueryResult(queryHash, []);
|
|
952
|
+
logger2.debug("QUERY_CACHE: Cached empty query result for not found", { queryHash });
|
|
758
953
|
} else {
|
|
954
|
+
logger2.debug("QUERY_CACHE: API error occurred", {
|
|
955
|
+
queryHash,
|
|
956
|
+
error: e instanceof Error ? e.message : String(e)
|
|
957
|
+
});
|
|
759
958
|
throw e;
|
|
760
959
|
}
|
|
761
960
|
}
|
|
961
|
+
logger2.debug("QUERY_CACHE: all() operation completed", {
|
|
962
|
+
queryHash,
|
|
963
|
+
resultCount: ret.length
|
|
964
|
+
});
|
|
762
965
|
return ret;
|
|
763
966
|
}
|
|
764
967
|
|
|
@@ -961,37 +1164,93 @@ async function executeOneLogic(query, locations, context) {
|
|
|
961
1164
|
}
|
|
962
1165
|
}
|
|
963
1166
|
const queryHash = createQueryHash(pkType, query, locations);
|
|
964
|
-
logger3.debug("Generated query hash for one", {
|
|
1167
|
+
logger3.debug("QUERY_CACHE: Generated query hash for one()", {
|
|
1168
|
+
queryHash,
|
|
1169
|
+
query: JSON.stringify(query),
|
|
1170
|
+
locations: JSON.stringify(locations),
|
|
1171
|
+
pkType
|
|
1172
|
+
});
|
|
1173
|
+
logger3.debug("QUERY_CACHE: Checking query cache for hash", { queryHash });
|
|
965
1174
|
const cachedItemKeys = await cacheMap.getQueryResult(queryHash);
|
|
966
1175
|
if (cachedItemKeys) {
|
|
967
|
-
logger3.debug("
|
|
1176
|
+
logger3.debug("QUERY_CACHE: Cache HIT - Found cached query result", {
|
|
1177
|
+
queryHash,
|
|
1178
|
+
cachedKeyCount: cachedItemKeys.length,
|
|
1179
|
+
itemKeys: cachedItemKeys.map((k) => JSON.stringify(k))
|
|
1180
|
+
});
|
|
968
1181
|
if (cachedItemKeys.length === 0) {
|
|
1182
|
+
logger3.debug("QUERY_CACHE: Cached empty result (not found)", { queryHash });
|
|
969
1183
|
return null;
|
|
970
1184
|
}
|
|
971
|
-
const
|
|
1185
|
+
const itemKey = cachedItemKeys[0];
|
|
1186
|
+
logger3.debug("QUERY_CACHE: Retrieving first cached item", {
|
|
1187
|
+
queryHash,
|
|
1188
|
+
itemKey: JSON.stringify(itemKey)
|
|
1189
|
+
});
|
|
1190
|
+
const item = await cacheMap.get(itemKey);
|
|
972
1191
|
if (item) {
|
|
1192
|
+
logger3.debug("QUERY_CACHE: Retrieved cached item successfully", {
|
|
1193
|
+
queryHash,
|
|
1194
|
+
itemKey: JSON.stringify(itemKey),
|
|
1195
|
+
itemKeyStr: JSON.stringify(item.key)
|
|
1196
|
+
});
|
|
973
1197
|
return item;
|
|
974
1198
|
} else {
|
|
975
|
-
logger3.debug("Cached item
|
|
1199
|
+
logger3.debug("QUERY_CACHE: Cached item MISSING from item cache, invalidating query cache", {
|
|
1200
|
+
queryHash,
|
|
1201
|
+
itemKey: JSON.stringify(itemKey)
|
|
1202
|
+
});
|
|
976
1203
|
cacheMap.deleteQueryResult(queryHash);
|
|
977
1204
|
}
|
|
1205
|
+
} else {
|
|
1206
|
+
logger3.debug("QUERY_CACHE: Cache MISS - No cached query result found", { queryHash });
|
|
978
1207
|
}
|
|
1208
|
+
logger3.debug("QUERY_CACHE: Attempting direct cache query using queryIn()", {
|
|
1209
|
+
queryHash,
|
|
1210
|
+
query: JSON.stringify(query),
|
|
1211
|
+
locations: JSON.stringify(locations)
|
|
1212
|
+
});
|
|
979
1213
|
try {
|
|
980
1214
|
const directCachedItems = await cacheMap.queryIn(query, locations);
|
|
981
1215
|
if (directCachedItems && directCachedItems.length > 0) {
|
|
982
|
-
logger3.debug("Found item
|
|
1216
|
+
logger3.debug("QUERY_CACHE: Direct cache query SUCCESS - Found item in item cache", {
|
|
1217
|
+
queryHash,
|
|
1218
|
+
itemCount: directCachedItems.length,
|
|
1219
|
+
itemKeys: directCachedItems.map((item) => JSON.stringify(item.key))
|
|
1220
|
+
});
|
|
983
1221
|
const foundItem = directCachedItems[0];
|
|
984
1222
|
await cacheMap.setQueryResult(queryHash, [foundItem.key]);
|
|
985
|
-
logger3.debug("
|
|
1223
|
+
logger3.debug("QUERY_CACHE: Stored query result from direct cache hit", {
|
|
1224
|
+
queryHash,
|
|
1225
|
+
itemKey: JSON.stringify(foundItem.key)
|
|
1226
|
+
});
|
|
986
1227
|
return foundItem;
|
|
1228
|
+
} else {
|
|
1229
|
+
logger3.debug("QUERY_CACHE: Direct cache query returned no items", { queryHash });
|
|
987
1230
|
}
|
|
988
1231
|
} catch (error) {
|
|
989
|
-
logger3.debug("Error querying cache directly, proceeding to API", {
|
|
1232
|
+
logger3.debug("QUERY_CACHE: Error querying cache directly, proceeding to API", {
|
|
1233
|
+
queryHash,
|
|
1234
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1235
|
+
});
|
|
990
1236
|
}
|
|
1237
|
+
logger3.debug("QUERY_CACHE: Fetching from API (cache miss or invalid)", {
|
|
1238
|
+
queryHash,
|
|
1239
|
+
query: JSON.stringify(query),
|
|
1240
|
+
locations: JSON.stringify(locations)
|
|
1241
|
+
});
|
|
991
1242
|
let retItem = null;
|
|
992
1243
|
try {
|
|
993
1244
|
retItem = await api.one(query, locations);
|
|
994
1245
|
if (retItem) {
|
|
1246
|
+
logger3.debug("QUERY_CACHE: API response received", {
|
|
1247
|
+
queryHash,
|
|
1248
|
+
itemKey: JSON.stringify(retItem.key)
|
|
1249
|
+
});
|
|
1250
|
+
logger3.debug("QUERY_CACHE: Storing item in item cache", {
|
|
1251
|
+
queryHash,
|
|
1252
|
+
itemKey: JSON.stringify(retItem.key)
|
|
1253
|
+
});
|
|
995
1254
|
await cacheMap.set(retItem.key, retItem);
|
|
996
1255
|
const keyStr = JSON.stringify(retItem.key);
|
|
997
1256
|
const metadata = await cacheMap.getMetadata(keyStr);
|
|
@@ -1011,21 +1270,38 @@ async function executeOneLogic(query, locations, context) {
|
|
|
1011
1270
|
for (const evictedKey of evictedKeys) {
|
|
1012
1271
|
const parsedKey = JSON.parse(evictedKey);
|
|
1013
1272
|
await cacheMap.delete(parsedKey);
|
|
1273
|
+
logger3.debug("QUERY_CACHE: Evicted item due to cache limits", {
|
|
1274
|
+
evictedKey,
|
|
1275
|
+
queryHash
|
|
1276
|
+
});
|
|
1014
1277
|
}
|
|
1015
1278
|
await cacheMap.setQueryResult(queryHash, [retItem.key]);
|
|
1016
|
-
logger3.debug("
|
|
1279
|
+
logger3.debug("QUERY_CACHE: Stored query result in query cache", {
|
|
1280
|
+
queryHash,
|
|
1281
|
+
itemKey: JSON.stringify(retItem.key)
|
|
1282
|
+
});
|
|
1017
1283
|
} else {
|
|
1284
|
+
logger3.debug("QUERY_CACHE: API returned null, caching empty result", { queryHash });
|
|
1018
1285
|
await cacheMap.setQueryResult(queryHash, []);
|
|
1019
|
-
logger3.debug("Cached empty query result", { queryHash });
|
|
1286
|
+
logger3.debug("QUERY_CACHE: Cached empty query result", { queryHash });
|
|
1020
1287
|
}
|
|
1021
1288
|
} catch (e) {
|
|
1022
1289
|
if (e instanceof NotFoundError2) {
|
|
1023
|
-
|
|
1024
|
-
|
|
1290
|
+
logger3.debug("QUERY_CACHE: API returned NotFoundError, caching empty result", { queryHash });
|
|
1291
|
+
await cacheMap.setQueryResult(queryHash, []);
|
|
1292
|
+
logger3.debug("QUERY_CACHE: Cached empty query result for not found", { queryHash });
|
|
1025
1293
|
} else {
|
|
1294
|
+
logger3.debug("QUERY_CACHE: API error occurred", {
|
|
1295
|
+
queryHash,
|
|
1296
|
+
error: e instanceof Error ? e.message : String(e)
|
|
1297
|
+
});
|
|
1026
1298
|
throw e;
|
|
1027
1299
|
}
|
|
1028
1300
|
}
|
|
1301
|
+
logger3.debug("QUERY_CACHE: one() operation completed", {
|
|
1302
|
+
queryHash,
|
|
1303
|
+
result: retItem ? JSON.stringify(retItem.key) : null
|
|
1304
|
+
});
|
|
1029
1305
|
return retItem || null;
|
|
1030
1306
|
}
|
|
1031
1307
|
|
|
@@ -1107,68 +1383,128 @@ var get = async (key, context) => {
|
|
|
1107
1383
|
return [context, result];
|
|
1108
1384
|
};
|
|
1109
1385
|
async function executeGetLogic(key, context) {
|
|
1386
|
+
const startTime = Date.now();
|
|
1110
1387
|
const { api, cacheMap, pkType, ttlManager, statsManager } = context;
|
|
1388
|
+
const keyStr = JSON.stringify(key);
|
|
1389
|
+
logger5.debug("CACHE_OP: get() started", {
|
|
1390
|
+
key: keyStr,
|
|
1391
|
+
ttlEnabled: ttlManager.isTTLEnabled(),
|
|
1392
|
+
defaultTTL: ttlManager.getDefaultTTL(),
|
|
1393
|
+
cacheType: cacheMap.implementationType
|
|
1394
|
+
});
|
|
1111
1395
|
statsManager.incrementRequests();
|
|
1112
1396
|
if (!isValidItemKey(key)) {
|
|
1113
|
-
logger5.error("
|
|
1397
|
+
logger5.error("CACHE_OP: Invalid key for get", { key: keyStr });
|
|
1114
1398
|
throw new Error("Key for Get is not a valid ItemKey");
|
|
1115
1399
|
}
|
|
1116
1400
|
if (context.options?.bypassCache) {
|
|
1117
|
-
logger5.debug("Cache bypass enabled, fetching directly from API", { key });
|
|
1401
|
+
logger5.debug("CACHE_OP: Cache bypass enabled, fetching directly from API", { key: keyStr });
|
|
1118
1402
|
statsManager.incrementMisses();
|
|
1119
1403
|
try {
|
|
1404
|
+
const apiStartTime = Date.now();
|
|
1120
1405
|
const ret2 = await api.get(key);
|
|
1406
|
+
const apiDuration = Date.now() - apiStartTime;
|
|
1121
1407
|
if (ret2) {
|
|
1122
|
-
logger5.debug("API response received (not cached
|
|
1408
|
+
logger5.debug("CACHE_OP: API response received (bypass mode, not cached)", {
|
|
1409
|
+
key: keyStr,
|
|
1410
|
+
apiDuration,
|
|
1411
|
+
totalDuration: Date.now() - startTime
|
|
1412
|
+
});
|
|
1123
1413
|
return ret2;
|
|
1124
1414
|
} else {
|
|
1125
|
-
logger5.debug("API returned null", {
|
|
1415
|
+
logger5.debug("CACHE_OP: API returned null (bypass mode)", {
|
|
1416
|
+
key: keyStr,
|
|
1417
|
+
apiDuration
|
|
1418
|
+
});
|
|
1126
1419
|
return null;
|
|
1127
1420
|
}
|
|
1128
1421
|
} catch (error) {
|
|
1129
|
-
logger5.error("API request failed", {
|
|
1422
|
+
logger5.error("CACHE_OP: API request failed in bypass mode", {
|
|
1423
|
+
key: keyStr,
|
|
1424
|
+
duration: Date.now() - startTime,
|
|
1425
|
+
error
|
|
1426
|
+
});
|
|
1130
1427
|
throw error;
|
|
1131
1428
|
}
|
|
1132
1429
|
}
|
|
1133
1430
|
if (ttlManager.isTTLEnabled()) {
|
|
1134
|
-
const
|
|
1431
|
+
const cacheCheckStart = Date.now();
|
|
1135
1432
|
const cachedItem = await cacheMap.get(key);
|
|
1433
|
+
const cacheCheckDuration = Date.now() - cacheCheckStart;
|
|
1136
1434
|
if (cachedItem) {
|
|
1137
|
-
|
|
1435
|
+
logger5.debug("CACHE_OP: Item found in cache, checking TTL validity", {
|
|
1436
|
+
key: keyStr,
|
|
1437
|
+
cacheCheckDuration,
|
|
1438
|
+
defaultTTL: ttlManager.getDefaultTTL()
|
|
1439
|
+
});
|
|
1440
|
+
const ttlCheckStart = Date.now();
|
|
1441
|
+
const isValid = await ttlManager.validateItem(keyStr, cacheMap);
|
|
1442
|
+
const ttlCheckDuration = Date.now() - ttlCheckStart;
|
|
1138
1443
|
if (isValid) {
|
|
1139
|
-
|
|
1444
|
+
const totalDuration = Date.now() - startTime;
|
|
1445
|
+
logger5.debug("CACHE_OP: Cache HIT with valid TTL", {
|
|
1446
|
+
key: keyStr,
|
|
1447
|
+
cacheCheckDuration,
|
|
1448
|
+
ttlCheckDuration,
|
|
1449
|
+
totalDuration,
|
|
1450
|
+
defaultTTL: ttlManager.getDefaultTTL()
|
|
1451
|
+
});
|
|
1140
1452
|
statsManager.incrementHits();
|
|
1141
1453
|
return cachedItem;
|
|
1142
1454
|
} else {
|
|
1143
|
-
logger5.debug("Cache item
|
|
1455
|
+
logger5.debug("CACHE_OP: Cache item EXPIRED, removing from cache", {
|
|
1456
|
+
key: keyStr,
|
|
1457
|
+
cacheCheckDuration,
|
|
1458
|
+
ttlCheckDuration
|
|
1459
|
+
});
|
|
1144
1460
|
cacheMap.delete(key);
|
|
1145
1461
|
statsManager.incrementMisses();
|
|
1146
1462
|
}
|
|
1147
1463
|
} else {
|
|
1464
|
+
logger5.debug("CACHE_OP: Cache MISS (no item found)", {
|
|
1465
|
+
key: keyStr,
|
|
1466
|
+
cacheCheckDuration
|
|
1467
|
+
});
|
|
1148
1468
|
statsManager.incrementMisses();
|
|
1149
1469
|
}
|
|
1150
|
-
logger5.debug("
|
|
1470
|
+
logger5.debug("CACHE_OP: Proceeding to API fetch (TTL-enabled cache miss or expired)", {
|
|
1471
|
+
key: keyStr,
|
|
1472
|
+
defaultTTL: ttlManager.getDefaultTTL()
|
|
1473
|
+
});
|
|
1151
1474
|
} else {
|
|
1475
|
+
const cacheCheckStart = Date.now();
|
|
1152
1476
|
const cachedItem = await cacheMap.get(key);
|
|
1477
|
+
const cacheCheckDuration = Date.now() - cacheCheckStart;
|
|
1153
1478
|
if (cachedItem) {
|
|
1154
|
-
|
|
1479
|
+
const totalDuration = Date.now() - startTime;
|
|
1480
|
+
logger5.debug("CACHE_OP: Cache HIT (TTL disabled)", {
|
|
1481
|
+
key: keyStr,
|
|
1482
|
+
cacheCheckDuration,
|
|
1483
|
+
totalDuration
|
|
1484
|
+
});
|
|
1155
1485
|
statsManager.incrementHits();
|
|
1156
1486
|
return cachedItem;
|
|
1157
1487
|
} else {
|
|
1488
|
+
logger5.debug("CACHE_OP: Cache MISS (TTL disabled)", {
|
|
1489
|
+
key: keyStr,
|
|
1490
|
+
cacheCheckDuration
|
|
1491
|
+
});
|
|
1158
1492
|
statsManager.incrementMisses();
|
|
1159
1493
|
}
|
|
1160
1494
|
}
|
|
1161
1495
|
let ret;
|
|
1162
|
-
const
|
|
1496
|
+
const requestKeyStr = keyToString(key);
|
|
1163
1497
|
try {
|
|
1164
|
-
const requestEntry = inFlightRequests.get(
|
|
1498
|
+
const requestEntry = inFlightRequests.get(requestKeyStr);
|
|
1165
1499
|
let apiRequest;
|
|
1500
|
+
const apiStartTime = Date.now();
|
|
1166
1501
|
if (!requestEntry) {
|
|
1502
|
+
logger5.debug("CACHE_OP: Creating new API request", { key: keyStr });
|
|
1167
1503
|
apiRequest = api.get(key);
|
|
1168
1504
|
if (apiRequest && typeof apiRequest.then === "function") {
|
|
1169
1505
|
const timestamp = Date.now();
|
|
1170
|
-
inFlightRequests.set(
|
|
1171
|
-
const cleanup = () => inFlightRequests.delete(
|
|
1506
|
+
inFlightRequests.set(requestKeyStr, { promise: apiRequest, timestamp });
|
|
1507
|
+
const cleanup = () => inFlightRequests.delete(requestKeyStr);
|
|
1172
1508
|
if (typeof apiRequest.finally === "function") {
|
|
1173
1509
|
apiRequest.finally(cleanup);
|
|
1174
1510
|
} else {
|
|
@@ -1176,37 +1512,90 @@ async function executeGetLogic(key, context) {
|
|
|
1176
1512
|
}
|
|
1177
1513
|
}
|
|
1178
1514
|
} else {
|
|
1179
|
-
logger5.debug("Using in-flight request
|
|
1515
|
+
logger5.debug("CACHE_OP: Using existing in-flight request", {
|
|
1516
|
+
key: keyStr,
|
|
1517
|
+
requestAge: Date.now() - requestEntry.timestamp
|
|
1518
|
+
});
|
|
1180
1519
|
apiRequest = requestEntry.promise;
|
|
1181
1520
|
}
|
|
1182
1521
|
ret = await apiRequest;
|
|
1522
|
+
const apiDuration = Date.now() - apiStartTime;
|
|
1183
1523
|
if (ret) {
|
|
1524
|
+
logger5.debug("CACHE_OP: API request successful, caching result", {
|
|
1525
|
+
key: keyStr,
|
|
1526
|
+
apiDuration,
|
|
1527
|
+
itemKeyMatches: JSON.stringify(ret.key) === keyStr
|
|
1528
|
+
});
|
|
1529
|
+
const cacheSetStart = Date.now();
|
|
1184
1530
|
await cacheMap.set(ret.key, ret);
|
|
1185
|
-
const
|
|
1186
|
-
const
|
|
1531
|
+
const cacheSetDuration = Date.now() - cacheSetStart;
|
|
1532
|
+
const itemKeyStr = JSON.stringify(ret.key);
|
|
1533
|
+
const metadataStart = Date.now();
|
|
1534
|
+
const metadata = await cacheMap.getMetadata(itemKeyStr);
|
|
1187
1535
|
if (!metadata) {
|
|
1188
1536
|
const now = Date.now();
|
|
1537
|
+
const estimatedSize = estimateValueSize(ret);
|
|
1189
1538
|
const baseMetadata = {
|
|
1190
|
-
key:
|
|
1539
|
+
key: itemKeyStr,
|
|
1191
1540
|
addedAt: now,
|
|
1192
1541
|
lastAccessedAt: now,
|
|
1193
1542
|
accessCount: 1,
|
|
1194
|
-
estimatedSize
|
|
1543
|
+
estimatedSize
|
|
1195
1544
|
};
|
|
1196
|
-
await cacheMap.setMetadata(
|
|
1545
|
+
await cacheMap.setMetadata(itemKeyStr, baseMetadata);
|
|
1546
|
+
logger5.debug("CACHE_OP: Created base metadata for cached item", {
|
|
1547
|
+
key: itemKeyStr,
|
|
1548
|
+
estimatedSize
|
|
1549
|
+
});
|
|
1550
|
+
}
|
|
1551
|
+
const metadataDuration = Date.now() - metadataStart;
|
|
1552
|
+
const evictionStart = Date.now();
|
|
1553
|
+
const evictedKeys = await context.evictionManager.onItemAdded(itemKeyStr, ret, cacheMap);
|
|
1554
|
+
const evictionDuration = Date.now() - evictionStart;
|
|
1555
|
+
if (evictedKeys.length > 0) {
|
|
1556
|
+
logger5.debug("CACHE_OP: Eviction triggered by new item", {
|
|
1557
|
+
key: itemKeyStr,
|
|
1558
|
+
evictedCount: evictedKeys.length,
|
|
1559
|
+
evictedKeys
|
|
1560
|
+
});
|
|
1197
1561
|
}
|
|
1198
|
-
const
|
|
1199
|
-
await ttlManager.onItemAdded(
|
|
1562
|
+
const ttlStart = Date.now();
|
|
1563
|
+
await ttlManager.onItemAdded(itemKeyStr, cacheMap);
|
|
1564
|
+
const ttlDuration = Date.now() - ttlStart;
|
|
1200
1565
|
for (const evictedKey of evictedKeys) {
|
|
1201
1566
|
const parsedKey = JSON.parse(evictedKey);
|
|
1202
1567
|
await cacheMap.delete(parsedKey);
|
|
1568
|
+
logger5.debug("CACHE_OP: Removed evicted item", { evictedKey });
|
|
1203
1569
|
}
|
|
1204
1570
|
const event = CacheEventFactory.itemRetrieved(ret.key, ret, "api");
|
|
1205
1571
|
context.eventEmitter.emit(event);
|
|
1572
|
+
const totalDuration = Date.now() - startTime;
|
|
1573
|
+
logger5.debug("CACHE_OP: get() completed successfully (cache miss)", {
|
|
1574
|
+
key: keyStr,
|
|
1575
|
+
apiDuration,
|
|
1576
|
+
cacheSetDuration,
|
|
1577
|
+
metadataDuration,
|
|
1578
|
+
evictionDuration,
|
|
1579
|
+
ttlDuration,
|
|
1580
|
+
totalDuration,
|
|
1581
|
+
evictedCount: evictedKeys.length
|
|
1582
|
+
});
|
|
1583
|
+
} else {
|
|
1584
|
+
logger5.debug("CACHE_OP: API returned null", {
|
|
1585
|
+
key: keyStr,
|
|
1586
|
+
apiDuration,
|
|
1587
|
+
totalDuration: Date.now() - startTime
|
|
1588
|
+
});
|
|
1206
1589
|
}
|
|
1207
1590
|
} catch (e) {
|
|
1208
|
-
inFlightRequests.delete(
|
|
1209
|
-
|
|
1591
|
+
inFlightRequests.delete(requestKeyStr);
|
|
1592
|
+
const duration = Date.now() - startTime;
|
|
1593
|
+
logger5.error("CACHE_OP: Error in get() operation", {
|
|
1594
|
+
key: keyStr,
|
|
1595
|
+
duration,
|
|
1596
|
+
message: e.message,
|
|
1597
|
+
stack: e.stack
|
|
1598
|
+
});
|
|
1210
1599
|
throw e;
|
|
1211
1600
|
}
|
|
1212
1601
|
return ret || null;
|
|
@@ -1218,43 +1607,88 @@ import {
|
|
|
1218
1607
|
} from "@fjell/core";
|
|
1219
1608
|
var logger6 = logger_default.get("retrieve");
|
|
1220
1609
|
var retrieve = async (key, context) => {
|
|
1610
|
+
const startTime = Date.now();
|
|
1221
1611
|
const { cacheMap, pkType, statsManager } = context;
|
|
1612
|
+
const keyStr = JSON.stringify(key);
|
|
1222
1613
|
logger6.default("retrieve", { key });
|
|
1614
|
+
logger6.debug("CACHE_OP: retrieve() started", {
|
|
1615
|
+
key: keyStr,
|
|
1616
|
+
cacheType: cacheMap.implementationType,
|
|
1617
|
+
bypassEnabled: !!context.options?.bypassCache
|
|
1618
|
+
});
|
|
1223
1619
|
statsManager.incrementRequests();
|
|
1224
1620
|
if (!isValidItemKey2(key)) {
|
|
1225
|
-
logger6.error("
|
|
1621
|
+
logger6.error("CACHE_OP: Invalid key for retrieve", { key: keyStr });
|
|
1226
1622
|
throw new Error("Key for Retrieve is not a valid ItemKey");
|
|
1227
1623
|
}
|
|
1228
1624
|
if (context.options?.bypassCache) {
|
|
1229
|
-
logger6.debug("Cache bypass enabled, fetching directly from API", { key });
|
|
1625
|
+
logger6.debug("CACHE_OP: Cache bypass enabled, fetching directly from API", { key: keyStr });
|
|
1230
1626
|
statsManager.incrementMisses();
|
|
1231
1627
|
try {
|
|
1628
|
+
const apiStartTime = Date.now();
|
|
1232
1629
|
const { api } = context;
|
|
1233
1630
|
const retrieved2 = await api.get(key);
|
|
1631
|
+
const apiDuration = Date.now() - apiStartTime;
|
|
1234
1632
|
if (retrieved2) {
|
|
1235
|
-
logger6.debug("API response received (
|
|
1633
|
+
logger6.debug("CACHE_OP: API response received (bypass mode)", {
|
|
1634
|
+
key: keyStr,
|
|
1635
|
+
apiDuration,
|
|
1636
|
+
hasValue: true
|
|
1637
|
+
});
|
|
1236
1638
|
return [null, retrieved2];
|
|
1237
1639
|
} else {
|
|
1238
|
-
logger6.debug("API returned null", {
|
|
1640
|
+
logger6.debug("CACHE_OP: API returned null (bypass mode)", {
|
|
1641
|
+
key: keyStr,
|
|
1642
|
+
apiDuration
|
|
1643
|
+
});
|
|
1239
1644
|
return [null, null];
|
|
1240
1645
|
}
|
|
1241
1646
|
} catch (error) {
|
|
1242
|
-
|
|
1647
|
+
const duration = Date.now() - startTime;
|
|
1648
|
+
logger6.error("CACHE_OP: API request failed in bypass mode", {
|
|
1649
|
+
key: keyStr,
|
|
1650
|
+
duration,
|
|
1651
|
+
error
|
|
1652
|
+
});
|
|
1243
1653
|
throw error;
|
|
1244
1654
|
}
|
|
1245
1655
|
}
|
|
1246
1656
|
const containsItemKey = await cacheMap.includesKey(key);
|
|
1657
|
+
logger6.debug("CACHE_OP: Cache key check completed", {
|
|
1658
|
+
key: keyStr,
|
|
1659
|
+
exists: containsItemKey
|
|
1660
|
+
});
|
|
1247
1661
|
let retrieved;
|
|
1248
1662
|
let contextToReturn;
|
|
1249
1663
|
if (containsItemKey) {
|
|
1250
1664
|
logger6.default("Looking for Object in Cache", key);
|
|
1665
|
+
logger6.debug("CACHE_OP: Cache HIT - retrieving from cache", { key: keyStr });
|
|
1666
|
+
const getStartTime = Date.now();
|
|
1251
1667
|
retrieved = await cacheMap.get(key);
|
|
1668
|
+
const getDuration = Date.now() - getStartTime;
|
|
1252
1669
|
contextToReturn = null;
|
|
1253
1670
|
statsManager.incrementHits();
|
|
1671
|
+
const totalDuration = Date.now() - startTime;
|
|
1672
|
+
logger6.debug("CACHE_OP: retrieve() completed (cache hit)", {
|
|
1673
|
+
key: keyStr,
|
|
1674
|
+
getDuration,
|
|
1675
|
+
totalDuration,
|
|
1676
|
+
hasValue: !!retrieved
|
|
1677
|
+
});
|
|
1254
1678
|
} else {
|
|
1255
1679
|
logger6.default("Object Not Found in Cache, Retrieving from Server API", { key });
|
|
1680
|
+
logger6.debug("CACHE_OP: Cache MISS - fetching from API", { key: keyStr });
|
|
1256
1681
|
statsManager.incrementMisses();
|
|
1682
|
+
const apiStartTime = Date.now();
|
|
1257
1683
|
[contextToReturn, retrieved] = await get(key, context);
|
|
1684
|
+
const apiDuration = Date.now() - apiStartTime;
|
|
1685
|
+
const totalDuration = Date.now() - startTime;
|
|
1686
|
+
logger6.debug("CACHE_OP: retrieve() completed (cache miss)", {
|
|
1687
|
+
key: keyStr,
|
|
1688
|
+
apiDuration,
|
|
1689
|
+
totalDuration,
|
|
1690
|
+
hasValue: !!retrieved
|
|
1691
|
+
});
|
|
1258
1692
|
}
|
|
1259
1693
|
const retValue = [
|
|
1260
1694
|
contextToReturn,
|
|
@@ -1749,44 +2183,107 @@ async function executeFindLogic(finder, params, locations, context) {
|
|
|
1749
2183
|
}
|
|
1750
2184
|
}
|
|
1751
2185
|
const queryHash = createFinderHash(finder, params, locations);
|
|
1752
|
-
logger14.debug("Generated query hash for find", {
|
|
2186
|
+
logger14.debug("QUERY_CACHE: Generated query hash for find()", {
|
|
2187
|
+
queryHash,
|
|
2188
|
+
finder,
|
|
2189
|
+
params: JSON.stringify(params),
|
|
2190
|
+
locations: JSON.stringify(locations)
|
|
2191
|
+
});
|
|
2192
|
+
logger14.debug("QUERY_CACHE: Checking query cache for hash", { queryHash });
|
|
1753
2193
|
const cachedItemKeys = await cacheMap.getQueryResult(queryHash);
|
|
1754
2194
|
if (cachedItemKeys) {
|
|
1755
|
-
logger14.debug("
|
|
2195
|
+
logger14.debug("QUERY_CACHE: Cache HIT - Found cached query result", {
|
|
2196
|
+
queryHash,
|
|
2197
|
+
cachedKeyCount: cachedItemKeys.length,
|
|
2198
|
+
itemKeys: cachedItemKeys.map((k) => JSON.stringify(k))
|
|
2199
|
+
});
|
|
1756
2200
|
const cachedItems = [];
|
|
1757
2201
|
let allItemsAvailable = true;
|
|
2202
|
+
const missingKeys = [];
|
|
1758
2203
|
for (const itemKey of cachedItemKeys) {
|
|
1759
2204
|
const item = await cacheMap.get(itemKey);
|
|
1760
2205
|
if (item) {
|
|
1761
2206
|
cachedItems.push(item);
|
|
2207
|
+
logger14.debug("QUERY_CACHE: Retrieved cached item", {
|
|
2208
|
+
itemKey: JSON.stringify(itemKey),
|
|
2209
|
+
itemKeyStr: JSON.stringify(item.key)
|
|
2210
|
+
});
|
|
1762
2211
|
} else {
|
|
1763
2212
|
allItemsAvailable = false;
|
|
2213
|
+
missingKeys.push(itemKey);
|
|
2214
|
+
logger14.debug("QUERY_CACHE: Cached item MISSING from item cache", {
|
|
2215
|
+
itemKey: JSON.stringify(itemKey),
|
|
2216
|
+
queryHash
|
|
2217
|
+
});
|
|
1764
2218
|
break;
|
|
1765
2219
|
}
|
|
1766
2220
|
}
|
|
1767
2221
|
if (allItemsAvailable) {
|
|
2222
|
+
logger14.debug("QUERY_CACHE: All cached items available, returning from cache", {
|
|
2223
|
+
queryHash,
|
|
2224
|
+
itemCount: cachedItems.length
|
|
2225
|
+
});
|
|
1768
2226
|
return cachedItems;
|
|
1769
2227
|
} else {
|
|
1770
|
-
logger14.debug("Some cached items missing, invalidating query cache"
|
|
2228
|
+
logger14.debug("QUERY_CACHE: Some cached items missing, invalidating query cache", {
|
|
2229
|
+
queryHash,
|
|
2230
|
+
missingKeys: missingKeys.map((k) => JSON.stringify(k)),
|
|
2231
|
+
foundCount: cachedItems.length,
|
|
2232
|
+
expectedCount: cachedItemKeys.length
|
|
2233
|
+
});
|
|
1771
2234
|
cacheMap.deleteQueryResult(queryHash);
|
|
1772
2235
|
}
|
|
2236
|
+
} else {
|
|
2237
|
+
logger14.debug("QUERY_CACHE: Cache MISS - No cached query result found", { queryHash });
|
|
1773
2238
|
}
|
|
2239
|
+
logger14.debug("QUERY_CACHE: Fetching from API (cache miss or invalid)", {
|
|
2240
|
+
queryHash,
|
|
2241
|
+
finder,
|
|
2242
|
+
params: JSON.stringify(params),
|
|
2243
|
+
locations: JSON.stringify(locations)
|
|
2244
|
+
});
|
|
1774
2245
|
const ret = await api.find(finder, params, locations);
|
|
2246
|
+
logger14.debug("QUERY_CACHE: API response received", {
|
|
2247
|
+
queryHash,
|
|
2248
|
+
itemCount: ret.length,
|
|
2249
|
+
itemKeys: ret.map((item) => JSON.stringify(item.key))
|
|
2250
|
+
});
|
|
2251
|
+
logger14.debug("QUERY_CACHE: Storing items in item cache", {
|
|
2252
|
+
queryHash,
|
|
2253
|
+
itemCount: ret.length
|
|
2254
|
+
});
|
|
1775
2255
|
for (const v of ret) {
|
|
1776
2256
|
await cacheMap.set(v.key, v);
|
|
2257
|
+
logger14.debug("QUERY_CACHE: Stored item in cache", {
|
|
2258
|
+
itemKey: JSON.stringify(v.key),
|
|
2259
|
+
queryHash
|
|
2260
|
+
});
|
|
1777
2261
|
const keyStr = JSON.stringify(v.key);
|
|
1778
2262
|
ttlManager.onItemAdded(keyStr, cacheMap);
|
|
1779
2263
|
const evictedKeys = await context.evictionManager.onItemAdded(keyStr, v, cacheMap);
|
|
1780
2264
|
for (const evictedKey of evictedKeys) {
|
|
1781
2265
|
const parsedKey = JSON.parse(evictedKey);
|
|
1782
2266
|
await cacheMap.delete(parsedKey);
|
|
2267
|
+
logger14.debug("QUERY_CACHE: Evicted item due to cache limits", {
|
|
2268
|
+
evictedKey,
|
|
2269
|
+
queryHash
|
|
2270
|
+
});
|
|
1783
2271
|
}
|
|
1784
2272
|
}
|
|
1785
2273
|
const itemKeys = ret.map((item) => item.key);
|
|
1786
|
-
cacheMap.setQueryResult(queryHash, itemKeys);
|
|
1787
|
-
logger14.debug("
|
|
2274
|
+
await cacheMap.setQueryResult(queryHash, itemKeys);
|
|
2275
|
+
logger14.debug("QUERY_CACHE: Stored query result in query cache", {
|
|
2276
|
+
queryHash,
|
|
2277
|
+
itemKeyCount: itemKeys.length,
|
|
2278
|
+
itemKeys: itemKeys.map((k) => JSON.stringify(k))
|
|
2279
|
+
});
|
|
1788
2280
|
const event = CacheEventFactory.createQueryEvent(params, locations, ret);
|
|
1789
2281
|
eventEmitter.emit(event);
|
|
2282
|
+
logger14.debug("QUERY_CACHE: Emitted query event", { queryHash });
|
|
2283
|
+
logger14.debug("QUERY_CACHE: find() operation completed", {
|
|
2284
|
+
queryHash,
|
|
2285
|
+
resultCount: ret.length
|
|
2286
|
+
});
|
|
1790
2287
|
return ret;
|
|
1791
2288
|
}
|
|
1792
2289
|
|
|
@@ -1824,34 +2321,86 @@ async function executeFindOneLogic(finder, finderParams, locations, context) {
|
|
|
1824
2321
|
}
|
|
1825
2322
|
}
|
|
1826
2323
|
const queryHash = createFinderHash(finder, finderParams, locations);
|
|
1827
|
-
logger15.debug("Generated query hash for findOne", {
|
|
2324
|
+
logger15.debug("QUERY_CACHE: Generated query hash for findOne()", {
|
|
2325
|
+
queryHash,
|
|
2326
|
+
finder,
|
|
2327
|
+
finderParams: JSON.stringify(finderParams),
|
|
2328
|
+
locations: JSON.stringify(locations)
|
|
2329
|
+
});
|
|
2330
|
+
logger15.debug("QUERY_CACHE: Checking query cache for hash", { queryHash });
|
|
1828
2331
|
const cachedItemKeys = await cacheMap.getQueryResult(queryHash);
|
|
1829
2332
|
if (cachedItemKeys && cachedItemKeys.length > 0) {
|
|
1830
|
-
logger15.debug("
|
|
1831
|
-
|
|
2333
|
+
logger15.debug("QUERY_CACHE: Cache HIT - Found cached query result", {
|
|
2334
|
+
queryHash,
|
|
2335
|
+
cachedKeyCount: cachedItemKeys.length,
|
|
2336
|
+
itemKeys: cachedItemKeys.map((k) => JSON.stringify(k))
|
|
2337
|
+
});
|
|
2338
|
+
const itemKey = cachedItemKeys[0];
|
|
2339
|
+
logger15.debug("QUERY_CACHE: Retrieving first cached item", {
|
|
2340
|
+
queryHash,
|
|
2341
|
+
itemKey: JSON.stringify(itemKey)
|
|
2342
|
+
});
|
|
2343
|
+
const item = await cacheMap.get(itemKey);
|
|
1832
2344
|
if (item) {
|
|
2345
|
+
logger15.debug("QUERY_CACHE: Retrieved cached item successfully", {
|
|
2346
|
+
queryHash,
|
|
2347
|
+
itemKey: JSON.stringify(itemKey),
|
|
2348
|
+
itemKeyStr: JSON.stringify(item.key)
|
|
2349
|
+
});
|
|
1833
2350
|
return item;
|
|
1834
2351
|
} else {
|
|
1835
|
-
logger15.debug("Cached item
|
|
2352
|
+
logger15.debug("QUERY_CACHE: Cached item MISSING from item cache, invalidating query cache", {
|
|
2353
|
+
queryHash,
|
|
2354
|
+
itemKey: JSON.stringify(itemKey)
|
|
2355
|
+
});
|
|
1836
2356
|
cacheMap.deleteQueryResult(queryHash);
|
|
1837
2357
|
}
|
|
2358
|
+
} else {
|
|
2359
|
+
logger15.debug("QUERY_CACHE: Cache MISS - No cached query result found", { queryHash });
|
|
1838
2360
|
}
|
|
2361
|
+
logger15.debug("QUERY_CACHE: Fetching from API (cache miss or invalid)", {
|
|
2362
|
+
queryHash,
|
|
2363
|
+
finder,
|
|
2364
|
+
finderParams: JSON.stringify(finderParams),
|
|
2365
|
+
locations: JSON.stringify(locations)
|
|
2366
|
+
});
|
|
1839
2367
|
const ret = await api.findOne(finder, finderParams, locations);
|
|
1840
2368
|
if (ret === null) {
|
|
2369
|
+
logger15.debug("QUERY_CACHE: API returned null, throwing error", { queryHash, finder });
|
|
1841
2370
|
throw new Error(`findOne returned null for finder: ${finder}`);
|
|
1842
2371
|
}
|
|
1843
|
-
|
|
2372
|
+
logger15.debug("QUERY_CACHE: API response received", {
|
|
2373
|
+
queryHash,
|
|
2374
|
+
itemKey: JSON.stringify(ret.key)
|
|
2375
|
+
});
|
|
2376
|
+
logger15.debug("QUERY_CACHE: Storing item in item cache", {
|
|
2377
|
+
queryHash,
|
|
2378
|
+
itemKey: JSON.stringify(ret.key)
|
|
2379
|
+
});
|
|
2380
|
+
await cacheMap.set(ret.key, ret);
|
|
1844
2381
|
const keyStr = JSON.stringify(ret.key);
|
|
1845
2382
|
ttlManager.onItemAdded(keyStr, cacheMap);
|
|
1846
2383
|
const evictedKeys = await context.evictionManager.onItemAdded(keyStr, ret, cacheMap);
|
|
1847
2384
|
for (const evictedKey of evictedKeys) {
|
|
1848
2385
|
const parsedKey = JSON.parse(evictedKey);
|
|
1849
2386
|
await cacheMap.delete(parsedKey);
|
|
2387
|
+
logger15.debug("QUERY_CACHE: Evicted item due to cache limits", {
|
|
2388
|
+
evictedKey,
|
|
2389
|
+
queryHash
|
|
2390
|
+
});
|
|
1850
2391
|
}
|
|
1851
|
-
cacheMap.setQueryResult(queryHash, [ret.key]);
|
|
1852
|
-
logger15.debug("
|
|
2392
|
+
await cacheMap.setQueryResult(queryHash, [ret.key]);
|
|
2393
|
+
logger15.debug("QUERY_CACHE: Stored query result in query cache", {
|
|
2394
|
+
queryHash,
|
|
2395
|
+
itemKey: JSON.stringify(ret.key)
|
|
2396
|
+
});
|
|
1853
2397
|
const event = CacheEventFactory.createQueryEvent(finderParams, locations, [ret]);
|
|
1854
2398
|
eventEmitter.emit(event);
|
|
2399
|
+
logger15.debug("QUERY_CACHE: Emitted query event", { queryHash });
|
|
2400
|
+
logger15.debug("QUERY_CACHE: findOne() operation completed", {
|
|
2401
|
+
queryHash,
|
|
2402
|
+
itemKey: JSON.stringify(ret.key)
|
|
2403
|
+
});
|
|
1855
2404
|
return ret;
|
|
1856
2405
|
}
|
|
1857
2406
|
|
|
@@ -1909,39 +2458,93 @@ var normalizeKey = (key) => {
|
|
|
1909
2458
|
return key;
|
|
1910
2459
|
};
|
|
1911
2460
|
var set = async (key, v, context) => {
|
|
2461
|
+
const startTime = Date.now();
|
|
1912
2462
|
const { cacheMap, pkType, ttlManager, evictionManager, eventEmitter } = context;
|
|
2463
|
+
const keyStr = JSON.stringify(key);
|
|
1913
2464
|
logger16.default("set", { key, v });
|
|
2465
|
+
logger16.debug("CACHE_OP: set() started", {
|
|
2466
|
+
key: keyStr,
|
|
2467
|
+
cacheType: cacheMap.implementationType
|
|
2468
|
+
});
|
|
1914
2469
|
if (!isValidItemKey6(key)) {
|
|
1915
|
-
logger16.error("
|
|
2470
|
+
logger16.error("CACHE_OP: Invalid key for set", { key: keyStr });
|
|
1916
2471
|
throw new Error("Key for Set is not a valid ItemKey");
|
|
1917
2472
|
}
|
|
1918
2473
|
if (!isItemKeyEqualNormalized(key, v.key)) {
|
|
1919
|
-
logger16.error("Key
|
|
2474
|
+
logger16.error("CACHE_OP: Key mismatch in set", {
|
|
2475
|
+
providedKey: keyStr,
|
|
2476
|
+
itemKey: JSON.stringify(v.key)
|
|
2477
|
+
});
|
|
1920
2478
|
throw new Error("Key does not match item key");
|
|
1921
2479
|
}
|
|
2480
|
+
const checkStartTime = Date.now();
|
|
1922
2481
|
const previousItem = await cacheMap.get(key);
|
|
2482
|
+
const checkDuration = Date.now() - checkStartTime;
|
|
2483
|
+
logger16.debug("CACHE_OP: Previous item check", {
|
|
2484
|
+
key: keyStr,
|
|
2485
|
+
hadPreviousItem: !!previousItem,
|
|
2486
|
+
checkDuration
|
|
2487
|
+
});
|
|
2488
|
+
const setStartTime = Date.now();
|
|
1923
2489
|
await cacheMap.set(key, v);
|
|
1924
|
-
const
|
|
2490
|
+
const setDuration = Date.now() - setStartTime;
|
|
2491
|
+
const metadataStartTime = Date.now();
|
|
1925
2492
|
const metadata = await cacheMap.getMetadata(keyStr);
|
|
1926
2493
|
if (!metadata) {
|
|
1927
2494
|
const now = Date.now();
|
|
2495
|
+
const estimatedSize = estimateValueSize(v);
|
|
1928
2496
|
const baseMetadata = {
|
|
1929
2497
|
key: keyStr,
|
|
1930
2498
|
addedAt: now,
|
|
1931
2499
|
lastAccessedAt: now,
|
|
1932
2500
|
accessCount: 1,
|
|
1933
|
-
estimatedSize
|
|
2501
|
+
estimatedSize
|
|
1934
2502
|
};
|
|
1935
2503
|
await cacheMap.setMetadata(keyStr, baseMetadata);
|
|
2504
|
+
logger16.debug("CACHE_OP: Created base metadata", {
|
|
2505
|
+
key: keyStr,
|
|
2506
|
+
estimatedSize
|
|
2507
|
+
});
|
|
2508
|
+
} else {
|
|
2509
|
+
logger16.debug("CACHE_OP: Metadata already exists", {
|
|
2510
|
+
key: keyStr,
|
|
2511
|
+
addedAt: new Date(metadata.addedAt).toISOString(),
|
|
2512
|
+
accessCount: metadata.accessCount
|
|
2513
|
+
});
|
|
1936
2514
|
}
|
|
2515
|
+
const metadataDuration = Date.now() - metadataStartTime;
|
|
2516
|
+
const ttlStartTime = Date.now();
|
|
1937
2517
|
await ttlManager.onItemAdded(keyStr, cacheMap);
|
|
2518
|
+
const ttlDuration = Date.now() - ttlStartTime;
|
|
2519
|
+
const evictionStartTime = Date.now();
|
|
1938
2520
|
const evictedKeys = await evictionManager.onItemAdded(keyStr, v, cacheMap);
|
|
2521
|
+
const evictionDuration = Date.now() - evictionStartTime;
|
|
2522
|
+
if (evictedKeys.length > 0) {
|
|
2523
|
+
logger16.debug("CACHE_OP: Eviction triggered by set", {
|
|
2524
|
+
key: keyStr,
|
|
2525
|
+
evictedCount: evictedKeys.length,
|
|
2526
|
+
evictedKeys
|
|
2527
|
+
});
|
|
2528
|
+
}
|
|
1939
2529
|
for (const evictedKey of evictedKeys) {
|
|
1940
2530
|
const parsedKey = JSON.parse(evictedKey);
|
|
1941
2531
|
await cacheMap.delete(parsedKey);
|
|
2532
|
+
logger16.debug("CACHE_OP: Removed evicted item", { evictedKey });
|
|
1942
2533
|
}
|
|
1943
2534
|
const event = CacheEventFactory.itemSet(key, v, previousItem);
|
|
1944
2535
|
eventEmitter.emit(event);
|
|
2536
|
+
const totalDuration = Date.now() - startTime;
|
|
2537
|
+
logger16.debug("CACHE_OP: set() completed", {
|
|
2538
|
+
key: keyStr,
|
|
2539
|
+
checkDuration,
|
|
2540
|
+
setDuration,
|
|
2541
|
+
metadataDuration,
|
|
2542
|
+
ttlDuration,
|
|
2543
|
+
evictionDuration,
|
|
2544
|
+
totalDuration,
|
|
2545
|
+
evictedCount: evictedKeys.length,
|
|
2546
|
+
wasUpdate: !!previousItem
|
|
2547
|
+
});
|
|
1945
2548
|
return [context, v];
|
|
1946
2549
|
};
|
|
1947
2550
|
|
|
@@ -5119,9 +5722,17 @@ var EvictionManager = class {
|
|
|
5119
5722
|
return;
|
|
5120
5723
|
}
|
|
5121
5724
|
try {
|
|
5725
|
+
logger24.debug("EVICTION: Item accessed, updating metadata", {
|
|
5726
|
+
key,
|
|
5727
|
+
strategy: this.evictionStrategy.getStrategyName()
|
|
5728
|
+
});
|
|
5122
5729
|
await this.evictionStrategy.onItemAccessed(key, metadataProvider);
|
|
5123
5730
|
} catch (error) {
|
|
5124
|
-
logger24.error("Error in eviction strategy onItemAccessed", {
|
|
5731
|
+
logger24.error("EVICTION: Error in eviction strategy onItemAccessed", {
|
|
5732
|
+
key,
|
|
5733
|
+
error,
|
|
5734
|
+
strategy: this.evictionStrategy?.getStrategyName()
|
|
5735
|
+
});
|
|
5125
5736
|
}
|
|
5126
5737
|
}
|
|
5127
5738
|
/**
|
|
@@ -5132,28 +5743,81 @@ var EvictionManager = class {
|
|
|
5132
5743
|
* @returns Array of keys that were evicted
|
|
5133
5744
|
*/
|
|
5134
5745
|
async onItemAdded(key, value, metadataProvider) {
|
|
5746
|
+
const startTime = Date.now();
|
|
5135
5747
|
const evictedKeys = [];
|
|
5136
5748
|
if (!this.evictionStrategy) {
|
|
5749
|
+
logger24.debug("EVICTION: No eviction strategy configured", { key });
|
|
5137
5750
|
return evictedKeys;
|
|
5138
5751
|
}
|
|
5139
5752
|
try {
|
|
5140
5753
|
const estimatedSize = estimateValueSize(value);
|
|
5754
|
+
logger24.debug("EVICTION: Item addition started", {
|
|
5755
|
+
key,
|
|
5756
|
+
estimatedSize,
|
|
5757
|
+
strategy: this.evictionStrategy.getStrategyName()
|
|
5758
|
+
});
|
|
5759
|
+
const contextStartTime = Date.now();
|
|
5141
5760
|
const context = await this.createEvictionContext(metadataProvider, estimatedSize);
|
|
5761
|
+
const contextDuration = Date.now() - contextStartTime;
|
|
5762
|
+
logger24.debug("EVICTION: Current cache state", {
|
|
5763
|
+
key,
|
|
5764
|
+
currentItemCount: context.currentSize.itemCount,
|
|
5765
|
+
currentSizeBytes: context.currentSize.sizeBytes,
|
|
5766
|
+
maxItems: context.limits.maxItems,
|
|
5767
|
+
maxSizeBytes: context.limits.maxSizeBytes,
|
|
5768
|
+
newItemSize: estimatedSize,
|
|
5769
|
+
contextDuration
|
|
5770
|
+
});
|
|
5771
|
+
const selectionStartTime = Date.now();
|
|
5142
5772
|
const keysToEvict = await this.evictionStrategy.selectForEviction(metadataProvider, context);
|
|
5773
|
+
const selectionDuration = Date.now() - selectionStartTime;
|
|
5774
|
+
if (keysToEvict.length > 0) {
|
|
5775
|
+
logger24.debug("EVICTION: Items selected for eviction", {
|
|
5776
|
+
key,
|
|
5777
|
+
evictCount: keysToEvict.length,
|
|
5778
|
+
keysToEvict,
|
|
5779
|
+
selectionDuration,
|
|
5780
|
+
strategy: this.evictionStrategy.getStrategyName()
|
|
5781
|
+
});
|
|
5782
|
+
}
|
|
5783
|
+
const removalStartTime = Date.now();
|
|
5143
5784
|
for (const evictKey of keysToEvict) {
|
|
5144
5785
|
await this.evictionStrategy.onItemRemoved(evictKey, metadataProvider);
|
|
5145
5786
|
evictedKeys.push(evictKey);
|
|
5787
|
+
logger24.debug("EVICTION: Marked item for eviction", {
|
|
5788
|
+
evictedKey: evictKey,
|
|
5789
|
+
newKey: key
|
|
5790
|
+
});
|
|
5146
5791
|
}
|
|
5792
|
+
const removalDuration = Date.now() - removalStartTime;
|
|
5793
|
+
const addMetadataStart = Date.now();
|
|
5147
5794
|
await this.evictionStrategy.onItemAdded(key, estimatedSize, metadataProvider);
|
|
5795
|
+
const addMetadataDuration = Date.now() - addMetadataStart;
|
|
5796
|
+
const totalDuration = Date.now() - startTime;
|
|
5148
5797
|
if (evictedKeys.length > 0) {
|
|
5149
|
-
logger24.debug("
|
|
5798
|
+
logger24.debug("EVICTION: Eviction completed", {
|
|
5150
5799
|
newKey: key,
|
|
5800
|
+
evictedCount: evictedKeys.length,
|
|
5151
5801
|
evictedKeys,
|
|
5152
|
-
strategy: this.evictionStrategy.getStrategyName()
|
|
5802
|
+
strategy: this.evictionStrategy.getStrategyName(),
|
|
5803
|
+
selectionDuration,
|
|
5804
|
+
removalDuration,
|
|
5805
|
+
addMetadataDuration,
|
|
5806
|
+
totalDuration
|
|
5807
|
+
});
|
|
5808
|
+
} else {
|
|
5809
|
+
logger24.debug("EVICTION: No eviction needed", {
|
|
5810
|
+
newKey: key,
|
|
5811
|
+
estimatedSize,
|
|
5812
|
+
totalDuration
|
|
5153
5813
|
});
|
|
5154
5814
|
}
|
|
5155
5815
|
} catch (error) {
|
|
5156
|
-
logger24.error("Error in eviction strategy onItemAdded", {
|
|
5816
|
+
logger24.error("EVICTION: Error in eviction strategy onItemAdded", {
|
|
5817
|
+
key,
|
|
5818
|
+
error,
|
|
5819
|
+
strategy: this.evictionStrategy?.getStrategyName()
|
|
5820
|
+
});
|
|
5157
5821
|
}
|
|
5158
5822
|
return evictedKeys;
|
|
5159
5823
|
}
|
|
@@ -5178,25 +5842,47 @@ var EvictionManager = class {
|
|
|
5178
5842
|
* @returns Array of keys that were evicted
|
|
5179
5843
|
*/
|
|
5180
5844
|
async performEviction(metadataProvider) {
|
|
5845
|
+
const startTime = Date.now();
|
|
5181
5846
|
const evictedKeys = [];
|
|
5182
5847
|
if (!this.evictionStrategy) {
|
|
5848
|
+
logger24.debug("EVICTION: No eviction strategy configured for manual eviction");
|
|
5183
5849
|
return evictedKeys;
|
|
5184
5850
|
}
|
|
5185
5851
|
try {
|
|
5852
|
+
logger24.debug("EVICTION: Manual eviction started", {
|
|
5853
|
+
strategy: this.evictionStrategy.getStrategyName()
|
|
5854
|
+
});
|
|
5186
5855
|
const context = await this.createEvictionContext(metadataProvider);
|
|
5856
|
+
logger24.debug("EVICTION: Manual eviction - current cache state", {
|
|
5857
|
+
currentItemCount: context.currentSize.itemCount,
|
|
5858
|
+
currentSizeBytes: context.currentSize.sizeBytes,
|
|
5859
|
+
maxItems: context.limits.maxItems,
|
|
5860
|
+
maxSizeBytes: context.limits.maxSizeBytes
|
|
5861
|
+
});
|
|
5187
5862
|
const keysToEvict = await this.evictionStrategy.selectForEviction(metadataProvider, context);
|
|
5188
5863
|
for (const evictKey of keysToEvict) {
|
|
5189
5864
|
await this.evictionStrategy.onItemRemoved(evictKey, metadataProvider);
|
|
5190
5865
|
evictedKeys.push(evictKey);
|
|
5191
5866
|
}
|
|
5867
|
+
const duration = Date.now() - startTime;
|
|
5192
5868
|
if (evictedKeys.length > 0) {
|
|
5193
|
-
logger24.debug("Manual eviction
|
|
5869
|
+
logger24.debug("EVICTION: Manual eviction completed", {
|
|
5870
|
+
evictedCount: evictedKeys.length,
|
|
5194
5871
|
evictedKeys,
|
|
5195
|
-
strategy: this.evictionStrategy.getStrategyName()
|
|
5872
|
+
strategy: this.evictionStrategy.getStrategyName(),
|
|
5873
|
+
duration
|
|
5874
|
+
});
|
|
5875
|
+
} else {
|
|
5876
|
+
logger24.debug("EVICTION: Manual eviction - no items to evict", {
|
|
5877
|
+
strategy: this.evictionStrategy.getStrategyName(),
|
|
5878
|
+
duration
|
|
5196
5879
|
});
|
|
5197
5880
|
}
|
|
5198
5881
|
} catch (error) {
|
|
5199
|
-
logger24.error("Error in manual eviction", {
|
|
5882
|
+
logger24.error("EVICTION: Error in manual eviction", {
|
|
5883
|
+
error,
|
|
5884
|
+
strategy: this.evictionStrategy?.getStrategyName()
|
|
5885
|
+
});
|
|
5200
5886
|
}
|
|
5201
5887
|
return evictedKeys;
|
|
5202
5888
|
}
|
|
@@ -6625,7 +7311,7 @@ var TTLManager = class {
|
|
|
6625
7311
|
metadata
|
|
6626
7312
|
});
|
|
6627
7313
|
if (!metadata) {
|
|
6628
|
-
logger25.
|
|
7314
|
+
logger25.debug("TTL_DEBUG: No metadata found for item when setting TTL", {
|
|
6629
7315
|
key,
|
|
6630
7316
|
metadataProviderType: metadataProvider?.constructor?.name,
|
|
6631
7317
|
metadataProviderMethods: metadataProvider ? Object.getOwnPropertyNames(Object.getPrototypeOf(metadataProvider)) : null
|
|
@@ -6665,12 +7351,28 @@ var TTLManager = class {
|
|
|
6665
7351
|
async isExpired(key, metadataProvider) {
|
|
6666
7352
|
const metadata = await metadataProvider.getMetadata(key);
|
|
6667
7353
|
if (!metadata || !metadata.expiresAt) {
|
|
7354
|
+
logger25.debug("TTL_CHECK: No TTL set for item", { key, hasMetadata: !!metadata });
|
|
6668
7355
|
return false;
|
|
6669
7356
|
}
|
|
6670
7357
|
const now = Date.now();
|
|
6671
7358
|
const expired = now >= metadata.expiresAt;
|
|
7359
|
+
const remainingMs = metadata.expiresAt - now;
|
|
6672
7360
|
if (expired) {
|
|
6673
|
-
logger25.
|
|
7361
|
+
logger25.debug("TTL_CHECK: Item EXPIRED", {
|
|
7362
|
+
key,
|
|
7363
|
+
expiresAt: new Date(metadata.expiresAt).toISOString(),
|
|
7364
|
+
now: new Date(now).toISOString(),
|
|
7365
|
+
expiredByMs: now - metadata.expiresAt,
|
|
7366
|
+
ttl: metadata.ttl
|
|
7367
|
+
});
|
|
7368
|
+
} else {
|
|
7369
|
+
logger25.debug("TTL_CHECK: Item still valid", {
|
|
7370
|
+
key,
|
|
7371
|
+
expiresAt: new Date(metadata.expiresAt).toISOString(),
|
|
7372
|
+
remainingMs,
|
|
7373
|
+
remainingSec: Math.floor(remainingMs / 1e3),
|
|
7374
|
+
ttl: metadata.ttl
|
|
7375
|
+
});
|
|
6674
7376
|
}
|
|
6675
7377
|
return expired;
|
|
6676
7378
|
}
|
|
@@ -6680,9 +7382,22 @@ var TTLManager = class {
|
|
|
6680
7382
|
*/
|
|
6681
7383
|
async validateItem(key, metadataProvider) {
|
|
6682
7384
|
if (!this.config.validateOnAccess) {
|
|
7385
|
+
logger25.debug("TTL_VALIDATE: Validation disabled, skipping check", { key });
|
|
6683
7386
|
return true;
|
|
6684
7387
|
}
|
|
6685
|
-
|
|
7388
|
+
logger25.debug("TTL_VALIDATE: Validating item", {
|
|
7389
|
+
key,
|
|
7390
|
+
ttlEnabled: this.isTTLEnabled(),
|
|
7391
|
+
defaultTTL: this.config.defaultTTL
|
|
7392
|
+
});
|
|
7393
|
+
const isExpired = await this.isExpired(key, metadataProvider);
|
|
7394
|
+
const isValid = !isExpired;
|
|
7395
|
+
logger25.debug("TTL_VALIDATE: Validation result", {
|
|
7396
|
+
key,
|
|
7397
|
+
isValid,
|
|
7398
|
+
isExpired
|
|
7399
|
+
});
|
|
7400
|
+
return isValid;
|
|
6686
7401
|
}
|
|
6687
7402
|
/**
|
|
6688
7403
|
* Get TTL information for an item
|
|
@@ -6707,17 +7422,44 @@ var TTLManager = class {
|
|
|
6707
7422
|
* Find all expired items
|
|
6708
7423
|
*/
|
|
6709
7424
|
async findExpiredItems(metadataProvider) {
|
|
7425
|
+
const startTime = Date.now();
|
|
6710
7426
|
const expiredKeys = [];
|
|
6711
7427
|
const allMetadata = await metadataProvider.getAllMetadata();
|
|
6712
7428
|
const now = Date.now();
|
|
7429
|
+
logger25.debug("TTL_CLEANUP: Scanning for expired items", {
|
|
7430
|
+
totalItems: allMetadata.size,
|
|
7431
|
+
now: new Date(now).toISOString()
|
|
7432
|
+
});
|
|
7433
|
+
let itemsWithTTL = 0;
|
|
6713
7434
|
for (const [key, metadata] of allMetadata) {
|
|
6714
7435
|
const ttlMetadata = metadata;
|
|
6715
|
-
if (ttlMetadata.expiresAt
|
|
6716
|
-
|
|
7436
|
+
if (ttlMetadata.expiresAt) {
|
|
7437
|
+
itemsWithTTL++;
|
|
7438
|
+
if (now >= ttlMetadata.expiresAt) {
|
|
7439
|
+
expiredKeys.push(key);
|
|
7440
|
+
logger25.debug("TTL_CLEANUP: Found expired item", {
|
|
7441
|
+
key,
|
|
7442
|
+
expiresAt: new Date(ttlMetadata.expiresAt).toISOString(),
|
|
7443
|
+
expiredByMs: now - ttlMetadata.expiresAt
|
|
7444
|
+
});
|
|
7445
|
+
}
|
|
6717
7446
|
}
|
|
6718
7447
|
}
|
|
7448
|
+
const duration = Date.now() - startTime;
|
|
6719
7449
|
if (expiredKeys.length > 0) {
|
|
6720
|
-
logger25.debug("
|
|
7450
|
+
logger25.debug("TTL_CLEANUP: Expired items found", {
|
|
7451
|
+
expiredCount: expiredKeys.length,
|
|
7452
|
+
totalItems: allMetadata.size,
|
|
7453
|
+
itemsWithTTL,
|
|
7454
|
+
keys: expiredKeys,
|
|
7455
|
+
duration
|
|
7456
|
+
});
|
|
7457
|
+
} else {
|
|
7458
|
+
logger25.debug("TTL_CLEANUP: No expired items found", {
|
|
7459
|
+
totalItems: allMetadata.size,
|
|
7460
|
+
itemsWithTTL,
|
|
7461
|
+
duration
|
|
7462
|
+
});
|
|
6721
7463
|
}
|
|
6722
7464
|
return expiredKeys;
|
|
6723
7465
|
}
|