From: stephan
Date: Sat, 7 Mar 2026 01:01:13 +0000 (+0000)
Subject: For backwards compatibility, ensure that the "opfs" VFS does not specifically require...
X-Git-Tag: major-release~100^2~7
X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=57d0fe254a9628776eb081750543c8ce1c62fc83;p=thirdparty%2Fsqlite.git
For backwards compatibility, ensure that the "opfs" VFS does not specifically require Atomics.waitAsync() (a new requirement of "opfs-wl"), but make use of it if available. Only apply jitter to the concurrency test runs at random intervals.
FossilOrigin-Name: f2175f526c00cfe562e8f332eb197b5ef2c3d6be1fff2aab1566c2c533a293ac
---
diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js
index f89f73c311..6362c6efd4 100644
--- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js
+++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js
@@ -668,8 +668,7 @@ const installAsyncProxy = function(){
__implicitLocks.delete(fid);
let rc = 0;
try{
- /* Make only one attempt to get the handle. */
- await getSyncHandle(fh, 'xLock');
+ await getSyncHandle(fh, 'xLock', state.asyncIdleWaitTime, 5);
}catch(e){
fh.xLock = oldLockType;
state.s11n.storeException(1, e);
@@ -794,15 +793,64 @@ const installAsyncProxy = function(){
const opView = state.sabOPView;
const slotWhichOp = opIds.whichOp;
const idleWaitTime = state.asyncIdleWaitTime;
+ const hasWaitAsync = !!Atomics.waitAsync;
while(!flagAsyncShutdown){
try {
- const opId = Atomics.load(opView, slotWhichOp);
- if( 0===opId ){
- const rv = Atomics.waitAsync(opView, slotWhichOp, 0,
- idleWaitTime);
- if( rv.async ) await rv.value;
- await releaseImplicitLocks();
- continue;
+ let opId;
+ if( hasWaitAsync ){
+ opId = Atomics.load(opView, slotWhichOp);
+ if( 0===opId ){
+ const rv = Atomics.waitAsync(opView, slotWhichOp, 0,
+ idleWaitTime);
+ if( rv.async ) await rv.value;
+ await releaseImplicitLocks();
+ continue;
+ }
+ }else{
+ /**
+ For browsers without Atomics.waitAsync(), we require
+ the legacy implementation. Browser versions where
+ waitAsync() arrived:
+
+ Chrome: 90 (2021-04-13)
+ Firefox: 145 (2025-11-11)
+ Safari: 16.4 (2023-03-27)
+
+ The "opfs" VFS was not born until Chrome was somewhere in
+ the v104-108 range and did not work with Safari < v17
+ (2023-09-18) due to a WebKit bug which restricted OPFS
+ access from sub-Workers.
+
+ The waitAsync() counterpart of this block has shown to be
+ slightly more performant for the "opfs" VFS than this
+ block (whereas "opfs-wl" _requires_ that block), so we
+ enable it where it's available, regardless of the value
+ of isWebLocker, with the note that if isWebLocker is true
+ then the bootstrapping of this script will have failed if
+ waitAsync() is not available.
+ */
+ if('not-equal'!==Atomics.wait(
+ state.sabOPView, slotWhichOp, 0, state.asyncIdleWaitTime
+ )){
+ /* Maintenance note: we compare against 'not-equal' because
+
+ https://github.com/tomayac/sqlite-wasm/issues/12
+
+ is reporting that this occasionally, under high loads,
+ returns 'ok', which leads to the whichOp being 0 (which
+ isn't a valid operation ID and leads to an exception,
+ along with a corresponding ugly console log
+ message). Unfortunately, the conditions for that cannot
+ be reliably reproduced. The only place in our code which
+ writes a 0 to the state.opIds.whichOp SharedArrayBuffer
+ index is a few lines down from here, and that instance
+ is required in order for clear communication between
+ the sync half of this proxy and this half.
+ */
+ await releaseImplicitLocks();
+ continue;
+ }
+ opId = Atomics.load(state.sabOPView, slotWhichOp);
}
Atomics.store(opView, slotWhichOp, 0);
const hnd = f.opHandlers[opId]?.f ?? toss("No waitLoop handler for whichOp #",opId);
@@ -812,6 +860,16 @@ const installAsyncProxy = function(){
operation */
) || [];
//error("waitLoop() whichOp =",opId, f.opHandlers[opId].key, args);
+//#if nope
+ if( isWebLocker && (opId==opIds.xLock || opIds==opIds.xUnlock) ){
+ /* An expert suggests that this introduces a race condition,
+ but my eyes aren't seeing it. The hope was that this
+ would improve the lock speed a tick, but it does not
+ appear to. */
+ hnd(...args);
+ continue;
+ }
+//#endif
await hnd(...args);
}catch(e){
error('in waitLoop():', e);
@@ -865,7 +923,7 @@ if(globalThis.window === globalThis){
}else if(!globalThis.Atomics){
wPost('opfs-unavailable', "Missing Atomics API.",
"The server must emit the COOP/COEP response headers to enable that.");
-}else if('opfs-wl'===vfsName && !globalThis.Atomics.waitAsync){
+}else if(isWebLocker && !globalThis.Atomics.waitAsync){
wPost('opfs-unavailable',"Missing required Atomics.waitSync() for "+vfsName);
}else if(!globalThis.FileSystemHandle ||
!globalThis.FileSystemDirectoryHandle ||
diff --git a/ext/wasm/tests/opfs/concurrency/index.html b/ext/wasm/tests/opfs/concurrency/index.html
index 54ed04a4f6..c5e929b010 100644
--- a/ext/wasm/tests/opfs/concurrency/index.html
+++ b/ext/wasm/tests/opfs/concurrency/index.html
@@ -25,15 +25,14 @@
the workers=N URL flag. Set the time between each
workload with interval=N (milliseconds). Set the
number of worker iterations with iterations=N.
- Enable OPFS VFS verbosity with verbose=1-3 (output
- goes to the dev console). Disable/enable "unlock ASAP" mode
- (higher concurrency, lower speed) with unlock-asap=0-1.
+ Disable/enable "unlock ASAP" mode (potentially higher
+ concurrency but lower speed) with unlock-asap=0-1.
Achtung: if it does not start to do anything within a couple of
seconds, check the dev console: Chrome sometimes fails to load
- the wasm module due to "cannot allocate WasmMemory." Closing and
- re-opening the tab usually resolves it, but sometimes restarting
- the browser is required.
+ the wasm module due to "cannot allocate WasmMemory" when
+ reloading the page. Closing and re-opening the tab usually
+ resolves it, but sometimes restarting the browser is required.
Links for various testing options:
diff --git a/ext/wasm/tests/opfs/concurrency/test.js b/ext/wasm/tests/opfs/concurrency/test.js
index bdc15a3c4b..f8d7f10399 100644
--- a/ext/wasm/tests/opfs/concurrency/test.js
+++ b/ext/wasm/tests/opfs/concurrency/test.js
@@ -139,12 +139,13 @@
return li.join('&');
};
for(const opt of [
- {interval: 500, workers: 1, iterations: 5, vfs: 'opfs-wl', opfsVerbose: 2},
- {interval: 500, workers: 2, iterations: 5, vfs: 'opfs-wl', opfsVerbose: 2},
{interval: 1000, workers: 5, iterations: 30},
{interval: 500, workers: 5, iterations: 30},
{interval: 250, workers: 3, iterations: 30},
- {interval: 600, workers: 5, iterations: 100}
+ {interval: 600, workers: 5, iterations: 100},
+ {interval: 500, workers: 1, iterations: 5, vfs: 'opfs-wl'},
+ {interval: 500, workers: 2, iterations: 10, vfs: 'opfs-wl'},
+ {interval: 500, workers: 5, iterations: 20, vfs: 'opfs-wl'},
]){
const li = document.createElement('li');
eTestLinks.appendChild(li);
@@ -176,4 +177,4 @@
// Have to delay onmessage assignment until after the loop
// to avoid that early workers get an undue head start.
workers.forEach((w)=>w.onmessage = workers.onmessage);
-})(self);
+})(globalThis);
diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js
index 75c2b8a64d..ccd1df932a 100644
--- a/ext/wasm/tests/opfs/concurrency/worker.js
+++ b/ext/wasm/tests/opfs/concurrency/worker.js
@@ -68,7 +68,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){
filename: 'file:'+dbName+'?opfs-unlock-asap='+options.unlockAsap,
flags: 'c'
});
- sqlite3.capi.sqlite3_busy_timeout(db.pointer, 15000);
+ sqlite3.capi.sqlite3_busy_timeout(db.pointer, 5000);
}
db.transaction((db)=>{
db.exec([
@@ -121,8 +121,11 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){
if(interval.error || maxIterations === interval.count){
finish();
}else{
- const jitter = (Math.random()*150 - Math.random()*150) | 0;
- setTimeout(timer, interval.delay + jitter);
+ const jitter = (Math.random()>=0.5)
+ ? ((Math.random()*100 - Math.random()*100) | 0)
+ : 0;
+ const n = interval.delay + jitter;
+ setTimeout(timer, n<50 ? interval.delay : n);
}
}, interval.delay);
}/*run()*/;
diff --git a/manifest b/manifest
index 6c368d0569..ecc54ab16c 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\ssome\sjitter\sand\sduration\sinfo\sto\sthe\sopfs\sconcurrency\stester.\sEnsure\sthat\sAtomics.waitAsync()\sis\savailable\sfor\sopfs-wl.\sFurther\stesting\shas\sshown\sthat\sWeb\sopfs-wl\sis\sconsistently\sfairer\sabout\sdoling\sout\scontested\slocks\sbut\sit's\sdog\sslow\scompared\sto\sthe\soriginal\sVFS\sunder\smoderate\sconcurrency.\sIn\ssingle-connection\suse\sthey're\seffectively\son\spar.
-D 2026-03-06T23:50:44.079
+C For\sbackwards\scompatibility,\sensure\sthat\sthe\s"opfs"\sVFS\sdoes\snot\sspecifically\srequire\sAtomics.waitAsync()\s(a\snew\srequirement\sof\s"opfs-wl"),\sbut\smake\suse\sof\sit\sif\savailable.\sOnly\sapply\sjitter\sto\sthe\sconcurrency\stest\sruns\sat\srandom\sintervals.
+D 2026-03-07T01:01:13.846
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -594,7 +594,7 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c
F ext/wasm/api/sqlite3-api-prologue.js 98fedc159c9239b226d19567d7172300dee5ffce176e5fa2f62dd1f17d088385
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938
F ext/wasm/api/sqlite3-license-version-header.js 98d90255a12d02214db634e041c8e7f2f133d9361a8ebf000ba9c9af4c6761cc
-F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 341468dc0f322d98b032c6922c9865ef9028fafc8f713b950c5ff2c0305e2c87
+F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 296b3d3701c3b42918357e4d9e5d82c5321b371115fb51a8a405c2eaeebd9f0f
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js a61dd2b4d919d2d5d83c5c7e49b89ecbff2525ff81419f6a6dbaecaf3819c490
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9
@@ -645,9 +645,9 @@ F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f80
F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c986e48af7d3d720fcd244
F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb
F ext/wasm/tester1.c-pp.js a4e79fbf63bb3255d2b8ffc1cd538c115d2f6b599bc324904c80f6644379a284
-F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
-F ext/wasm/tests/opfs/concurrency/test.js b315a5480197e8da80c626d21b7939a485784bc6a13ec681115d4f5384c9b971
-F ext/wasm/tests/opfs/concurrency/worker.js b247316330d2c11817b6debc7d16e4cbc51c689f56a4cb5d6c4ec4a2bca45ca7
+F ext/wasm/tests/opfs/concurrency/index.html c8ac239f6fb45440adbdddb33a0fde2c61a20799189d60b8926be702a27dd226
+F ext/wasm/tests/opfs/concurrency/test.js 520061e6a624fe0a7c07cf3438cb6b9b7c9dcbd606e644ccb5fb52518c48b342
+F ext/wasm/tests/opfs/concurrency/worker.js 90e51ff3e781a6e08f265cbaaa993bb10eb0b798893b78cf4d8a8a8b3b561392
F ext/wasm/tests/opfs/sahpool/digest-worker.js b0ab6218588f1f0a6d15a363b493ceaf29bfb87804d9e0165915a9996377cf79
F ext/wasm/tests/opfs/sahpool/digest.html 206d08a34dc8bd570b2581d3d9ab3ecad3201b516a598dd096dcf3cf8cd81df8
F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328
@@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 12dcd5425967b6306f3e3178babeac130962edb78e6298d545a429a1a20457cc
-R 587bc730112047fe7757e9bed1469d73
+P a9aecc987512d60f2663973f43c769cf086fc14149edfbcb18c0aec9f5aa3dbf
+R 825063f48a3ce6fa65e33b9852885bae
U stephan
-Z cdae14ec494ba9a4ab6ec30704fa3278
+Z a8fffcaa59d459a1613276d07e6e1f6d
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 3ea9463f59..a5dd212704 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-a9aecc987512d60f2663973f43c769cf086fc14149edfbcb18c0aec9f5aa3dbf
+f2175f526c00cfe562e8f332eb197b5ef2c3d6be1fff2aab1566c2c533a293ac