tailscale/util
Joe Tsai d145c594ad
util/deephash: improve cycle detection (#2470)
The previous algorithm used a map of all visited pointers.
The strength of this approach is that it quickly prunes any nodes
that we have ever visited before. The detriment of the approach
is that pruning is heavily dependent on the order that pointers
were visited. This is especially relevant for hashing a map
where map entries are visited in a non-deterministic manner,
which would cause the map hash to be non-deterministic
(which defeats the point of a hash).

This new algorithm uses a stack of all visited pointers,
similar to how github.com/google/go-cmp performs cycle detection.
When we visit a pointer, we push it onto the stack, and when
we leave a pointer, we pop it from the stack.
Before visiting a pointer, we first check whether the pointer exists
anywhere in the stack. If yes, then we prune the node.
The detriment of this approach is that we may hash a node more often
than before since we do not prune as aggressively.

The set of visited pointers up until any node is only the
path of nodes up to that node and not any other pointers
that may have been visited elsewhere. This provides us
deterministic hashing regardless of visit order.
We can now delete hashMapFallback and associated complexity,
which only exists because the previous approach was non-deterministic
in the presence of cycles.

This fixes a failure of the old algorithm where obviously different
values are treated as equal because the pruning was too aggresive.
See https://github.com/tailscale/tailscale/issues/2443#issuecomment-883653534

The new algorithm is slightly slower since it prunes less aggresively:
	name              old time/op    new time/op    delta
	Hash-8              66.1µs ± 1%    68.8µs ± 1%   +4.09%        (p=0.000 n=19+19)
	HashMapAcyclic-8    63.0µs ± 1%    62.5µs ± 1%   -0.76%        (p=0.000 n=18+19)
	TailcfgNode-8       9.79µs ± 2%    9.88µs ± 1%   +0.95%        (p=0.000 n=19+17)
	HashArray-8          643ns ± 1%     653ns ± 1%   +1.64%        (p=0.000 n=19+19)
However, a slower but more correct algorithm seems
more favorable than a faster but incorrect algorithm.

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
2021-07-22 15:22:48 -07:00
..
cibuild wgengine/magicsock: increase legacy ping timeout again 2021-02-10 13:50:18 -08:00
cmpver util/cmpver: move into OSS from corp repo. 2021-04-23 20:55:45 -07:00
deephash util/deephash: improve cycle detection (#2470) 2021-07-22 15:22:48 -07:00
dnsname util/dnsname: make ToFQDN take exactly 0 or 1 allocs for everything. 2021-05-31 21:13:50 -07:00
endian util/endian: add Native variable to get the platform's native binary.ByteOrder 2020-11-17 13:49:24 -08:00
groupmember cmd/tailscale/web: add support for QNAP 2021-06-10 19:06:05 +05:00
jsonutil util/jsonutil: new package 2020-11-19 13:58:35 -08:00
lineread util/lineread: add docs to Reader 2020-11-19 12:14:58 -08:00
osshare ipn/ipnlocal: add file sharing to windows shell 2021-04-23 13:32:33 -07:00
pidowner util/pidowner: add missing copyright header 2020-09-11 08:57:10 -07:00
racebuild util/racebuild: add package to export a race-is-enabled const 2020-11-16 10:11:53 -08:00
systemd util/systemd: explicitly check for os.ErrNotExist from sdnotify 2021-02-27 19:03:16 -08:00
uniq util/uniq: add new package 2020-10-02 11:00:56 -07:00
winutil net/dns: do not run wsl.exe as LocalSystem 2021-06-30 10:11:33 -07:00