From de010910e28479f8a085f075d2651056022e3adb Mon Sep 17 00:00:00 2001 From: Charlie Vieth Date: Fri, 21 Nov 2025 18:07:59 -0500 Subject: [PATCH] plugin/cache: remove superfluous allocations in item.toMsg (#7700) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit removes superfluous allocations of the Answer, Ns, and Extra slices when copying a cached a dns.Msg. The allocations are superfluous because we immediately overwrite the newly copied slices with filterRRSlice. It also updates filterRRSlice to pre-calculate the size of the slice being copied into. Benchmark results: goos: darwin goarch: arm64 pkg: github.com/coredns/coredns/plugin/cache cpu: Apple M4 Pro │ base.10.txt │ new.10.txt │ │ sec/op │ sec/op vs base │ CacheResponse-14 471.1n ± 0% 462.9n ± 2% -1.74% (p=0.009 n=10) │ base.10.txt │ new.10.txt │ │ B/op │ B/op vs base │ CacheResponse-14 672.0 ± 0% 656.0 ± 0% -2.38% (p=0.000 n=10) │ base.10.txt │ new.10.txt │ │ allocs/op │ allocs/op vs base │ CacheResponse-14 13.00 ± 0% 12.00 ± 0% -7.69% (p=0.000 n=10) Signed-off-by: Charlie Vieth --- plugin/cache/cache_test.go | 11 ++++++++++- plugin/cache/dnssec.go | 10 ++++++++-- plugin/cache/item.go | 4 ---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/plugin/cache/cache_test.go b/plugin/cache/cache_test.go index 1a4d178f2..ed1d38c41 100644 --- a/plugin/cache/cache_test.go +++ b/plugin/cache/cache_test.go @@ -594,16 +594,25 @@ func BenchmarkCacheResponse(b *testing.B) { ctx := context.TODO() + // Add some answers since these need to be duplicated when + // serving a cached response. + answer := []dns.RR{ + test.MX("miek.nl. 3601 IN MX 1 aspmx.l.google.com."), + test.MX("miek.nl. 3601 IN MX 10 aspmx2.googlemail.com."), + } reqs := make([]*dns.Msg, 5) for i, q := range []string{"example1", "example2", "a", "b", "ddd"} { reqs[i] = new(dns.Msg) reqs[i].SetQuestion(q+".example.org.", dns.TypeA) + reqs[i].Answer = answer } + b.ResetTimer() + rw := &test.ResponseWriter{} j := 0 for b.Loop() { req := reqs[j] - c.ServeDNS(ctx, &test.ResponseWriter{}, req) + c.ServeDNS(ctx, rw, req) j = (j + 1) % 5 } } diff --git a/plugin/cache/dnssec.go b/plugin/cache/dnssec.go index da7e1e9b3..e0059403b 100644 --- a/plugin/cache/dnssec.go +++ b/plugin/cache/dnssec.go @@ -6,8 +6,14 @@ import "github.com/miekg/dns" // If dup is true the RRs in rrs are _copied_ before adjusting their // TTL and the slice of copied RRs is returned. func filterRRSlice(rrs []dns.RR, ttl uint32, dup bool) []dns.RR { + n := 0 + for _, r := range rrs { + if r.Header().Rrtype != dns.TypeOPT { + n++ + } + } + rs := make([]dns.RR, n) j := 0 - rs := make([]dns.RR, len(rrs)) for _, r := range rrs { if r.Header().Rrtype == dns.TypeOPT { continue @@ -20,5 +26,5 @@ func filterRRSlice(rrs []dns.RR, ttl uint32, dup bool) []dns.RR { rs[j].Header().Ttl = ttl j++ } - return rs[:j] + return rs } diff --git a/plugin/cache/item.go b/plugin/cache/item.go index c5aeccdcc..3259d4a72 100644 --- a/plugin/cache/item.go +++ b/plugin/cache/item.go @@ -82,10 +82,6 @@ func (i *item) toMsg(m *dns.Msg, now time.Time, do bool, ad bool) *dns.Msg { m1.RecursionAvailable = i.RecursionAvailable m1.Rcode = i.Rcode - m1.Answer = make([]dns.RR, len(i.Answer)) - m1.Ns = make([]dns.RR, len(i.Ns)) - m1.Extra = make([]dns.RR, len(i.Extra)) - ttl := uint32(i.ttl(now)) m1.Answer = filterRRSlice(i.Answer, ttl, true) m1.Ns = filterRRSlice(i.Ns, ttl, true)