]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Implementations of WebLock-based opfs::xLock() and xUnlock(). Still completely untest...
authorstephan <stephan@noemail.net>
Tue, 3 Mar 2026 21:07:46 +0000 (21:07 +0000)
committerstephan <stephan@noemail.net>
Tue, 3 Mar 2026 21:07:46 +0000 (21:07 +0000)
FossilOrigin-Name: 3343e3aabe465f4ab91dd148dfc5a60346e9afb560c10d1f92aeae98763ec3ce

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

index 79fc47393e74355aba207d94d33efae27ec8bd7b..ede2bc7cd4f3432d61b615df2994bcfb9a3bd5e3 100644 (file)
@@ -318,7 +318,7 @@ const installAsyncProxy = function(){
       }
       log("Got",opName+"() sync handle for",fh.filenameAbs,
           'in',performance.now() - t,'ms');
-      if(!fh.xLock){
+      if(!fh.xLock && !state.lock/*set by opfs-wl*/){
         __implicitLocks.add(fh.fid);
         log("Acquired implicit lock for",opName+"()",fh.fid,fh.filenameAbs);
       }
@@ -703,6 +703,39 @@ const installAsyncProxy = function(){
     return state.s11n;
   }/*initS11n()*/;
 
+  /**
+     Starts a new WebLock request.
+  */
+  const handleLockRequest = async function(){
+    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);
+
+    await navigator.locks.request('sqlite3-vfs-opfs:'+args[0], {
+      mode: (lockType===state.sq3Codes.SQLITE_LOCK_EXCLUSIVE)
+        ? 'exclusive' : 'shared'
+    }, async (wl)=>{
+      /**
+         A. Tell the C-side we have the browser lock. We use the same
+         handshake slot, but a specific 'Granted' value.
+      */
+      Atomics.store(view, slock.atomicsHandshake, 2);
+      Atomics.notify(view, slock.atomicsHandshake);
+      /**
+         B. Sit here and keep the lock room occupied until the
+         Receptionist receives 'unlockControl'.
+      */
+      while( 1!==Atomics.load(view, slock.atomicsHandshake) ){
+        Atomics.wait(view. slock.atomicsHandshake, 2);
+      }
+      /* C. Reset the handshake slot. */
+      Atomics.store(view, slock.atomicsHandshake, 0);
+      Atomics.notify(view, lock.atomicsHandshake);
+    });
+  };
+
   const waitLoop = async function f(){
     const opHandlers = Object.create(null);
     for(let k of Object.keys(state.opIds)){
@@ -713,10 +746,11 @@ const installAsyncProxy = function(){
       o.key = k;
       o.f = vi;
     }
+    const opIds = state.opIds;
     while(!flagAsyncShutdown){
       try {
         if('not-equal'!==Atomics.wait(
-          state.sabOPView, state.opIds.whichOp, 0, state.asyncIdleWaitTime
+          state.sabOPView, opIds.whichOp, 0, state.asyncIdleWaitTime
         )){
           /* Maintenance note: we compare against 'not-equal' because
 
@@ -736,8 +770,11 @@ const installAsyncProxy = function(){
           await releaseImplicitLocks();
           continue;
         }
-        const opId = Atomics.load(state.sabOPView, state.opIds.whichOp);
-        Atomics.store(state.sabOPView, state.opIds.whichOp, 0);
+        const opId = Atomics.exchange(state.sabOPView, opIds.whichOp, 0);
+        if( opId===opIds.lockControl ){
+          handleLockRequest();
+          continue;
+        }
         const hnd = 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
index 9fe09269cf5294f6bde111868fd2e3c4acaf594d..99e176c396a96157d8b22c564c29570b60934d84 100644 (file)
@@ -372,7 +372,6 @@ const installOpfsVfs = function callee(options){
       state.opIds.xWrite = i++;
       state.opIds.mkdir = i++;
       state.opIds.lockControl = i++ /* we signal the intent to lock here */;
-      state.opIds.lockType
       /** Internal signals which are used only during development and
           testing via the dev console. */
       state.opIds['opfs-async-metrics'] = i++;
@@ -384,8 +383,8 @@ const installOpfsVfs = function callee(options){
 
       /* Slots for submitting the lock type and receiving its acknowledgement. */
       state.lock = nu({
-        type: i++,
-        atomicsHandshake: i++
+        type: i++ /* SQLITE_LOCK_xyz value */,
+        atomicsHandshake: i++ /* 1=release, 2=granted */
       });
       state.sabOP = new SharedArrayBuffer(
         i * 4/* ==sizeof int32, noting that Atomics.wait() and friends
@@ -425,7 +424,12 @@ const installOpfsVfs = function callee(options){
       'SQLITE_OPEN_CREATE',
       'SQLITE_OPEN_DELETEONCLOSE',
       'SQLITE_OPEN_MAIN_DB',
-      'SQLITE_OPEN_READONLY'
+      'SQLITE_OPEN_READONLY',
+      'SQLITE_LOCK_NONE',
+      'SQLITE_LOCK_SHARED',
+      'SQLITE_LOCK_RESERVED',
+      'SQLITE_LOCK_PENDING',
+      'SQLITE_LOCK_EXCLUSIVE'
     ].forEach((k)=>{
       if(undefined === (state.sq3Codes[k] = capi[k])){
         toss("Maintenance required: not found:",k);
@@ -787,7 +791,7 @@ const installOpfsVfs = function callee(options){
         mTimeEnd();
         return rc;
       },
-      xLock: function(pFile,lockType){
+      xLock: function(pFile, lockType){
         mTimeStart('xLock');
         const f = __openFiles[pFile];
         let rc = 0;
@@ -796,8 +800,23 @@ const installOpfsVfs = function callee(options){
            type. If no lock is active, have the async counterpart
            lock the file. */
         if( !f.lockType ) {
-          rc = opRun('xLock', pFile, lockType);
-          if( 0===rc ) f.lockType = lockType;
+          try{
+            const view = state.sabOPView;
+            /* We need to pass pFile's name through so that the other
+               side can create the WebLock name. */
+            state.s11n.serialize(f.filename)
+            Atomics.store(view, state.lock.type, lockType);
+            Atomics.store(view, state.opIds.whichOp, state.opIds.lockControl);
+            Atomics.notify(state.sabOPView, state.opIds.whichOp)
+            while('not-equal'!==Atomics.wait(view, state.lock.atomicsHandshake, 0)){
+              /* Loop is a workaround for environment-specific quirks. See
+                 notes in similar loops. */
+            }
+            f.lockType = lockType;
+          }catch(e){
+            error("xLock(",arguments,") failed", e, f);
+            rc = capi.SQLITE_IOERR_LOCK;
+          }
         }else{
           f.lockType = lockType;
         }
@@ -842,9 +861,16 @@ const installOpfsVfs = function callee(options){
         mTimeStart('xUnlock');
         const f = __openFiles[pFile];
         let rc = 0;
-        if( capi.SQLITE_LOCK_NONE === lockType
-          && f.lockType ){
-          rc = opRun('xUnlock', pFile, lockType);
+        if( lockType < f.lockType ){
+          try{
+            const view = state.sabOPView;
+            Atomics.store(view, state.lock.atomicsHandshake, 1);
+            Atomics.notify(view, state.lock.atomicsHandshake);
+            Atomics.wait(view, state.lock.atomicsHandshake, 1);
+          }catch(e){
+            error("xUnlock(",pFile,lockType,") failed",e, f);
+            rc = capi.SQLITE_IOERR_LOCK;
+          }
         }
         if( 0===rc ) f.lockType = lockType;
         mTimeEnd();
@@ -932,7 +958,7 @@ const installOpfsVfs = function callee(options){
         }
         const fh = Object.create(null);
         fh.fid = pFile;
-        fh.filename = zName;
+        fh.filename = wasm.cstrToJs(zName);
         fh.sab = new SharedArrayBuffer(state.fileBufferSize);
         fh.flags = flags;
         fh.readOnly = !(capi.SQLITE_OPEN_CREATE & flags)
index 7e05ddc666e7e903a4fca7298870255fe92096d8..1ef5d804a87d6099714eff1ffa2bcfa6a5890a9e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\strunk\sinto\sthe\sopfs-wl\sbranch.
-D 2026-03-03T18:34:59.705
+C Implementations\sof\sWebLock-based\sopfs::xLock()\sand\sxUnlock().\sStill\scompletely\suntested\sand\snot\syet\sintegrated\sinto\sthe\sbuild.
+D 2026-03-03T21:07:46.412
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -592,11 +592,11 @@ F ext/wasm/api/sqlite3-api-oo1.c-pp.js 45454631265d9ce82685f1a64e1650ee19c8e121c
 F ext/wasm/api/sqlite3-api-prologue.js 1fefd40ab21e3dbf46f43b6fafb07f13eb13cc157a884f7c1134caf631ddb3f2
 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.js 92d6d327a862f1627ff3e88e60fdfea9def06ad539d98929ba46490e64372736
+F ext/wasm/api/sqlite3-opfs-async-proxy.js 912ddb17627e933eb9596d393227f7ea47b1136fc2fb0d957d9979e71de59e81
 F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
 F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 2ccf4322f42063aefc150972943e750c77f7926b866f1639d40eec05df075b6e
 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 1575ea6bbcf2da1e6df6892c17521a0c1c1c199a672e9090176ea0b88de48bd9
-F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js 38484644c21b21b97f60979dddd620e47bdba628bde4ae62b6ce8859870e4f85
+F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js c3e453a5736ee1bb9b08247c6e97c1433933a320c7548bedd20481eae7922a48
 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3
 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81
 F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29
@@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 372f18ae909bafd7167b70051935832e3107ede72aaeccbf5c042db7ba791912 88dce64242552e7443d9fb496f6f3ad71dc5b4a882ce21b7ef1d5ea4e26f1e61
-R 75fb07a85007c6410c69c66cd4391b75
+P 81bc4b3b6abc19f98d1f3b1065c4b39a42620a0d7abebe98605dca62dd2d6f9a
+R f9d18b4e8da91823211b005773e17736
 U stephan
-Z 42a2789071a18d2bcb63e8ba8c976a45
+Z e389fe2e9ad12fa6369004db9e3f215f
 # Remove this line to create a well-formed Fossil manifest.
index cb69ee9652a3470485b16b8b40d0238e5369ffcd..976e29a8810365c2a2030b9ee904f6b786d019e7 100644 (file)
@@ -1 +1 @@
-81bc4b3b6abc19f98d1f3b1065c4b39a42620a0d7abebe98605dca62dd2d6f9a
+3343e3aabe465f4ab91dd148dfc5a60346e9afb560c10d1f92aeae98763ec3ce