openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
123 lines (122 loc) • 5.76 kB
JavaScript
import { d as readDatabasePathIdentitySync } from "./sqlite-worker-identity-BRNRpRyc.mjs";
import { r as getChildLogger } from "./logger-BhL9CiBr.mjs";
import { i as runQueuedStoreWrite, n as isActiveStoreWriter } from "./store-writer-queue-x_P9TrZs.mjs";
import { n as agentDatabaseWriteAdmissionState } from "./openclaw-agent-write-admission-state-MeRNaC3M.mjs";
import { l as resolveOpenClawAgentSqlitePath } from "./openclaw-agent-db.paths-BbmZlEP5.mjs";
import { t as runStoreWriterAcquisitions } from "./store-writer-acquisitions-Q--yqQda.mjs";
import { isMainThread, threadId } from "node:worker_threads";
import { performance } from "node:perf_hooks";
//#region src/state/openclaw-agent-write-admission.ts
function observeWriteAdmission(operation, timing, run) {
if (timing) return run(timing);
const observed = {};
const enqueuedAt = performance.now();
const report = (outcome) => {
if (observed.reentrant !== false || observed.startedAt === void 0 || observed.finishedAt === void 0 || observed.finishedAt - observed.startedAt < 1e3) return;
const completedAt = performance.now();
try {
getChildLogger({ subsystem: "session-sqlite" }).warn({
operation,
outcome,
pid: process.pid,
threadId,
isMainThread,
reentrant: false,
elapsedMs: Math.round(completedAt - enqueuedAt),
queueWaitMs: Math.round(observed.startedAt - enqueuedAt),
writerExecutionMs: Math.round(observed.finishedAt - observed.startedAt),
completionDelayMs: Math.round(completedAt - observed.finishedAt)
}, "slow agent database reservation");
} catch {}
};
return run(observed).then((value) => {
report("ok");
return value;
}, (error) => {
report("error");
throw error;
});
}
function runOpenClawAgentWriteAdmission(options, run, reentrant = false, timing, signal) {
const pathname = resolveOpenClawAgentSqlitePath(options);
const identity = readDatabasePathIdentitySync(pathname);
const storePath = identity.canonicalPath;
const assertCurrent = () => {
const current = readDatabasePathIdentitySync(pathname);
if (current.canonicalPath !== storePath || identity.key.startsWith("file:") && (current.key !== identity.key || current.birthtime !== identity.birthtime)) throw new Error("Agent database target changed before write admission");
};
return observeWriteAdmission("direct", timing, (observed) => runQueuedStoreWrite({
queues: agentDatabaseWriteAdmissionState.queues,
storePath,
label: "agent database write admission",
reentrant: reentrant && !agentDatabaseWriteAdmissionState.workers.has(storePath),
fn: async () => {
assertCurrent();
return await run(identity, assertCurrent);
},
timing: observed,
signal
}));
}
/** Reserve a native write permit without admitting inherited foreground callbacks. */
function runOpenClawAgentWorkerWrite(options, run, timing, signal) {
return observeWriteAdmission("worker", timing, (observed) => {
if ("target" in options) {
const { handle, incarnation } = options.target;
return runQueuedStoreWrite({
queues: agentDatabaseWriteAdmissionState.queues,
storePath: `ephemeral:${handle}:${incarnation}`,
label: "incognito agent database write admission",
reentrant: false,
fn: async () => {
options.assertCurrent();
return run();
},
timing: observed,
signal
});
}
return runOpenClawAgentWriteAdmission(options, async ({ canonicalPath: storePath }) => {
const owner = {};
agentDatabaseWriteAdmissionState.workers.set(storePath, owner);
try {
return await run();
} finally {
if (agentDatabaseWriteAdmissionState.workers.get(storePath) === owner) agentDatabaseWriteAdmissionState.workers.delete(storePath);
}
}, true, observed, signal);
});
}
/** Compose the existing foreground queues without inverting inherited acquisition order. */
async function runOpenClawAgentWriteAdmissions(options, run, reentrant = false, signal) {
signal?.throwIfAborted();
let selected = new Map(options.map((option) => [resolveOpenClawAgentSqlitePath(option), option]));
const inherited = [...agentDatabaseWriteAdmissionState.queues.keys()].filter((pathname) => isActiveStoreWriter(agentDatabaseWriteAdmissionState.queues, pathname));
if (selected.size > 1) {
const physicalKey = (pathname) => {
const identity = readDatabasePathIdentitySync(pathname);
return `${identity.key}:${identity.birthtime ?? ""}`;
};
const representatives = new Map(inherited.map((pathname) => [physicalKey(pathname), pathname]));
const physical = /* @__PURE__ */ new Map();
for (const [pathname, option] of selected) {
const identity = physicalKey(pathname);
const representative = representatives.get(identity) ?? pathname;
representatives.set(identity, representative);
physical.set(representative, {
...option,
path: representative
});
}
selected = physical;
}
const paths = [...selected.keys()].toSorted();
if (paths.some((pathname) => inherited.includes(pathname) && (!reentrant || paths.length !== 1 || agentDatabaseWriteAdmissionState.workers.has(pathname)))) throw new Error("Session read batch cannot reenter an active SQLite writer admission");
if (paths.some((pathname) => inherited.some((held) => held > pathname))) throw new Error("Session read batch would invert inherited SQLite writer admission order");
return await runStoreWriterAcquisitions((index, next) => {
const pathname = paths[index];
return pathname === void 0 ? Promise.resolve().then(run) : observeWriteAdmission("ordered-read", void 0, (timing) => runOpenClawAgentWriteAdmission(selected.get(pathname), next, true, timing, signal));
});
}
//#endregion
export { runOpenClawAgentWriteAdmission as n, runOpenClawAgentWriteAdmissions as r, runOpenClawAgentWorkerWrite as t };