From: stephan Date: Tue, 3 Mar 2026 21:07:46 +0000 (+0000) Subject: Implementations of WebLock-based opfs::xLock() and xUnlock(). Still completely untest... X-Git-Tag: major-release~100^2~30 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e2309eebd74193efe65014896ec264a743026810;p=thirdparty%2Fsqlite.git Implementations of WebLock-based opfs::xLock() and xUnlock(). Still completely untested and not yet integrated into the build. FossilOrigin-Name: 3343e3aabe465f4ab91dd148dfc5a60346e9afb560c10d1f92aeae98763ec3ce --- diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.js b/ext/wasm/api/sqlite3-opfs-async-proxy.js index 79fc47393e..ede2bc7cd4 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.js @@ -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 diff --git a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js index 9fe09269cf..99e176c396 100644 --- a/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js +++ b/ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js @@ -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) diff --git a/manifest b/manifest index 7e05ddc666..1ef5d804a8 100644 --- 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. diff --git a/manifest.uuid b/manifest.uuid index cb69ee9652..976e29a881 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -81bc4b3b6abc19f98d1f3b1065c4b39a42620a0d7abebe98605dca62dd2d6f9a +3343e3aabe465f4ab91dd148dfc5a60346e9afb560c10d1f92aeae98763ec3ce