Skip to content

Commit eb7494c

Browse files
committed
dev: measure cache rate and fix an edge-case
1 parent 7c29d7c commit eb7494c

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

src/backend/src/services/file-cache/FileCacheService.js

+42-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
const { AdvancedBase } = require("@heyputer/putility");
2121
const { FileTracker } = require("./FileTracker");
2222
const { pausing_tee } = require("../../util/streamutil");
23+
const putility = require("@heyputer/putility");
24+
const { EWMA } = require("../../util/opmath");
2325

2426
/**
2527
* FileCacheService
@@ -71,6 +73,11 @@ class FileCacheService extends AdvancedBase {
7173
this.precache = new Map();
7274
this.uid_to_tracker = new Map();
7375

76+
this.cache_hit_rate = new EWMA({
77+
initial: 0.5,
78+
alpha: 0.2,
79+
});
80+
7481
this.init();
7582

7683
this._register_commands(services.get('commands'));
@@ -139,7 +146,12 @@ class FileCacheService extends AdvancedBase {
139146
* @param {string} uid - The unique identifier of the file.
140147
* @returns {string} The full path where the file is stored on disk.
141148
*/
142-
async try_get (fsNode, opt_log) {
149+
async try_get(fsNode, opt_log) {
150+
const result = await this.try_get_(fsNode, opt_log);
151+
this.cache_hit_rate.put(result ? 1 : 0);
152+
return result;
153+
}
154+
async try_get_ (fsNode, opt_log) {
143155
const tracker = this.uid_to_tracker.get(await fsNode.get('uid'));
144156

145157
if ( ! tracker ) {
@@ -153,6 +165,27 @@ class FileCacheService extends AdvancedBase {
153165

154166
tracker.touch();
155167

168+
// If the file is in pending, that means it's currenty being read
169+
// for cache entry, so we wait for it to be ready.
170+
if ( tracker.phase === FileTracker.PHASE_PENDING ) {
171+
Promise.race([
172+
tracker.p_ready,
173+
new Promise(resolve => setTimeout(resolve, 2000))
174+
]);
175+
}
176+
177+
// If the file is still in pending it means we waited too long;
178+
// it's possible that reading the file failed is is delayed.
179+
if ( tracker.phase === FileTracker.PHASE_PENDING ) {
180+
return this._get_path(await fsNode.get('uid'));
181+
}
182+
183+
// Since we waited for the file to be ready, it's not impossible
184+
// that it was evicted in the meantime; just very unlikely.
185+
if ( tracker.phase === FileTracker.PHASE_GONE ) {
186+
return null;
187+
}
188+
156189
if ( tracker.phase === FileTracker.PHASE_PRECACHE ) {
157190
if ( opt_log ) opt_log.info('obtained from precache');
158191
return this.precache.get(await fsNode.get('uid'));
@@ -218,6 +251,7 @@ class FileCacheService extends AdvancedBase {
218251
// Add file tracker
219252
const tracker = new FileTracker({ key, size });
220253
this.uid_to_tracker.set(key, tracker);
254+
tracker.p_ready = new putility.libs.promise.TeePromise();
221255
tracker.touch();
222256

223257

@@ -236,6 +270,7 @@ class FileCacheService extends AdvancedBase {
236270
await this._precache_make_room(size);
237271
this.precache.set(key, data);
238272
tracker.phase = FileTracker.PHASE_PRECACHE;
273+
tracker.p_ready.resolve();
239274
})()
240275

241276
return { cached: true, stream: replace_stream };
@@ -395,6 +430,12 @@ class FileCacheService extends AdvancedBase {
395430

396431
log.log(JSON.stringify(status, null, 2));
397432
}
433+
},
434+
{
435+
id: 'hitrate',
436+
handler: async (args, log) => {
437+
log.log(this.cache_hit_rate.get());
438+
}
398439
}
399440
]);
400441
}

0 commit comments

Comments
 (0)