4.5 The Cache
The cache's key and lifetimes are set by PSPU §6.7. This article is how resolvd computes them and what it does at the edges.
4.5.1 The cache key #
- An entry is keyed by the candidate in lower case, the record type, and
the scope key (§1.3). The class is not part of the key; every question
resolvd asks is class
IN. The stub rejects other classes before consulting the cache (§6.1), even when a matchingINanswer is held. - The same name asked through two scopes is two entries, and a single label's expansions are each cached under the expanded name.
4.5.2 What is stored #
Only replies a server sent with response code NOERROR or NXDOMAIN
are stored, under the candidate and the scope the candidate was routed
to:
| Reply | Stored as | Lifetime |
|---|---|---|
NOERROR with relevant answer records of class IN (§4.8) | found with those records | The least TTL among those records, capped at 86 400 s |
NOERROR with no relevant answer records of class IN | found with none | Negative lifetime |
NXDOMAIN | notfound | Negative lifetime |
4.5.2.1 The negative lifetime #
- The negative lifetime comes from the first
INSOArecord in the reply's authority section whose owner is the effective name or an enclosing domain. The effective name is the candidate after following its relevant CNAME path (§4.8); suffix matching respects label boundaries. Use the lesser of the SOA'sMINIMUMfield and its own TTL, capped at 300 s. When an alias leads to NXDOMAIN, also cap the lifetime at the least TTL of that alias path. - A reply with no qualifying
SOAin its authority section has a negative lifetime of zero.
4.5.2.2 A zero lifetime is not stored #
An entry whose lifetime is zero is not stored. A positive answer with a
zero TTL, and a negative answer without an SOA, are therefore never
cached.
4.5.2.3 What is never stored #
Never stored: synthetic answers, unavailable, transport failures, a
UDP reply with TC set (the reply to its TCP retry is the one
considered), and
replies with any other response code.
4.5.2.4 The TTLs inside an entry #
The records in an entry are kept with the TTLs the server sent. Only the entry's lifetime is capped.
4.5.3 Hits #
- An entry is live while its expiry is in the future. A live entry is returned with each record's TTL lowered to the whole number of seconds the entry has left, rounded down, when that is less than the record's own.
- A
notfoundhit with further candidates waiting moves to the next candidate, as anotfoundfrom a server would (§4.1).
4.5.4 Bypassing the cache #
- A
resolverequest withno_cacheset skips the lookup for each of its candidates. The reply it gets is still stored. - Stub queries,
lookupandreversealways consult the cache.
4.5.5 Capacity and eviction #
- The cache holds at most 8 192 entries.
- Expiry alone does not remove an entry. Looking up an expired key
removes it immediately, before any replacement answer arrives. Otherwise
it stays until overwritten, flushed, or removed during admission at
capacity. The
cache_entriescount instatusincludes expired entries that have not yet been removed.
4.5.5.1 Eviction #
Storing an entry under a key the cache does not already hold, when it already holds 8 192 entries, first evicts:
- every entry whose expiry is at or before the current time;
- then, if the cache still holds 8 192 entries, the one entry with the earliest expiry — any one of them, when several share it.
4.5.5.2 A long-lived answer preserves other live entries #
The sweep compares against the current time, independently of the new answer's lifetime. A day-long answer arriving at a full cache of live, shorter-lived answers replaces only the entry with the earliest expiry; the cache still holds 8 192 entries. If removing expired entries makes room, no live entry is evicted.
Older builds compared against the incoming answer's expiry and could empty a cache of live answers.
4.5.5.3 Overwriting a held key #
Storing under a key the cache already holds replaces that entry, live or expired, and evicts nothing else.
4.5.6 Flushes #
| Event | Discards |
|---|---|
| A snapshot in which a scope is new, has a different server list, or is missing (§3.3) | That scope's entries |
A registry change to FallbackServers in content or order (§2.3) | The fallback scope's entries |
A flush request (§5.3) | Everything |
| A restart | Everything |
Nothing else discards entries. Changes to static names, search domains,
the hostname, ControlSecurity, scope flags and metrics leave the cache
as it is.
4.5.6.1 A reply after its scope was flushed #
In source b4f7085,
a reply that arrives after its scope was flushed is still stored, under
the same scope key.
4.5.6.2 Proposed admission rule for invalidated tasks #
The proposed source correction
also invalidates pending tasks' permission to store answers. A global
flush affects every pending task. Removing an interface scope or
changing its server list affects tasks currently associated with that
scope; changing the fallback-server list affects tasks associated with
the fallback scope.
An invalidated task still completes its original requester normally, but cannot store any further answers. This restriction persists through UDP-to-TCP fallback, timeout retries and later search candidates, even if a later attempt uses a new server list. Removing and re-adding a scope does not restore the task's permission. Fresh requests can cache normally.
Changes only to metrics, search domains or other scope properties with unchanged server lists do not invalidate admission; unrelated scopes' pending tasks are unaffected. This changes cache admission, not request cancellation or routing. Cache keys, TTLs and eviction policy are unchanged. It describes proposed source behavior, not a released package or an installed resolver; check the installed source revision before relying on it.