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