updated snapshots logic
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-01-28 09:47:51 +11:00
parent c566456ebd
commit b9eae50f69

View File

@@ -1145,10 +1145,35 @@ func buildHourlyTotals(ctx context.Context, logger *slog.Logger, dbConn *sqlx.DB
recordIndex = selectedIndex recordIndex = selectedIndex
continue continue
} }
var prev *SnapshotRecord
for prevIndex := selectedIndex - 1; prevIndex >= 0; prevIndex-- {
record := records[prevIndex]
if record.SnapshotTime.After(hourEnd) {
continue
}
if err := db.ValidateTableName(record.TableName); err != nil {
return nil, err
}
if record.SnapshotCount == 0 {
continue
}
if record.SnapshotCount < 0 {
rowsExist, err := db.TableHasRows(ctx, dbConn, record.TableName)
if err != nil || !rowsExist {
continue
}
}
prev = &record
break
}
recordIndex = selectedIndex recordIndex = selectedIndex
hourStartUnix := hourWindowStart.Unix() hourStartUnix := hourWindowStart.Unix()
hourEndUnix := hourEnd.Unix() hourEndUnix := hourEnd.Unix()
durationSeconds := float64(hourEndUnix - hourStartUnix) durationSeconds := float64(hourEndUnix - hourStartUnix)
prevTableName := selected.TableName
if prev != nil {
prevTableName = prev.TableName
}
startExpr := `CASE WHEN "CreationTime" IS NOT NULL AND "CreationTime" > 0 AND "CreationTime" > ? THEN "CreationTime" ELSE ? END` 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` 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) overlapExpr := fmt.Sprintf(`CASE WHEN %s > %s THEN (CAST((%s - %s) AS REAL) / ?) ELSE 0 END`, endExpr, startExpr, endExpr, startExpr)
@@ -1193,6 +1218,44 @@ lifecycle AS (
FROM vm_lifecycle_cache FROM vm_lifecycle_cache
GROUP BY vm_key GROUP BY vm_key
), ),
prev_base AS (
SELECT
%s AS vm_key,
"VcpuCount",
"RamGB",
LOWER(COALESCE("ResourcePool", '')) AS pool,
NULLIF("CreationTime", 0) AS creation_time,
NULLIF("DeletionTime", 0) AS deletion_time
FROM %s
WHERE %s
),
prev_agg AS (
SELECT
vm_key,
MAX("VcpuCount") AS "VcpuCount",
MAX("RamGB") AS "RamGB",
MAX(pool) AS pool,
MIN(creation_time) AS creation_time,
MIN(deletion_time) AS deletion_time
FROM prev_base
GROUP BY vm_key
),
missing_deleted AS (
SELECT
prev_agg.vm_key,
prev_agg."VcpuCount",
prev_agg."RamGB",
prev_agg.pool,
prev_agg.creation_time AS creation_time,
COALESCE(lifecycle.deleted_at, prev_agg.deletion_time) AS deletion_time,
%s AS presence
FROM prev_agg
LEFT JOIN lifecycle ON lifecycle.vm_key = prev_agg.vm_key
LEFT JOIN agg ON agg.vm_key = prev_agg.vm_key
WHERE agg.vm_key IS NULL
AND COALESCE(lifecycle.deleted_at, prev_agg.deletion_time, 0) > 0
AND COALESCE(lifecycle.deleted_at, prev_agg.deletion_time) > ? AND COALESCE(lifecycle.deleted_at, prev_agg.deletion_time) < ?
),
agg_presence AS ( agg_presence AS (
SELECT SELECT
agg.vm_key, agg.vm_key,
@@ -1204,6 +1267,16 @@ agg_presence AS (
%s AS presence %s AS presence
FROM agg FROM agg
LEFT JOIN lifecycle ON lifecycle.vm_key = agg.vm_key LEFT JOIN lifecycle ON lifecycle.vm_key = agg.vm_key
UNION ALL
SELECT
missing_deleted.vm_key,
missing_deleted."VcpuCount",
missing_deleted."RamGB",
missing_deleted.pool,
missing_deleted.creation_time,
missing_deleted.deletion_time,
missing_deleted.presence
FROM missing_deleted
), ),
diag AS ( diag AS (
SELECT SELECT
@@ -1253,7 +1326,7 @@ SELECT
agg_diag.deleted_in_interval, agg_diag.deleted_in_interval,
agg_diag.partial_presence agg_diag.partial_presence
FROM diag, agg_diag FROM diag, agg_diag
`, vmKeyExpr, overlapExpr, selected.TableName, templateExclusionFilter(), aggOverlapExpr) `, vmKeyExpr, overlapExpr, selected.TableName, templateExclusionFilter(), vmKeyExpr, prevTableName, templateExclusionFilter(), aggOverlapExpr, aggOverlapExpr)
query = dbConn.Rebind(query) query = dbConn.Rebind(query)
var row struct { var row struct {
VmCount int64 `db:"vm_count"` VmCount int64 `db:"vm_count"`
@@ -1280,20 +1353,20 @@ FROM diag, agg_diag
DeletedInInterval int64 `db:"deleted_in_interval"` DeletedInInterval int64 `db:"deleted_in_interval"`
PartialPresence int64 `db:"partial_presence"` PartialPresence int64 `db:"partial_presence"`
} }
args := []interface{}{ overlapArgs := []interface{}{
hourEndUnix, hourEndUnix, hourEndUnix, hourEndUnix,
hourStartUnix, hourStartUnix, hourStartUnix, hourStartUnix,
hourEndUnix, hourEndUnix, hourEndUnix, hourEndUnix,
hourStartUnix, hourStartUnix, hourStartUnix, hourStartUnix,
durationSeconds, durationSeconds,
hourEndUnix, hourEndUnix,
hourStartUnix, hourStartUnix,
hourEndUnix, hourEndUnix,
hourStartUnix, hourStartUnix,
durationSeconds,
hourStartUnix, hourEndUnix,
hourStartUnix, hourEndUnix,
} }
args := make([]interface{}, 0, len(overlapArgs)*3+6)
args = append(args, overlapArgs...)
args = append(args, overlapArgs...)
args = append(args, hourStartUnix, hourEndUnix)
args = append(args, overlapArgs...)
args = append(args, hourStartUnix, hourEndUnix)
args = append(args, hourStartUnix, hourEndUnix)
if err := dbConn.GetContext(ctx, &row, query, args...); err != nil { if err := dbConn.GetContext(ctx, &row, query, args...); err != nil {
return nil, err return nil, err
} }