mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-10-16 00:49:57 +00:00
Stats endpoints read hourly rollup tables filled once per closed hour by one advisory-locked task, instead of materialized views that re-scanned every observation on each refresh. IATA-set tables give exact distinct counts for any IATA set or region. Cleanup holds raw rows for unrolled hours (up to 24h). Adds /stats/series; ingest keeps packet observation counts, observer last IATA, channel message counts and trace tag summaries. 001_baseline.sql is rewritten, so pre-release 2.0 databases must be recreated. See docs/historical-stats.md.
65 lines
1.7 KiB
Go
65 lines
1.7 KiB
Go
// Copyright 2026 Beacon Contributors
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
sqlc "github.com/MeshCore-Beacon/beacon-server/db/sqlc"
|
|
"github.com/MeshCore-Beacon/beacon-server/internal/api"
|
|
)
|
|
|
|
func (s *Store) GetStatsSeries(ctx context.Context, since, until time.Time, iatas []string) (*api.StatsSeries, error) {
|
|
// Read the revision first: a roll landing mid-request then shows up as a newer revision next time.
|
|
rev, err := s.q.GetAnalyticsRevision(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
earliest, err := s.q.GetEarliestCompleteRollupHour(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rows, err := s.q.GetStatsSeries(ctx, sqlc.GetStatsSeriesParams{Since: ts(since), Until: ts(until), Iatas: iatas})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := &api.StatsSeries{
|
|
Since: since.UnixMilli(),
|
|
Until: until.UnixMilli(),
|
|
Revision: rev,
|
|
Hours: make([]api.StatsSeriesHour, 0, len(rows)),
|
|
}
|
|
if earliest.Valid {
|
|
ms := earliest.Time.UnixMilli()
|
|
out.EarliestComplete = &ms
|
|
}
|
|
for _, r := range rows {
|
|
v := api.StatsSeriesValues{
|
|
Observations: r.Observations,
|
|
UniquePackets: r.UniquePackets,
|
|
ActiveObservers: r.ActiveObservers,
|
|
ActiveIATAs: r.ActiveIatas,
|
|
ScopedPackets: r.ScopedPackets,
|
|
ActiveScopes: r.ActiveScopes,
|
|
MaxPathEntries: r.MaxPathEntries,
|
|
SNRSum: r.SnrSum,
|
|
SNRSamples: r.SnrSamples,
|
|
RSSISum: r.RssiSum,
|
|
RSSISamples: r.RssiSamples,
|
|
}
|
|
if !r.Hour.Valid {
|
|
out.Summary = v
|
|
continue
|
|
}
|
|
h := api.StatsSeriesHour{Hour: r.Hour.Time.UnixMilli(), Status: r.Status}
|
|
if r.Status == "complete" {
|
|
h.Values = &v
|
|
out.CompleteHours++
|
|
}
|
|
out.Hours = append(out.Hours, h)
|
|
}
|
|
return out, nil
|
|
}
|