Files
HealthLog/src/lib/cache/__tests__/closed-block-invalidation.test.ts
T
Marc-André Bombeck f5d6710670 perf(analytics): keep closed blocks of past readings cached across syncs
Every sync marked all of an account's analytics cells stale, so the slice
re-read the pre-fold remainder (every reading older than five years,
folded per source and day, the slice's largest statement on a long
history) and the day view re-read its past history blocks, although a
sync of today's readings cannot change either.

A cache key can now name the instant its value's readings end before
(closedBlockKeyPart). invalidateUserMeasurements takes touchedFrom, the
earliest measuredAt a write created, changed or removed, and leaves such
blocks in place when it is not earlier; without it every block goes as
before. The batch route passes it from the identities it wrote. The
pre-fold remainder moves into its own module and is cached as a closed
block; the day view's past history blocks carry their end, with a day of
margin for a night across midnight.

The batch route's two up-front reads move into batch-stored-rows.ts with
the once-per-batch key rule they share.
2026-10-22 07:24:59 +02:00

50 lines
1.7 KiB
TypeScript

import { beforeEach, describe, expect, it } from "vitest";
import {
closedBlockKeyPart,
closedBlockUntouched,
invalidateUserMeasurements,
} from "../invalidate";
import { caches, type ServerCache } from "../server-cache";
const analytics = caches.analytics as ServerCache<{ v: number }>;
const USER = "u-closed";
const SPLIT = Date.UTC(2021, 9, 22);
const closedKey = `${USER}|pre-fold-remainder|${closedBlockKeyPart(SPLIT)}|x`;
const openKey = `${USER}|dashboard-snapshot|en`;
describe("closed analytics blocks", () => {
beforeEach(() => {
analytics.deleteByPrefix(`${USER}|`);
analytics.set(closedKey, { v: 1 });
analytics.set(openKey, { v: 2 });
});
it("reads the instant a closed block ends before", () => {
expect(closedBlockUntouched(closedKey, new Date(SPLIT))).toBe(true);
expect(closedBlockUntouched(closedKey, new Date(SPLIT - 1))).toBe(false);
expect(closedBlockUntouched(openKey, new Date(SPLIT))).toBe(false);
});
it("survives a write of newer readings, evicting or marking stale", () => {
for (const evict of [false, true]) {
invalidateUserMeasurements(USER, {
evict,
touchedFrom: new Date(SPLIT + 86_400_000),
});
expect(analytics.get(closedKey)).toEqual({ v: 1 });
expect(analytics.get(openKey)).toBeNull();
analytics.set(openKey, { v: 2 });
}
});
it("goes with a write that reaches before it, or does not say", () => {
invalidateUserMeasurements(USER, { touchedFrom: new Date(SPLIT - 1) });
expect(analytics.get(closedKey)).toBeNull();
analytics.set(closedKey, { v: 1 });
invalidateUserMeasurements(USER);
expect(analytics.get(closedKey)).toBeNull();
});
});