Files
OpenFlare/internal/repository/analytics/clickhouse_maintenance.go
T
ryan 58624db397 perf(clickhouse): Phase 2 legacy governance — TTL cleanup, unified pool, MV, ops API
- Replace retention ALTER DELETE with MATERIALIZE TTL; use TRUNCATE for delete-all
- Remove GORM ClickHouse pool; migrate user access log reads to ChConn
- Drop query-side trim(remote_addr); enable wait_for_async_insert=1
- Add of_node_traffic_hourly MV and dashboard traffic trend fallback
- Add GET /admin/status/clickhouse operational metrics endpoint
2026-07-02 15:47:38 +08:00

74 lines
2.2 KiB
Go

// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
package analytics
import (
"context"
"fmt"
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
)
const (
// CleanupModeTTLMaterialize expires rows via table TTL instead of ALTER DELETE mutations.
CleanupModeTTLMaterialize = "ttl_materialize"
// CleanupModeTruncate removes all rows via TRUNCATE TABLE.
CleanupModeTruncate = "truncate"
)
// CleanupOutcome describes a non-mutation ClickHouse cleanup operation.
type CleanupOutcome struct {
EligibleCount int64
Mode string
}
func countClickHouseRows(ctx context.Context, conn driver.Conn, countSQL string, countArgs []any) (int64, error) {
var count uint64
if err := conn.QueryRow(ctx, countSQL, countArgs...).Scan(&count); err != nil {
return 0, fmt.Errorf("count clickhouse rows: %w", err)
}
return safeInt64Count(count), nil
}
func materializeTableTTL(ctx context.Context, conn driver.Conn, tableName string) error {
sql := fmt.Sprintf("ALTER TABLE %s MATERIALIZE TTL", tableName)
if err := conn.Exec(ctx, sql); err != nil {
return fmt.Errorf("materialize ttl on %s: %w", tableName, err)
}
return nil
}
func expireRowsViaTTL(ctx context.Context, conn driver.Conn, tableName string, countSQL string, countArgs []any) (CleanupOutcome, error) {
count, err := countClickHouseRows(ctx, conn, countSQL, countArgs)
if err != nil {
return CleanupOutcome{}, err
}
if count == 0 {
return CleanupOutcome{Mode: CleanupModeTTLMaterialize}, nil
}
if err := materializeTableTTL(ctx, conn, tableName); err != nil {
return CleanupOutcome{}, err
}
return CleanupOutcome{
EligibleCount: count,
Mode: CleanupModeTTLMaterialize,
}, nil
}
func truncateClickHouseTable(ctx context.Context, conn driver.Conn, tableName string) (CleanupOutcome, error) {
count, err := countClickHouseRows(ctx, conn, "SELECT count() FROM "+tableName, nil)
if err != nil {
return CleanupOutcome{}, err
}
if count == 0 {
return CleanupOutcome{Mode: CleanupModeTruncate}, nil
}
if err := conn.Exec(ctx, "TRUNCATE TABLE "+tableName); err != nil {
return CleanupOutcome{}, fmt.Errorf("truncate %s: %w", tableName, err)
}
return CleanupOutcome{
EligibleCount: count,
Mode: CleanupModeTruncate,
}, nil
}