github: shadowy octopus with the head of a robot, emblazoned with the Dreamwidth swirl (Default)
github ([personal profile] github) wrote in [site community profile] changelog2026-07-08 11:52 pm

Standardize in-process caching behind DW::Cache (request + process scopes) (#3652)

Standardize in-process caching behind DW::Cache (request + process scopes) (#3652)

  • Standardize request-scoped caching behind DW::RequestCache

Request caches lived in a sprawl of package globals (%LJ::REQ_CACHE*, %LJ::REQUEST_CACHE, %LJ::S2::REQ_CACHE_*, etc.) wiped by a hand-maintained clear-list in LJ::start_request. That list drifted -- %LJ::REQ_CACHE (UniqCookie) and %LJ::REQ_CACHE_POLL already escaped it and leaked across requests on persistent workers -- and DW::CacheStats kept a second, separately drifting copy for size sampling. The SQS task workers never called start_request at all, so every request cache lived for the whole worker process.

Introduce DW::RequestCache: one module whose single clear() empties everything routed through it, so a cache added here cannot leak. It offers a namespaced KV memoization API (get/set/memoize/remove/clear_ns) plus a registration API (register_var/register_reset) for state that keeps direct package-var access. LJ::start_request's clear-block collapses to one DW::RequestCache->clear call, and DW::CacheStats now samples the same registry it clears (via ->registered), so the two sets can no longer drift.

Migrate all existing request caches onto the interface (users, rel, usertags, trustmask, S2 style/layer/layer-info, poll, uniqcookie, langdatfile, OAuth consumer/access) and register the remaining scratch/accumulator state and singleton resets. Wire DW::TaskQueue::start_work to wrap each job in start_request/end_request, matching the legacy TheSchwartz/Gearman workers; a scope guard guarantees end_request runs on the die and timeout exit paths.

Tests reaching into the old package vars are updated to the new API. Adds t/request-cache.t covering the KV API, registration, the clear() guarantee, and per-request/per-job isolation via LJ::start_request.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

  • Address review: guard ScopeGuard DESTROY and clear OAuth consumer by id

  • DW::TaskQueue::ScopeGuard::DESTROY now runs its cleanup under local $@ + eval, so a die in LJ::end_request can't mask a job's own exception during unwinding.

  • DW::OAuth::Consumer::deletecache clears the request-cache entry keyed by id as well as by token (the consumer is cached under both), matching the memcache invalidation right above it.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

  • Rework into DW::Cache with request/process scopes; retire DW::CacheStats

Replace DW::RequestCache with DW::Cache, one facade over two scope singletons sharing a single store implementation: DW::Cache->request (wiped per web request / background job by LJ::start_request) and DW::Cache->process (global reference data -- props, moods, codes, styles, translations -- wiped on config reload by LJ::handle_caches, whose hand-maintained clear-list collapses to one process->clear the same way start_request's did). Each scope has the same KV memoization + register_var/register_reset API, and each scope's clear() and sizing draw from the same registry, so cleared and measured sets cannot drift.

DW::CacheStats is deleted. Cache byte sizes are now emitted by DW::Cache->report_sizes (dw.cache.bytes tagged cache:, scope:, sampled at $LJ::CACHE_STATS_SAMPLE_RATE), restoring per-family series for the migrated request caches. Process RSS moves to DW::Stats::report_rss (dw.process.rss_bytes, its own $LJ::PROCESS_STATS_SAMPLE_RATE knob) since it is process health, not cache instrumentation. The per-class singleton registries (Entry/Comment/Message/Userpic) and Lang's TXT_CACHE self-register with their scope, which both clears and sizes them; %LJ::CACHE_PROPID and TXT_CACHE were previously measured but never cleared even on reload -- now they are.

t/request-cache.t becomes t/cache.t and also covers scope independence and the handle_caches/process-scope integration.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

  • Fix stale cache-terminology comments flagged in review

"process cache" comments on request-scope lookups in LJ/User/Account.pm now say "request cache" (an actual process scope exists, so the old wording misleads), and the trusted-anon rationale in LJ/Session.pm + t/session-trust.t no longer cites the retired never-cleared %LJ::REQ_CACHE; t/vgift-trans.t explains the manual rel-cache invalidation instead of referencing REQ_CACHE_REL.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com