diigo-cache: invalidate the last N days of cached pages

invalidateRecent(days) drops the cached pages holding anything diigo
updated within the last N days (on the cache's injected clock), and
every page before them, so the next read or fill refetches them; item
rows stay. Exposed on the fill capability (private and public) and on
the webkey page as "invalidate the last N days" per cache.

A user-requested refetch, not a change in what stored state means.

Generated-by: Claude Opus 5.5
This commit is contained in:
dckc committed 2026-10-07 08:27:13 -05:00
1 parent cffb1fa9b2
commit 904f620f06
5 files changed
+91 -1

No files matched your search

+31
View File
@@ -245,6 +245,37 @@ abstract class PagedCache extends DurableObject<CacheEnv> {
return stopped;
}
/**
* drop the cached pages holding anything diigo updated in the last
* `days` days, and every page before them (newer still; and new
* updates push items back), so the next read or fill refetches them.
* Item rows stay. Returns how many pages were dropped.
*/
async invalidateRecent(days: number): Promise<{ pages: number }> {
if (!Number.isInteger(days) || days < 1 || days > 3650) throw new Error("days: expected a whole number from 1 to 3650");
this.#schema();
const cutoff = Math.floor(this.#clock.now() / 1000) - days * 24 * 60 * 60;
const sql = this.ctx.storage.sql;
const deepest = sql
.exec<{ last: number | null }>(
"select max(page_members.page_num) as last from page_members join items on items.item_id = page_members.item_id where cast(items.updated as integer) >= ?",
cutoff,
)
.toArray()[0]?.last;
if (!deepest) {
console.log({ event: "cache", kind: this.kind, outcome: "invalidated", days, pages: 0 });
return { pages: 0 };
}
let pages = 0;
this.ctx.storage.transactionSync(() => {
pages = Number(sql.exec<{ n: number }>("select count(*) as n from pages where page_num <= ?", deepest).toArray()[0].n);
sql.exec("delete from page_members where page_num <= ?", deepest);
sql.exec("delete from pages where page_num <= ?", deepest);
});
console.log({ event: "cache", kind: this.kind, outcome: "invalidated", days, pages });
return { pages };
}
/** one fill step: up to `fillStep` pages, progress saved after each,
* then the next step is scheduled (or the job ends) */
async alarm(): Promise<void> {