Skip to content

Cache DNS section parsing instead of re-serializing per access #85

Description

@EONRaider

Target: 1.4.0 (Tier 1 — earn the benchmark)

layer7/dns.py calls bytes(self) — a full re-serialization of the
whole DNS message — from six separate sites (lines 190, 213, 259, 287,
314, 346). _labels() is called once per record and again per name
inside _decode_rdata(), so record parsing is O(records × message
size) in allocations.

Worse, answers, authorities and additionals (dns.py:390-403)
each call _resource_records(), which re-parses all three sections
from scratch
. Reading all three parses the message three times.

Nothing in the library caches anything — there is no functools
import, no cached_property, no lru_cache anywhere in src/.

Measured

On a 96-byte response with 3 records:

AccessCost
.answers alone19.0 µs
.answers + .authorities + .additionals55.7 µs (2.9×)
bytes(self) calls for one .answers14

For scale, decoding an entire frame takes ~26 µs. One DNS accessor
costs most of a frame.

What to do

Two independent wins, either order:

  1. Parse the three sections once and slice the result, rather than
    re-parsing per accessor.
  2. Stop round-tripping through bytes(self) — the parser should work
    from the already-held sections bytes plus the header, not
    re-serialize the object it is a method on.

Caching on a frozen dataclass needs object.__setattr__ or a
module-level memo; functools.cached_property does not work with
slots=True. Whatever is chosen must not break the
bytes(decode(x)) == x guarantee or make instances unhashable.

Acceptance criteria

  • Reading all three sections parses the message once.
  • bytes(self) is not called from any accessor.
  • Round-trip and DNS corpus assertions unchanged.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions