UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

75 lines (74 loc) 3.07 kB
import { s as asFiniteNumber } from "./number-coercion-CLj0HTDM.js"; import { t as openNodeSqliteDatabase } from "./node-sqlite-BpQX3W0e.js"; import { s as resolveOpenClawStateSqlitePath } from "./openclaw-state-db-schema-version-c1ZL6JGz.js"; import { y as listOpenClawRegisteredAgentDatabases } from "./openclaw-agent-db-maintenance-wTIy-jt-.js"; import "./openclaw-agent-db-CWtDoRbC.js"; import { t as note } from "./note-DqHk3fA1.js"; import { n as formatBytes } from "./doctor-disk-space-qV5PlSCz.js"; import fs from "node:fs"; //#region src/commands/doctor-db-bloat.ts const BLOAT_MIN_FILE_BYTES = 134217728; const BLOAT_MIN_FREE_BYTES = 33554432; const BLOAT_FREE_RATIO = .25; const LARGE_DB_WARN_BYTES = 1073741824; function readSqliteBloatStats(pathname) { let fileBytes; try { fileBytes = fs.statSync(pathname, { throwIfNoEntry: false })?.size ?? 0; } catch { return null; } if (fileBytes <= 0) return null; let db; try { db = openNodeSqliteDatabase(pathname, { readOnly: true }); const pageSize = readPragmaNumber(db, "page_size") ?? 4096; const freelistCount = readPragmaNumber(db, "freelist_count") ?? 0; const autoVacuum = readPragmaNumber(db, "auto_vacuum") ?? 0; return { fileBytes, freeBytes: freelistCount * pageSize, incrementalAutoVacuum: autoVacuum === 2 }; } catch { return null; } finally { db?.close(); } } function readPragmaNumber(db, pragma) { const row = db.prepare(`PRAGMA ${pragma}`).get(); return asFiniteNumber(row?.[pragma]) ?? null; } function describeBloat(label, stats) { const freeRatio = stats.fileBytes > 0 ? stats.freeBytes / stats.fileBytes : 0; if (stats.fileBytes >= BLOAT_MIN_FILE_BYTES && stats.freeBytes >= BLOAT_MIN_FREE_BYTES && freeRatio >= BLOAT_FREE_RATIO) { const remedy = stats.incrementalAutoVacuum ? "incremental vacuum will release it gradually" : "run `VACUUM` offline (gateway stopped) to reclaim it"; return `${label}: ${formatBytes(stats.fileBytes)} on disk with ${formatBytes(stats.freeBytes)} reclaimable free pages; ${remedy}.`; } if (stats.fileBytes >= LARGE_DB_WARN_BYTES) return `${label}: ${formatBytes(stats.fileBytes)} on disk; review session/transcript retention settings if growth is unexpected.`; return null; } function collectSqliteBloatWarnings(deps) { const env = deps?.env ?? process.env; const warnings = []; const stateStats = readSqliteBloatStats(resolveOpenClawStateSqlitePath(env)); if (stateStats) { const warning = describeBloat("state DB", stateStats); if (warning) warnings.push(warning); } for (const registered of listOpenClawRegisteredAgentDatabases({ env })) { const stats = readSqliteBloatStats(registered.path); if (!stats) continue; const warning = describeBloat(`agent DB (${registered.agentId})`, stats); if (warning) warnings.push(warning); } return warnings; } function noteSqliteDatabaseBloat(_cfg, deps) { const warnings = collectSqliteBloatWarnings(deps); if (warnings.length === 0) return; note(warnings.join("\n"), "SQLite database size"); } //#endregion export { noteSqliteDatabaseBloat };