BLite.Wasm: two tabs on one database lose a committed write (IndexedDB) or cannot open it (OPFS)
Maintainers usually reply within 2 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 45/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- javascript, wasm
- Domain
- databases
Research direction
Start with IndexedDbPageStorage.OpenAsync, OpfsPageStorage.OpenAsync, and the locking/worker handling in src/BLite.Wasm/wwwroot/*.mjs, then run the named Two_tabs browser tests. Confirm the implementation consistently prevents concurrent writers and reports a BLite-level error when another tab owns the database, including the OPFS access-handle failure. Update WASM_SUPPORT.md to describe the supported two-tab behavior; broader reader/writer coordination is a separate design effort.
Written by the indexing model from the issue text.
Description
Two tabs of the same origin open the same database. On IndexedDB, both tabs' writes are acknowledged and checkpointed, and a fresh third tab sees only the second tab's: the first tab's committed write is gone, with no error anywhere. On OPFS the second tab cannot open the database at all. Nothing in BLite.Wasm coordinates tabs, and nothing tells the user that a second tab is unsupported.
Two tabs are two processes on one database, the case the README's multi-process mode covers on desktop ("N-reader / 1-writer access across OS processes", opt-in, with the .wal-shm sidecar). In the browser there is no opt-in, no lock, and no error.
Found by the browser harness (tests/BLite.Wasm.BrowserTests, https://github.com/EntglDb/BLite/pull/295), which carries the affected rows as known candidate BW5 until this is fixed.
Repro
Rows Two_tabs_writing_the_same_database_keep_both_writes IndexedDb and Opfs.
tab A: engine = await BLiteWasm.CreateAsync("shared", IndexedDb)
tab B: engine = await BLiteWasm.CreateAsync("shared", IndexedDb)
tab A: InsertAsync(name="a"); CheckpointAsync() -> ok
tab B: InsertAsync(name="b"); CheckpointAsync() -> ok
tab B: FindAllAsync -> b
tab C: await BLiteWasm.CreateAsync("shared", IndexedDb); FindAllAsync -> b
dotnet test tests/BLite.Wasm.BrowserTests --filter "FullyQualifiedName~Two_tabs"
OPFS: the second CreateAsync throws
JSException: Failed to execute 'createSyncAccessHandle' on 'FileSystemFileHandle': Access Handles cannot be created if there is another open Access Handle or Writable stream associated with the same file.
Expected: a third tab sees a,b; or the second tab gets a clear error on open (as desktop does without AllowMultiProcessAccess), on both backends.
Actual: IndexedDB, a silent lost update; OPFS, an unhandled JSException from the Worker.
Mechanism (verified on 0450b97)
- Each tab's page store loads every page into its own managed cache on open (
IndexedDbPageStorage.OpenAsync,OpfsPageStorage.OpenAsync) and writes the dirty ones back inFlushAsync. Tab B opened before A's write, so its cache has no page of A's; B's allocation hands out the same page ids, and B's checkpoint writes them over A's. The next page id is a single stored value (idbSaveNextPageId) that each tab overwrites with its own. - The JS modules take no lock and publish no change: no
navigator.locks,BroadcastChanneloronversionchangehandling insrc/BLite.Wasm/wwwroot/*.mjs, so neither tab learns of the other. - On OPFS the browser itself refuses a second
createSyncAccessHandleon the file; the error is surfaced raw from the Worker, nothing inOpfsPageStorage.OpenAsyncturns it into a BLite error or falls back.
Affected versions: BLite.Wasm since #63 (830e83e, v4.4.0) through v5.2.3.
Fix considerations
- The cheapest safe behaviour: one writer per origin. Take a
navigator.lockslock on the database name inOpenAsync(exclusive,ifAvailable), fail the second open with a BLite exception that says another tab holds the database, and catch the OPFS access-handle error the same way. Then a second tab is a clear error, not a lost update. - A reader/writer scheme (one tab writes, others read through a shared WAL) is the multi-process mode's design; in the browser the WAL could be the IndexedDB store with a
BroadcastChannelfor the generation, as.wal-shmis on desktop. That is a larger piece and a design choice for the maintainers. - Either way WASM_SUPPORT.md should state what happens with two tabs.
Related: #110 (the .wal-shm sidecar, the desktop answer to the same problem), #197 / #198 / #200 / #203 / #216 (lost commits between processes, fixed on desktop), #188, #220, #226 (multi-process, open), #57 / #63 (BLite.Wasm). The other issues from the same harness: #289, #290, #292, #293.
- Dominant language
- C#
- Stars
- 66
- Forks
- 6
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 58
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from EntglDb/BLite
-
GdprMode.Strict warns that deleted documents are not zeroed, but every delete zero-fills themPossibly taken @CaffeinatedCoder claimed this 2 days ago. Openbug gdpr package/core severity/low
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
EntglDb/BLite#299 · 1 comment ·
Maintainers usually reply within 2 days
-
bug package/core severity/medium triage
Difficulty 4/5 3-5 days Newbie friendliness 54/100
Maintainers usually reply within 2 days
-
bug package/core severity/medium
Difficulty 4/5 3-5 days Newbie friendliness 48/100
EntglDb/BLite#322 · 1 comment ·
Maintainers usually reply within 2 days
-
enhancement package/core
Difficulty 4/5 3-5 days Newbie friendliness 48/100
EntglDb/BLite#320 · 1 comment ·
Maintainers usually reply within 2 days
-
BLiteSession.Rollback() does not await the rollback: it returns while the transaction is still active, and failures go unobservedPossibly taken @CaffeinatedCoder claimed this 2 days ago. Openbug package/core severity/medium
Difficulty 3/5 1-2 days Newbie friendliness 78/100
EntglDb/BLite#307 · 1 comment ·
Maintainers usually reply within 2 days
Similar issues
-
The test-platform skill doesn't say what three of its failures look likePossibly taken @yasmoradi claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
bitfoundation/bitplatform#14022 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
getsentry/sentry-dotnet#5756 · 1 comment ·
Maintainers usually reply within 1 day
-
area-TableView bug needs-triage team-Controls
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
microsoft/microsoft-ui-xaml#12351 · 1 comment ·
Maintainers usually reply within 2 days
-
AudioClient and ImageClient file path overloads send the full local path as the multipart file namePossibly taken @sebxt claimed this today. Openarea: audio area: images feature-request
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
openai/openai-dotnet#1453 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
Maintainers usually reply within 1 day