Documentation
¶
Overview ¶
Package state owns the agent's authoritative cumulative counters, keyed by bpf.FlowKey — the staging area between the scraper, which feeds raw kernel readings, and the metrics Collector, which emits cumulatives to Prometheus.
Three invariants a caller must not break:
- Delta math compares the entry-identity stamp, never counter magnitudes. See GlobalState.ApplyDelta.
- A row whose attribution is about to change or die is folded via GlobalState.Settle first, or its whole history re-buckets at the next scrape.
- Every reader takes one lock across live rows AND settled buckets. A snapshot torn across a fold double-counts or drops the bytes.
docs/architecture/contracts.md#required-contracts
Index ¶
- func AddDelta(total, lastRaw *uint64, current uint64)
- type Counter
- type Entry
- type GlobalState
- func (g *GlobalState) Add(key bpf.FlowKey, m bpf.FlowMetrics)
- func (g *GlobalState) ApplyDelta(key bpf.FlowKey, raw bpf.FlowMetrics)
- func (g *GlobalState) Len() int
- func (g *GlobalState) PruneServerSettled(alive map[string]struct{}) int
- func (g *GlobalState) PruneTenantSettled(alive map[string]struct{}) int
- func (g *GlobalState) Resolve(key bpf.FlowKey, total, lastRaw bpf.FlowMetrics)
- func (g *GlobalState) Restore(records []Record)
- func (g *GlobalState) RestoreServerSettled(records []ServerSettledRecord)
- func (g *GlobalState) RestoreTenantSettled(records []TenantSettledRecord)
- func (g *GlobalState) RestoreTotalSettled(records []TotalSettledRecord)
- func (g *GlobalState) ServerSettledLen() int
- func (g *GlobalState) Settle(mode SettleMode, ...) int
- func (g *GlobalState) Snapshot(dst []Entry) []Entry
- func (g *GlobalState) SnapshotForWAL(flows []Record, settled []TenantSettledRecord, ...) ([]Record, []TenantSettledRecord, []ServerSettledRecord, []TotalSettledRecord)
- func (g *GlobalState) SnapshotWithSettled(flows []Entry, settled []TenantSettledRecord, ...) ([]Entry, []TenantSettledRecord, []ServerSettledRecord, []TotalSettledRecord)
- func (g *GlobalState) TenantSettledLen() int
- func (g *GlobalState) TotalSettledLen() int
- type Record
- type ServerSettledKey
- type ServerSettledRecord
- type SettleMode
- type TenantSettledKey
- type TenantSettledRecord
- type TotalSettledKey
- type TotalSettledRecord
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddDelta ¶
AddDelta integrates a raw counter into a cumulative total. current < lastRaw is treated as a kernel-side reset: the new current is itself the delta, not (max_u64 − lastRaw + current) (Implementation Contract #5, the u64 wraparound guard). Exported so the UnresolvedBuffer (internal/unresolved) computes per-scrape deltas for buffered flows with the identical guard rather than a second copy that could drift.
Types ¶
type Counter ¶
type Counter struct {
// Total is the agent-side cumulative — bytes and packets since
// the flow was first observed, surviving kernel evictions and,
// once a WAL is in place, agent restarts.
Total bpf.FlowMetrics
// LastEbpfRaw is the most recent raw value read from the kernel.
// The next ApplyDelta computes Δ = current − LastEbpfRaw, then
// updates LastEbpfRaw to current.
LastEbpfRaw bpf.FlowMetrics
}
Counter holds the per-flow cumulative state plus the last raw kernel reading needed for delta math. Mutated in place by GlobalState.ApplyDelta while the write lock is held.
type Entry ¶
type Entry struct {
Key bpf.FlowKey
Total bpf.FlowMetrics
}
Entry is the value type emitted by GlobalState.Snapshot: a (key, cumulative) pair safe to use after the RLock is released.
type GlobalState ¶
type GlobalState struct {
// contains filtered or unexported fields
}
GlobalState is the agent's authoritative flow-keyed counter store plus the settled-bytes accumulators that keep an exposed series monotone after its flows stop resolving. All maps live under one mutex: Settle moves value between them, and a reader that saw only one side would lose or double-count the folded bytes.
docs/architecture/data-structures.md#settled-bytes
func (*GlobalState) Add ¶
func (g *GlobalState) Add(key bpf.FlowKey, m bpf.FlowMetrics)
Add folds m into key's cumulative without delta math, for already-computed totals (the UnresolvedBuffer's fold to "unknown"). It never touches LastEbpfRaw, so a key only ever passed to Add stays monotone. Never mix Add and ApplyDelta on one key.
docs/architecture/data-structures.md#userspace-structures
func (*GlobalState) ApplyDelta ¶
func (g *GlobalState) ApplyDelta(key bpf.FlowKey, raw bpf.FlowMetrics)
ApplyDelta integrates a raw kernel reading for one flow key. First sight of a key sets Total=LastEbpfRaw=raw (no delta). Subsequent readings increment Total by current−lastRaw, treating current<lastRaw as a kernel-side reset where current itself is the delta (Implementation Contract #5).
Hot path: zero allocations after the first sighting of each key.
func (*GlobalState) Len ¶
func (g *GlobalState) Len() int
Len returns the number of distinct flows currently tracked.
func (*GlobalState) PruneServerSettled ¶
func (g *GlobalState) PruneServerSettled(alive map[string]struct{}) int
PruneServerSettled drops buckets whose ServerID is not in alive — a server's series ends when it leaves the Nova list, never on a TTL. alive MUST come from a successful, non-empty Nova fetch; pruning on missing data ends live servers' series. Returns buckets dropped.
docs/architecture/data-structures.md#settled-bytes
func (*GlobalState) PruneTenantSettled ¶
func (g *GlobalState) PruneTenantSettled(alive map[string]struct{}) int
PruneTenantSettled releases buckets absent from alive — a settle-to-parent, not a delete: each dying bucket folds into the total absorber or lachesis_bytes_total dips. alive MUST come from a successful, non-empty Keystone fetch and MUST include metadata.UnknownTenantID.
docs/architecture/data-structures.md#settled-bytes
func (*GlobalState) Resolve ¶
func (g *GlobalState) Resolve(key bpf.FlowKey, total, lastRaw bpf.FlowMetrics)
Resolve credits a late-bound flow whose MAC just became known: it folds the buffer's accumulated total in and sets LastEbpfRaw to lastRaw. Omitting that write-back is the classic double-count — the next ApplyDelta re-counts everything total already captured.
docs/architecture/data-structures.md#userspace-structures
func (*GlobalState) Restore ¶
func (g *GlobalState) Restore(records []Record)
Restore seeds the map from records previously written to the WAL. Intended to run once at boot before any scraper or collector goroutine starts; takes the write lock defensively. Existing keys are overwritten, matching the "WAL is the source of truth on boot" contract.
func (*GlobalState) RestoreServerSettled ¶
func (g *GlobalState) RestoreServerSettled(records []ServerSettledRecord)
RestoreServerSettled seeds the server-settled accumulator from records previously written to the WAL. Same contract as GlobalState.Restore: boot-time only, existing buckets overwritten.
func (*GlobalState) RestoreTenantSettled ¶
func (g *GlobalState) RestoreTenantSettled(records []TenantSettledRecord)
RestoreTenantSettled seeds the settled accumulator from records previously written to the WAL. Same contract as GlobalState.Restore: boot-time only, existing buckets overwritten.
func (*GlobalState) RestoreTotalSettled ¶
func (g *GlobalState) RestoreTotalSettled(records []TotalSettledRecord)
RestoreTotalSettled seeds the total-settled accumulator from records previously written to the WAL. Same contract as GlobalState.Restore: boot-time only, existing buckets overwritten.
func (*GlobalState) ServerSettledLen ¶
func (g *GlobalState) ServerSettledLen() int
ServerSettledLen returns the number of server-settled buckets held.
func (*GlobalState) Settle ¶
func (g *GlobalState) Settle(mode SettleMode, resolve func(bpf.FlowKey) (tenant, extNet, server string, ok bool)) int
Settle folds every resolvable row into the settled accumulators and evicts or rebases it per mode, in ONE critical section so the exposed aggregate never changes across the fold. Call it at the last moment the attribution is knowable. extNet must already be the gated label.
docs/architecture/contracts.md#required-contracts
func (*GlobalState) Snapshot ¶
func (g *GlobalState) Snapshot(dst []Entry) []Entry
Snapshot appends every (key, Total) pair to dst and returns the resulting slice. Reusing the prior return value keeps steady-state allocations at zero; capacity grows only when the flow count exceeds the prior peak.
Holds the RLock for the full iteration (Implementation Contract #2).
func (*GlobalState) SnapshotForWAL ¶
func (g *GlobalState) SnapshotForWAL(flows []Record, settled []TenantSettledRecord, serverSettled []ServerSettledRecord, totalSettled []TotalSettledRecord) ([]Record, []TenantSettledRecord, []ServerSettledRecord, []TotalSettledRecord)
SnapshotForWAL appends flows and settled buckets under ONE RLock; same reuse contract as GlobalState.Snapshot. The combined walk is for atomicity against Settle, as in GlobalState.SnapshotWithSettled — a torn WAL snapshot persists the folded bytes twice or not at all, and a crash makes that permanent. Values are copied out, so records outlive the RLock.
func (*GlobalState) SnapshotWithSettled ¶
func (g *GlobalState) SnapshotWithSettled(flows []Entry, settled []TenantSettledRecord, serverSettled []ServerSettledRecord, totalSettled []TotalSettledRecord) ([]Entry, []TenantSettledRecord, []ServerSettledRecord, []TotalSettledRecord)
SnapshotWithSettled appends live flows and settled buckets under ONE RLock — the Collector's read path. Two snapshots would let a concurrent fold move value between them, double-counting or dropping the bytes for that exposure. Both slices follow the GlobalState.Snapshot reuse contract.
func (*GlobalState) TenantSettledLen ¶
func (g *GlobalState) TenantSettledLen() int
TenantSettledLen returns the number of settled buckets currently held.
func (*GlobalState) TotalSettledLen ¶
func (g *GlobalState) TotalSettledLen() int
TotalSettledLen returns the number of total-settled buckets held.
type Record ¶
Record is the (Key, Counter) pair the WAL round-trips. The Counter carries both Total and LastEbpfRaw, so a restored state computes deltas against the kernel's next reading without re-baselining.
INVARIANT — no kernel-internal identifiers in the WAL. FlowKey is deliberately free of the u32 tenant_id, which is re-interned every boot; adding any such ID re-keys the flow on restart and it never merges with post-restart traffic.
type ServerSettledKey ¶
type ServerSettledKey struct {
ServerID string
Tenant string
ExtNet string
Zone bpf.ZoneCode
Dir bpf.Direction
}
ServerSettledKey identifies one server-settled bucket. Unlike TenantSettledKey it KEEPS the server dimension — it is exactly the lachesis_server_bytes_total tuple, which is what makes a server's series monotone across a lost port or a re-created NIC. Released when the server leaves the Nova list.
docs/architecture/billing.md
type ServerSettledRecord ¶
type ServerSettledRecord struct {
Key ServerSettledKey
Bytes uint64
Packets uint64
}
ServerSettledRecord is one server-settled bucket's cumulative totals, emitted by the snapshot methods and round-tripped through the WAL (additive schema v4). Like TenantSettledRecord it carries no delta-math or recency fields.
type SettleMode ¶
type SettleMode int
SettleMode selects what GlobalState.Settle does with a flow row after folding its Total into the settled accumulator. The right mode is decided by whether the row's kernel telemetry_map counters still exist — see the constants.
const ( // SettleEvict deletes the folded row. Correct when the flow's // kernel counters are already gone (the ghost sweep deletes them // first), so nothing will feed the row again: a later reappearance // of the same key is a genuinely new flow whose kernel counter // restarts at zero and must re-baseline from first sight. SettleEvict SettleMode = iota // SettleRebase zeroes the folded row's Total but keeps the row and // its LastEbpfRaw. Correct when the kernel counters live on (a live // port changed tenant): the next ApplyDelta must count only bytes // arriving after the fold, not re-count the kernel cumulative that // was just settled. SettleRebase )
type TenantSettledKey ¶
TenantSettledKey identifies one settled bucket. It is exactly the tenant tier's metric label tuple, so a fold lands in the same series the live flows occupied. ExtNet must already be the gated label.
type TenantSettledRecord ¶
type TenantSettledRecord struct {
Key TenantSettledKey
Bytes uint64
Packets uint64
}
TenantSettledRecord is one settled bucket's cumulative totals, emitted by the snapshot methods and round-tripped through the WAL. TenantSettled buckets carry no LastEbpfRaw — they are past delta math by definition — and no LastSeenNs — recency belongs to live flows.
type TotalSettledKey ¶
TotalSettledKey identifies one total-settled bucket. The total family is DERIVED from the tenant tier, so a released tenant bucket folds here instead of vanishing — otherwise the immortal total series would decrease. Bounded by construction: zones × external networks × 2.
docs/architecture/billing.md
type TotalSettledRecord ¶
type TotalSettledRecord struct {
Key TotalSettledKey
Bytes uint64
Packets uint64
}
TotalSettledRecord is one total-settled bucket's cumulative totals, emitted by the snapshot methods and round-tripped through the WAL (additive schema v5). Like TenantSettledRecord it carries no delta-math or recency fields.