From ec950ea77c4195c528b78222455c5e0ec9575862 Mon Sep 17 00:00:00 2001 From: efeire <15682810+efeire@users.noreply.github.com> Date: Fri, 9 Oct 2026 18:50:03 +0800 Subject: [PATCH] fix(oceanbase): preserve concurrent full-value hydration during save preparation --- .../__tests__/useDataGridEditor.spec.ts | 2 +- .../src/composables/useDataGridLargeValues.ts | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/composables/__tests__/useDataGridEditor.spec.ts b/apps/desktop/src/composables/__tests__/useDataGridEditor.spec.ts index 915e3a4aca..8df93221e8 100644 --- a/apps/desktop/src/composables/__tests__/useDataGridEditor.spec.ts +++ b/apps/desktop/src/composables/__tests__/useDataGridEditor.spec.ts @@ -1395,7 +1395,7 @@ describe("useDataGridEditor saveChanges reload", () => { it("loads complete original baselines before generating forward and rollback SQL", async () => { const source = { columns: ["id", "status"], rows: [[1, "LOB preview"]] as CellValue[][] }; - const prepareSaveBaseline = vi.fn(async (changes) => { + const prepareSaveBaseline = vi.fn(async (changes: Parameters>[0]) => { expect(changes.dirtyRows.get(0).get(1)).toBeNull(); source.rows[0]![1] = "complete original LOB"; }); diff --git a/apps/desktop/src/composables/useDataGridLargeValues.ts b/apps/desktop/src/composables/useDataGridLargeValues.ts index 8fe4fe9c10..9bca2b9f4a 100644 --- a/apps/desktop/src/composables/useDataGridLargeValues.ts +++ b/apps/desktop/src/composables/useDataGridLargeValues.ts @@ -660,11 +660,21 @@ export function useDataGridLargeValues(options: UseDataGridLargeValuesOptions) { rows[cell.row_index]![cell.column_index] = value; } if (!isCurrent()) throw new Error("LOB result context changed"); + // Other consumers can hydrate another cell while these requests await. + // Merge only the requested baselines into the latest rows and budget. + const mergedRows = source.rows.map((row) => [...row]); + const mergedSizes = new Map(materializedSnapshotBytes.get(source)); + for (const cell of cells) { + mergedRows[cell.row_index]![cell.column_index] = rows[cell.row_index]![cell.column_index]; + const key = largeValueCellKey(cell.row_index, cell.column_index); + mergedSizes.set(key, sizes.get(key)!); + } + if ([...mergedSizes.values()].reduce((sum, size) => sum + size, 0) > 64 * 1024 * 1024) throw new Error("LOB save baseline exceeds the 64 MiB view/edit limit; reload and edit a smaller selection"); source.large_value_refs = [...new Set([...(source.large_value_refs ?? []), ...cells.map((cell) => cell.value_ref!)])]; const resolved = new Set(cells.map((cell) => largeValueCellKey(cell.row_index, cell.column_index))); - source.rows = rows; + source.rows = mergedRows; source.large_value_cells = source.large_value_cells?.filter((cell) => !resolved.has(largeValueCellKey(cell.row_index, cell.column_index))); - materializedSnapshotBytes.set(source, sizes); + materializedSnapshotBytes.set(source, mergedSizes); options.largeValueResolutionVersion.value += 1; options.clearCellFormatCache(); options.invalidateResultEstimate(source);