From 053c2680cee307dc1f52302c9d8b8c48dae45fcd Mon Sep 17 00:00:00 2001 From: Will Cohen Date: Wed, 26 Aug 2026 14:29:59 -0400 Subject: [PATCH] Budget the worker decode cache by bytes --- CHANGELOG.md | 5 +++++ packages/backproj/src/wasmts-handler.ts | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6851ae6..73f3c70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## [Unreleased] + +### Changed +- The worker decode cache is budgeted by input bytes instead of entry count + ## [0.0.5] - 2026-08-26 ### Added diff --git a/packages/backproj/src/wasmts-handler.ts b/packages/backproj/src/wasmts-handler.ts index 7faeea1..6920f9b 100644 --- a/packages/backproj/src/wasmts-handler.ts +++ b/packages/backproj/src/wasmts-handler.ts @@ -72,14 +72,17 @@ let projHandler: any = null; * an FNV-1a hash and re-decode on mismatch. Cached features are shared * across chain calls: everything downstream reads them without * mutating (see groupDecodedFeatures). + * + * Budgeted by input bytes; decoded output runs ~10x the PBF. */ -const DECODE_CACHE_MAX = 16; +const DECODE_CACHE_MAX_BYTES = 2 * 1024 * 1024; interface DecodeCacheEntry { byteLength: number; hash: number; features: DecodedFeature[]; } const decodeCache = new Map(); +let decodeCacheBytes = 0; function fnv1a(bytes: Uint8Array): number { let h = 0x811c9dc5; @@ -106,10 +109,17 @@ function decodedFeaturesFor( return entry.features; } const features = decodeTile(data, coord); - decodeCache.delete(key); + const stale = decodeCache.get(key); + if (stale) { + decodeCache.delete(key); + decodeCacheBytes -= stale.byteLength; + } decodeCache.set(key, { byteLength: bytes.length, hash, features }); - if (decodeCache.size > DECODE_CACHE_MAX) { - decodeCache.delete(decodeCache.keys().next().value!); + decodeCacheBytes += bytes.length; + while (decodeCacheBytes > DECODE_CACHE_MAX_BYTES && decodeCache.size > 1) { + const oldestKey = decodeCache.keys().next().value!; + decodeCacheBytes -= decodeCache.get(oldestKey)!.byteLength; + decodeCache.delete(oldestKey); } counts.misses++; return features;