blob: 30b24869d66b36ab79d634cd96a4af64eb721da9 [file] [log] [blame] [edit]
//#if not target:node
/*
2026-02-20
The author disclaims copyright to this source code. In place of a
legal notice, here is a blessing:
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
***********************************************************************
This file is a reimplementation of the "opfs" VFS (as distinct from
"opfs-sahpool") which uses WebLocks for locking instead of a bespoke
custom Atomics.wait()/notify() protocol. This file holds the
"synchronous half" of the VFS, whereas it shares the "asynchronous
half" of the "opfs" VFS.
This file is intended to be appended to the main sqlite3 JS
deliverable somewhere after sqlite3-api-oo1.js.
TODOs (2026-03-03):
- For purposes of tester1.js we need to figure out which of these
VFSes will install the (internal-use-only) sqlite3.opfs utility code
namespace. We need that in order to clean up OPFS files during test
runs. Alternately, move those into their own
sqlite3ApiBootstrap.initializers entry which precedes both of the
VFSes, so they'll have access to it during bootstrapping. The
sqlite3.opfs namespace is removed at the end of bootstrapping unless
the library is told to run in testing mode (which is not a
documented feature).
*/
'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if( !sqlite3.opfs || sqlite3.config.disable?.vfs?.['opfs-wl'] ){
return;
}
const util = sqlite3.util,
toss = sqlite3.util.toss;
const opfsUtil = sqlite3.opfs;
const vfsName = 'opfs-wl';
/**
installOpfsWlVfs() returns a Promise which, on success, installs an
sqlite3_vfs named "opfs-wl", suitable for use with all sqlite3 APIs
which accept a VFS. It is intended to be called via
sqlite3ApiBootstrap.initializers or an equivalent mechanism.
This VFS is essentially identical to the "opfs" VFS but uses
WebLocks for its xLock() and xUnlock() implementations.
Quirks specific to this VFS:
- 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(options){
options = opfsUtil.initOptions(vfsName,options);
if( !options ) return sqlite3;
const capi = sqlite3.capi,
state = opfsUtil.createVfsState(),
opfsVfs = state.vfs,
metrics = opfsVfs.metrics.counters,
mTimeStart = opfsVfs.mTimeStart,
mTimeEnd = opfsVfs.mTimeEnd,
opRun = opfsVfs.opRun,
debug = (...args)=>sqlite3.config.debug(vfsName+":",...args),
warn = (...args)=>sqlite3.config.warn(vfsName+":",...args),
__openFiles = opfsVfs.__openFiles;
//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){
mTimeStart('xLock');
//debug("xLock()...");
const f = __openFiles[pFile];
const rc = opRun('xLock', pFile, lockType);
if( !rc ) f.lockType = lockType;
mTimeEnd();
return rc;
},
xUnlock: function(pFile,lockType){
mTimeStart('xUnlock');
const f = __openFiles[pFile];
const rc = opRun('xUnlock', pFile, lockType);
if( !rc ) f.lockType = lockType;
mTimeEnd();
return rc;
}
}), function(sqlite3, vfs){
/* Post-VFS-registration initialization... */
if(sqlite3.oo1){
const OpfsWlDb = function(...args){
const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args);
opt.vfs = vfs.$zName;
sqlite3.oo1.DB.dbCtorHelper.call(this, opt);
};
OpfsWlDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
sqlite3.oo1.OpfsWlDb = OpfsWlDb;
OpfsWlDb.importDb = opfsUtil.importDb;
/* 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()*/;
globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
return installOpfsWlVfs().catch((e)=>{
sqlite3.config.warn("Ignoring inability to install the",vfsName,"sqlite3_vfs:",e);
});
});
}/*sqlite3ApiBootstrap.initializers.push()*/);
//#/if target:node