浏览代码

libnetwork/resolvconf: simplify hashData() and improve performance

The code seemed overly complicated, requiring a reader to be constructed,
where in all cases, the data was already available in a variable. This patch
simplifies the utility to not require a reader, which also makes it a bit
more performant:

    go install golang.org/x/perf/cmd/benchstat@latest
    GO111MODULE=off go test -run='^$' -bench=. -count=20 > old.txt
    GO111MODULE=off go test -run='^$' -bench=. -count=20 > new.txt

    benchstat old.txt new.txt
    name         old time/op    new time/op    delta
    HashData-10     201ns ± 1%     128ns ± 1%  -36.16%  (p=0.000 n=18+20)

    name         old alloc/op   new alloc/op   delta
    HashData-10      416B ± 0%      208B ± 0%  -50.00%  (p=0.000 n=20+20)

    name         old allocs/op  new allocs/op  delta
    HashData-10      6.00 ± 0%      3.00 ± 0%  -50.00%  (p=0.000 n=20+20)

A small change was made in `Build()`, which previously returned the resolv.conf
data, even if the function failed to write it. In the new variation, `nil` is
consistently returned on failures.

Note that in various places, the hash is not even used, so we may be able to
simplify things more after this.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 2 年之前
父节点
当前提交
630fc3839e

+ 4 - 13
libnetwork/resolvconf/resolvconf.go

@@ -102,11 +102,7 @@ func GetSpecific(path string) (*File, error) {
 	if err != nil {
 		return nil, err
 	}
-	hash, err := hashData(bytes.NewReader(resolv))
-	if err != nil {
-		return nil, err
-	}
-	return &File{Content: resolv, Hash: hash}, nil
+	return &File{Content: resolv, Hash: hashData(resolv)}, nil
 }
 
 // FilterResolvDNS cleans up the config in resolvConf.  It has two main jobs:
@@ -132,11 +128,7 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) {
 		}
 		cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...)
 	}
-	hash, err := hashData(bytes.NewReader(cleanedResolvConf))
-	if err != nil {
-		return nil, err
-	}
-	return &File{Content: cleanedResolvConf, Hash: hash}, nil
+	return &File{Content: cleanedResolvConf, Hash: hashData(cleanedResolvConf)}, nil
 }
 
 // getLines parses input into lines and strips away comments.
@@ -246,10 +238,9 @@ func Build(path string, dns, dnsSearch, dnsOptions []string) (*File, error) {
 		}
 	}
 
-	hash, err := hashData(bytes.NewReader(content.Bytes()))
-	if err != nil {
+	if err := os.WriteFile(path, content.Bytes(), 0o644); err != nil {
 		return nil, err
 	}
 
-	return &File{Content: content.Bytes(), Hash: hash}, os.WriteFile(path, content.Bytes(), 0644)
+	return &File{Content: content.Bytes(), Hash: hashData(content.Bytes())}, nil
 }

+ 1 - 4
libnetwork/resolvconf/resolvconf_linux_test.go

@@ -18,10 +18,7 @@ func TestGet(t *testing.T) {
 	if string(resolvConfUtils.Content) != string(resolvConfSystem) {
 		t.Fatalf("/etc/resolv.conf and GetResolvConf have different content.")
 	}
-	hashSystem, err := hashData(bytes.NewReader(resolvConfSystem))
-	if err != nil {
-		t.Fatal(err)
-	}
+	hashSystem := hashData(resolvConfSystem)
 	if resolvConfUtils.Hash != hashSystem {
 		t.Fatalf("/etc/resolv.conf and GetResolvConf have different hashes.")
 	}

+ 4 - 8
libnetwork/resolvconf/utils.go

@@ -3,14 +3,10 @@ package resolvconf
 import (
 	"crypto/sha256"
 	"encoding/hex"
-	"io"
 )
 
-// hashData returns the sha256 sum of src.
-func hashData(src io.Reader) (string, error) {
-	h := sha256.New()
-	if _, err := io.Copy(h, src); err != nil {
-		return "", err
-	}
-	return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
+// hashData returns the sha256 sum of data.
+func hashData(data []byte) string {
+	f := sha256.Sum256(data)
+	return "sha256:" + hex.EncodeToString(f[:])
 }

+ 11 - 11
libnetwork/resolvconf/utils_test.go

@@ -1,18 +1,18 @@
 package resolvconf
 
-import (
-	"strings"
-	"testing"
-)
+import "testing"
 
 func TestHashData(t *testing.T) {
-	reader := strings.NewReader("hash-me")
-	actual, err := hashData(reader)
-	if err != nil {
-		t.Fatal(err)
-	}
-	expected := "sha256:4d11186aed035cc624d553e10db358492c84a7cd6b9670d92123c144930450aa"
-	if actual != expected {
+	const expected = "sha256:4d11186aed035cc624d553e10db358492c84a7cd6b9670d92123c144930450aa"
+	if actual := hashData([]byte("hash-me")); actual != expected {
 		t.Fatalf("Expecting %s, got %s", expected, actual)
 	}
 }
+
+func BenchmarkHashData(b *testing.B) {
+	b.ReportAllocs()
+	data := []byte("hash-me")
+	for i := 0; i < b.N; i++ {
+		_ = hashData(data)
+	}
+}