mirror of
https://github.com/coredns/coredns.git
synced 2025-11-12 15:02:17 -05:00
* plugin/file: improve performance of function tree.less(..) PrevLabel always begins its iteration from the tail of domain name. less(..) loop can improve its performance by calling PrevLabel starting from the last processed label. As the benchmark results showed, the performance is improved by about 15%. $ go test -bench=Less -run=^$ goos: linux goarch: amd64 pkg: github.com/coredns/coredns/plugin/file/tree cpu: Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz BenchmarkLess/base-16 99003 12105 ns/op BenchmarkLess/optimized-16 114522 10590 ns/op PASS ok github.com/coredns/coredns/plugin/file/tree 2.416s Signed-off-by: yuwenchao <ywc689@163.com> * plugin/file: performance enhancement for nameFromRight(..) Similar to tree.less(..), performance of function nameFromRight can boost by utilizing dns.PrevLabel more efficiently. As benchmark tests shown, performance of this function with the optimization is gained by double or triple. * Benchmark test result for the original implementation: BenchmarkNameFromRight/i0_origin-16 430719652 2.794 ns/op BenchmarkNameFromRight/eq_origin_i1_shot-16 30933135 37.52 ns/op BenchmarkNameFromRight/two_labels_i1-16 29375857 40.71 ns/op BenchmarkNameFromRight/two_labels_i2-16 18556830 63.97 ns/op BenchmarkNameFromRight/two_labels_i3_shot-16 14678812 84.73 ns/op BenchmarkNameFromRight/ten_labels_i5-16 8522132 133.0 ns/op BenchmarkNameFromRight/ten_labels_i11_shot-16 3154410 378.2 ns/op BenchmarkNameFromRight/not_subdomain_shot-16 35297224 33.59 ns/op BenchmarkNameFromRightRandomized-16 10638702 113.4 ns/op 0 B/op 0 allocs/op * Benchmark test result with this optimization: BenchmarkNameFromRight/i0_origin-16 425864671 2.808 ns/op BenchmarkNameFromRight/eq_origin_i1_shot-16 60903428 19.53 ns/op BenchmarkNameFromRight/two_labels_i1-16 50209297 24.21 ns/op BenchmarkNameFromRight/two_labels_i2-16 42483711 27.88 ns/op BenchmarkNameFromRight/two_labels_i3_shot-16 40898925 29.24 ns/op BenchmarkNameFromRight/ten_labels_i5-16 27916532 44.54 ns/op BenchmarkNameFromRight/ten_labels_i11_shot-16 17540040 67.59 ns/op BenchmarkNameFromRight/not_subdomain_shot-16 67180514 17.46 ns/op BenchmarkNameFromRightRandomized-16 32692081 38.21 ns/op 0 B/op 0 allocs/op Signed-off-by: yuwenchao <yuwenchao@bytedance.com> --------- Signed-off-by: yuwenchao <ywc689@163.com> Signed-off-by: yuwenchao <yuwenchao@bytedance.com> Co-authored-by: yuwenchao <yuwenchao@bytedance.com>
185 lines
3.9 KiB
Go
185 lines
3.9 KiB
Go
package file
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/coredns/coredns/plugin/file/tree"
|
|
"github.com/coredns/coredns/plugin/pkg/upstream"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
// Zone is a structure that contains all data related to a DNS zone.
|
|
type Zone struct {
|
|
origin string
|
|
origLen int
|
|
file string
|
|
*tree.Tree
|
|
Apex
|
|
Expired bool
|
|
|
|
sync.RWMutex
|
|
|
|
StartupOnce sync.Once
|
|
TransferFrom []string
|
|
|
|
ReloadInterval time.Duration
|
|
reloadShutdown chan bool
|
|
|
|
Upstream *upstream.Upstream // Upstream for looking up external names during the resolution process.
|
|
}
|
|
|
|
// Apex contains the apex records of a zone: SOA, NS and their potential signatures.
|
|
type Apex struct {
|
|
SOA *dns.SOA
|
|
NS []dns.RR
|
|
SIGSOA []dns.RR
|
|
SIGNS []dns.RR
|
|
}
|
|
|
|
// NewZone returns a new zone.
|
|
func NewZone(name, file string) *Zone {
|
|
return &Zone{
|
|
origin: dns.Fqdn(name),
|
|
origLen: dns.CountLabel(dns.Fqdn(name)),
|
|
file: filepath.Clean(file),
|
|
Tree: &tree.Tree{},
|
|
reloadShutdown: make(chan bool),
|
|
}
|
|
}
|
|
|
|
// Copy copies a zone.
|
|
func (z *Zone) Copy() *Zone {
|
|
z1 := NewZone(z.origin, z.file)
|
|
z1.TransferFrom = z.TransferFrom
|
|
z1.Expired = z.Expired
|
|
|
|
z1.Apex = z.Apex
|
|
return z1
|
|
}
|
|
|
|
// CopyWithoutApex copies zone z without the Apex records.
|
|
func (z *Zone) CopyWithoutApex() *Zone {
|
|
z1 := NewZone(z.origin, z.file)
|
|
z1.TransferFrom = z.TransferFrom
|
|
z1.Expired = z.Expired
|
|
|
|
return z1
|
|
}
|
|
|
|
// Insert inserts r into z.
|
|
func (z *Zone) Insert(r dns.RR) error {
|
|
// r.Header().Name = strings.ToLower(r.Header().Name)
|
|
if r.Header().Rrtype != dns.TypeSRV {
|
|
r.Header().Name = strings.ToLower(r.Header().Name)
|
|
}
|
|
|
|
switch h := r.Header().Rrtype; h {
|
|
case dns.TypeNS:
|
|
r.(*dns.NS).Ns = strings.ToLower(r.(*dns.NS).Ns)
|
|
|
|
if r.Header().Name == z.origin {
|
|
z.NS = append(z.NS, r)
|
|
return nil
|
|
}
|
|
case dns.TypeSOA:
|
|
r.(*dns.SOA).Ns = strings.ToLower(r.(*dns.SOA).Ns)
|
|
r.(*dns.SOA).Mbox = strings.ToLower(r.(*dns.SOA).Mbox)
|
|
|
|
z.SOA = r.(*dns.SOA)
|
|
return nil
|
|
case dns.TypeNSEC3, dns.TypeNSEC3PARAM:
|
|
return fmt.Errorf("NSEC3 zone is not supported, dropping RR: %s for zone: %s", r.Header().Name, z.origin)
|
|
case dns.TypeRRSIG:
|
|
x := r.(*dns.RRSIG)
|
|
switch x.TypeCovered {
|
|
case dns.TypeSOA:
|
|
z.SIGSOA = append(z.SIGSOA, x)
|
|
return nil
|
|
case dns.TypeNS:
|
|
if r.Header().Name == z.origin {
|
|
z.SIGNS = append(z.SIGNS, x)
|
|
return nil
|
|
}
|
|
}
|
|
case dns.TypeCNAME:
|
|
r.(*dns.CNAME).Target = strings.ToLower(r.(*dns.CNAME).Target)
|
|
case dns.TypeMX:
|
|
r.(*dns.MX).Mx = strings.ToLower(r.(*dns.MX).Mx)
|
|
case dns.TypeSRV:
|
|
// r.(*dns.SRV).Target = strings.ToLower(r.(*dns.SRV).Target)
|
|
}
|
|
|
|
z.Tree.Insert(r)
|
|
return nil
|
|
}
|
|
|
|
// File retrieves the file path in a safe way.
|
|
func (z *Zone) File() string {
|
|
z.RLock()
|
|
defer z.RUnlock()
|
|
return z.file
|
|
}
|
|
|
|
// SetFile updates the file path in a safe way.
|
|
func (z *Zone) SetFile(path string) {
|
|
z.Lock()
|
|
z.file = path
|
|
z.Unlock()
|
|
}
|
|
|
|
// ApexIfDefined returns the apex nodes from z. The SOA record is the first record, if it does not exist, an error is returned.
|
|
func (z *Zone) ApexIfDefined() ([]dns.RR, error) {
|
|
z.RLock()
|
|
defer z.RUnlock()
|
|
if z.SOA == nil {
|
|
return nil, fmt.Errorf("no SOA")
|
|
}
|
|
|
|
rrs := []dns.RR{z.SOA}
|
|
|
|
if len(z.SIGSOA) > 0 {
|
|
rrs = append(rrs, z.SIGSOA...)
|
|
}
|
|
if len(z.NS) > 0 {
|
|
rrs = append(rrs, z.NS...)
|
|
}
|
|
if len(z.SIGNS) > 0 {
|
|
rrs = append(rrs, z.SIGNS...)
|
|
}
|
|
|
|
return rrs, nil
|
|
}
|
|
|
|
// NameFromRight returns the labels from the right, staring with the
|
|
// origin and then i labels extra. When we are overshooting the name
|
|
// the returned boolean is set to true.
|
|
func (z *Zone) nameFromRight(qname string, i int) (string, bool) {
|
|
if i <= 0 {
|
|
return z.origin, false
|
|
}
|
|
|
|
n := len(qname)
|
|
for j := 1; j <= z.origLen; j++ {
|
|
if m, shot := dns.PrevLabel(qname[:n], 1); shot {
|
|
return qname, shot
|
|
} else {
|
|
n = m
|
|
}
|
|
}
|
|
|
|
for j := 1; j <= i; j++ {
|
|
m, shot := dns.PrevLabel(qname[:n], 1)
|
|
if shot {
|
|
return qname, shot
|
|
} else {
|
|
n = m
|
|
}
|
|
}
|
|
return qname[n:], false
|
|
}
|