/** * The rows run: rows written into a ClickHouse logs table held at a rate an hour. * * Every hour the run reads how many rows ClickHouse wrote into the table in the * last complete hour from its own `system.part_log` (NewPart rows, the meter that * equalled the hot count to the row in the gate run on 1.1.147 and ClickHouse * 26.5; `system.query_log` written_rows drifted with the exporter's async-insert * entries), reads each statement's lines an hour from the Receiver's own * Prometheus counters, and rewrites each service's total and each statement's * limit, in events, so the excess goes to the account's own bucket before * ClickHouse receives it. On ClickHouse an offloaded line never enters the table, * so there is no in-flight term, and the destination cannot count what was moved, * which is why the rates come from the Receiver and not from the table. * * The plan works in events with no residency: * allowance A = R - O - (nothing in flight), each service's floor past its * total counted through regulator-pass.ts, so the criterion is the meter at or * under R. */ import { type BudgetAction } from './budget-tick.js'; import type { RowsBudget } from './policy-loader.js'; import type { CustomerMetricsBackend } from './customer-metrics.js'; export interface ChCreds { url: string; username: string; password: string; } /** CLICKHOUSE_URL with CLICKHOUSE_API_KEY, or CLICKHOUSE_USER and CLICKHOUSE_PASSWORD, as the POC connector reads them. */ export declare function chCredsFromEnv(env?: NodeJS.ProcessEnv): ChCreds | undefined; /** One SQL statement, answered as TSV text (no header). */ export type ChQuery = (sql: string) => Promise; export declare function chRequester(creds: ChCreds, timeoutMs?: number): ChQuery; /** `database.table`, each side an identifier, so the name can sit in a query unquoted. */ export declare function splitTable(table: string): { db: string; tbl: string; }; export declare function sysTable(name: string, cluster?: string): string; export interface StatementLines { container: string; hash: string; pattern: string; severity: string; route: string; linesPerHour: number; } export interface RowsReads { table: string; /** Rows written into the table in the last complete hour (part_log NewPart). */ rowsLastHour: number; /** The same per complete window over the lookback, oldest first, each scaled to an hour. */ rowsByHour: Array<{ hourStartSec: number; rows: number; }>; /** Active rows in the table now (system.parts), the cross-check. */ activeRows: number; /** Lines an hour the Receiver returned marked pass, and marked offload, over the same hour. */ passLinesPerHour: number; offloadLinesPerHour: number; statements: StatementLines[]; queries: string[]; } export declare function tsvRows(text: string): string[][]; /** * The meter and the rates. `nowSec` is the run's clock; the meter's hour is the * last complete one before it, read from the event's own time, never from a part * or object's creation time. */ export declare function readRowsInputs(nowSec: number, rows: RowsBudget, ch: ChQuery, prom: CustomerMetricsBackend, envId?: string, lookbackHours?: number): Promise; export interface RowsRow { container: string; action: BudgetAction; instances: number; /** Fleet lines an hour the service sends now. */ linesPerHour: number; /** Fleet lines an hour kept in the table under this run. */ keptPerHour: number; /** Per-statement limit, lines per window per node; 0 exempts the service. */ cap: number; /** Service total, lines per window per node. */ total: number; } export interface RowsPlan { /** R, rows an hour. */ targetRows: number; targetSource: string; /** W, the meter's last complete hour. */ rowsLastHour: number; activeRows: number; /** O, rows an hour other writers put into the table (the policy's outside_rows_per_hour). */ outsidePerHour: number; /** Meter rows on the Receiver over the pass lines its counters read: each statement's rate is scaled by it. */ counterScale: number; allowancePerHour: number; levelPerHour?: number; floorPerHour: number; floorExceedsRate: boolean; movedPerHour: number; /** Rows an hour the table takes at these limits. */ projectedPerHour: number; overRate: boolean; rows: RowsRow[]; star: { action: BudgetAction; instances: number; cap: number; total: number; keptPerHour: number; }; heldLine: string; lines: string[]; warnings: string[]; } export interface RowsPlanInput { rows: RowsBudget; reads: RowsReads; instances: Record; nodesTotal: number; exceptions: string[]; targetServices: string[]; /** R recorded by an earlier run when the policy says `auto`. */ recordedRate?: number; } export declare function fmtRows(n: number): string; export declare function planRows(input: RowsPlanInput): RowsPlan; export declare function renderRowsReport(plan: RowsPlan, rows: RowsBudget, nowSec: number): string;