Expand description
Process-wide ceiling for the page render caches (READ_CACHE_BOUNDED).
Provides render_cache::budget, render_cache::set_budget,
render_cache::resident_bytes, render_cache::enforce and
render_cache::clear. Since 0.33 the render caches are bounded by default
(render_cache::DEFAULT_BUDGET, 256 MiB); set_budget(usize::MAX) restores
the unbounded behaviour of earlier releases.
Process-wide ceiling for the page render caches.
Rendering a page memoises what it decoded — the wavelet background, the JB2
mask, the converted RGB pixmaps, the composited tiles (see
[crate::djvu_render::PageLayers]). That makes the second render of a page
nearly free, and it is why a viewer can pan and zoom without re-decoding.
Until 0.33 nothing bounded it. The eviction API
(crate::DjVuDocument::enforce_cache_budget and friends) needed
&mut DjVuDocument, and every render entry point holds a shared &DjVuPage
— so a program that only rendered could never shrink what it grew. A sweep
through a colour book cost about 5.3 MB per page and never gave any of it
back.
This module closes that: every page cache registers itself here, every cache
fill reports its new size, and when the total goes over
[budget] the least-recently-used layers are dropped until it is under
again. The default ceiling is [DEFAULT_BUDGET]; set your own with
[set_budget], or lift it entirely with set_budget(usize::MAX).
The unit of eviction is a layer, not a page (#813): each decoded background, mask, converted pixmap and tile store carries its own last-used tick and size, and a sweep ranks them across every live page. A page whose mask was just used keeps its mask while its stale background goes. Only the layer being filled at that moment is protected, so the resident total can exceed the ceiling by at most one layer. (Until this change the sweep dropped whole pages and protected the whole page being rendered, so the overshoot was a page’s cache and a warm layer went with its cold neighbours.)
Eviction is safe at any moment. A cached layer is handed to a render as a shared handle, so dropping the cache’s own handle mid-render only means the render finishes with the copy it already holds. A render in progress therefore holds the layers it has already fetched whether or not the cache still does; that memory is the render’s, not the cache’s, and is not part of the resident total.
The ceiling is process-wide on purpose: memory is a process-wide resource,
and a page does not know which document it belongs to. Per-document control
is still available through crate::DjVuDocument::enforce_cache_budget,
which stays page-granular.
See PERF_EXPERIMENTS.md READ_CACHE_BOUNDED and RENDER_CACHE_LAYER_EVICT.
Constants§
- DEFAULT_
BUDGET - The ceiling applied when the program sets none: 256 MiB.
Functions§
- budget
- The ceiling on the total resident bytes of all page render caches.
- clear
- Drop every registered page cache, whatever the ceiling. Returns bytes freed.
- enforce
- Drop least-recently-used cached layers until the total is at most
budget. Returns the bytes freed; 0 when already under the ceiling. - resident_
bytes - Approximate resident bytes held by every page render cache in this process.
- set_
budget - Set the ceiling. Pass
usize::MAXto render without one (the behaviour of 0.32 and earlier).