]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
The opfs-wl lock hang has been traced to starvation between the WebLock and the tight...
authorstephan <stephan@noemail.net>
Thu, 5 Mar 2026 06:30:57 +0000 (06:30 +0000)
committerstephan <stephan@noemail.net>
Thu, 5 Mar 2026 06:30:57 +0000 (06:30 +0000)
FossilOrigin-Name: 113bd910e12fea17f9f4a0a3baf706f15627c08cfa6b47a960a83eee761ef4dd

ext/wasm/api/opfs-common-shared.c-pp.js
ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js
ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js
manifest
manifest.uuid

index 72c366adabaac9c798335c36018e267ada8a4b6e..43a1b05cdc9b1bbb80dad33d644cc228e865f2eb 100644 (file)
@@ -585,7 +585,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
        of this value is also used for determining how long to wait on
        lock contention to free up.
     */
-    state.asyncIdleWaitTime = isWebLocker ? 300 : 150;
+    state.asyncIdleWaitTime = isWebLocker ? 100 : 150;
 
     /**
        Whether the async counterpart should log exceptions to
@@ -1262,6 +1262,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
               }
               break;
             }
+            case 'debug':
+              warn("debug message from worker:",data);
+              break;
             default: {
               const errMsg = (
                 "Unexpected message from the OPFS async worker: " +
index f682c4ce42b9efead64669c63ff507a8b05c2ea4..8338b96c057c46613c3b3c02b6fc7dd903a31f9c 100644 (file)
@@ -615,15 +615,18 @@ const installAsyncProxy = function(){
      Starts a new WebLock request.
   */
   const handleLockRequest = async function(){
+    const view = state.sabOPView;
+//#if not nope
     const args = state.s11n.deserialize(true)
           || toss("Expecting a filename argument from the proxy xLock()");
-    const view = state.sabOPView;
     const slock = state.lock;
     const lockType = Atomics.load(view, slock.type);
-    warn("handleLockRequest()", args, lockType);
-    navigator.locks.request('sqlite3-vfs-opfs:'+args[0], {
-      mode: (lockType===state.sq3Codes.SQLITE_LOCK_EXCLUSIVE)
-        ? 'exclusive' : 'shared'
+    warn("handleLockRequest()", args, lockType, JSON.stringify(slock));
+    //hangs warn(JSON.stringify((await navigator.locks.query()).held));
+    //warn("Navigator locks:", !!navigator.locks);
+    await navigator.locks.request('sqlite3-vfs-opfs:'+args[0], {
+      mode: 'exclusive' /*(lockType===state.sq3Codes.SQLITE_LOCK_EXCLUSIVE)
+        ? 'exclusive' : 'shared'*/
     }, async (wl)=>{
       warn("handleLockRequest() starting lock", args, lockType);
       /**
@@ -637,24 +640,57 @@ const installAsyncProxy = function(){
          Receptionist receives 'unlockControl'.
       */
       while( 1!==Atomics.load(view, slock.atomicsHandshake) ){
-        Atomics.wait(view. slock.atomicsHandshake, 2);
+        Atomics.wait(view, slock.atomicsHandshake, 2);
       }
       /* C. Reset the handshake slot. */
       Atomics.store(view, slock.atomicsHandshake, 0);
       Atomics.notify(view, lock.atomicsHandshake);
     });
     warn("handleLockRequest() ending", args, lockType);
+    //setTimeout(waitLoop, 0);
+//#else
+    warn("handleLockRequest()", ...arguments);
+    const [filename] = state.s11n.deserialize(true);
+    const lockType = Atomics.load(view, state.lock.type);
+    warn("handleLockRequest()", filename, lockType);
+    // Use 'exclusive' to ensure we aren't getting a weak shared lock
+    navigator.locks.request(filename, { mode: 'exclusive' }, (lock) => {
+      warn("handleLockRequest() inside the lock");
+      // VIOLENT DEBUGGING: Use globalThis.postMessage to bypass Atomics
+      globalThis.postMessage({type: 'debug', msg: 'CALLBACK ENTERED'});
+
+      // 1. Signal C-side: "I have it"
+      Atomics.store(view, state.lock.atomicsHandshake, 2);
+      Atomics.notify(view, state.lock.atomicsHandshake);
+
+      // 2. The Guard: This loop must not be async.
+      // It must stay synchronous to keep the callback alive.
+      while(Atomics.load(view, state.lock.atomicsHandshake) !== 1){
+        Atomics.wait(view, state.lock.atomicsHandshake, 2, 100);
+      }
+
+      // 3. Departure
+      Atomics.store(view, state.lock.atomicsHandshake, 0);
+      globalThis.postMessage({type: 'debug', msg: 'CALLBACK EXITING'});
+      return new Promise(()=>{/* never resolve to keep lock held until Departure */});
+    }).catch(e => {
+      globalThis.postMessage({type: 'debug', msg: 'LOCK ERROR: ' + e.message});
+    });
+//#endif
   };
 
   const waitLoop = async function f(){
-    const opHandlers = Object.create(null);
-    for(let k of Object.keys(state.opIds)){
-      const vi = vfsAsyncImpls[k];
-      if(!vi) continue;
-      const o = Object.create(null);
-      opHandlers[state.opIds[k]] = o;
-      o.key = k;
-      o.f = vi;
+    if( !f.inited ){
+      f.inited = true;
+      f.opHandlers = Object.create(null);
+      for(let k of Object.keys(state.opIds)){
+        const vi = vfsAsyncImpls[k];
+        if(!vi) continue;
+        const o = Object.create(null);
+        f.opHandlers[state.opIds[k]] = o;
+        o.key = k;
+        o.f = vi;
+      }
     }
     const opIds = state.opIds;
     while(!flagAsyncShutdown){
@@ -684,9 +720,10 @@ const installAsyncProxy = function(){
         warn("opId =",opId, opIds);
         if( opId===opIds.lockControl ){
           handleLockRequest();
-          continue;
+          setTimeout(f, 50);
+          return;
         }
-        const hnd = opHandlers[opId] ?? toss("No waitLoop handler for whichOp #",opId);
+        const hnd = f.opHandlers[opId] ?? toss("No waitLoop handler for whichOp #",opId);
         const args = state.s11n.deserialize(
           true /* clear s11n to keep the caller from confusing this with
                   an exception string written by the upcoming
index 6b18a3869165999194a473dfcde078b94b16add6..b2d25b85e4f42801a10d132876226aa40d99a9b8 100644 (file)
@@ -92,11 +92,17 @@ const installOpfsWlVfs = async function callee(options){
           Atomics.store(view, state.opIds.whichOp, state.opIds.lockControl);
           Atomics.notify(state.sabOPView, state.opIds.whichOp)
           debug("xLock waiting...");
+//#if not nope
+          while( 2 !== Atomics.load(view, state.lock.atomicsHandshake) ){
+            Atomics.wait(view, state.lock.atomicsHandshake, 0);
+          }
+//#else
           while('not-equal'!==Atomics.wait(view, state.lock.atomicsHandshake, 0)){
             /* Loop is a workaround for environment-specific quirks. See
                notes in similar loops. */
             debug("xLock still waiting...");
           }
+//#endif
           debug("xLock done waiting");
           f.lockType = lockType;
         }catch(e){
index 68ce7cc0151b75e8cee37abbfc52104beacb2c9a..a92a7a8886ac27f29293c4f2c33ad6d7dd04b8b2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\ssome\sdebugging\soutput\sto\sopfs\sand\strack\sdown\sthe\sbreakage\sto\sthe\sinitial\sWebLock\srequest,\swhich\sis\snever\sreaching\sits\scallback.\sStill\sbroken,\sbut\sthis\sis\sprogress.
-D 2026-03-04T21:16:36.068
+C The\sopfs-wl\slock\shang\shas\sbeen\straced\sto\sstarvation\sbetween\sthe\sWebLock\sand\sthe\stight\swait-on-VFS-calls\sAtomics.wait()\sloop.\sThis\scan\sreportedly\sbe\sresolved\swith\sanother\slevel\sof\sindirection\sin\swhich\sthe\sWebLock\stakes\sover\sthe\swait-on-VFS-calls\spart\suntil\sit's\sunlocked,\sreturning\sto\sthe\sglobal\sloop\swhen\sit's\sdone.\sThat\sexceeds\sthis\smorning's\sambitions\sbut\sis\snext\sto\stry\sout.
+D 2026-03-05T06:30:57.097
 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 1218fb9e72f3a208e62a4caafcf1fb0a41b66ca46df27601e5bfb06220822f24
+F ext/wasm/api/opfs-common-shared.c-pp.js 404aa8fd676791f0ce71e5c48f5f19e13e7b8e967a9af6a76927d524bbb46158
 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,11 +594,11 @@ 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 792a18708a6207d9bf274b04dcddd06fd805e93d1b7f716230df3c745f2800ee
+F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 82339eb043af53638b127a4649685da62b6fa33426d2013520eb6aeb114ede46
 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
-F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 1e6e087a89e9cd202d457c84dae29fa4808612ff9f37210c383eb6bbab3dfd34
+F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 88add6362468df4ecbbd00878c7a83cd81e555c677103ead51c34bd2be1a3963
 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 50a955ef393722d498177ad09c9e2d05bbe8dccae4c40c501482a860ca30017d
 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81
 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29
@@ -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 3b27310aa29ea84f459974981a600301abac5c705029a289d3872ecacf231da3
-R 5c13d459ac5b107e6cc5943524da9a40
+P 62fc8b35aeec75f5648b3daa24162c638999d447aa874bdfcbac1431c5c97b6f
+R 4e4429a4d6f21ed4af3f33058413d5c8
 U stephan
-Z 9fafbc035e4ee3a2d442f9b59c8a5807
+Z 5eeca3e1560bb544ee40d011df9232c0
 # Remove this line to create a well-formed Fossil manifest.
index 6c88a8044b206471c88fe1fcd2ed41e7b47b1c10..c36b9ce9ac886ef234621163dee1fd0b2911cd76 100644 (file)
@@ -1 +1 @@
-62fc8b35aeec75f5648b3daa24162c638999d447aa874bdfcbac1431c5c97b6f
+113bd910e12fea17f9f4a0a3baf706f15627c08cfa6b47a960a83eee761ef4dd