From: stephan Date: Fri, 6 Mar 2026 23:50:44 +0000 (+0000) Subject: Add some jitter and duration info to the opfs concurrency tester. Ensure that Atomics... X-Git-Tag: major-release~100^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ac63b524acdf789c9a44623023bda10d693a4e7e;p=thirdparty%2Fsqlite.git Add some jitter and duration info to the opfs concurrency tester. Ensure that Atomics.waitAsync() is available for opfs-wl. Further testing has shown that Web opfs-wl is consistently fairer about doling out contested locks but it's dog slow compared to the original VFS under moderate concurrency. In single-connection use they're effectively on par. FossilOrigin-Name: a9aecc987512d60f2663973f43c769cf086fc14149edfbcb18c0aec9f5aa3dbf --- diff --git a/ext/wasm/api/opfs-common-shared.c-pp.js b/ext/wasm/api/opfs-common-shared.c-pp.js index 0bbaed930e..17916426ef 100644 --- a/ext/wasm/api/opfs-common-shared.c-pp.js +++ b/ext/wasm/api/opfs-common-shared.c-pp.js @@ -402,21 +402,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ descriptive error message if they're not found. This is intended to be run as part of async VFS installation steps. */ - opfsUtil.vfsInstallationFeatureCheck = function(){ - if(!globalThis.SharedArrayBuffer - || !globalThis.Atomics){ - throw new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. "+ - "The server must emit the COOP/COEP response headers to enable those. "+ - "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep"); - }else if('undefined'===typeof WorkerGlobalScope){ - throw new Error("The OPFS sqlite3_vfs cannot run in the main thread "+ - "because it requires Atomics.wait()."); - }else if(!globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || - !navigator?.storage?.getDirectory){ - throw new newError("Missing required OPFS APIs."); + opfsUtil.vfsInstallationFeatureCheck = function(vfsName){ + if( !globalThis.SharedArrayBuffer || !globalThis.Atomics ){ + toss("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics.", + "The server must emit the COOP/COEP response headers to enable those.", + "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep"); + }else if( 'undefined'===typeof WorkerGlobalScope ){ + toss("The OPFS sqlite3_vfs cannot run in the main thread", + "because it requires Atomics.wait()."); + }else if( !globalThis.FileSystemHandle || + !globalThis.FileSystemDirectoryHandle || + !globalThis.FileSystemFileHandle?.prototype?.createSyncAccessHandle || + !navigator?.storage?.getDirectory ){ + toss("Missing required OPFS APIs."); + }else if( 'opfs-wl'===vfsName && !globalThis.Atomics.waitAsync ){ + toss('The',vfsName,'VFS requires Atomics.waitAsync(), which is not available.'); } }; @@ -446,12 +446,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ */ opfsUtil.initOptions = function callee(vfsName, options){ const urlParams = new URL(globalThis.location.href).searchParams; - if(urlParams.has(vfsName+'-disable')){ + if( urlParams.has(vfsName+'-disable') ){ //sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.'); return; } try{ - opfsUtil.vfsInstallationFeatureCheck(); + opfsUtil.vfsInstallationFeatureCheck(vfsName); }catch(e){ return; } 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 797407e2c4..f89f73c311 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js @@ -89,7 +89,7 @@ const installAsyncProxy = function(){ 2 = warnings and errors 3 = debug, warnings, and errors */ - state.verbose = 2; + state.verbose = 1; const loggers = { 0:console.error.bind(console), diff --git a/ext/wasm/tests/opfs/concurrency/test.js b/ext/wasm/tests/opfs/concurrency/test.js index 18c01a5b7e..bdc15a3c4b 100644 --- a/ext/wasm/tests/opfs/concurrency/test.js +++ b/ext/wasm/tests/opfs/concurrency/test.js @@ -59,7 +59,7 @@ ) || 3; options.opfsVerbose = ( urlArgsHtml.has('verbose') ? +urlArgsHtml.get('verbose') : 1 - ) || 1; + ) || 0; options.interval = ( urlArgsHtml.has('interval') ? +urlArgsHtml.get('interval') : 1000 ) || 1000; @@ -76,41 +76,52 @@ for(const w of workers) w.postMessage({type, payload:args}); }; workers.counts = {loaded: 0, passed: 0, failed: 0}; + let timeStart; + const calcTime = (endDate)=>{ + return endDate.getTime() - timeStart?.getTime?.(); + }; const checkFinished = function(){ if(workers.counts.passed + workers.counts.failed !== workers.length){ return; } + stdout("Total Worker run time:",calcTime(new Date()),"ms"); if(workers.counts.failed>0){ logCss('tests-fail',"Finished with",workers.counts.failed,"failure(s)."); }else{ logCss('tests-pass',"All",workers.length,"workers finished."); } }; + workers.onmessage = function(msg){ msg = msg.data; const prefix = 'Worker #'+msg.worker+':'; switch(msg.type){ - case 'loaded': - stdout(prefix,"loaded"); - if(++workers.counts.loaded === workers.length){ - stdout("All",workers.length,"workers loaded. Telling them to run..."); - workers.post('run'); - } - break; - case 'stdout': stdout(prefix,...msg.payload); break; - case 'stderr': stderr(prefix,...msg.payload); break; - case 'error': stderr(prefix,"ERROR:",...msg.payload); break; - case 'finished': - ++workers.counts.passed; - logCss('tests-pass',prefix,...msg.payload); - checkFinished(); - break; - case 'failed': - ++workers.counts.failed; - logCss('tests-fail',prefix,"FAILED:",...msg.payload); - checkFinished(); - break; - default: logCss('error',"Unhandled message type:",msg); break; + case 'loaded': + stdout(prefix,"loaded"); + if(++workers.counts.loaded === workers.length){ + timeStart = new Date(); + stdout(timeStart,"All",workers.length,"workers loaded. Telling them to run..."); + workers.post('run'); + } + break; + case 'stdout': stdout(prefix,...msg.payload); break; + case 'stderr': stderr(prefix,...msg.payload); break; + case 'error': stderr(prefix,"ERROR:",...msg.payload); break; + case 'finished': { + ++workers.counts.passed; + const timeEnd = new Date(); + logCss('tests-pass',prefix,timeEnd,"("+calcTime(timeEnd)+"ms) ", ...msg.payload); + checkFinished(); + break; + } + case 'failed': { + ++workers.counts.failed; + const timeEnd = new Date(); + logCss('tests-fail',prefix,timeEnd,"("+calcTime(timeEnd)+"ms) FAILED:",...msg.payload); + checkFinished(); + break; + } + default: logCss('error',"Unhandled message type:",msg); break; } }; diff --git a/ext/wasm/tests/opfs/concurrency/worker.js b/ext/wasm/tests/opfs/concurrency/worker.js index 0f9c9b68cb..75c2b8a64d 100644 --- a/ext/wasm/tests/opfs/concurrency/worker.js +++ b/ext/wasm/tests/opfs/concurrency/worker.js @@ -80,7 +80,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ }catch(e){ if(e instanceof sqlite3.SQLite3Error && sqlite3.capi.SQLITE_BUSY===e.resultCode){ - stderr("Retrying for BUSY: ",e.message); + stderr("Retrying",(db ? "db init" : "open()"),"for BUSY:",e.message); continue; } throw e; @@ -106,7 +106,7 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ }catch(e){ if(e instanceof sqlite3.SQLite3Error && sqlite3.capi.SQLITE_BUSY===e.resultCode){ - stderr("Retrying for BUSY: ",e.message); + stderr("Retrying interval #",interval.count,"for BUSY:",e.message); continue; } stderr("Error: ",e.message); @@ -121,7 +121,8 @@ globalThis.sqlite3InitModule().then(async function(sqlite3){ if(interval.error || maxIterations === interval.count){ finish(); }else{ - setTimeout(timer, interval.delay); + const jitter = (Math.random()*150 - Math.random()*150) | 0; + setTimeout(timer, interval.delay + jitter); } }, interval.delay); }/*run()*/; diff --git a/manifest b/manifest index 72316086e1..6c368d0569 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Get\s"opfs"\sand\s"opfs-wl"\sproperly\ssplit.\sSpeedtest1\sand\sthe\sconcurrency\stester\sare\shappy\swith\sopfs-wl\sbut\sit\sis\snot\syet\splugged\sin\sto\stester1. -D 2026-03-06T22:21:06.784 +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 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -585,7 +585,7 @@ F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b4724 F ext/wasm/api/extern-post-js.c-pp.js d9f42ecbedc784c0d086bc37800e52946a14f7a21600b291daa3f963c314f930 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/opfs-common-inline.c-pp.js 5be8d6d91963849e218221b48206ae55612630bb2cd7f30b1b6fcf7a9e374b76 -F ext/wasm/api/opfs-common-shared.c-pp.js b41b71ac06264e2d2db9a08e9cd7d5ee0e5730d224a4e81e0c42b0928028844e +F ext/wasm/api/opfs-common-shared.c-pp.js 612df64a2a159db30786c742c70a09d75b993d034f360367125747d2eca531a5 F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b F ext/wasm/api/post-js-header.js f35d2dcf1ab7f22a93d565f8e0b622a2934fc4e743edf3b708e4dd8140eeff55 F ext/wasm/api/pre-js.c-pp.js 9234ea680a2f6a2a177e8dcd934bdc5811a9f8409165433a252b87f4c07bba6f @@ -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 6025b22ebb92f9216e68d85c4e27c228e148f4d081e306f27d0a50342e56ec37 +F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 341468dc0f322d98b032c6922c9865ef9028fafc8f713b950c5ff2c0305e2c87 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 @@ -646,8 +646,8 @@ F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c9 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 74f4ef9a827d081e6bb0ffb1d124bb54015dab8f7ae47abd5b5f26d71633331a -F ext/wasm/tests/opfs/concurrency/worker.js ce1d5d7545b17f62bac2dcce2505a89c3690e1d9209512cc51512cee6e3024f5 +F ext/wasm/tests/opfs/concurrency/test.js b315a5480197e8da80c626d21b7939a485784bc6a13ec681115d4f5384c9b971 +F ext/wasm/tests/opfs/concurrency/worker.js b247316330d2c11817b6debc7d16e4cbc51c689f56a4cb5d6c4ec4a2bca45ca7 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 247ffed141f66a6a5a396a3e002995a9f00c70333271199200530066e77956c4 -R d5ab78b2216c6ac5e35f6ab8d6aa4867 +P 12dcd5425967b6306f3e3178babeac130962edb78e6298d545a429a1a20457cc +R 587bc730112047fe7757e9bed1469d73 U stephan -Z 836eb4f55d744876555cc67389157d1f +Z cdae14ec494ba9a4ab6ec30704fa3278 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 31efc532c3..3ea9463f59 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -12dcd5425967b6306f3e3178babeac130962edb78e6298d545a429a1a20457cc +a9aecc987512d60f2663973f43c769cf086fc14149edfbcb18c0aec9f5aa3dbf