in depth fix of deletion/creation data
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-01-23 13:02:58 +11:00
parent 2caf2763f6
commit b4a3c0fb3a
4 changed files with 124 additions and 26 deletions

View File

@@ -1079,14 +1079,15 @@ type totalsPoint struct {
func buildHourlyTotals(ctx context.Context, dbConn *sqlx.DB, records []SnapshotRecord) ([]totalsPoint, error) {
type hourBucket struct {
samples int
vmSum float64
vcpuSum float64
ramSum float64
tinSum float64
bronzeSum float64
silverSum float64
goldSum float64
samples int
vmSum float64
vcpuSum float64
ramSum float64
presenceSum float64
tinSum float64
bronzeSum float64
silverSum float64
goldSum float64
}
buckets := make(map[int64]*hourBucket)
@@ -1107,19 +1108,35 @@ func buildHourlyTotals(ctx context.Context, dbConn *sqlx.DB, records []SnapshotR
continue
}
}
hourStart := record.SnapshotTime.Local().Truncate(time.Hour)
hourStartUnix := hourStart.Unix()
hourEndUnix := hourStart.Add(time.Hour).Unix()
durationSeconds := float64(hourEndUnix - hourStartUnix)
startExpr := `CASE WHEN "CreationTime" IS NOT NULL AND "CreationTime" > 0 AND "CreationTime" > ? THEN "CreationTime" ELSE ? END`
endExpr := `CASE WHEN "DeletionTime" IS NOT NULL AND "DeletionTime" > 0 AND "DeletionTime" < ? THEN "DeletionTime" ELSE ? END`
overlapExpr := fmt.Sprintf(`CASE WHEN %s > %s THEN (CAST((%s - %s) AS REAL) / ?) ELSE 0 END`, endExpr, startExpr, endExpr, startExpr)
query := fmt.Sprintf(`
SELECT
COUNT(DISTINCT "VmId") AS vm_count,
COALESCE(SUM(CASE WHEN "VcpuCount" IS NOT NULL THEN "VcpuCount" ELSE 0 END), 0) AS vcpu_total,
COALESCE(SUM(CASE WHEN "RamGB" IS NOT NULL THEN "RamGB" ELSE 0 END), 0) AS ram_total,
1.0 AS presence_ratio,
COALESCE(SUM(CASE WHEN LOWER("ResourcePool") = 'tin' THEN 1 ELSE 0 END), 0) AS tin_total,
COALESCE(SUM(CASE WHEN LOWER("ResourcePool") = 'bronze' THEN 1 ELSE 0 END), 0) AS bronze_total,
COALESCE(SUM(CASE WHEN LOWER("ResourcePool") = 'silver' THEN 1 ELSE 0 END), 0) AS silver_total,
COALESCE(SUM(CASE WHEN LOWER("ResourcePool") = 'gold' THEN 1 ELSE 0 END), 0) AS gold_total
FROM %s
WHERE %s
`, record.TableName, templateExclusionFilter())
COALESCE(SUM(presence), 0) AS presence_ratio,
COALESCE(SUM(CASE WHEN pool = 'tin' THEN presence ELSE 0 END), 0) AS tin_total,
COALESCE(SUM(CASE WHEN pool = 'bronze' THEN presence ELSE 0 END), 0) AS bronze_total,
COALESCE(SUM(CASE WHEN pool = 'silver' THEN presence ELSE 0 END), 0) AS silver_total,
COALESCE(SUM(CASE WHEN pool = 'gold' THEN presence ELSE 0 END), 0) AS gold_total
FROM (
SELECT
"VmId",
"VcpuCount",
"RamGB",
LOWER(COALESCE("ResourcePool", '')) AS pool,
%s AS presence
FROM %s
WHERE %s
) t
`, overlapExpr, record.TableName, templateExclusionFilter())
query = dbConn.Rebind(query)
var row struct {
VmCount int64 `db:"vm_count"`
VcpuTotal int64 `db:"vcpu_total"`
@@ -1130,10 +1147,17 @@ WHERE %s
SilverTotal float64 `db:"silver_total"`
GoldTotal float64 `db:"gold_total"`
}
if err := dbConn.GetContext(ctx, &row, query); err != nil {
args := []interface{}{
hourEndUnix, hourEndUnix,
hourStartUnix, hourStartUnix,
hourEndUnix, hourEndUnix,
hourStartUnix, hourStartUnix,
durationSeconds,
}
if err := dbConn.GetContext(ctx, &row, query, args...); err != nil {
return nil, err
}
hourKey := record.SnapshotTime.Local().Truncate(time.Hour).Unix()
hourKey := hourStartUnix
bucket := buckets[hourKey]
if bucket == nil {
bucket = &hourBucket{}
@@ -1143,6 +1167,7 @@ WHERE %s
bucket.vmSum += float64(row.VmCount)
bucket.vcpuSum += float64(row.VcpuTotal)
bucket.ramSum += float64(row.RamTotal)
bucket.presenceSum += row.PresenceRatio
bucket.tinSum += row.TinTotal
bucket.bronzeSum += row.BronzeTotal
bucket.silverSum += row.SilverTotal
@@ -1163,16 +1188,31 @@ WHERE %s
}
denom := float64(bucket.samples)
vmAvg := bucket.vmSum / denom
presenceAvg := bucket.presenceSum / denom
tinAvg := bucket.tinSum / denom
bronzeAvg := bucket.bronzeSum / denom
silverAvg := bucket.silverSum / denom
goldAvg := bucket.goldSum / denom
slog.Debug(
"hourly totals bucket",
"hour_start", time.Unix(key, 0).Local().Format("2006-01-02 15:00"),
"samples", bucket.samples,
"presence_ratio", presenceAvg,
"tin_total", tinAvg,
"bronze_total", bronzeAvg,
"silver_total", silverAvg,
"gold_total", goldAvg,
)
points = append(points, totalsPoint{
Label: time.Unix(key, 0).Local().Format("2006-01-02 15:00"),
VmCount: vmAvg,
VcpuTotal: bucket.vcpuSum / denom,
RamTotal: bucket.ramSum / denom,
PresenceRatio: vmAvg,
TinTotal: bucket.tinSum / denom,
BronzeTotal: bucket.bronzeSum / denom,
SilverTotal: bucket.silverSum / denom,
GoldTotal: bucket.goldSum / denom,
PresenceRatio: presenceAvg,
TinTotal: tinAvg,
BronzeTotal: bronzeAvg,
SilverTotal: silverAvg,
GoldTotal: goldAvg,
})
}
return points, nil