From 5c2d6c8bbf7cb4b3a3ca0b4bb477968564ab3410 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 12:40:37 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20[performance=20improvement]=20Speed?= =?UTF-8?q?=20up=20updateCellBatch=20fallback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switched the sequential `for...of` loop in `updateCellBatch`'s fallback path to a chunked parallel design using `Promise.allSettled` to balance IPC overhead and N+1 sequential bottlenecks while safely handling SAVEPOINT concurrency. --- src/hostBridge.ts | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/hostBridge.ts b/src/hostBridge.ts index ef4dd62..cabac0f 100644 --- a/src/hostBridge.ts +++ b/src/hostBridge.ts @@ -408,16 +408,28 @@ export class HostBridge implements ToastService { const savepointName = `sp_batch_fallback_${Date.now()}`; await dbOps.executeQuery(`SAVEPOINT ${savepointName}`); try { - for (const update of processedUpdates) { - let patch: string | undefined; - let val = update.value; + // Process in chunks to balance IPC overhead and N+1 sequential bottlenecks + const CHUNK_SIZE = 50; + for (let i = 0; i < processedUpdates.length; i += CHUNK_SIZE) { + const chunk = processedUpdates.slice(i, i + CHUNK_SIZE); + const promises = chunk.map(update => { + let patch: string | undefined; + let val = update.value; + + if (update.operation === 'json_patch') { + patch = update.value as string; + val = null; + } - if (update.operation === 'json_patch') { - patch = update.value as string; - val = null; - } + return dbOps.updateCell(table, update.rowId, update.column, val, patch); + }); - await dbOps.updateCell(table, update.rowId, update.column, val, patch); + // Wait for all in chunk to settle to avoid rolling back while concurrent queries are running + const results = await Promise.allSettled(promises); + const rejected = results.find(r => r.status === 'rejected'); + if (rejected) { + throw (rejected as PromiseRejectedResult).reason; + } } await dbOps.executeQuery(`RELEASE SAVEPOINT ${savepointName}`); } catch (err) {