coredns/middleware/file/tree/elem.go
Miek Gieben 2adbdf34d9 Use qname/qtype for lookups
Drop the use of dns.RR when in fact the only thing we use is the name

and type of the RR. Cleans up a bunch of stuff and also stops the weird

making of dns.RRs just for a lookup. Should safe some memory as well.



Fixes: #66
2016-04-02 17:49:13 +01:00

120 lines
2.3 KiB
Go

package tree
import (
"github.com/miekg/coredns/middleware"
"github.com/miekg/dns"
)
type Elem struct {
m map[uint16][]dns.RR
}
// newElem returns a new elem.
func newElem(rr dns.RR) *Elem {
e := Elem{m: make(map[uint16][]dns.RR)}
e.m[rr.Header().Rrtype] = []dns.RR{rr}
return &e
}
// Types returns the RRs with type qtype from e.
func (e *Elem) Types(qtype uint16) []dns.RR {
if rrs, ok := e.m[qtype]; ok {
return rrs
}
// nodata
return nil
}
// All returns all RRs from e, regardless of type.
func (e *Elem) All() []dns.RR {
list := []dns.RR{}
for _, rrs := range e.m {
list = append(list, rrs...)
}
return list
}
// Name returns the name for this node.
func (e *Elem) Name() string {
for _, rrs := range e.m {
return rrs[0].Header().Name
}
return ""
}
// Insert inserts rr into e. If rr is equal to existing rrs this is a noop.
func (e *Elem) Insert(rr dns.RR) {
t := rr.Header().Rrtype
if e.m == nil {
e.m = make(map[uint16][]dns.RR)
e.m[t] = []dns.RR{rr}
return
}
rrs, ok := e.m[t]
if !ok {
e.m[t] = []dns.RR{rr}
return
}
for _, er := range rrs {
if equalRdata(er, rr) {
return
}
}
rrs = append(rrs, rr)
e.m[t] = rrs
}
// Delete removes rr from e. When e is empty after the removal the returned bool is true.
func (e *Elem) Delete(rr dns.RR) (empty bool) {
if e.m == nil {
return true
}
t := rr.Header().Rrtype
rrs, ok := e.m[t]
if !ok {
return
}
for i, er := range rrs {
if equalRdata(er, rr) {
rrs = removeFromSlice(rrs, i)
e.m[t] = rrs
empty = len(rrs) == 0
if empty {
delete(e.m, t)
}
return
}
}
return
}
// Less is a tree helper function that calles middleware.Less.
func Less(a *Elem, name string) int { return middleware.Less(name, a.Name()) }
// Assuming the same type and name this will check if the rdata is equal as well.
func equalRdata(a, b dns.RR) bool {
switch x := a.(type) {
// TODO(miek): more types, i.e. all types. + tests for this.
case *dns.A:
return x.A.Equal(b.(*dns.A).A)
case *dns.AAAA:
return x.AAAA.Equal(b.(*dns.AAAA).AAAA)
case *dns.MX:
if x.Mx == b.(*dns.MX).Mx && x.Preference == b.(*dns.MX).Preference {
return true
}
}
return false
}
// removeFromSlice removes index i from the slice.
func removeFromSlice(rrs []dns.RR, i int) []dns.RR {
if i >= len(rrs) {
return rrs
}
rrs = append(rrs[:i], rrs[i+1:]...)
return rrs
}