UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

148 lines (147 loc) • 5.59 kB
import { a as resolveGlobalSingleton } from "./global-singleton-0m-JziJW.mjs"; import { t as pruneMapToMaxSize } from "./map-size-CNcWiFKu.mjs"; //#region src/infra/kysely-sync-cache-state.ts const { kyselyByDatabase, queryErrorHandlerByDatabase } = resolveGlobalSingleton(Symbol.for("openclaw.sqliteKyselyCacheState"), () => ({ kyselyByDatabase: /* @__PURE__ */ new WeakMap(), queryErrorHandlerByDatabase: /* @__PURE__ */ new WeakMap() })); const statementCacheSymbol = Symbol.for("openclaw.kyselySyncStatementCache"); const statementInvalidationSymbol = Symbol.for("openclaw.kyselySyncStatementInvalidation"); const statementCacheEnabledSymbol = Symbol.for("openclaw.kyselySyncStatementCacheEnabled"); const authorizerActiveSymbol = Symbol.for("openclaw.kyselySyncAuthorizerActive"); const disposeCallbacksSymbol = Symbol.for("openclaw.sqliteDisposeCallbacks"); const statementCacheCapacity = 64; const statementCacheEntryBytes = 65536; /** Retire dependent native resources before this connection closes or is replaced. */ function registerNodeSqliteDisposeCallback(db, callback) { const owner = db; installStatementInvalidation(owner); const callbacks = owner[disposeCallbacksSymbol] ??= /* @__PURE__ */ new Set(); callbacks.add(callback); return () => { callbacks.delete(callback); }; } function disposeNodeSqliteDependents(owner, reason = "close") { for (const callback of owner[disposeCallbacksSymbol] ?? []) callback(reason); } /** Register the lifecycle owner's handler for synchronous Kysely query failures. */ function registerNodeSqliteKyselyQueryErrorHandler(db, handler) { queryErrorHandlerByDatabase.set(db, handler); } /** Drop cached Kysely state for a DatabaseSync. */ function clearNodeSqliteKyselyCacheForDatabase(db) { delete db[statementCacheSymbol]; kyselyByDatabase.delete(db); queryErrorHandlerByDatabase.delete(db); } function installStatementInvalidation(owner) { if (owner[statementInvalidationSymbol]) return; if (typeof owner.setAuthorizer === "function") { const setAuthorizer = owner.setAuthorizer.bind(owner); Object.defineProperty(owner, "setAuthorizer", { configurable: true, writable: true, value(callback) { setAuthorizer(callback); this[authorizerActiveSymbol] = callback !== null; delete this[statementCacheSymbol]; } }); } if (typeof owner.deserialize === "function") { const deserialize = owner.deserialize.bind(owner); Object.defineProperty(owner, "deserialize", { configurable: true, writable: true, value(...args) { disposeNodeSqliteDependents(this, "replace"); try { deserialize(...args); } finally { delete this[statementCacheSymbol]; } } }); } for (const method of ["close", Symbol.dispose]) if (typeof owner[method] === "function") { const dispose = owner[method].bind(owner); Object.defineProperty(owner, method, { configurable: true, writable: true, value() { disposeNodeSqliteDependents(this); clearNodeSqliteKyselyCacheForDatabase(this); return dispose(); } }); } Object.defineProperty(owner, statementInvalidationSymbol, { configurable: true, value: true }); } /** * Enable bounded statement caching for a lifecycle-owned database that has not * installed an authorizer before this call. */ function enableNodeSqliteKyselyStatementCache(db) { const owner = db; installStatementInvalidation(owner); owner[statementCacheEnabledSymbol] = true; } function queryFitsStatementCache(sql, parameters) { let bytes = Buffer.byteLength(sql); if (bytes > statementCacheEntryBytes) return false; for (const parameter of parameters) { if (typeof parameter === "string") { if (parameter.length > statementCacheEntryBytes - bytes) return false; bytes += Buffer.byteLength(parameter); } else if (ArrayBuffer.isView(parameter)) bytes += parameter.byteLength; if (bytes > statementCacheEntryBytes) return false; } return true; } function executeWithCachedStatement(db, sql, parameters, execute) { const owner = db; if (!owner[statementCacheEnabledSymbol] || owner[authorizerActiveSymbol] || !queryFitsStatementCache(sql, parameters)) return execute(db.prepare(sql)); let cache = owner[statementCacheSymbol]; if (!cache) { cache = { statements: /* @__PURE__ */ new Map(), candidates: /* @__PURE__ */ new Set(), active: /* @__PURE__ */ new WeakSet() }; Object.defineProperty(owner, statementCacheSymbol, { configurable: true, value: cache }); } const cached = cache.statements.get(sql); let statement; if (cached && !cache.active.has(cached)) { cache.statements.delete(sql); cache.statements.set(sql, cached); statement = cached; } else { statement = db.prepare(sql); if (!cached && cache.candidates.delete(sql)) { cache.statements.set(sql, statement); pruneMapToMaxSize(cache.statements, statementCacheCapacity); } else if (!cached) { cache.candidates.add(sql); if (cache.candidates.size > statementCacheCapacity) { const oldestCandidate = cache.candidates.values().next().value; if (oldestCandidate !== void 0) cache.candidates.delete(oldestCandidate); } } } cache.active.add(statement); try { return execute(statement); } finally { cache.active.delete(statement); } } //#endregion export { installStatementInvalidation as a, registerNodeSqliteDisposeCallback as c, executeWithCachedStatement as i, registerNodeSqliteKyselyQueryErrorHandler as l, disposeNodeSqliteDependents as n, kyselyByDatabase as o, enableNodeSqliteKyselyStatementCache as r, queryErrorHandlerByDatabase as s, clearNodeSqliteKyselyCacheForDatabase as t };