/**
Must be called by the VFS's main installation routine and passed
the options object that function receives and a reference to that
- function itself (which is assumed to have a defaultProxyUri
- property set on it. See sqlite3-vfs-opfs{,-wl}.c-pp.js for
- examples.
+ function itself (we don't need this anymore).
It throws if OPFS is not available.
- Call opfvs.bindVfs()
*/
- opfsUtil.initOptions = function callee(options, callee){
+ opfsUtil.initOptions = function callee(vfsName, options){
const urlParams = new URL(globalThis.location.href).searchParams;
- if(urlParams.has('opfs-disable')){
+ if(urlParams.has(vfsName+'-disable')){
//sqlite3.config.warn('Explicitly not installing "opfs" VFS due to opfs-disable flag.');
return;
}
return;
}
options = util.nu(options);
+ options.vfsName = vfsName;
options.verbose ??= urlParams.has('opfs-verbose')
? (+urlParams.get('opfs-verbose') || 2) : 1;
options.sanityChecks ??= urlParams.has('opfs-sanity-check');
- options.proxyUri ??= callee.defaultProxyUri;
+
+ if( true ){
+ /* Doing this from one scope up does not work */
+ opfsUtil.proxyUri = "sqlite3-opfs-async-proxy.js";
+ if( sqlite3.scriptInfo?.sqlite3Dir ){
+ opfsUtil.proxyUri = (
+ sqlite3.scriptInfo.sqlite3Dir + opfsUtil.proxyUri
+ );
+ }
+ //sqlite3.config.error("proxyUri =",opfsUtil.proxyUri, sqlite3.scriptInfo);
+ }
+
+ options.proxyUri ??= opfsUtil.proxyUri;
if('function' === typeof options.proxyUri){
options.proxyUri = options.proxyUri();
}
options.workerId ??= (Math.random() * 10000000) | 0;
}
//sqlite3.config.warn("opfsUtil options =",JSON.stringify(options), 'urlParams =', urlParams);
- return options;
+ return opfsUtil.options = options;
};
/**
only cloneable or sharable objects. After the worker's "inited"
message arrives, other types of data may be added to it.
*/
- opfsUtil.createVfsState = function(vfsName, options){
+ opfsUtil.createVfsState = function(){
const state = util.nu();
+ const options = opfsUtil.options;
state.verbose = options.verbose;
const loggers = [
sqlite3.config.warn,
sqlite3.config.log
];
+ const vfsName = options.vfsName
+ || toss("Maintenance required: missing VFS name");
const logImpl = (level,...args)=>{
- if(state.verbose>level) loggers[level]("OPFS syncer:",...args);
+ if(state.verbose>level) loggers[level](vfsName+":",...args);
};
const log = (...args)=>logImpl(2, ...args),
warn = (...args)=>logImpl(1, ...args),
*/
);
- const isWebLocker = 'opfs-wl'===vfsName;
opfsVfs.metrics = util.nu({
counters: util.nu(),
dump: function(){
of this value is also used for determining how long to wait on
lock contention to free up.
*/
- state.asyncIdleWaitTime = isWebLocker ? 250 : 150;
+ state.asyncIdleWaitTime = 150;
/**
Whether the async counterpart should log exceptions to
(see sqlite3-opfs-async-proxy.c-pp.js).
*/
const opRun = opfsVfs.opRun = (op,...args)=>{
- const opNdx = state.opIds[op] || toss("Invalid op ID:",op);
+ const opNdx = state.opIds[op] || toss(opfsVfs.vfsName+": Invalid op ID:",op);
state.s11n.serialize(...args);
Atomics.store(state.sabOPView, state.opIds.rc, -1);
Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx);
promiseWasRejected = false;
return promiseResolve_(sqlite3);
};
+ const options = opfsUtil.options;
let proxyUri = options.proxyUri +(
(options.proxyUri.indexOf('?')<0) ? '?' : '&'
)+'vfs='+vfsName;
if( options.workerId ){
proxyUri += '&opfs-async-proxy-id='+encodeURIComponent(options.workerId);
}
+ //sqlite3.config.error("proxyUri",options.proxyUri, (new Error()));
const W = opfsVfs.worker =
//#if target:es6-bundler-friendly
(()=>{
*/
"use strict";
const urlParams = new URL(globalThis.location.href).searchParams;
-if( !urlParams.has('vfs') ){
+const vfsName = urlParams.get('vfs');
+if( !vfsName ){
throw new Error("Expecting vfs=opfs|opfs-wl URL argument for this worker");
}
const workerId = urlParams.get('opfs-async-proxy-id')
*/
const __openFiles = Object.create(null);
/**
- __implicitLocks is a Set of sqlite3_file pointers (integers) which were
- "auto-locked". i.e. those for which we obtained a sync access
- handle without an explicit xLock() call. Such locks will be
- released during db connection idle time, whereas a sync access
- handle obtained via xLock(), or subsequently xLock()'d after
- auto-acquisition, will not be released until xUnlock() is called.
+ __implicitLocks is a Set of sqlite3_file pointers (integers)
+ which were "auto-locked". i.e. those for which we necessarily
+ obtain a sync access handle without an explicit xLock() call
+ guarding access. Such locks will be released during
+ `waitLoop()`'s idle time, whereas a sync access handle obtained
+ via xLock(), or subsequently xLock()'d after auto-acquisition,
+ will not be released until xUnlock() is called.
Maintenance reminder: if we relinquish auto-locks at the end of the
operation which acquires them, we pay a massive performance
wPost('opfs-async-loaded');
}).catch((e)=>error("error initializing OPFS asyncer:",e));
}/*installAsyncProxy()*/;
-if(!globalThis.SharedArrayBuffer){
+if(globalThis.window === globalThis){
+ wPost('opfs-unavailable',
+ "This code cannot run from the main thread.",
+ "Load it as a Worker from a separate Worker.");
+}else if(!globalThis.SharedArrayBuffer){
wPost('opfs-unavailable', "Missing SharedArrayBuffer API.",
"The server must emit the COOP/COEP response headers to enable that.");
}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){
+ wPost('opfs-unavailable',"Missing required Atomics.waitSync() for "+vfsName);
}else if(!globalThis.FileSystemHandle ||
!globalThis.FileSystemDirectoryHandle ||
- !globalThis.FileSystemFileHandle ||
- !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle ||
+ !globalThis.FileSystemFileHandle?.prototype?.createSyncAccessHandle ||
!navigator?.storage?.getDirectory){
wPost('opfs-unavailable',"Missing required OPFS APIs.");
}else{
Quirks specific to this VFS:
- - Because WebLocks effectively block until they return, they will
- effectively hang on locks rather than returning SQLITE_BUSY.
+ - The (officially undocumented) 'opfs-wl-disable' URL
+ argument will disable OPFS, making this function a no-op.
Aside from locking differences in the VFSes, this function
otherwise behaves the same as
sqlite3-vfs-opfs.c-pp.js:installOpfsVfs().
*/
-const installOpfsWlVfs = async function callee(options){
- options = opfsUtil.initOptions(options, callee);
+const installOpfsWlVfs = async function(options){
+ options = opfsUtil.initOptions('opfs-wl',options);
if( !options ) return sqlite3;
options.verbose = 2;
const capi = sqlite3.capi,
- debug = (...args)=>sqlite3.config.warn("opfs-wl:",...args),
- state = opfsUtil.createVfsState('opfs-wl', options),
+ state = opfsUtil.createVfsState(),
opfsVfs = state.vfs,
metrics = opfsVfs.metrics.counters,
mTimeStart = opfsVfs.mTimeStart,
mTimeEnd = opfsVfs.mTimeEnd,
+ opRun = opfsVfs.opRun,
+ debug = (...args)=>sqlite3.config.debug("opfs-wl:",...args),
+ warn = (...args)=>sqlite3.config.warn("opfs-wl:",...args),
__openFiles = opfsVfs.__openFiles;
- //debug("state",JSON.stringify(state,false,' '));
- /* At this point, createVfsState() has populated state and opfsVfs
- with any code common to both the "opfs" and "opfs-wl" VFSes. Now
- comes the VFS-dependent work... */
+
+ //debug("state",JSON.stringify(options));
+ /*
+ At this point, createVfsState() has populated:
+
+ - state: the configuration object we share with the async proxy.
+
+ - opfsVfs: an sqlite3_vfs instance with lots of JS state attached
+ to it.
+
+ with any code common to both the "opfs" and "opfs-wl" VFSes. Now
+ comes the VFS-dependent work...
+ */
return opfsVfs.bindVfs(util.nu({
- xLock: function(pFile,lockType){
+ xLock: function(pFile,lockType){
mTimeStart('xLock');
- ++metrics.xLock.count;
+ //debug("xLock()...");
const f = __openFiles[pFile];
- let rc = 0;
- /* All OPFS locks are exclusive locks. If xLock() has
- previously succeeded, do nothing except record the lock
- type. If no lock is active, have the async counterpart
- lock the file. */
- if( f.lockType ) {
- f.lockType = lockType;
- }else{
- rc = opRun('xLock', pFile, lockType);
- if( 0===rc ) f.lockType = lockType;
- }
+ const rc = opRun('xLock', pFile, lockType);
+ if( !rc ) f.lockType = lockType;
mTimeEnd();
return rc;
},
xUnlock: function(pFile,lockType){
mTimeStart('xUnlock');
- ++metrics.xUnlock.count;
const f = __openFiles[pFile];
- let rc = 0;
- if( capi.SQLITE_LOCK_NONE === lockType
- && f.lockType ){
- rc = opRun('xUnlock', pFile, lockType);
- }
- if( 0===rc ) f.lockType = lockType;
+ const rc = opRun('xUnlock', pFile, lockType);
+ if( !rc ) f.lockType = lockType;
mTimeEnd();
return rc;
}
}), function(sqlite3, vfs){
- //debug("registered VFS");
+ /* Post-VFS-registration initialization... */
if(sqlite3.oo1){
const OpfsWlDb = function(...args){
const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args);
OpfsWlDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
sqlite3.oo1.OpfsWlDb = OpfsWlDb;
OpfsWlDb.importDb = opfsUtil.importDb;
- }/*extend sqlite3.oo1*/
+ /* The "opfs" VFS variant adds a
+ oo1.DB.dbCtorHelper.setVfsPostOpenCallback() callback to set
+ a high busy_timeout. That was a design mis-decision and is
+ inconsistent with sqlite3_open() and friends, but is retained
+ against the risk of introducing regressions if it's removed.
+ This variant does not repeat that mistake.
+ */
+ }
})/*bindVfs()*/;
}/*installOpfsWlVfs()*/;
-installOpfsWlVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js";
globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
- try{
- let proxyJs = installOpfsWlVfs.defaultProxyUri;
- if( sqlite3.scriptInfo?.sqlite3Dir ){
- installOpfsWlVfs.defaultProxyUri =
- sqlite3.scriptInfo.sqlite3Dir + proxyJs;
- //sqlite3.config.warn("installOpfsWlVfs.defaultProxyUri =",installOpfsWlVfs.defaultProxyUri);
- }
- return installOpfsWlVfs().catch((e)=>{
- sqlite3.config.warn("Ignoring inability to install OPFS-WL sqlite3_vfs:",e);
- });
- }catch(e){
- sqlite3.config.error("installOpfsWlVfs() exception:",e);
- return Promise.reject(e);
- }
+ return installOpfsWlVfs().catch((e)=>{
+ sqlite3.config.warn("Ignoring inability to install the 'opfs-wl' sqlite3_vfs:",e);
+ });
});
}/*sqlite3ApiBootstrap.initializers.push()*/);
//#endif target:node
The argument may optionally be a plain object with the following
configuration options:
- - proxyUri: name of the async proxy JS file.
+ - proxyUri: name of the async proxy JS file or a synchronous function
+ which, when called, returns such a name.
- verbose (=2): an integer 0-3. 0 disables all logging, 1 enables
logging of errors. 2 enables logging of warnings and errors. 3
as there are legitimate non-error reasons for OPFS not to be
available.
*/
-const installOpfsVfs = async function callee(options){
- options = opfsUtil.initOptions(options, callee);
+const installOpfsVfs = async function(options){
+ options = opfsUtil.initOptions('opfs',options);
if( !options ) return sqlite3;
const capi = sqlite3.capi,
- state = opfsUtil.createVfsState('opfs', options),
+ state = opfsUtil.createVfsState(),
opfsVfs = state.vfs,
+ metrics = opfsVfs.metrics.counters,
mTimeStart = opfsVfs.mTimeStart,
mTimeEnd = opfsVfs.mTimeEnd,
opRun = opfsVfs.opRun,
__openFiles = opfsVfs.__openFiles;
//debug("options:",JSON.stringify(options));
- /* At this point, createVfsState() has populated `state` and
- `opfsVfs` with any code common to both the "opfs" and "opfs-wl"
- VFSes. Now comes the VFS-dependent work... */
+ /*
+ At this point, createVfsState() has populated:
+
+ - state: the configuration object we share with the async proxy.
+
+ - opfsVfs: an sqlite3_vfs instance with lots of JS state attached
+ to it.
+
+ with any code common to both the "opfs" and "opfs-wl" VFSes. Now
+ comes the VFS-dependent work...
+ */
return opfsVfs.bindVfs(util.nu({
xLock: function(pFile,lockType){
mTimeStart('xLock');
- //debug("xLock()...");
+ ++metrics.xLock.count;
const f = __openFiles[pFile];
- const rc = opRun('xLock', pFile, lockType);
- if( rc ){
- warn("xLock() rc ",rc);
- }else{
+ let rc = 0;
+ /* All OPFS locks are exclusive locks. If xLock() has
+ previously succeeded, do nothing except record the lock
+ type. If no lock is active, have the async counterpart
+ lock the file. */
+ if( f.lockType ) {
f.lockType = lockType;
+ }else{
+ rc = opRun('xLock', pFile, lockType);
+ if( 0===rc ) f.lockType = lockType;
}
mTimeEnd();
return rc;
},
xUnlock: function(pFile,lockType){
mTimeStart('xUnlock');
+ ++metrics.xUnlock.count;
const f = __openFiles[pFile];
- const rc = opRun('xUnlock', pFile, lockType);
+ let rc = 0;
+ if( capi.SQLITE_LOCK_NONE === lockType
+ && f.lockType ){
+ rc = opRun('xUnlock', pFile, lockType);
+ }
if( 0===rc ) f.lockType = lockType;
mTimeEnd();
return rc;
}
}), function(sqlite3, vfs){
+ /* Post-VFS-registration initialization... */
if(sqlite3.oo1){
const OpfsDb = function(...args){
const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args);
OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
sqlite3.oo1.OpfsDb = OpfsDb;
OpfsDb.importDb = opfsUtil.importDb;
- if( false ){
+ if( true ){
+ /* 2026-03-06: this was a design mis-decision and is
+ inconsistent with sqlite3_open() and friends, but is
+ retained against the risk of introducing regressions if
+ it's removed. */
sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback(
opfsVfs.pointer,
function(oo1Db, sqlite3){
}/*extend sqlite3.oo1*/
})/*bindVfs()*/;
}/*installOpfsVfs()*/;
-installOpfsVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js";
globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
- try{
- let proxyJs = installOpfsVfs.defaultProxyUri;
- if( sqlite3.scriptInfo?.sqlite3Dir ){
- installOpfsVfs.defaultProxyUri =
- sqlite3.scriptInfo.sqlite3Dir + proxyJs;
- //sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri);
- }
- return installOpfsVfs().catch((e)=>{
- sqlite3.config.warn("Ignoring inability to install OPFS sqlite3_vfs:",e);
- });
- }catch(e){
- sqlite3.config.error("installOpfsVfs() exception:",e);
- return Promise.reject(e);
- }
+ return installOpfsVfs().catch((e)=>{
+ sqlite3.config.warn("Ignoring inability to install 'opfs' sqlite3_vfs:",e);
+ })
});
}/*sqlite3ApiBootstrap.initializers.push()*/);
//#endif target:node
-C Minor\scleanups\sand\sdocs.\sTeach\sthe\sOPFS\sconcurrency\stester\sto\sdeal\swith\sSQLITE_BUSY\sinstead\sof\sfailing.
-D 2026-03-06T19:33:25.647
+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
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
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 eccb37a2347b8b17a664401cd8ef0ee0a7e18cb81939ee4ef404905e8e9188bf
+F ext/wasm/api/opfs-common-shared.c-pp.js b41b71ac06264e2d2db9a08e9cd7d5ee0e5730d224a4e81e0c42b0928028844e
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
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 c19ca5986bceb60561973635bd68acbb93f5e1752b1d1b7f4cae20abaa8d5bd1
+F ext/wasm/api/sqlite3-opfs-async-proxy.c-pp.js 6025b22ebb92f9216e68d85c4e27c228e148f4d081e306f27d0a50342e56ec37
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 8233c5f9021b0213134e2adbaf6036b8f1dffd4747083a4087c1c19ae107f962
-F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js f3bef4dbb8364a37471e4bc33e9b1e52795596456090007aaeae25acc35d2e85
+F ext/wasm/api/sqlite3-vfs-opfs-wl.c-pp.js f65903e15f49a5475eaf8fd3f35971d4c4c4b43f0a00167f1a2c98389cf84900
+F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 872c29aa760b05c2703185368a39b4b2e1a8abf15c29ee7e23ee8ca7cdcbed9d
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81
F ext/wasm/api/sqlite3-wasm.c 45bb20e19b245136711f9b78584371233975811b6560c29ed9b650e225417e29
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js aa9715f661fb700459a5a6cb1c32a4d6a770723b47aa9ac0e16c2cf87d622a66
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P ba81d95febc5fd0f9bbb2685fef5b1b10f9991751f2bdfafba80c15877af1cef
-R 5bd89f58e70b2c6dcff7610e01717205
+P 247ffed141f66a6a5a396a3e002995a9f00c70333271199200530066e77956c4
+R d5ab78b2216c6ac5e35f6ab8d6aa4867
U stephan
-Z 52bcc9f2059e4acc631f2cd7a59885ba
+Z 836eb4f55d744876555cc67389157d1f
# Remove this line to create a well-formed Fossil manifest.
-247ffed141f66a6a5a396a3e002995a9f00c70333271199200530066e77956c4
+12dcd5425967b6306f3e3178babeac130962edb78e6298d545a429a1a20457cc