Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions cmd/ingestor/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,45 @@ type RetentionConfig struct {
// coverage rows in client_receptions / client_observers; 0 disables. Bounds
// the table the opt-in coverage feature would otherwise grow without limit.
ClientRxDays int `json:"clientRxDays"`
// The opt-in windows below cover the tables nothing else prunes (#329);
// 0 disables each. See TableRetention.
InactiveNodeDays int `json:"inactiveNodeDays"`
NodeChangeDays int `json:"nodeChangeDays"`
ObserverPurgeDays int `json:"observerPurgeDays"`
}

// TableRetention holds the opt-in retention windows, in days, of the tables
// nothing else prunes (#329). 0 disables a window, so an instance that sets
// none of them keeps every row, as before. ping_triggers has no window and is
// kept forever: the all-time Ping Scores records join it with the history
// sidecar (#349, #241).
type TableRetention struct {
// InactiveNodeDays deletes inactive_nodes rows whose last advert is
// older, once the node has not come back.
InactiveNodeDays int
// NodeChangeDays deletes node_changes rows detected longer ago.
NodeChangeDays int
// ObserverPurgeDays hard-deletes observers that observerDays already
// soft-deleted, once nothing still references them (upstream#1886).
ObserverPurgeDays int
}

// Enabled reports whether any window is set.
func (r TableRetention) Enabled() bool {
return r.InactiveNodeDays > 0 || r.NodeChangeDays > 0 || r.ObserverPurgeDays > 0
}

// TableRetention returns the configured opt-in table retention windows,
// with unset and negative values as 0 (disabled).
func (c *Config) TableRetention() TableRetention {
if c.Retention == nil {
return TableRetention{}
}
return TableRetention{
InactiveNodeDays: max(c.Retention.InactiveNodeDays, 0),
NodeChangeDays: max(c.Retention.NodeChangeDays, 0),
ObserverPurgeDays: max(c.Retention.ObserverPurgeDays, 0),
}
}

// PacketDaysOrZero returns the configured retention.packetDays or 0
Expand Down
17 changes: 16 additions & 1 deletion cmd/ingestor/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,17 @@ func main() {
}
}

// Opt-in retention for the tables nothing else prunes (#329): after the
// observer soft-delete and the metrics and transmission prunes above, so
// the observer purge's reference guards see what they left. Every window
// unset (the default) = nothing deleted.
tableRetention := cfg.TableRetention()
if r := tableRetention; r.Enabled() {
log.Printf("[prune] table retention enabled (0 = off): inactiveNodeDays=%d nodeChangeDays=%d observerPurgeDays=%d",
r.InactiveNodeDays, r.NodeChangeDays, r.ObserverPurgeDays)
}
runTableRetention(store, tableRetention, "startup")

vacuumPages := cfg.IncrementalVacuumPages()
store.RunIncrementalVacuum(vacuumPages)

Expand Down Expand Up @@ -308,14 +319,18 @@ func main() {
}
}()

// Daily ticker for observer retention (every 24h, staggered 90s after startup)
// Daily ticker for observer retention (every 24h, staggered 90s after
// startup), followed by the opt-in table retention (#329), whose observer
// purge must follow the soft-delete.
observerRetentionTicker := time.NewTicker(24 * time.Hour)
go func() {
time.Sleep(90 * time.Second) // stagger after metrics prune
store.RemoveStaleObservers(observerDays)
runTableRetention(store, tableRetention, "daily")
store.RunIncrementalVacuum(vacuumPages)
for range observerRetentionTicker.C {
store.RemoveStaleObservers(observerDays)
runTableRetention(store, tableRetention, "daily")
store.RunIncrementalVacuum(vacuumPages)
}
}()
Expand Down
Loading
Loading