Skip to content

Commit 8ca599c

Browse files
zknprclaude
andcommitted
diag(web): extend instrumentation to read-path RPC + per-file reads (#421 Codex review)
Codex correctly flagged that the diagnostic would miss the actual #418 stall: 1. (P2) The trace stopped at initializeDatabase, but the loading screen then awaits ping -> fetchSchema -> fetchTableCount/fetchTableData (viewer.js). A hang in any of those would show 'establishConnection complete' then nothing, with no unmatched 'start'. Now the browser facade wraps ping, fetchSchema, fetchTableCount, fetchTableData, getTableInfo, getPragmas in diagStep too. 2. (P2) loadDatabaseFiles was a single wrapper hiding three awaits (stat, main readFile, optional -wal readFile via Promise.all). A never-settling -wal read over vscode-vfs would hang the open with no specific marker. loadDatabaseFiles now takes an optional diag callback and logs each fs op independently. tsc clean; build worker-free; workerFactory_browser.test.ts passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d3e76b6 commit 8ca599c

1 file changed

Lines changed: 35 additions & 11 deletions

File tree

src/workerFactory.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ async function createInProcessWasmDatabaseConnection(
247247
// Browser mode always reads database bytes through the VS Code filesystem.
248248
// There is no file-path fast path because the web extension host cannot
249249
// access local disk paths directly.
250-
const [dbContent, walContent] = await diagStep('loadDatabaseFiles', () => loadDatabaseFiles(fileUri));
250+
const [dbContent, walContent] = await diagStep('loadDatabaseFiles', () => loadDatabaseFiles(fileUri, diag));
251251
diag(` db bytes=${dbContent?.byteLength ?? 'null'} wal bytes=${walContent?.byteLength ?? 'null'}`);
252252

253253
// Preload sql.js WASM bytes from the extension assets directory so
@@ -298,20 +298,25 @@ async function createInProcessWasmDatabaseConnection(
298298
endpoint.updateCellBatch(table, updates),
299299
addColumn: (table: string, column: string, type: string, defaultValue?: string) =>
300300
endpoint.addColumn(table, column, type, defaultValue),
301+
// The read-path methods below run during the loading screen (viewer.js
302+
// awaits ping -> fetchSchema -> fetchTableCount/fetchTableData on open).
303+
// Wrap them in diagStep so a stall in any of THEM — not just
304+
// establishConnection's awaits — is pinpointed by the last unmatched
305+
// "start" in the trace. (#418 diagnostic)
301306
fetchTableData: (table: string, options: TableQueryOptions) =>
302-
endpoint.fetchTableData(table, options),
307+
diagStep(`fetchTableData(${table})`, () => endpoint.fetchTableData(table, options)),
303308
fetchTableCount: (table: string, options: TableCountOptions) =>
304-
endpoint.fetchTableCount(table, options),
309+
diagStep(`fetchTableCount(${table})`, () => endpoint.fetchTableCount(table, options)),
305310
fetchSchema: () =>
306-
endpoint.fetchSchema(),
311+
diagStep('fetchSchema', () => endpoint.fetchSchema()),
307312
getTableInfo: (table: string) =>
308-
endpoint.getTableInfo(table),
313+
diagStep(`getTableInfo(${table})`, () => endpoint.getTableInfo(table)),
309314
getPragmas: () =>
310-
endpoint.getPragmas(),
315+
diagStep('getPragmas', () => endpoint.getPragmas()),
311316
setPragma: (pragma: string, value: CellValue) =>
312317
endpoint.setPragma(pragma, value),
313318
ping: () =>
314-
endpoint.ping(),
319+
diagStep('ping', () => endpoint.ping()),
315320
writeToFile: (path: string) =>
316321
endpoint.writeToFile(path)
317322
};
@@ -541,10 +546,16 @@ async function createWorkerBackedWasmDatabaseConnection(
541546
* Load database file and optional WAL file.
542547
*
543548
* @param uri - Database file URI
549+
* @param diag - Optional diagnostic logger (#418). When provided, each internal
550+
* filesystem await (stat, main readFile, optional -wal readFile) is logged
551+
* separately so a stall in one specific call is identifiable. The -wal read is
552+
* a prime suspect: reading a (usually nonexistent) `-wal` over vscode-vfs may
553+
* never settle in the web extension host.
544554
* @returns Tuple of [database content, WAL content]
545555
*/
546556
async function loadDatabaseFiles(
547-
uri: vsc.Uri
557+
uri: vsc.Uri,
558+
diag?: (message: string) => void
548559
): Promise<[Uint8Array | null, Uint8Array | null]> {
549560
// Untitled documents start empty
550561
if (uri.scheme === 'untitled') {
@@ -554,17 +565,30 @@ async function loadDatabaseFiles(
554565
const maxSize = getMaximumFileSizeBytes();
555566

556567
// Check file size
568+
diag?.('▶ fs.stat(db) … start');
557569
const fileStat = await Promise.resolve(vsc.workspace.fs.stat(uri)).catch(() => ({ size: 0 }));
570+
diag?.(` ✓ fs.stat(db) ok (size=${fileStat.size})`);
558571
if (maxSize !== 0 && fileStat.size > maxSize) {
559572
throw new Error(`File size (${(fileStat.size / (1024 * 1024)).toFixed(2)} MB) exceeds the maximum allowed size (${(maxSize / (1024 * 1024)).toFixed(2)} MB). Configure 'sqliteExplorer.maxFileSize' to increase the limit.`);
560573
}
561574

562575
// Construct WAL file URI
563576
const walUri = uri.with({ path: uri.path + '-wal' });
564577

565-
// Read both files concurrently
578+
// Read both files concurrently. Log each independently so a hang in the main
579+
// DB read vs. the optional -wal read is distinguishable in the #418 trace.
566580
return Promise.all([
567-
vsc.workspace.fs.readFile(uri),
568-
Promise.resolve(vsc.workspace.fs.readFile(walUri)).catch(() => null)
581+
(async () => {
582+
diag?.('▶ fs.readFile(db) … start');
583+
const r = await vsc.workspace.fs.readFile(uri);
584+
diag?.(` ✓ fs.readFile(db) ok (${r?.byteLength ?? 'null'} bytes)`);
585+
return r;
586+
})(),
587+
(async () => {
588+
diag?.('▶ fs.readFile(-wal, optional) … start');
589+
const r = await Promise.resolve(vsc.workspace.fs.readFile(walUri)).catch(() => null);
590+
diag?.(` ✓ fs.readFile(-wal) settled (${r ? r.byteLength + ' bytes' : 'absent'})`);
591+
return r;
592+
})()
569593
]);
570594
}

0 commit comments

Comments
 (0)