Skip to content

Commit 47f928c

Browse files
committed
trying
1 parent 3d0e484 commit 47f928c

3 files changed

Lines changed: 150 additions & 8 deletions

File tree

cache/__tests__/test-cache-fill.sh

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/bin/bash
2+
3+
# Simple test to verify cache can be filled with unique entries
4+
# Tests sequentially to avoid any race conditions
5+
6+
API_BASE="http://localhost:3001/v1"
7+
NUM_REQUESTS=100
8+
9+
echo "═══════════════════════════════════════════════════════════════════════"
10+
echo " Test Sequential Cache Fill ($NUM_REQUESTS unique queries)"
11+
echo "═══════════════════════════════════════════════════════════════════════"
12+
echo ""
13+
14+
# Check server
15+
echo -n "[INFO] Checking server... "
16+
if ! curl -s -f "${API_BASE}/API.html" > /dev/null 2>&1; then
17+
echo "FAIL"
18+
echo "[ERROR] Server is not running at ${API_BASE}"
19+
exit 1
20+
fi
21+
echo "OK"
22+
23+
# Clear cache
24+
echo -n "[INFO] Clearing cache... "
25+
curl -s "${API_BASE}/api/cache/clear" > /dev/null
26+
sleep 1
27+
echo "OK"
28+
29+
# Get initial stats
30+
initial_stats=$(curl -s "${API_BASE}/api/cache/stats")
31+
initial_length=$(echo "$initial_stats" | grep -oP '"length":\K[0-9]+')
32+
initial_sets=$(echo "$initial_stats" | grep -oP '"sets":\K[0-9]+')
33+
echo "[INFO] Initial cache: length=$initial_length, sets=$initial_sets"
34+
echo ""
35+
36+
# Send requests SEQUENTIALLY
37+
echo "[INFO] Sending $NUM_REQUESTS sequential requests with unique queries..."
38+
echo ""
39+
40+
for i in $(seq 0 $((NUM_REQUESTS - 1))); do
41+
endpoint="${API_BASE}/api/query"
42+
data="{\"_seqTest\":${i}}"
43+
44+
http_code=$(curl -s -X POST "$endpoint" \
45+
-H "Content-Type: application/json" \
46+
-d "$data" \
47+
-w '%{http_code}' \
48+
-o /dev/null 2>&1)
49+
50+
if [ "$http_code" != "200" ]; then
51+
echo "[ERROR] Request $i failed with HTTP $http_code"
52+
exit 1
53+
fi
54+
55+
# Progress indicator every 10 requests
56+
if [ $((i % 10)) -eq 9 ]; then
57+
echo -n "."
58+
fi
59+
done
60+
echo ""
61+
echo ""
62+
63+
# Wait for cache to stabilize
64+
echo "[INFO] Waiting 2 seconds for cache.set() to complete..."
65+
sleep 2
66+
67+
# Get final stats
68+
final_stats=$(curl -s "${API_BASE}/api/cache/stats")
69+
final_length=$(echo "$final_stats" | grep -oP '"length":\K[0-9]+')
70+
final_sets=$(echo "$final_stats" | grep -oP '"sets":\K[0-9]+')
71+
final_hits=$(echo "$final_stats" | grep -oP '"hits":\K[0-9]+')
72+
final_misses=$(echo "$final_stats" | grep -oP '"misses":\K[0-9]+')
73+
74+
echo ""
75+
echo "═══════════════════════════════════════════════════════════════════════"
76+
echo " Results"
77+
echo "═══════════════════════════════════════════════════════════════════════"
78+
echo ""
79+
echo "Initial stats:"
80+
echo " Length: $initial_length"
81+
echo " Sets: $initial_sets"
82+
echo ""
83+
echo "Final stats:"
84+
echo " Length: $final_length"
85+
echo " Sets: $final_sets"
86+
echo " Hits: $final_hits"
87+
echo " Misses: $final_misses"
88+
echo ""
89+
echo "Delta:"
90+
echo " Length: $((final_length - initial_length))"
91+
echo " Sets: $((final_sets - initial_sets))"
92+
echo ""
93+
94+
# Check if we got all unique entries
95+
expected=$NUM_REQUESTS
96+
actual=$((final_length - initial_length))
97+
98+
if [ $actual -eq $expected ]; then
99+
echo "[PASS] ✓ All $expected requests created unique cache entries"
100+
exit 0
101+
elif [ $actual -gt $((expected * 95 / 100)) ]; then
102+
echo "[WARN] ⚠ $actual/$expected unique cache entries created (${actual}00/$expected%) "
103+
echo "[INFO] This is acceptable (>95% success rate)"
104+
exit 0
105+
else
106+
echo "[FAIL] ✗ Only $actual/$expected unique cache entries created"
107+
echo ""
108+
echo "Diagnosis:"
109+
sets_delta=$((final_sets - initial_sets))
110+
if [ $sets_delta -lt $expected ]; then
111+
echo " - Only $sets_delta cache.set() calls (expected $expected)"
112+
echo " - This means $((expected - sets_delta)) requests hit existing cache entries"
113+
echo " - Cache keys are NOT unique despite different query parameters"
114+
else
115+
echo " - $sets_delta cache.set() calls were made (good)"
116+
echo " - But only $actual entries in cache"
117+
echo " - This suggests $((sets_delta - actual)) evictions occurred"
118+
echo " - Check if maxLength is too low or cache is being cleared"
119+
fi
120+
exit 1
121+
fi
122+

cache/index.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class ClusterCache {
3838

3939
this.allKeys = new Set()
4040
this.keyAccessTimes = new Map() // Track access time for LRU eviction
41+
this.keyCreationTimes = new Map() // Track creation time for age display
4142
this.keySizes = new Map() // Track size of each cached value in bytes
4243
this.totalBytes = 0 // Track total cache size in bytes
4344
this.localCache = new Map()
@@ -78,11 +79,12 @@ class ClusterCache {
7879
*/
7980
async get(key) {
8081
try {
81-
const value = await this.clusterCache.get(key, undefined)
82-
if (value !== undefined) {
82+
const wrappedValue = await this.clusterCache.get(key, undefined)
83+
if (wrappedValue !== undefined) {
8384
this.stats.hits++
8485
this.keyAccessTimes.set(key, Date.now()) // Update access time for LRU
85-
return value
86+
// Unwrap the value from metadata
87+
return wrappedValue.data !== undefined ? wrappedValue.data : wrappedValue
8688
}
8789
if (this.localCache.has(key)) {
8890
this.stats.hits++
@@ -153,10 +155,20 @@ class ClusterCache {
153155
clusterTotalBytes = await this._getClusterTotalBytes()
154156
}
155157

156-
await this.clusterCache.set(key, value, this.ttl)
158+
// Wrap value with metadata including creation time
159+
const wrappedValue = {
160+
data: value,
161+
createdAt: Date.now(),
162+
size: valueSize
163+
}
164+
165+
await this.clusterCache.set(key, wrappedValue, this.ttl)
157166
this.stats.sets++
158167
this.allKeys.add(key)
159168
this.keyAccessTimes.set(key, Date.now()) // Track access time
169+
if (!isUpdate) {
170+
this.keyCreationTimes.set(key, Date.now()) // Track creation time (only on new entries)
171+
}
160172
this.keySizes.set(key, valueSize) // Track size
161173
this.totalBytes += valueSize
162174
this.localCache.set(key, value)
@@ -182,6 +194,9 @@ class ClusterCache {
182194
this.localCache.set(key, value)
183195
this.allKeys.add(key)
184196
this.keyAccessTimes.set(key, Date.now())
197+
if (!isUpdate) {
198+
this.keyCreationTimes.set(key, Date.now())
199+
}
185200
this.keySizes.set(key, valueSize)
186201
this.totalBytes += valueSize
187202
this.stats.sets++
@@ -197,6 +212,7 @@ class ClusterCache {
197212
await this.clusterCache.delete(key)
198213
this.allKeys.delete(key)
199214
this.keyAccessTimes.delete(key) // Clean up access time tracking
215+
this.keyCreationTimes.delete(key) // Clean up creation time tracking
200216
const size = this.keySizes.get(key) || 0
201217
this.keySizes.delete(key)
202218
this.totalBytes -= size
@@ -206,6 +222,7 @@ class ClusterCache {
206222
this.localCache.delete(key)
207223
this.allKeys.delete(key)
208224
this.keyAccessTimes.delete(key) // Clean up access time tracking
225+
this.keyCreationTimes.delete(key) // Clean up creation time tracking
209226
const size = this.keySizes.get(key) || 0
210227
this.keySizes.delete(key)
211228
this.totalBytes -= size
@@ -223,6 +240,7 @@ class ClusterCache {
223240
await this.clusterCache.flush()
224241
this.allKeys.clear()
225242
this.keyAccessTimes.clear() // Clear access time tracking
243+
this.keyCreationTimes.clear() // Clear creation time tracking
226244
this.keySizes.clear() // Clear size tracking
227245
this.totalBytes = 0
228246
this.localCache.clear()
@@ -245,6 +263,7 @@ class ClusterCache {
245263
this.localCache.clear()
246264
this.allKeys.clear()
247265
this.keyAccessTimes.clear() // Clear access time tracking
266+
this.keyCreationTimes.clear() // Clear creation time tracking
248267
this.keySizes.clear() // Clear size tracking
249268
this.totalBytes = 0
250269
this.stats.evictions++

cache/middleware.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,10 +405,11 @@ const cacheStats = async (req, res) => {
405405
const details = []
406406
let position = 0
407407
for (const key of allKeys) {
408-
const value = await cache.clusterCache.get(key, undefined)
409-
const size = cache._calculateSize(value)
410-
const accessTime = cache.keyAccessTimes.get(key) || 0
411-
const age = accessTime > 0 ? Date.now() - accessTime : 0
408+
const wrappedValue = await cache.clusterCache.get(key, undefined)
409+
const value = wrappedValue?.data !== undefined ? wrappedValue.data : wrappedValue
410+
const size = wrappedValue?.size || cache._calculateSize(value)
411+
const creationTime = wrappedValue?.createdAt || Date.now()
412+
const age = Date.now() - creationTime
412413

413414
details.push({
414415
position,

0 commit comments

Comments
 (0)