You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailscale/util
Joe Tsai 539c5e44c5
util/deephash: always keep values addressable (#5328)
The logic of deephash is both simpler and easier to reason about
if values are always addressable.

In Go, the composite kinds are slices, arrays, maps, structs,
interfaces, pointers, channels, and functions,
where we define "composite" as a Go value that encapsulates
some other Go value (e.g., a map is a collection of key-value entries).

In the cases of pointers and slices, the sub-values are always addressable.

In the cases of arrays and structs, the sub-values are always addressable
if and only if the parent value is addressable.

In the case of maps and interfaces, the sub-values are never addressable.
To make them addressable, we need to copy them onto the heap.

For the purposes of deephash, we do not care about channels and functions.

For all non-composite kinds (e.g., strings and ints), they are only addressable
if obtained from one of the composite kinds that produce addressable values
(i.e., pointers, slices, addressable arrays, and addressable structs).
A non-addressible, non-composite kind can be made addressable by
allocating it on the heap, obtaining a pointer to it, and dereferencing it.

Thus, if we can ensure that values are addressable at the entry points,
and shallow copy sub-values whenever we encounter an interface or map,
then we can ensure that all values are always addressable and
assume such property throughout all the logic.

Performance:

	name                 old time/op    new time/op    delta
	Hash-24                21.5µs ± 1%    19.7µs ± 1%  -8.29%  (p=0.000 n=9+9)
	HashPacketFilter-24    2.61µs ± 1%    2.62µs ± 0%  +0.29%  (p=0.037 n=10+9)
	HashMapAcyclic-24      30.8µs ± 1%    30.9µs ± 1%    ~     (p=0.400 n=9+10)
	TailcfgNode-24         1.84µs ± 1%    1.84µs ± 2%    ~     (p=0.928 n=10+10)
	HashArray-24            324ns ± 2%     332ns ± 2%  +2.45%  (p=0.000 n=10+10)

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
3 years ago
..
cibuild all: use cibuild.On 4 years ago
clientmetric all: gofmt for Go 1.19 3 years ago
cloudenv all: use syncs.AtomicValue 3 years ago
cmpver util/cmpver: move into OSS from corp repo. 5 years ago
codegen all: convert more code to use net/netip directly 3 years ago
deephash util/deephash: always keep values addressable (#5328) 3 years ago
dnsname all: use Go 1.18's strings.Cut 4 years ago
endian all: gofmt with Go 1.17 4 years ago
groupmember util/groupmember: remove redundant code (#4298) 4 years ago
jsonutil all: use any instead of interface{} 4 years ago
lineread util/lineread: add docs to Reader 5 years ago
mak util/mak: move tailssh's mapSet into a new package for reuse elsewhere 4 years ago
multierr all: gofmt for Go 1.19 3 years ago
must util/must: rename Do->Get, add Do 3 years ago
osshare all: gofmt with Go 1.17 4 years ago
pidowner all: gofmt with Go 1.17 4 years ago
precompress cmd/tsconnect,util/precompress: move precompression to its own package 3 years ago
racebuild all: gofmt with Go 1.17 4 years ago
singleflight all: gofmt for Go 1.19 3 years ago
strs util/strs: add new package for string utility funcs 3 years ago
systemd all: gofmt for Go 1.19 3 years ago
uniq all: use any instead of interface{} 4 years ago
winutil net/dns, paths, util/winutil: change net/dns/windowsManager NRPT management to support more than 50 domains. 4 years ago