mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-10-22 21:11:26 +00:00
feat(db): retain 30-day analytics independently of packet expiry (#167)
This commit is contained in:
1 parent
db30c9b573
commit
fd7c6b3eb7
10 files changed
+1108
-34
No files matched your search
@@ -16,6 +16,164 @@ type Account struct {
|
||||
DeactivatedAt pgtype.Timestamptz `json:"deactivated_at"`
|
||||
}
|
||||
|
||||
type AnalyticsHourlyIataStat struct {
|
||||
Iata string `json:"iata"`
|
||||
Hour pgtype.Timestamptz `json:"hour"`
|
||||
ObservationCount int64 `json:"observation_count"`
|
||||
UniquePackets int64 `json:"unique_packets"`
|
||||
}
|
||||
|
||||
type AnalyticsLiveHourlyIataStat struct {
|
||||
Iata string `json:"iata"`
|
||||
Hour pgtype.Timestamptz `json:"hour"`
|
||||
ObservationCount int64 `json:"observation_count"`
|
||||
UniquePackets int64 `json:"unique_packets"`
|
||||
}
|
||||
|
||||
type AnalyticsLiveObserverActivityHourly struct {
|
||||
ObserverID uuid.UUID `json:"observer_id"`
|
||||
PayloadType int16 `json:"payload_type"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
Observations int64 `json:"observations"`
|
||||
AirtimeMs float32 `json:"airtime_ms"`
|
||||
AirtimeN int64 `json:"airtime_n"`
|
||||
SnrSum float32 `json:"snr_sum"`
|
||||
SnrN int64 `json:"snr_n"`
|
||||
SnrMin float32 `json:"snr_min"`
|
||||
RssiSum int64 `json:"rssi_sum"`
|
||||
RssiN int64 `json:"rssi_n"`
|
||||
}
|
||||
|
||||
type AnalyticsLivePathStatsHourly struct {
|
||||
Iata string `json:"iata"`
|
||||
Hour interface{} `json:"hour"`
|
||||
Category int32 `json:"category"`
|
||||
HashBytes int32 `json:"hash_bytes"`
|
||||
Entries int32 `json:"entries"`
|
||||
Receptions int64 `json:"receptions"`
|
||||
}
|
||||
|
||||
type AnalyticsLivePayloadBreakdownByIatum struct {
|
||||
Iata string `json:"iata"`
|
||||
PayloadType *int16 `json:"payload_type"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
type AnalyticsLiveSignalStatsHourly struct {
|
||||
Iata string `json:"iata"`
|
||||
Hour interface{} `json:"hour"`
|
||||
Kind int32 `json:"kind"`
|
||||
SnrBin int32 `json:"snr_bin"`
|
||||
RssiBin int32 `json:"rssi_bin"`
|
||||
Receptions int64 `json:"receptions"`
|
||||
SnrSamples int64 `json:"snr_samples"`
|
||||
SnrSum float64 `json:"snr_sum"`
|
||||
RssiSamples int64 `json:"rssi_samples"`
|
||||
RssiSum float64 `json:"rssi_sum"`
|
||||
}
|
||||
|
||||
type AnalyticsLiveTopAdvertisersByIatum struct {
|
||||
Iata string `json:"iata"`
|
||||
NodeID uuid.UUID `json:"node_id"`
|
||||
Name *string `json:"name"`
|
||||
NodeType int16 `json:"node_type"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
AdvertCount int64 `json:"advert_count"`
|
||||
FloodAdvertCount int64 `json:"flood_advert_count"`
|
||||
DirectAdvertCount int64 `json:"direct_advert_count"`
|
||||
LastHeard interface{} `json:"last_heard"`
|
||||
}
|
||||
|
||||
type AnalyticsLiveTopObserversByIatum struct {
|
||||
Iata string `json:"iata"`
|
||||
ObserverID uuid.UUID `json:"observer_id"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
ObserverType *string `json:"observer_type"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
ObservationCount int64 `json:"observation_count"`
|
||||
}
|
||||
|
||||
type AnalyticsLiveTopTalkersByIatum struct {
|
||||
Iata string `json:"iata"`
|
||||
SenderName *string `json:"sender_name"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
MessageCount int64 `json:"message_count"`
|
||||
LastSent interface{} `json:"last_sent"`
|
||||
}
|
||||
|
||||
type AnalyticsObserverActivityHourly struct {
|
||||
ObserverID uuid.UUID `json:"observer_id"`
|
||||
PayloadType int16 `json:"payload_type"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
Observations int64 `json:"observations"`
|
||||
AirtimeMs *float32 `json:"airtime_ms"`
|
||||
AirtimeN int64 `json:"airtime_n"`
|
||||
SnrSum *float32 `json:"snr_sum"`
|
||||
SnrN int64 `json:"snr_n"`
|
||||
SnrMin *float32 `json:"snr_min"`
|
||||
RssiSum *int64 `json:"rssi_sum"`
|
||||
RssiN int64 `json:"rssi_n"`
|
||||
}
|
||||
|
||||
type AnalyticsPathStatsHourly struct {
|
||||
Iata string `json:"iata"`
|
||||
Hour pgtype.Timestamptz `json:"hour"`
|
||||
Category int32 `json:"category"`
|
||||
HashBytes int32 `json:"hash_bytes"`
|
||||
Entries int32 `json:"entries"`
|
||||
Receptions int64 `json:"receptions"`
|
||||
}
|
||||
|
||||
type AnalyticsPayloadBreakdownByIatum struct {
|
||||
Iata string `json:"iata"`
|
||||
PayloadType int16 `json:"payload_type"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
type AnalyticsSignalStatsHourly struct {
|
||||
Iata string `json:"iata"`
|
||||
Hour pgtype.Timestamptz `json:"hour"`
|
||||
Kind int32 `json:"kind"`
|
||||
SnrBin int32 `json:"snr_bin"`
|
||||
RssiBin int32 `json:"rssi_bin"`
|
||||
Receptions int64 `json:"receptions"`
|
||||
SnrSamples int64 `json:"snr_samples"`
|
||||
SnrSum *float64 `json:"snr_sum"`
|
||||
RssiSamples int64 `json:"rssi_samples"`
|
||||
RssiSum *float64 `json:"rssi_sum"`
|
||||
}
|
||||
|
||||
type AnalyticsTopAdvertisersByIatum struct {
|
||||
Iata string `json:"iata"`
|
||||
NodeID uuid.UUID `json:"node_id"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
AdvertCount int64 `json:"advert_count"`
|
||||
FloodAdvertCount int64 `json:"flood_advert_count"`
|
||||
DirectAdvertCount int64 `json:"direct_advert_count"`
|
||||
LastHeard pgtype.Timestamptz `json:"last_heard"`
|
||||
Name *string `json:"name"`
|
||||
NodeType *int16 `json:"node_type"`
|
||||
}
|
||||
|
||||
type AnalyticsTopObserversByIatum struct {
|
||||
Iata string `json:"iata"`
|
||||
ObserverID uuid.UUID `json:"observer_id"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
ObservationCount int64 `json:"observation_count"`
|
||||
DisplayName *string `json:"display_name"`
|
||||
ObserverType *string `json:"observer_type"`
|
||||
}
|
||||
|
||||
type AnalyticsTopTalkersByIatum struct {
|
||||
Iata string `json:"iata"`
|
||||
SenderName string `json:"sender_name"`
|
||||
Bucket pgtype.Timestamptz `json:"bucket"`
|
||||
MessageCount int64 `json:"message_count"`
|
||||
LastSent pgtype.Timestamptz `json:"last_sent"`
|
||||
}
|
||||
|
||||
type Channel struct {
|
||||
ID int32 `json:"id"`
|
||||
ChannelHash []byte `json:"channel_hash"`
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ type Querier interface {
|
||||
// Opt-in age-out: preserve retained history and manually recorded ownership.
|
||||
// Bound deletions per cleanup tick and skip observers being updated by ingest.
|
||||
DeleteOldObservers(ctx context.Context, lastSeen pgtype.Timestamptz) ([]uuid.UUID, error)
|
||||
// One batch of expired packets; observations and channel messages cascade.
|
||||
// Locks, archives and cascades one bounded packet cohort in a single transaction.
|
||||
DeleteOldPackets(ctx context.Context, arg DeleteOldPacketsParams) (int64, error)
|
||||
// One batch of routes past retention, or past grace with too few observations.
|
||||
// GREATEST keeps the scan on idx_known_routes_last_seen.
|
||||
|
||||
+7
-17
@@ -124,17 +124,8 @@ func (q *Queries) DeleteOldObservers(ctx context.Context, lastSeen pgtype.Timest
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const deleteOldPackets = `-- name: DeleteOldPackets :execrows
|
||||
WITH expired AS (
|
||||
SELECT ep.packet_hash
|
||||
FROM packets ep
|
||||
WHERE ep.last_heard_at < $1
|
||||
ORDER BY ep.last_heard_at
|
||||
LIMIT $2
|
||||
FOR UPDATE OF ep SKIP LOCKED
|
||||
)
|
||||
DELETE FROM packets p USING expired e
|
||||
WHERE p.packet_hash = e.packet_hash
|
||||
const deleteOldPackets = `-- name: DeleteOldPackets :one
|
||||
SELECT archive_delete_packets($1::timestamptz, $2::integer)::bigint
|
||||
`
|
||||
|
||||
type DeleteOldPacketsParams struct {
|
||||
@@ -142,13 +133,12 @@ type DeleteOldPacketsParams struct {
|
||||
BatchSize int32 `json:"batch_size"`
|
||||
}
|
||||
|
||||
// One batch of expired packets; observations and channel messages cascade.
|
||||
// Locks, archives and cascades one bounded packet cohort in a single transaction.
|
||||
func (q *Queries) DeleteOldPackets(ctx context.Context, arg DeleteOldPacketsParams) (int64, error) {
|
||||
result, err := q.db.Exec(ctx, deleteOldPackets, arg.Cutoff, arg.BatchSize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.RowsAffected(), nil
|
||||
row := q.db.QueryRow(ctx, deleteOldPackets, arg.Cutoff, arg.BatchSize)
|
||||
var column_1 int64
|
||||
err := row.Scan(&column_1)
|
||||
return column_1, err
|
||||
}
|
||||
|
||||
const deleteOldRoutes = `-- name: DeleteOldRoutes :execrows
|
||||
|
||||
Reference in new issue
Block a user