feat(ops): add usage_logs partition status to ops dashboard
Add partition management integration to the smart ops system: - Backend: Add GetUsageLogsPartitionStatus endpoint in OpsHandler - Backend: Add partition query methods in OpsRepository - Backend: Add UsageLogsPartitionStatus type in OpsService - Frontend: Add OpsPartitionStatusCard component - Frontend: Add partition status display in OpsDashboard - i18n: Add Chinese and English translations The partition status card shows: - Whether usage_logs is partitioned - Current row count vs threshold (100K) - Partition count (if partitioned) - Warning message when partitioning is recommended This allows administrators to monitor partition status directly from the ops dashboard without checking server logs.
This commit is contained in:
@@ -1526,3 +1526,78 @@ func opsNullInt16(v *int16) any {
|
||||
}
|
||||
return sql.NullInt64{Int64: int64(*v), Valid: true}
|
||||
}
|
||||
|
||||
// ==================== Usage Logs Partition Management ====================
|
||||
|
||||
// IsUsageLogsPartitioned checks if usage_logs table is partitioned.
|
||||
func (r *opsRepository) IsUsageLogsPartitioned(ctx context.Context) (bool, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return false, fmt.Errorf("nil ops repository")
|
||||
}
|
||||
|
||||
var isPartitioned bool
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM pg_partitioned_table pt
|
||||
JOIN pg_class c ON c.oid = pt.partrelid
|
||||
WHERE c.relname = 'usage_logs'
|
||||
)
|
||||
`).Scan(&isPartitioned)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("check usage_logs partitioned: %w", err)
|
||||
}
|
||||
return isPartitioned, nil
|
||||
}
|
||||
|
||||
// GetUsageLogsRowCount returns the approximate row count of usage_logs table.
|
||||
func (r *opsRepository) GetUsageLogsRowCount(ctx context.Context) (int64, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return 0, fmt.Errorf("nil ops repository")
|
||||
}
|
||||
|
||||
var rowCount int64
|
||||
// Use pg_class.reltuples for fast approximate count (avoid slow COUNT(*) on large tables)
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
SELECT COALESCE(
|
||||
(SELECT reltuples::bigint FROM pg_class WHERE relname = 'usage_logs'),
|
||||
0
|
||||
)
|
||||
`).Scan(&rowCount)
|
||||
if err != nil {
|
||||
// Fallback to actual COUNT if pg_class estimate fails
|
||||
err = r.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM usage_logs`).Scan(&rowCount)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("get usage_logs row count: %w", err)
|
||||
}
|
||||
}
|
||||
return rowCount, nil
|
||||
}
|
||||
|
||||
// GetUsageLogsPartitionCount returns the number of partitions for usage_logs table.
|
||||
func (r *opsRepository) GetUsageLogsPartitionCount(ctx context.Context) (int, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return 0, fmt.Errorf("nil ops repository")
|
||||
}
|
||||
|
||||
var count int
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
SELECT COUNT(*)
|
||||
FROM pg_class c
|
||||
WHERE c.relkind = 'r'
|
||||
AND c.relname LIKE 'usage_logs_%'
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM pg_inherits i
|
||||
WHERE i.inhrelid = c.oid
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM pg_class parent
|
||||
WHERE parent.oid = i.inhparent
|
||||
AND parent.relname = 'usage_logs'
|
||||
)
|
||||
)
|
||||
`).Scan(&count)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("get usage_logs partition count: %w", err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user