Optimize the RR reading further

remove len(strings) from the code. 16% increase
in speed. Getting about 35K RR/s
This commit is contained in:
Miek Gieben 2012-01-30 21:26:29 +01:00
parent f3eacbb9fb
commit ed61734c89
5 changed files with 58 additions and 46 deletions

View File

@ -197,26 +197,29 @@ func (dns *Msg) IsEdns0() (ok bool) {
} }
// IsDomainName checks if s is a valid domainname, it returns // IsDomainName checks if s is a valid domainname, it returns
// the number of labels and true, when a domain name is valid. When false // the number of labels, total length and true, when a domain name is valid.
// the returned labelcount isn't specified. // When false the returned labelcount and length is 0 and 0.
func IsDomainName(s string) (uint8, bool) { // copied from net package. func IsDomainName(s string) (uint8, uint8, bool) { // copied from net package.
// See RFC 1035, RFC 3696. // See RFC 1035, RFC 3696.
if len(s) == 0 { l := len(s)
return 0, false if l == 0 || l > 255 {
return 0, 0, false
} }
if len(s) > 255 { // Not true...? // Simplify checking loop: make the name end in a dot
return 0, false // Don't call Fqdn() to save another len(s)
} if s[l-1] != '.' {
s = Fqdn(s) // simplify checking loop: make name end in dot s += "."
l++
}
last := byte('.') last := byte('.')
ok := false // ok once we've seen a letter ok := false // ok once we've seen a letter
partlen := 0 partlen := 0
labels := uint8(0) labels := uint8(0)
for i := 0; i < len(s); i++ { for i := 0; i < l; i++ {
c := s[i] c := s[i]
switch { switch {
default: default:
return 0, false return 0, uint8(l), false
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c == '*': case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c == '*':
ok = true ok = true
partlen++ partlen++
@ -228,28 +231,27 @@ func IsDomainName(s string) (uint8, bool) { // copied from net package.
case c == '-': case c == '-':
// byte before dash cannot be dot // byte before dash cannot be dot
if last == '.' { if last == '.' {
return 0, false return 0, uint8(l), false
} }
partlen++ partlen++
case c == '.': case c == '.':
// byte before dot cannot be dot, dash // byte before dot cannot be dot, dash
if last == '.' || last == '-' { if last == '.' || last == '-' {
return 0, false return 0, uint8(l), false
} }
if last == '\\' { // Ok, escaped dot. if last == '\\' { // Ok, escaped dot.
partlen++ partlen++
break break
} }
if partlen > 63 || partlen == 0 { if partlen > 63 || partlen == 0 {
return 0, false return 0, uint8(l), false
} }
partlen = 0 partlen = 0
labels++ labels++
} }
last = c last = c
} }
return labels, uint8(l), ok
return labels, ok
} }
// IsFqdn checks if a domain name is fully qualified // IsFqdn checks if a domain name is fully qualified

View File

@ -201,7 +201,7 @@ func (s *RR_RRSIG) Sign(k PrivateKey, rrset []RR) error {
s.OrigTtl = rrset[0].Header().Ttl s.OrigTtl = rrset[0].Header().Ttl
s.TypeCovered = rrset[0].Header().Rrtype s.TypeCovered = rrset[0].Header().Rrtype
s.TypeCovered = rrset[0].Header().Rrtype s.TypeCovered = rrset[0].Header().Rrtype
s.Labels, _ = IsDomainName(rrset[0].Header().Name) s.Labels, _, _ = IsDomainName(rrset[0].Header().Name)
// ... // ...
if strings.HasPrefix(rrset[0].Header().Name, "*") { if strings.HasPrefix(rrset[0].Header().Name, "*") {
s.Labels-- // wildcard, remove from label count s.Labels-- // wildcard, remove from label count

View File

@ -7,15 +7,14 @@
# explain # explain
.,CH,TXT,QUERY,NOERROR,qr,aa,tc,RD,ra,ad,cd,z,1,0,0,0,DO,65535,NSID .,CH,TXT,QUERY,NOERROR,qr,aa,tc,RD,ra,ad,cd,z,1,0,0,0,DO,65535,NSID
# explain # explain
.,IN,TXT,QUERY,NOERROR,qr,aa,tc,RD,ra,ad,cd,z,1,0,0,0,DO,128,NSID
.,IN,TXT,QUERY,NOERROR,qr,aa,tc,RD,ra,ad,cd,z,1,0,0,0,DO,127,NSID .,IN,TXT,QUERY,NOERROR,qr,aa,tc,RD,ra,ad,cd,z,1,0,0,0,DO,127,NSID
# explain # explain
.,CH,TXT,UPDATE,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid .,CH,TXT,UPDATE,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid
.,CH,TXT,UPDATE,BADTRUNC,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid .,CH,TXT,UPDATE,BADTRUNC,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid
# explain # explain
.,IN,TXT,IQUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid .,IN,TXT,IQUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid
.,IN,TXT,QUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,DO,128,nsid .,IN,TXT,QUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,DO,768,nsid
.,IN,TXT,QUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,DO,128,nsid .,IN,TXT,QUERY,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,DO,801,nsid
# explain # explain
.,IN,TXT,STATUS,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid .,IN,TXT,STATUS,NOERROR,qr,AA,tc,RD,ra,ad,cd,z,1,0,0,0,do,0,nsid
# explain # explain

View File

@ -161,11 +161,12 @@ func parseZone(r io.Reader, f string, t chan Token, include int) {
st = _EXPECT_OWNER_DIR st = _EXPECT_OWNER_DIR
case _OWNER: case _OWNER:
h.Name = l.token h.Name = l.token
if _, ok := IsDomainName(l.token); !ok { _, ld, ok := IsDomainName(l.token)
if !ok {
t <- Token{Error: &ParseError{f, "bad owner name", l}} t <- Token{Error: &ParseError{f, "bad owner name", l}}
return return
} }
if !IsFqdn(h.Name) { if h.Name[ld-1] != '.' {
h.Name += origin h.Name += origin
} }
st = _EXPECT_OWNER_BL st = _EXPECT_OWNER_BL
@ -378,8 +379,10 @@ func zlexer(s scanner.Scanner, c chan lex) {
c <- l c <- l
return return
} }
switch x := s.TokenText(); x { // Each token we get is one byte, so we switch on that x[0]. This
case " ", "\t": // avoids a len(x) that Go otherwise will perform when comparing strings.
switch x := s.TokenText(); x[0] {
case ' ', '\t':
escape = false escape = false
if commt { if commt {
break break
@ -424,7 +427,7 @@ func zlexer(s scanner.Scanner, c chan lex) {
} }
owner = false owner = false
space = true space = true
case ";": case ';':
if escape { if escape {
escape = false escape = false
str[stri] = ';' str[stri] = ';'
@ -438,7 +441,7 @@ func zlexer(s scanner.Scanner, c chan lex) {
break break
} }
commt = true commt = true
case "\n": case '\n':
// Hmmm, escape newline // Hmmm, escape newline
escape = false escape = false
if commt { if commt {
@ -485,7 +488,7 @@ func zlexer(s scanner.Scanner, c chan lex) {
commt = false commt = false
rrtype = false rrtype = false
owner = true owner = true
case "\\": case '\\':
if commt { if commt {
break break
} }
@ -498,7 +501,7 @@ func zlexer(s scanner.Scanner, c chan lex) {
str[stri] = '\\' str[stri] = '\\'
stri++ stri++
escape = true escape = true
case "\"": case '"':
if commt { if commt {
break break
} }
@ -510,7 +513,7 @@ func zlexer(s scanner.Scanner, c chan lex) {
} }
// str += "\"" don't add quoted quotes // str += "\"" don't add quoted quotes
quote = !quote quote = !quote
case "(": case '(':
if commt { if commt {
break break
} }
@ -521,7 +524,7 @@ func zlexer(s scanner.Scanner, c chan lex) {
break break
} }
brace++ brace++
case ")": case ')':
if commt { if commt {
break break
} }

View File

@ -123,10 +123,11 @@ func setNS(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
l := <-c l := <-c
rr.Ns = l.token rr.Ns = l.token
if _, ok := IsDomainName(l.token); !ok { _, ld, ok := IsDomainName(l.token)
if !ok {
return nil, &ParseError{f, "bad NS Ns", l} return nil, &ParseError{f, "bad NS Ns", l}
} }
if !IsFqdn(rr.Ns) { if rr.Ns[ld-1]!= '.' {
rr.Ns += o rr.Ns += o
} }
return rr, nil return rr, nil
@ -145,10 +146,11 @@ func setMX(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
<-c // _BLANK <-c // _BLANK
l = <-c // _STRING l = <-c // _STRING
rr.Mx = l.token rr.Mx = l.token
if _, ok := IsDomainName(l.token); !ok { _, ld, ok := IsDomainName(l.token)
if !ok {
return nil, &ParseError{f, "bad MX Mx", l} return nil, &ParseError{f, "bad MX Mx", l}
} }
if !IsFqdn(rr.Mx) { if rr.Mx[ld-1] != '.' {
rr.Mx += o rr.Mx += o
} }
return rr, nil return rr, nil
@ -160,10 +162,11 @@ func setCNAME(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
l := <-c l := <-c
rr.Cname = l.token rr.Cname = l.token
if _, ok := IsDomainName(l.token); !ok { _, ld, ok := IsDomainName(l.token)
if !ok {
return nil, &ParseError{f, "bad CNAME", l} return nil, &ParseError{f, "bad CNAME", l}
} }
if !IsFqdn(rr.Cname) { if rr.Cname[ld-1] != '.' {
rr.Cname += o rr.Cname += o
} }
return rr, nil return rr, nil
@ -176,19 +179,21 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
l := <-c l := <-c
rr.Ns = l.token rr.Ns = l.token
<-c // _BLANK <-c // _BLANK
if _, ok := IsDomainName(l.token); !ok { _, ld, ok := IsDomainName(l.token)
if !ok {
return nil, &ParseError{f, "bad SOA mname", l} return nil, &ParseError{f, "bad SOA mname", l}
} }
if !IsFqdn(rr.Ns) { if rr.Ns[ld-1] != '.' {
rr.Ns += o rr.Ns += o
} }
l = <-c l = <-c
rr.Mbox = l.token rr.Mbox = l.token
if _, ok := IsDomainName(l.token); !ok { _, ld, ok = IsDomainName(l.token)
if !ok {
return nil, &ParseError{f, "bad SOA rname", l} return nil, &ParseError{f, "bad SOA rname", l}
} }
if !IsFqdn(rr.Mbox) { if rr.Mbox[ld-1]!='.' {
rr.Mbox += o rr.Mbox += o
} }
<-c // _BLANK <-c // _BLANK
@ -274,10 +279,11 @@ func setRRSIG(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
<-c // _BLANK <-c // _BLANK
l = <-c l = <-c
rr.SignerName = l.token rr.SignerName = l.token
if _, ok := IsDomainName(l.token); !ok { _, ld, ok := IsDomainName(l.token)
if !ok {
return nil, &ParseError{f, "bad RRSIG signername", l} return nil, &ParseError{f, "bad RRSIG signername", l}
} }
if !IsFqdn(rr.SignerName) { if rr.SignerName[ld-1] != '.' {
rr.SignerName += o rr.SignerName += o
} }
// Get the remaining data until we see a NEWLINE // Get the remaining data until we see a NEWLINE
@ -304,10 +310,11 @@ func setNSEC(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
l := <-c l := <-c
rr.NextDomain = l.token rr.NextDomain = l.token
if _, ok := IsDomainName(l.token); !ok { _, ld, ok := IsDomainName(l.token)
if !ok {
return nil, &ParseError{f, "bad NSEC nextdomain", l} return nil, &ParseError{f, "bad NSEC nextdomain", l}
} }
if !IsFqdn(rr.NextDomain) { if rr.NextDomain[ld-1] != '.' {
rr.NextDomain += o rr.NextDomain += o
} }
@ -364,10 +371,11 @@ func setNSEC3(h RR_Header, c chan lex, o, f string) (RR, *ParseError) {
l = <-c l = <-c
rr.HashLength = uint8(len(l.token)) rr.HashLength = uint8(len(l.token))
rr.NextDomain = l.token rr.NextDomain = l.token
if _, ok := IsDomainName(l.token); !ok { _, ld, ok := IsDomainName(l.token)
if !ok {
return nil, &ParseError{f, "bad NSEC nextdomain", l} return nil, &ParseError{f, "bad NSEC nextdomain", l}
} }
if !IsFqdn(rr.NextDomain) { if rr.NextDomain[ld-1] != '.' {
rr.NextDomain += o rr.NextDomain += o
} }