mirror of
https://github.com/moby/moby.git
synced 2026-08-08 00:52:17 +00:00
libnet/internal/resolvconf: optimize Generate() without text/template
Rewrite this function to not use text/template, which is ~74× faster,
~25× less memory, and ~56× fewer allocations.
Before/After:
BenchmarkGenerate-10 42550 27439 ns/op 18083 B/op 394 allocs/op
BenchmarkGenerate-10 3148328 373 ns/op 712 B/op 7 allocs/op
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
@@ -21,7 +21,6 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/netip"
|
||||
@@ -29,7 +28,6 @@ import (
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/moby/sys/atomicwriter"
|
||||
@@ -71,7 +69,7 @@ type ExtDNSEntry struct {
|
||||
|
||||
func (ed ExtDNSEntry) String() string {
|
||||
if ed.HostLoopback {
|
||||
return fmt.Sprintf("host(%s)", ed.Addr)
|
||||
return "host(" + ed.Addr.String() + ")"
|
||||
}
|
||||
return ed.Addr.String()
|
||||
}
|
||||
@@ -291,70 +289,106 @@ func (rc *ResolvConf) TransformForIntNS(
|
||||
// is true, the file will include header information if supplied, and a trailing
|
||||
// comment that describes how the file was constructed and lists external resolvers.
|
||||
func (rc *ResolvConf) Generate(comments bool) ([]byte, error) {
|
||||
s := struct {
|
||||
Md *metadata
|
||||
NameServers []netip.Addr
|
||||
Search []string
|
||||
Options []string
|
||||
Other []string
|
||||
Overrides []string
|
||||
Comments bool
|
||||
}{
|
||||
Md: &rc.md,
|
||||
NameServers: rc.nameServers,
|
||||
Search: rc.search,
|
||||
Options: rc.options,
|
||||
Other: rc.other,
|
||||
Comments: comments,
|
||||
var b bytes.Buffer
|
||||
b.Grow(512) // estimated size for a regular resolv.conf we produce.
|
||||
|
||||
if comments && rc.md.Header != "" {
|
||||
b.WriteString(rc.md.Header + "\n")
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
if rc.md.NSOverride {
|
||||
s.Overrides = append(s.Overrides, "nameservers")
|
||||
for _, ns := range rc.nameServers {
|
||||
b.WriteString("nameserver ")
|
||||
b.WriteString(ns.String())
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
if rc.md.SearchOverride {
|
||||
s.Overrides = append(s.Overrides, "search")
|
||||
if len(rc.search) > 0 {
|
||||
b.WriteString("search ")
|
||||
for i, s := range rc.search {
|
||||
if i > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteString(s)
|
||||
}
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
if rc.md.OptionsOverride {
|
||||
s.Overrides = append(s.Overrides, "options")
|
||||
if len(rc.options) > 0 {
|
||||
b.WriteString("options ")
|
||||
for i, s := range rc.options {
|
||||
if i > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteString(s)
|
||||
}
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
for _, o := range rc.other {
|
||||
b.WriteString(o)
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
|
||||
const templateText = `{{if .Comments}}{{with .Md.Header}}{{.}}
|
||||
if comments {
|
||||
b.WriteByte('\n')
|
||||
b.WriteString("# Based on host file: '" + rc.md.SourcePath + "'")
|
||||
if rc.md.Transform != "" {
|
||||
b.WriteString(" (" + rc.md.Transform + ")")
|
||||
}
|
||||
b.WriteByte('\n')
|
||||
for _, w := range rc.md.Warnings {
|
||||
b.WriteString("# ")
|
||||
b.WriteString(w)
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
if len(rc.md.ExtNameServers) > 0 {
|
||||
b.WriteString("# ExtServers: [")
|
||||
for i, ext := range rc.md.ExtNameServers {
|
||||
if i > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteString(ext.String())
|
||||
}
|
||||
b.WriteByte(']')
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
if len(rc.md.InvalidNSs) > 0 {
|
||||
b.WriteString("# Invalid nameservers: [")
|
||||
for i, ext := range rc.md.InvalidNSs {
|
||||
if i > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteString(ext)
|
||||
}
|
||||
b.WriteByte(']')
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
|
||||
{{end}}{{end}}{{range .NameServers -}}
|
||||
nameserver {{.}}
|
||||
{{end}}{{with .Search -}}
|
||||
search {{join . " "}}
|
||||
{{end}}{{with .Options -}}
|
||||
options {{join . " "}}
|
||||
{{end}}{{with .Other -}}
|
||||
{{join . "\n"}}
|
||||
{{end}}{{if .Comments}}
|
||||
# Based on host file: '{{.Md.SourcePath}}'{{with .Md.Transform}} ({{.}}){{end}}
|
||||
{{range .Md.Warnings -}}
|
||||
# {{.}}
|
||||
{{end -}}
|
||||
{{with .Md.ExtNameServers -}}
|
||||
# ExtServers: {{.}}
|
||||
{{end -}}
|
||||
{{with .Md.InvalidNSs -}}
|
||||
# Invalid nameservers: {{.}}
|
||||
{{end -}}
|
||||
# Overrides: {{.Overrides}}
|
||||
{{with .Md.NDotsFrom -}}
|
||||
# Option ndots from: {{.}}
|
||||
{{end -}}
|
||||
{{end -}}
|
||||
`
|
||||
b.WriteString("# Overrides: [")
|
||||
var overrides int
|
||||
if rc.md.NSOverride {
|
||||
b.WriteString("nameservers")
|
||||
overrides++
|
||||
}
|
||||
if rc.md.SearchOverride {
|
||||
if overrides > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteString("search")
|
||||
overrides++
|
||||
}
|
||||
if rc.md.OptionsOverride {
|
||||
if overrides > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteString("options")
|
||||
}
|
||||
b.WriteByte(']')
|
||||
b.WriteByte('\n')
|
||||
|
||||
funcs := template.FuncMap{"join": strings.Join}
|
||||
var buf bytes.Buffer
|
||||
templ, err := template.New("summary").Funcs(funcs).Parse(templateText)
|
||||
if err != nil {
|
||||
return nil, errSystem{err}
|
||||
if rc.md.NDotsFrom != "" {
|
||||
b.WriteString("# Option ndots from: " + rc.md.NDotsFrom + "\n")
|
||||
}
|
||||
}
|
||||
if err := templ.Execute(&buf, s); err != nil {
|
||||
return nil, errSystem{err}
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
// WriteFile generates content and writes it to path. If hashPath is non-zero, it
|
||||
|
||||
Reference in New Issue
Block a user