ipn/ipnlocal, tka: compact TKA state after every sync

Previously a TKA compaction would only run when a node starts, which means a long-running node could use unbounded storage as it accumulates ever-increasing amounts of TKA state. This patch changes TKA so it runs a compaction after every sync.

Updates https://github.com/tailscale/corp/issues/33537

Change-Id: I91df887ea0c5a5b00cb6caced85aeffa2a4b24ee
Signed-off-by: Alex Chan <alexc@tailscale.com>
This commit is contained in:
Alex Chan
2025-11-17 16:38:57 +00:00
committed by Alex Chan
parent 38ccdbe35c
commit e1dd9222d4
10 changed files with 276 additions and 31 deletions
+21 -1
View File
@@ -19,6 +19,8 @@ import (
"github.com/fxamacker/cbor/v2"
"tailscale.com/atomicfile"
"tailscale.com/tstime"
"tailscale.com/util/testenv"
)
// Chonk implementations provide durable storage for AUMs and other
@@ -92,6 +94,7 @@ type Mem struct {
mu sync.RWMutex
aums map[AUMHash]AUM
commitTimes map[AUMHash]time.Time
clock tstime.Clock
// parentIndex is a map of AUMs to the AUMs for which they are
// the parent.
@@ -103,6 +106,23 @@ type Mem struct {
lastActiveAncestor *AUMHash
}
// ChonkMem returns an implementation of Chonk which stores TKA state
// in-memory.
func ChonkMem() *Mem {
return &Mem{
clock: tstime.DefaultClock{},
}
}
// SetClock sets the clock used by [Mem]. This is only for use in tests,
// and will panic if called from non-test code.
func (c *Mem) SetClock(clock tstime.Clock) {
if !testenv.InTest() {
panic("used SetClock in non-test code")
}
c.clock = clock
}
func (c *Mem) SetLastActiveAncestor(hash AUMHash) error {
c.mu.Lock()
defer c.mu.Unlock()
@@ -173,7 +193,7 @@ updateLoop:
for _, aum := range updates {
aumHash := aum.Hash()
c.aums[aumHash] = aum
c.commitTimes[aumHash] = time.Now()
c.commitTimes[aumHash] = c.clock.Now()
parent, ok := aum.Parent()
if ok {