diff --git a/control/controlclient/netmap.go b/control/controlclient/netmap.go index d9e9d76cf..71c00f90c 100644 --- a/control/controlclient/netmap.go +++ b/control/controlclient/netmap.go @@ -10,6 +10,7 @@ import ( "encoding/json" "fmt" "log" + "reflect" "strings" "time" @@ -83,11 +84,12 @@ func (nm *NetworkMap) Concise() string { for i, e := range p.Endpoints { // Align vertically on the ':' between IP and port colon := strings.IndexByte(e, ':') - for colon > 0 && len(e)-colon < 6 { - e += " " + spaces := 0 + for colon > 0 && len(e)+spaces-colon < 6 { + spaces++ colon-- } - ep[i] = fmt.Sprintf("%21v", e) + ep[i] = fmt.Sprintf("%21v", e+strings.Repeat(" ", spaces)) } derp := p.DERP @@ -108,6 +110,10 @@ func (nm *NetworkMap) Concise() string { } func (b *NetworkMap) ConciseDiffFrom(a *NetworkMap) string { + if reflect.DeepEqual(a, b) { + // Fast path that only does one allocation. + return "" + } out := []string{} ra := strings.Split(a.Concise(), "\n") rb := strings.Split(b.Concise(), "\n") diff --git a/control/controlclient/netmap_test.go b/control/controlclient/netmap_test.go new file mode 100644 index 000000000..93f511b75 --- /dev/null +++ b/control/controlclient/netmap_test.go @@ -0,0 +1,36 @@ +// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package controlclient + +import ( + "testing" + + "tailscale.com/tailcfg" +) + +func TestNetworkMapConcise(t *testing.T) { + nm := &NetworkMap{ + Peers: []*tailcfg.Node{ + { + Name: "foo", + Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"}, + }, + { + Name: "bar", + Endpoints: []string{"10.2.0.100:12", "10.1.0.100:12345"}, + }, + }, + } + var got string + n := int(testing.AllocsPerRun(1000, func() { + got = nm.Concise() + })) + t.Logf("Allocs = %d", n) + want := "netmap: self: [AAAAA] auth=machine-unknown :0 []\n" + + " [AAAAA] : 192.168.0.100:12 192.168.0.100:12354\n [AAAAA] : 10.2.0.100:12 10.1.0.100:12345\n" + if got != want { + t.Errorf("Wrong output\n Got: %q\nWant: %q\n## Got (unescaped):\n%s\n## Want (unescaped):\n%s\n", got, want, got, want) + } +}