/** * UsageWindowStore SQL twins([ref]-T1)——core 5.8.0 部署级 token 治理窗 * (`RunnerDeps.usageWindows` + `usageWindowStore`)的 TiDB/PG 双方言实现。 * * 语义单源 = core 纯函数(`chargeUsageRecord`/`readUsageRecord`,dist/core/usage-window-store.js): * 本层只负责 record 的持久化与多副本并发正确性;窗算法(rolling slots 按最宽 horizon 自剪、 * first-use bucket lapsed 即弃)完全由 core 纯函数执行——SQL 层零窗语义。 * * 并发正确性(本 store 的靶心;两副本同 key 并发 charge 绝不能丢账——丢账方向=治理窗漏放): * - **ensure-first + 行锁**(mailbox twin 正字先例,[ref] 复审靶1):事务内先幂等建空行 * (形 A,S-127:MySQL `ON DUPLICATE KEY UPDATE = ` / PG `ON CONFLICT DO NOTHING`)⇒ * `SELECT … FOR UPDATE` 时行恒在,「无行 FOR UPDATE + INSERT」的并发死锁/dup 撞车形整个消掉。 * MySQL 侧动词**不能**是 `INSERT IGNORE`:InnoDB 对重复键的 IGNORE 取 S 锁,随后的 FOR UPDATE 要升 X, * 两个并发 charge 各持一把 S 互等 ⇒ ER_LOCK_DEADLOCK(B-013);ON DUPLICATE 的重复键取的就是 X。 * - charge 频率低(core 只在任务进场/turn 边界/收尾 delta 提交),悲观锁简单正确,不用乐观 CAS。 * - `read` 无锁单 SELECT(readUsageRecord 纯函数);行缺席 = EMPTY_USAGE_WINDOW_RECORD。 * - record JSON 坏形(手工污染)= **fail-loud throw**:治理窗算错=计费面撒谎,不 fail-open。 * * 列型:record 用 MySQL 方言 LONGTEXT(rolling slots 高并发长窗可破 64K TEXT——复审新5, * background-agent LONGTEXT 同案);PG TEXT 不限长。key 列 VARCHAR(190)(principal 或 * GLOBAL_USAGE_KEY,均为受控标识,无字节等价诉求——不是用户可写身份键)。 * * residue([ref] 04 §复审处置在档):不再被 charge 的 key 行永存(单行成本可忽略); * GLOBAL 单行=并发 charge 串一把行锁的吞吐热点(出现瓶颈再分片)。 */ import type { Pool as MySqlPool } from "mysql2/promise"; import type { Pool as PgPool } from "pg"; import type { UsageWindow, UsageWindowReading, UsageWindowStore } from "@sema-agent/core"; export declare const USAGE_WINDOW_TABLE = "usage_window"; export declare function ensureTiDBUsageWindowSchema(pool: MySqlPool): Promise; export declare function ensurePgUsageWindowSchema(q: (text: string, params?: unknown[]) => Promise): Promise; export declare class TiDBUsageWindowStore implements UsageWindowStore { private readonly pool; constructor(pool: MySqlPool); charge(key: string, tokens: number, at: number, windows: readonly UsageWindow[], costMicroUsd?: number | null): Promise; read(key: string, windows: readonly UsageWindow[], now: number): Promise; } export declare class PgUsageWindowStore implements UsageWindowStore { private readonly pool; constructor(pool: PgPool); charge(key: string, tokens: number, at: number, windows: readonly UsageWindow[], costMicroUsd?: number | null): Promise; read(key: string, windows: readonly UsageWindow[], now: number): Promise; } //# sourceMappingURL=usage-window-store-sql.d.ts.map