mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
Add persistence load and commit attribution diagnostics
This commit is contained in:
105
index.js
105
index.js
@@ -1666,6 +1666,10 @@ function normalizeLoadDiagnosticsMs(value = 0) {
|
||||
return Math.round((Number(value) || 0) * 10) / 10;
|
||||
}
|
||||
|
||||
function normalizePersistDeltaDiagnosticsMs(value = 0) {
|
||||
return Math.round((Number(value) || 0) * 10) / 10;
|
||||
}
|
||||
|
||||
function updatePersistDeltaDiagnostics(snapshot = null) {
|
||||
const nextSnapshot =
|
||||
snapshot && typeof snapshot === "object" && !Array.isArray(snapshot)
|
||||
@@ -9418,6 +9422,7 @@ async function loadGraphFromIndexedDb(
|
||||
totalMs: normalizeLoadDiagnosticsMs(readLoadDiagnosticsNow() - loadStartedAt),
|
||||
});
|
||||
let exportSnapshotMs = 0;
|
||||
let preApplyMs = 0;
|
||||
let exportSnapshotSource = "";
|
||||
if (!normalizedChatId) {
|
||||
const result = {
|
||||
@@ -9801,6 +9806,7 @@ async function loadGraphFromIndexedDb(
|
||||
};
|
||||
}
|
||||
|
||||
preApplyMs = readLoadDiagnosticsNow() - loadStartedAt;
|
||||
const applyInvokeStartedAt = readLoadDiagnosticsNow();
|
||||
const loadResult = applyIndexedDbSnapshotToRuntime(normalizedChatId, snapshot, {
|
||||
source,
|
||||
@@ -9811,6 +9817,8 @@ async function loadGraphFromIndexedDb(
|
||||
reasonPrefix: snapshotStore.reasonPrefix,
|
||||
});
|
||||
const applyInvokeMs = readLoadDiagnosticsNow() - applyInvokeStartedAt;
|
||||
const totalLoadMs = readLoadDiagnosticsNow() - loadStartedAt;
|
||||
const loadAccountedMs = preApplyMs + applyInvokeMs;
|
||||
if (commitMarkerDiagnostic?.reason && loadResult?.loaded) {
|
||||
updateGraphPersistenceState({
|
||||
persistMismatchReason: commitMarkerDiagnostic.reason,
|
||||
@@ -9828,7 +9836,14 @@ async function loadGraphFromIndexedDb(
|
||||
commitMarkerMismatched: commitMarkerMismatch.mismatched === true,
|
||||
exportSnapshotSource: exportSnapshotSource || "snapshot-prepared",
|
||||
exportSnapshotMs: normalizeLoadDiagnosticsMs(exportSnapshotMs),
|
||||
preApplyMs: normalizeLoadDiagnosticsMs(preApplyMs),
|
||||
preApplyOtherMs: normalizeLoadDiagnosticsMs(
|
||||
Math.max(0, preApplyMs - exportSnapshotMs),
|
||||
),
|
||||
applyInvokeMs: normalizeLoadDiagnosticsMs(applyInvokeMs),
|
||||
untrackedMs: normalizeLoadDiagnosticsMs(
|
||||
Math.max(0, totalLoadMs - loadAccountedMs),
|
||||
),
|
||||
});
|
||||
return loadResult;
|
||||
} catch (error) {
|
||||
@@ -9862,6 +9877,16 @@ async function loadGraphFromIndexedDb(
|
||||
error: error?.message || String(error),
|
||||
exportSnapshotSource: exportSnapshotSource || "unknown",
|
||||
exportSnapshotMs: normalizeLoadDiagnosticsMs(exportSnapshotMs),
|
||||
preApplyMs: normalizeLoadDiagnosticsMs(
|
||||
preApplyMs || (readLoadDiagnosticsNow() - loadStartedAt),
|
||||
),
|
||||
preApplyOtherMs: normalizeLoadDiagnosticsMs(
|
||||
Math.max(
|
||||
0,
|
||||
(preApplyMs || (readLoadDiagnosticsNow() - loadStartedAt)) -
|
||||
exportSnapshotMs,
|
||||
),
|
||||
),
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -13363,12 +13388,19 @@ async function saveGraphToIndexedDb(
|
||||
let nativePersistPreloadStatus = "not-requested";
|
||||
let nativePersistPreloadError = "";
|
||||
let nativePersistPreloadMs = 0;
|
||||
let baseSnapshotReadMs = 0;
|
||||
let graphSnapshotBuildMs = 0;
|
||||
const persistDeltaStartedAt = readPersistDeltaDiagnosticsNow();
|
||||
|
||||
if (!delta) {
|
||||
baseSnapshot =
|
||||
readCachedIndexedDbSnapshot(normalizedChatId, localStore) ||
|
||||
(await db.exportSnapshot());
|
||||
const baseSnapshotReadStartedAt = readPersistDeltaDiagnosticsNow();
|
||||
baseSnapshot = readCachedIndexedDbSnapshot(normalizedChatId, localStore);
|
||||
if (!baseSnapshot) {
|
||||
baseSnapshot = await db.exportSnapshot();
|
||||
}
|
||||
baseSnapshotReadMs =
|
||||
readPersistDeltaDiagnosticsNow() - baseSnapshotReadStartedAt;
|
||||
const graphSnapshotBuildStartedAt = readPersistDeltaDiagnosticsNow();
|
||||
snapshot = buildSnapshotFromGraph(graph, {
|
||||
chatId: normalizedChatId,
|
||||
revision: requestedRevision,
|
||||
@@ -13383,6 +13415,8 @@ async function saveGraphToIndexedDb(
|
||||
hostChatId: currentIdentity.hostChatId || "",
|
||||
},
|
||||
});
|
||||
graphSnapshotBuildMs =
|
||||
readPersistDeltaDiagnosticsNow() - graphSnapshotBuildStartedAt;
|
||||
}
|
||||
const nativePersistBridgeMode = String(
|
||||
currentSettings.persistNativeDeltaBridgeMode || "json",
|
||||
@@ -13555,6 +13589,12 @@ async function saveGraphToIndexedDb(
|
||||
requestedRevision,
|
||||
markSyncDirty: true,
|
||||
});
|
||||
const commitDiagnostics =
|
||||
commitResult?.diagnostics &&
|
||||
typeof commitResult.diagnostics === "object" &&
|
||||
!Array.isArray(commitResult.diagnostics)
|
||||
? cloneRuntimeDebugValue(commitResult.diagnostics, {})
|
||||
: null;
|
||||
const committedRevision = normalizeIndexedDbRevision(
|
||||
commitResult?.revision,
|
||||
requestedRevision,
|
||||
@@ -13564,6 +13604,7 @@ async function saveGraphToIndexedDb(
|
||||
let scheduleUploadWarning = "";
|
||||
if (graph) {
|
||||
if (!snapshot) {
|
||||
const graphSnapshotBuildStartedAt = readPersistDeltaDiagnosticsNow();
|
||||
snapshot = buildSnapshotFromGraph(graph, {
|
||||
chatId: normalizedChatId,
|
||||
revision: committedRevision,
|
||||
@@ -13578,6 +13619,8 @@ async function saveGraphToIndexedDb(
|
||||
hostChatId: currentIdentity.hostChatId || "",
|
||||
},
|
||||
});
|
||||
graphSnapshotBuildMs +=
|
||||
readPersistDeltaDiagnosticsNow() - graphSnapshotBuildStartedAt;
|
||||
}
|
||||
if (!snapshot.meta || typeof snapshot.meta !== "object" || Array.isArray(snapshot.meta)) {
|
||||
snapshot.meta = {};
|
||||
@@ -13620,6 +13663,14 @@ async function saveGraphToIndexedDb(
|
||||
}
|
||||
}
|
||||
|
||||
const persistTotalMs = readPersistDeltaDiagnosticsNow() - persistDeltaStartedAt;
|
||||
const persistAccountedMs =
|
||||
Number(nativePersistPreloadMs || 0) +
|
||||
Number(baseSnapshotReadMs || 0) +
|
||||
Number(graphSnapshotBuildMs || 0) +
|
||||
Number(persistDeltaBuildDiagnostics?.buildMs || 0) +
|
||||
Number(commitDiagnostics?.queueWaitMs || 0) +
|
||||
Number(commitDiagnostics?.commitMs || 0);
|
||||
const persistDeltaDiagnostics = {
|
||||
...cloneRuntimeDebugValue(persistDeltaBuildDiagnostics, {}),
|
||||
chatId: normalizedChatId,
|
||||
@@ -13669,13 +13720,59 @@ async function saveGraphToIndexedDb(
|
||||
moduleError: String(
|
||||
nativePersistModuleStatus?.error || nativePersistPreloadError || "",
|
||||
),
|
||||
baseSnapshotReadMs: normalizePersistDeltaDiagnosticsMs(baseSnapshotReadMs),
|
||||
snapshotBuildMs: normalizePersistDeltaDiagnosticsMs(graphSnapshotBuildMs),
|
||||
commitStorageKind: String(
|
||||
commitDiagnostics?.storageKind || localStore.storagePrimary || "",
|
||||
),
|
||||
commitStoreMode: String(
|
||||
commitDiagnostics?.storeMode || localStore.storageMode || "",
|
||||
),
|
||||
commitQueueWaitMs: normalizePersistDeltaDiagnosticsMs(
|
||||
commitDiagnostics?.queueWaitMs,
|
||||
),
|
||||
commitMs: normalizePersistDeltaDiagnosticsMs(commitDiagnostics?.commitMs),
|
||||
commitTxMs: normalizePersistDeltaDiagnosticsMs(commitDiagnostics?.txMs),
|
||||
commitSnapshotReadMs: normalizePersistDeltaDiagnosticsMs(
|
||||
commitDiagnostics?.snapshotReadMs,
|
||||
),
|
||||
commitSnapshotWriteMs: normalizePersistDeltaDiagnosticsMs(
|
||||
commitDiagnostics?.snapshotWriteMs,
|
||||
),
|
||||
commitManifestReadMs: normalizePersistDeltaDiagnosticsMs(
|
||||
commitDiagnostics?.manifestReadMs,
|
||||
),
|
||||
commitWalWriteMs: normalizePersistDeltaDiagnosticsMs(
|
||||
commitDiagnostics?.walWriteMs,
|
||||
),
|
||||
commitManifestWriteMs: normalizePersistDeltaDiagnosticsMs(
|
||||
commitDiagnostics?.manifestWriteMs,
|
||||
),
|
||||
commitCacheApplyMs: normalizePersistDeltaDiagnosticsMs(
|
||||
commitDiagnostics?.cacheApplyMs,
|
||||
),
|
||||
commitPayloadBytes: Math.max(
|
||||
0,
|
||||
Math.floor(Number(commitDiagnostics?.payloadBytes || 0)),
|
||||
),
|
||||
commitWalBytes: Math.max(
|
||||
0,
|
||||
Math.floor(Number(commitDiagnostics?.walBytes || 0)),
|
||||
),
|
||||
commitRuntimeMetaKeyCount: Math.max(
|
||||
0,
|
||||
Math.floor(Number(commitDiagnostics?.runtimeMetaKeyCount || 0)),
|
||||
),
|
||||
status: "committed",
|
||||
commitRevision: normalizeIndexedDbRevision(
|
||||
commitResult?.revision,
|
||||
requestedRevision,
|
||||
),
|
||||
commitDelta: cloneRuntimeDebugValue(commitResult?.delta, null),
|
||||
totalMs: readPersistDeltaDiagnosticsNow() - persistDeltaStartedAt,
|
||||
totalMs: normalizePersistDeltaDiagnosticsMs(persistTotalMs),
|
||||
untrackedMs: normalizePersistDeltaDiagnosticsMs(
|
||||
Math.max(0, persistTotalMs - persistAccountedMs),
|
||||
),
|
||||
};
|
||||
persistDeltaDiagnostics.fallbackReason =
|
||||
persistDeltaDiagnostics.requestedNative && !persistDeltaDiagnostics.usedNative
|
||||
|
||||
@@ -109,6 +109,26 @@ function normalizeNonNegativeInteger(value, fallback = 0) {
|
||||
return Math.max(0, Math.floor(parsed));
|
||||
}
|
||||
|
||||
function readPersistCommitNow() {
|
||||
if (typeof performance === "object" && typeof performance.now === "function") {
|
||||
return performance.now();
|
||||
}
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
function normalizePersistCommitMs(value = 0) {
|
||||
return Math.round((Number(value) || 0) * 10) / 10;
|
||||
}
|
||||
|
||||
function estimatePersistPayloadBytes(value = null) {
|
||||
if (value == null) return 0;
|
||||
try {
|
||||
return JSON.stringify(value).length;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function toPlainData(value, fallbackValue = null) {
|
||||
if (value == null) {
|
||||
return fallbackValue;
|
||||
@@ -2530,6 +2550,7 @@ export class BmeDatabase {
|
||||
|
||||
async commitDelta(delta = {}, options = {}) {
|
||||
const db = await this.open();
|
||||
const commitRequestedAt = readPersistCommitNow();
|
||||
const nowMs = Date.now();
|
||||
const normalizedDelta =
|
||||
delta && typeof delta === "object" && !Array.isArray(delta) ? delta : {};
|
||||
@@ -2554,6 +2575,7 @@ export class BmeDatabase {
|
||||
const reason = String(options.reason || "commitDelta");
|
||||
const requestedRevision = normalizeRevision(options.requestedRevision);
|
||||
const shouldMarkSyncDirty = options.markSyncDirty !== false;
|
||||
const payloadBytes = estimatePersistPayloadBytes(normalizedDelta);
|
||||
const normalizedCountDelta =
|
||||
normalizedDelta.countDelta &&
|
||||
typeof normalizedDelta.countDelta === "object" &&
|
||||
@@ -2567,7 +2589,9 @@ export class BmeDatabase {
|
||||
edges: 0,
|
||||
tombstones: 0,
|
||||
};
|
||||
let transactionMs = 0;
|
||||
|
||||
const transactionStartedAt = readPersistCommitNow();
|
||||
await db.transaction(
|
||||
"rw",
|
||||
db.table("nodes"),
|
||||
@@ -2614,6 +2638,7 @@ export class BmeDatabase {
|
||||
);
|
||||
},
|
||||
);
|
||||
transactionMs = readPersistCommitNow() - transactionStartedAt;
|
||||
|
||||
return {
|
||||
revision: nextRevision,
|
||||
@@ -2630,6 +2655,17 @@ export class BmeDatabase {
|
||||
deleteEdgeIds: deleteEdgeIds.length,
|
||||
tombstones: tombstones.length,
|
||||
},
|
||||
diagnostics: {
|
||||
storageKind: "indexeddb",
|
||||
storeMode: "indexeddb",
|
||||
queueWaitMs: 0,
|
||||
commitMs: normalizePersistCommitMs(
|
||||
readPersistCommitNow() - commitRequestedAt,
|
||||
),
|
||||
txMs: normalizePersistCommitMs(transactionMs),
|
||||
payloadBytes,
|
||||
runtimeMetaKeyCount: Object.keys(runtimeMetaPatch).length,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,26 @@ function normalizeNonNegativeInteger(value, fallback = 0) {
|
||||
return Math.floor(parsed);
|
||||
}
|
||||
|
||||
function readPersistCommitNow() {
|
||||
if (typeof performance === "object" && typeof performance.now === "function") {
|
||||
return performance.now();
|
||||
}
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
function normalizePersistCommitMs(value = 0) {
|
||||
return Math.round((Number(value) || 0) * 10) / 10;
|
||||
}
|
||||
|
||||
function estimatePersistPayloadBytes(value = null) {
|
||||
if (value == null) return 0;
|
||||
try {
|
||||
return JSON.stringify(value).length;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function deriveNodeSourceFloor(node = {}) {
|
||||
const directSourceFloor = normalizeSourceFloor(node?.sourceFloor);
|
||||
if (directSourceFloor != null) return directSourceFloor;
|
||||
@@ -970,13 +990,19 @@ class LegacyOpfsGraphStore {
|
||||
}
|
||||
|
||||
async commitDelta(delta = {}, options = {}) {
|
||||
const commitRequestedAt = readPersistCommitNow();
|
||||
return await this._runSerializedWrite(
|
||||
String(options?.reason || "commitDelta"),
|
||||
async () => {
|
||||
const commitStartedAt = readPersistCommitNow();
|
||||
const queueWaitMs = commitStartedAt - commitRequestedAt;
|
||||
const nowMs = Date.now();
|
||||
const normalizedDelta =
|
||||
delta && typeof delta === "object" && !Array.isArray(delta) ? delta : {};
|
||||
const payloadBytes = estimatePersistPayloadBytes(normalizedDelta);
|
||||
const snapshotReadStartedAt = readPersistCommitNow();
|
||||
const currentSnapshot = await this._loadSnapshot({ awaitWrites: false });
|
||||
const snapshotReadMs = readPersistCommitNow() - snapshotReadStartedAt;
|
||||
const nodeMap = new Map();
|
||||
const edgeMap = new Map();
|
||||
const tombstoneMap = new Map();
|
||||
@@ -1093,7 +1119,9 @@ class LegacyOpfsGraphStore {
|
||||
edges: Array.from(edgeMap.values()),
|
||||
tombstones: Array.from(tombstoneMap.values()),
|
||||
};
|
||||
const snapshotWriteStartedAt = readPersistCommitNow();
|
||||
await this._writeResolvedSnapshot(nextSnapshot);
|
||||
const snapshotWriteMs = readPersistCommitNow() - snapshotWriteStartedAt;
|
||||
|
||||
return {
|
||||
revision: nextRevision,
|
||||
@@ -1110,6 +1138,18 @@ class LegacyOpfsGraphStore {
|
||||
deleteEdgeIds: deleteEdgeIds.length,
|
||||
tombstones: tombstones.length,
|
||||
},
|
||||
diagnostics: {
|
||||
storageKind: OPFS_STORE_KIND,
|
||||
storeMode: this.storeMode,
|
||||
queueWaitMs: normalizePersistCommitMs(queueWaitMs),
|
||||
commitMs: normalizePersistCommitMs(
|
||||
readPersistCommitNow() - commitStartedAt,
|
||||
),
|
||||
snapshotReadMs: normalizePersistCommitMs(snapshotReadMs),
|
||||
snapshotWriteMs: normalizePersistCommitMs(snapshotWriteMs),
|
||||
payloadBytes,
|
||||
runtimeMetaKeyCount: Object.keys(runtimeMetaPatch).length,
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
@@ -2326,12 +2366,18 @@ export class OpfsGraphStore {
|
||||
}
|
||||
|
||||
async commitDelta(delta = {}, options = {}) {
|
||||
const commitRequestedAt = readPersistCommitNow();
|
||||
return await this._runSerializedWrite(
|
||||
String(options?.reason || "commitDelta"),
|
||||
async () => {
|
||||
const commitStartedAt = readPersistCommitNow();
|
||||
const queueWaitMs = commitStartedAt - commitRequestedAt;
|
||||
const manifestReadStartedAt = readPersistCommitNow();
|
||||
const manifest = await this._ensureV2Ready({ awaitWrites: false });
|
||||
const manifestReadMs = readPersistCommitNow() - manifestReadStartedAt;
|
||||
const nowMs = Date.now();
|
||||
const normalizedDelta = sanitizeOpfsV2Delta(delta, nowMs);
|
||||
const payloadBytes = estimatePersistPayloadBytes(normalizedDelta);
|
||||
const requestedRevision = normalizeRevision(options.requestedRevision);
|
||||
const shouldMarkSyncDirty = options.markSyncDirty !== false;
|
||||
const reason = String(options.reason || "commitDelta");
|
||||
@@ -2370,10 +2416,12 @@ export class OpfsGraphStore {
|
||||
runtimeMetaPatch: normalizedDelta.runtimeMetaPatch,
|
||||
countDelta: nextCountDelta,
|
||||
};
|
||||
const walWriteStartedAt = readPersistCommitNow();
|
||||
const walDirectory = await this._getWalDirectory();
|
||||
const walFilename = buildOpfsV2WalFilename(nextRevision);
|
||||
await writeJsonFile(walDirectory, walFilename, walRecord);
|
||||
const walByteLength = JSON.stringify(walRecord).length;
|
||||
const walWriteMs = readPersistCommitNow() - walWriteStartedAt;
|
||||
|
||||
const hadPendingWal =
|
||||
normalizeRevision(manifest?.pendingLogFromRevision) <= currentHeadRevision;
|
||||
@@ -2400,9 +2448,13 @@ export class OpfsGraphStore {
|
||||
lastReason: reason,
|
||||
},
|
||||
};
|
||||
const manifestWriteStartedAt = readPersistCommitNow();
|
||||
await this._writeManifest(nextManifest);
|
||||
const manifestWriteMs = readPersistCommitNow() - manifestWriteStartedAt;
|
||||
|
||||
let cacheApplyMs = 0;
|
||||
if (this._snapshotCache) {
|
||||
const cacheApplyStartedAt = readPersistCommitNow();
|
||||
const nextSnapshot = applyOpfsV2DeltaToSnapshot(
|
||||
this._snapshotCache,
|
||||
normalizedDelta,
|
||||
@@ -2414,6 +2466,7 @@ export class OpfsGraphStore {
|
||||
};
|
||||
nextSnapshot.state = normalizeSnapshotState(nextSnapshot);
|
||||
this._snapshotCache = nextSnapshot;
|
||||
cacheApplyMs = readPersistCommitNow() - cacheApplyStartedAt;
|
||||
}
|
||||
|
||||
this._maybeScheduleCompaction(nextManifest, reason);
|
||||
@@ -2433,6 +2486,23 @@ export class OpfsGraphStore {
|
||||
deleteEdgeIds: normalizedDelta.deleteEdgeIds.length,
|
||||
tombstones: normalizedDelta.tombstones.length,
|
||||
},
|
||||
diagnostics: {
|
||||
storageKind: OPFS_STORE_KIND,
|
||||
storeMode: this.storeMode,
|
||||
queueWaitMs: normalizePersistCommitMs(queueWaitMs),
|
||||
commitMs: normalizePersistCommitMs(
|
||||
readPersistCommitNow() - commitStartedAt,
|
||||
),
|
||||
manifestReadMs: normalizePersistCommitMs(manifestReadMs),
|
||||
walWriteMs: normalizePersistCommitMs(walWriteMs),
|
||||
manifestWriteMs: normalizePersistCommitMs(manifestWriteMs),
|
||||
cacheApplyMs: normalizePersistCommitMs(cacheApplyMs),
|
||||
payloadBytes,
|
||||
walBytes: walByteLength,
|
||||
runtimeMetaKeyCount: Object.keys(
|
||||
normalizedDelta.runtimeMetaPatch || {},
|
||||
).length,
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
@@ -123,6 +123,7 @@ function evaluatePersistNativeDeltaGate() {
|
||||
};
|
||||
}
|
||||
function readPersistDeltaDiagnosticsNow() { return Date.now(); }
|
||||
function normalizePersistDeltaDiagnosticsMs(value = 0) { return Math.round((Number(value) || 0) * 10) / 10; }
|
||||
function updatePersistDeltaDiagnostics() {}
|
||||
function buildPersistDelta() {
|
||||
return {
|
||||
|
||||
103
ui/panel.js
103
ui/panel.js
@@ -1532,13 +1532,64 @@ function _formatPersistencePersistDeltaSummary(persistDelta = null) {
|
||||
|
||||
const pathText = String(diagnostics.path || "").trim() || "—";
|
||||
const totalText = _formatDurationMs(diagnostics.totalMs || diagnostics.buildMs);
|
||||
const commitText = _formatDurationMs(diagnostics.commitMs);
|
||||
const gateText = String(_formatPersistDeltaGateText(diagnostics) || "").trim();
|
||||
const parts = [pathText];
|
||||
if (totalText !== "—") parts.push(totalText);
|
||||
if (commitText !== "—") parts.push(`commit ${commitText}`);
|
||||
if (gateText) parts.push(`native ${gateText}`);
|
||||
return parts.join(" · ");
|
||||
}
|
||||
|
||||
function _formatPersistCommitPhaseText(diagnostics = null) {
|
||||
const snapshot = _readPersistenceDiagnosticObject(diagnostics);
|
||||
if (!snapshot) return "—";
|
||||
const queueText = _formatDurationMs(snapshot.commitQueueWaitMs);
|
||||
const commitText = _formatDurationMs(snapshot.commitMs);
|
||||
if (queueText === "—" && commitText === "—") return "—";
|
||||
return `${queueText} / ${commitText}`;
|
||||
}
|
||||
|
||||
function _formatPersistCommitBreakdownText(diagnostics = null) {
|
||||
const snapshot = _readPersistenceDiagnosticObject(diagnostics);
|
||||
if (!snapshot) return "—";
|
||||
const parts = [
|
||||
snapshot.commitTxMs ? `tx ${_formatDurationMs(snapshot.commitTxMs)}` : "",
|
||||
snapshot.commitSnapshotReadMs
|
||||
? `snapshot-read ${_formatDurationMs(snapshot.commitSnapshotReadMs)}`
|
||||
: "",
|
||||
snapshot.commitSnapshotWriteMs
|
||||
? `snapshot-write ${_formatDurationMs(snapshot.commitSnapshotWriteMs)}`
|
||||
: "",
|
||||
snapshot.commitManifestReadMs
|
||||
? `manifest-read ${_formatDurationMs(snapshot.commitManifestReadMs)}`
|
||||
: "",
|
||||
snapshot.commitWalWriteMs
|
||||
? `wal ${_formatDurationMs(snapshot.commitWalWriteMs)}`
|
||||
: "",
|
||||
snapshot.commitManifestWriteMs
|
||||
? `manifest-write ${_formatDurationMs(snapshot.commitManifestWriteMs)}`
|
||||
: "",
|
||||
snapshot.commitCacheApplyMs
|
||||
? `cache ${_formatDurationMs(snapshot.commitCacheApplyMs)}`
|
||||
: "",
|
||||
].filter(Boolean);
|
||||
return parts.join(" · ") || "—";
|
||||
}
|
||||
|
||||
function _formatPersistCommitBytesText(diagnostics = null) {
|
||||
const snapshot = _readPersistenceDiagnosticObject(diagnostics);
|
||||
if (!snapshot) return "—";
|
||||
const parts = [];
|
||||
const payloadText = _formatDataSizeBytes(snapshot.commitPayloadBytes);
|
||||
const walText = _formatDataSizeBytes(snapshot.commitWalBytes);
|
||||
const metaKeyCount = Number(snapshot.commitRuntimeMetaKeyCount || 0);
|
||||
if (payloadText !== "—") parts.push(`payload ${payloadText}`);
|
||||
if (walText !== "—") parts.push(`wal ${walText}`);
|
||||
if (metaKeyCount > 0) parts.push(`meta ${metaKeyCount} keys`);
|
||||
return parts.join(" · ") || "—";
|
||||
}
|
||||
|
||||
function _buildLoadDiagnosticRows(loadDiagnostics = null) {
|
||||
const diagnostics = _readPersistenceDiagnosticObject(loadDiagnostics);
|
||||
if (!diagnostics) {
|
||||
@@ -1561,10 +1612,13 @@ function _buildLoadDiagnosticRows(loadDiagnostics = null) {
|
||||
["Load 状态", statusText],
|
||||
["Load 原因", String(diagnostics.reason || "—")],
|
||||
["Load 总耗时", _formatDurationMs(diagnostics.totalMs)],
|
||||
["Load 前置", _formatDurationMs(diagnostics.preApplyMs)],
|
||||
["导出快照", _formatDurationMs(diagnostics.exportSnapshotMs)],
|
||||
["前置(除导出)", _formatDurationMs(diagnostics.preApplyOtherMs)],
|
||||
["Hydrate", _formatDurationMs(diagnostics.hydrateMs)],
|
||||
["Apply 调用", _formatDurationMs(diagnostics.applyInvokeMs)],
|
||||
["Apply 运行", _formatDurationMs(diagnostics.applyRuntimeMs)],
|
||||
["Load 未归因", _formatDurationMs(diagnostics.untrackedMs)],
|
||||
["Load 更新时间", updatedAtText],
|
||||
];
|
||||
}
|
||||
@@ -1586,6 +1640,12 @@ function _buildPersistDeltaDiagnosticRows(persistDelta = null) {
|
||||
)}E / ${Number(diagnostics.deleteNodeCount || 0)}DN / ${Number(
|
||||
diagnostics.deleteEdgeCount || 0,
|
||||
)}DE`;
|
||||
const commitStoreText = `${String(diagnostics.commitStorageKind || "—")} / ${String(
|
||||
diagnostics.commitStoreMode || "—",
|
||||
)}`;
|
||||
const commitPhaseText = _formatPersistCommitPhaseText(diagnostics);
|
||||
const commitBreakdownText = _formatPersistCommitBreakdownText(diagnostics);
|
||||
const commitBytesText = _formatPersistCommitBytesText(diagnostics);
|
||||
const updatedAtText = diagnostics.updatedAt
|
||||
? _formatTaskProfileTime(diagnostics.updatedAt)
|
||||
: "—";
|
||||
@@ -1594,8 +1654,11 @@ function _buildPersistDeltaDiagnosticRows(persistDelta = null) {
|
||||
["Persist 路径", String(diagnostics.path || "—")],
|
||||
["Native Gate", _formatPersistDeltaGateText(diagnostics)],
|
||||
["Bridge 模式", bridgeText],
|
||||
["Commit 存储", commitStoreText],
|
||||
["Persist 总耗时", _formatDurationMs(diagnostics.totalMs || diagnostics.buildMs)],
|
||||
["构建耗时", _formatDurationMs(diagnostics.buildMs)],
|
||||
["Base 快照读取", _formatDurationMs(diagnostics.baseSnapshotReadMs)],
|
||||
["图谱快照构建", _formatDurationMs(diagnostics.snapshotBuildMs)],
|
||||
[
|
||||
"Prepare / Native",
|
||||
`${_formatDurationMs(diagnostics.prepareMs)} / ${_formatDurationMs(diagnostics.nativeAttemptMs)}`,
|
||||
@@ -1605,11 +1668,15 @@ function _buildPersistDeltaDiagnosticRows(persistDelta = null) {
|
||||
`${_formatDurationMs(diagnostics.lookupMs)} / ${_formatDurationMs(diagnostics.jsDiffMs)}`,
|
||||
],
|
||||
["Hydrate", _formatDurationMs(diagnostics.hydrateMs)],
|
||||
["Commit 排队 / 提交", commitPhaseText],
|
||||
["Commit 细分", commitBreakdownText],
|
||||
["Commit Payload", commitBytesText],
|
||||
["Preload", String(diagnostics.preloadStatus || "—")],
|
||||
["Native 来源", String(diagnostics.moduleSource || "—")],
|
||||
["Fallback 原因", String(diagnostics.fallbackReason || "—")],
|
||||
["Preload / Native 错误", errorText || "—"],
|
||||
["增量规模", deltaSizeText],
|
||||
["Persist 未归因", _formatDurationMs(diagnostics.untrackedMs)],
|
||||
["Persist 更新时间", updatedAtText],
|
||||
];
|
||||
}
|
||||
@@ -8293,6 +8360,16 @@ function _formatDurationMs(durationMs) {
|
||||
return `${(normalized / 1000).toFixed(normalized >= 10000 ? 0 : 1)}s`;
|
||||
}
|
||||
|
||||
function _formatDataSizeBytes(byteCount) {
|
||||
const normalized = Number(byteCount);
|
||||
if (!Number.isFinite(normalized) || normalized <= 0) return "—";
|
||||
if (normalized < 1024) return `${Math.round(normalized)} B`;
|
||||
if (normalized < 1024 * 1024) {
|
||||
return `${(normalized / 1024).toFixed(normalized >= 10 * 1024 ? 0 : 1)} KB`;
|
||||
}
|
||||
return `${(normalized / (1024 * 1024)).toFixed(normalized >= 10 * 1024 * 1024 ? 0 : 1)} MB`;
|
||||
}
|
||||
|
||||
function _getMonitorTaskTypeLabel(taskType = "") {
|
||||
const normalized = String(taskType || "").trim().toLowerCase();
|
||||
const labels = {
|
||||
@@ -8767,6 +8844,12 @@ function _renderPersistDeltaTraceCard(state) {
|
||||
const payloadCharsText = diagnostics.combinedSerializedChars
|
||||
? `${Number(diagnostics.combinedSerializedChars || 0)} / ${Number(diagnostics.minCombinedSerializedChars || 0)}`
|
||||
: "—";
|
||||
const snapshotBuildText = `${_formatDurationMs(diagnostics.baseSnapshotReadMs)} / ${_formatDurationMs(
|
||||
diagnostics.snapshotBuildMs,
|
||||
)}`;
|
||||
const commitPhaseText = _formatPersistCommitPhaseText(diagnostics);
|
||||
const commitBreakdownText = _formatPersistCommitBreakdownText(diagnostics);
|
||||
const commitBytesText = _formatPersistCommitBytesText(diagnostics);
|
||||
const cacheText = `${Number(diagnostics.serializationCacheHits || 0)}H / ${Number(
|
||||
diagnostics.serializationCacheMisses || 0,
|
||||
)}M`;
|
||||
@@ -8819,6 +8902,10 @@ function _renderPersistDeltaTraceCard(state) {
|
||||
<span>构建耗时</span>
|
||||
<strong>${_escHtml(_formatDurationMs(diagnostics.buildMs))}</strong>
|
||||
</div>
|
||||
<div class="bme-ai-monitor-kv__row">
|
||||
<span>Base / Snapshot</span>
|
||||
<strong>${_escHtml(snapshotBuildText)}</strong>
|
||||
</div>
|
||||
<div class="bme-ai-monitor-kv__row">
|
||||
<span>Prepare / Native</span>
|
||||
<strong>${_escHtml(
|
||||
@@ -8837,6 +8924,18 @@ function _renderPersistDeltaTraceCard(state) {
|
||||
`${_formatDurationMs(diagnostics.hydrateMs)} / ${cacheText}`,
|
||||
)}</strong>
|
||||
</div>
|
||||
<div class="bme-ai-monitor-kv__row">
|
||||
<span>Commit 排队 / 提交</span>
|
||||
<strong>${_escHtml(commitPhaseText)}</strong>
|
||||
</div>
|
||||
<div class="bme-ai-monitor-kv__row">
|
||||
<span>Commit 细分</span>
|
||||
<strong>${_escHtml(commitBreakdownText)}</strong>
|
||||
</div>
|
||||
<div class="bme-ai-monitor-kv__row">
|
||||
<span>Commit Payload</span>
|
||||
<strong>${_escHtml(commitBytesText)}</strong>
|
||||
</div>
|
||||
<div class="bme-ai-monitor-kv__row">
|
||||
<span>PreparedSet Cache</span>
|
||||
<strong>${_escHtml(preparedSetCacheText)}</strong>
|
||||
@@ -8855,6 +8954,10 @@ function _renderPersistDeltaTraceCard(state) {
|
||||
`${Number(diagnostics.upsertNodeCount || 0)}N / ${Number(diagnostics.upsertEdgeCount || 0)}E / ${Number(diagnostics.deleteNodeCount || 0)}DN / ${Number(diagnostics.deleteEdgeCount || 0)}DE`,
|
||||
)}</strong>
|
||||
</div>
|
||||
<div class="bme-ai-monitor-kv__row">
|
||||
<span>未归因</span>
|
||||
<strong>${_escHtml(_formatDurationMs(diagnostics.untrackedMs))}</strong>
|
||||
</div>
|
||||
</div>
|
||||
${_renderMessageTraceTextBlock(
|
||||
"Fallback reason",
|
||||
|
||||
Reference in New Issue
Block a user