mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Filter the OPFS VFSes out of the sqlite3-node.mjs build. Add another level of subdirectory to the sahpool to later enable transparent support of client-provided files under the VFS's root dir. Rework the awkward sahpool-via-oo1 mapping.
FossilOrigin-Name: 080a4d0aba30d8f3802b49be4a113205f069b3bdea8cebf525d654055642ff62
This commit is contained in:
@ -376,7 +376,7 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-v-helper.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
|
||||
|
||||
# SOAP.js is an external API file which is part of our distribution
|
||||
|
@ -91,7 +91,7 @@ browser client:
|
||||
directly to the (async) OPFS API and channels those results back
|
||||
to its synchronous counterpart. This file, because it must be
|
||||
started in its own Worker, is not part of the amalgamation.
|
||||
- **`sqlite3-vfs-opfs-sahpool.js`**\
|
||||
- **`sqlite3-vfs-opfs-sahpool.c-pp.js`**\
|
||||
is another sqlite3 VFS supporting the OPFS, but uses a completely
|
||||
different approach that the above-listed one.
|
||||
- **`sqlite3-api-cleanup.js`**\
|
||||
@ -111,13 +111,15 @@ browser client:
|
||||
with `c-pp`](#c-pp), noting that such preprocessing may be applied
|
||||
after all of the relevant files are concatenated. That extension is
|
||||
used primarily to keep the code maintainers cognisant of the fact that
|
||||
those files contain constructs which will not run as-is in JavaScript.
|
||||
those files contain constructs which may not run as-is in any given
|
||||
JavaScript environment.
|
||||
|
||||
The build process glues those files together, resulting in
|
||||
`sqlite3-api.js`, which is everything except for the `post-js-*.js`
|
||||
files, and `sqlite3.js`, which is the Emscripten-generated amalgamated
|
||||
output and includes the `post-js-*.js` parts, as well as the
|
||||
Emscripten-provided module loading pieces.
|
||||
`sqlite3-api.js`, which is everything except for the
|
||||
`pre/post-js-*.js` files, and `sqlite3.js`, which is the
|
||||
Emscripten-generated amalgamated output and includes the
|
||||
`pre/post-js-*.js` parts, as well as the Emscripten-provided module
|
||||
loading pieces.
|
||||
|
||||
The non-JS outlier file is `sqlite3-wasm.c`: it is a proxy for
|
||||
`sqlite3.c` which `#include`'s that file and adds a couple more
|
||||
|
@ -1,3 +1,4 @@
|
||||
//#ifnot target=node
|
||||
/*
|
||||
2023-07-14
|
||||
|
||||
@ -52,8 +53,8 @@
|
||||
major browsers released since March 2023). If that API is not
|
||||
detected, the VFS is not registered.
|
||||
*/
|
||||
'use strict';
|
||||
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
'use strict';
|
||||
const toss = sqlite3.util.toss;
|
||||
const toss3 = sqlite3.util.toss3;
|
||||
const initPromises = Object.create(null);
|
||||
@ -79,6 +80,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
capi.SQLITE_OPEN_WAL /* noting that WAL support is
|
||||
unavailable in the WASM build.*/;
|
||||
|
||||
/** Subdirectory of the VFS's space where "opaque" (randomly-named)
|
||||
files are stored. Changing this effectively invalidates the data
|
||||
stored under older names (orphaning it), so don't do that. */
|
||||
const OPAQUE_DIR_NAME = ".opaque";
|
||||
|
||||
/**
|
||||
Returns short a string of random alphanumeric characters
|
||||
suitable for use as a random filename.
|
||||
@ -423,6 +429,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
vfsDir;
|
||||
/* Directory handle to this.vfsDir. */
|
||||
#dhVfsRoot;
|
||||
/* Directory handle to the subdir of this.#dhVfsRoot which holds
|
||||
the randomly-named "opaque" files. This subdir exists in the
|
||||
hope that we can eventually support client-created files in
|
||||
this.#dhVfsRoot. */
|
||||
#dhOpaque;
|
||||
/* Directory handle to this.dhVfsRoot's parent dir. Needed
|
||||
for a VFS-wipe op. */
|
||||
#dhVfsParent;
|
||||
@ -447,11 +458,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
#verbosity;
|
||||
|
||||
constructor(options = Object.create(null)){
|
||||
this.#verbosity = options.verbosity ?? optionDefaults.verbosity;
|
||||
this.vfsName = options.name || optionDefaults.name;
|
||||
if( sqlite3.capi.sqlite3_vfs_find(this.vfsName)){
|
||||
toss3("VFS name is already registered:", this.vfsName);
|
||||
}
|
||||
this.#verbosity = options.verbosity ?? optionDefaults.verbosity;
|
||||
this.#cVfs = createOpfsVfs(this.vfsName);
|
||||
setPoolForVfs(this.#cVfs.pointer, this);
|
||||
this.vfsDir = options.directory || ("."+this.vfsName);
|
||||
@ -491,7 +502,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
async addCapacity(n){
|
||||
for(let i = 0; i < n; ++i){
|
||||
const name = getRandomName();
|
||||
const h = await this.#dhVfsRoot.getFileHandle(name, {create:true});
|
||||
const h = await this.#dhOpaque.getFileHandle(name, {create:true});
|
||||
const ah = await h.createSyncAccessHandle();
|
||||
this.#mapSAHToName.set(ah,name);
|
||||
this.setAssociatedPath(ah, '', 0);
|
||||
@ -512,7 +523,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
const name = this.#mapSAHToName.get(ah);
|
||||
ah.close();
|
||||
await this.#dhVfsRoot.removeEntry(name);
|
||||
await this.#dhOpaque.removeEntry(name);
|
||||
this.#mapSAHToName.delete(ah);
|
||||
this.#availableSAH.delete(ah);
|
||||
++nRm;
|
||||
@ -532,7 +543,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
|
||||
/**
|
||||
Opens all files under this.vfsDir/this.#dhVfsRoot and acquires
|
||||
Opens all files under this.vfsDir/this.#dhOpaque and acquires
|
||||
a SAH for each. returns a Promise which resolves to no value
|
||||
but completes once all SAHs are acquired. If acquiring an SAH
|
||||
throws, SAHPool.$error will contain the corresponding
|
||||
@ -544,7 +555,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
*/
|
||||
async acquireAccessHandles(clearFiles){
|
||||
const files = [];
|
||||
for await (const [name,h] of this.#dhVfsRoot){
|
||||
for await (const [name,h] of this.#dhOpaque){
|
||||
if('file'===h.kind){
|
||||
files.push([name,h]);
|
||||
}
|
||||
@ -680,6 +691,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}
|
||||
this.#dhVfsRoot = h;
|
||||
this.#dhVfsParent = prev;
|
||||
this.#dhOpaque = await this.#dhVfsRoot.getDirectoryHandle(
|
||||
OPAQUE_DIR_NAME,{create:true}
|
||||
);
|
||||
this.releaseAccessHandles();
|
||||
return this.acquireAccessHandles(clearFiles);
|
||||
}
|
||||
@ -691,6 +705,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
- a URL object
|
||||
- A JS string representing a file name
|
||||
- Wasm C-string representing a file name
|
||||
|
||||
All "../" parts and duplicate slashes are resolve/removed from
|
||||
the returned result.
|
||||
*/
|
||||
getPath(arg) {
|
||||
if(wasm.isPtr(arg)) arg = wasm.cstrToJs(arg);
|
||||
@ -790,17 +807,17 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
VFS has already been shut down.
|
||||
*/
|
||||
async removeVfs(){
|
||||
if(!this.#cVfs.pointer) return false;
|
||||
if(!this.#cVfs.pointer || !this.#dhOpaque) return false;
|
||||
capi.sqlite3_vfs_unregister(this.#cVfs.pointer);
|
||||
this.#cVfs.dispose();
|
||||
try{
|
||||
this.releaseAccessHandles();
|
||||
if(this.#dhVfsParent){
|
||||
await this.#dhVfsParent.removeEntry(
|
||||
this.#dhVfsRoot.name, {recursive: true}
|
||||
);
|
||||
this.#dhVfsRoot = this.#dhVfsParent = undefined;
|
||||
}
|
||||
await this.#dhVfsRoot.removeEntry(OPAQUE_DIR_NAME, {recursive: true});
|
||||
this.#dhOpaque = undefined;
|
||||
await this.#dhVfsParent.removeEntry(
|
||||
this.#dhVfsRoot.name, {recursive: true}
|
||||
);
|
||||
this.#dhVfsRoot = this.#dhVfsParent = undefined;
|
||||
}catch(e){
|
||||
sqlite3.config.error(this.vfsName,"removeVfs() failed:",e);
|
||||
/*otherwise ignored - there is no recovery strategy*/
|
||||
@ -1120,7 +1137,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
/** The poolUtil object will be the result of the
|
||||
resolved Promise. */
|
||||
const poolUtil = new OpfsSAHPoolUtil(thePool);
|
||||
|
||||
if(sqlite3.oo1){
|
||||
const oo1 = sqlite3.oo1;
|
||||
const theVfs = thePool.getVfs();
|
||||
@ -1130,12 +1146,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
oo1.DB.dbCtorHelper.call(this, opt);
|
||||
};
|
||||
OpfsSAHPoolDb.prototype = Object.create(oo1.DB.prototype);
|
||||
OpfsSAHPoolDb.PoolUtil = poolUtil;
|
||||
if(!oo1.OpfsSAHPool){
|
||||
oo1.OpfsSAHPool = Object.create(null);
|
||||
oo1.OpfsSAHPool.default = OpfsSAHPoolDb;
|
||||
}
|
||||
oo1.OpfsSAHPool[vfsName] = OpfsSAHPoolDb;
|
||||
// yes or no? OpfsSAHPoolDb.PoolUtil = poolUtil;
|
||||
poolUtil.OpfsSAHPoolDb = OpfsSAHPoolDb;
|
||||
oo1.DB.dbCtorHelper.setVfsPostOpenSql(
|
||||
theVfs.pointer,
|
||||
function(oo1Db, sqlite3){
|
||||
@ -1159,3 +1171,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
});
|
||||
}/*installOpfsSAHPoolVfs()*/;
|
||||
}/*sqlite3ApiBootstrap.initializers*/);
|
||||
//#else
|
||||
/*
|
||||
The OPFS SAH Pool VFS parts are elided from builds targeting
|
||||
node.js.
|
||||
*/
|
||||
//#endif target=node
|
@ -1,3 +1,4 @@
|
||||
//#ifnot target=node
|
||||
/*
|
||||
2022-09-18
|
||||
|
||||
@ -1370,3 +1371,6 @@ globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
|
||||
}
|
||||
});
|
||||
}/*sqlite3ApiBootstrap.initializers.push()*/);
|
||||
//#else
|
||||
/* The OPFS VFS parts are elided from builds targeting node.js. */
|
||||
//#endif target=node
|
||||
|
@ -3054,16 +3054,13 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
run. */)
|
||||
.assert(u1.getCapacity() + 2 === (await u2.addCapacity(2)))
|
||||
.assert(2 === (await u2.reduceCapacity(2)))
|
||||
.assert(sqlite3.oo1.OpfsSAHPool.default instanceof Function)
|
||||
.assert(sqlite3.oo1.OpfsSAHPool.default ===
|
||||
sqlite3.oo1.OpfsSAHPool[sahPoolConfig.name])
|
||||
.assert(sqlite3.capi.sqlite3_js_vfs_list().indexOf(sahPoolConfig.name) >= 0);
|
||||
|
||||
T.assert(0 === u1.getFileCount());
|
||||
const DbCtor = sqlite3.oo1.OpfsSAHPool.default;
|
||||
const dbName = '/foo.db';
|
||||
let db = new DbCtor(dbName);
|
||||
T.assert(1 === u1.getFileCount());
|
||||
let db = new u1.OpfsSAHPoolDb(dbName);
|
||||
T.assert(db instanceof sqlite3.oo1.DB)
|
||||
.assert(1 === u1.getFileCount());
|
||||
db.exec([
|
||||
'create table t(a);',
|
||||
'insert into t(a) values(1),(2),(3)'
|
||||
@ -3072,14 +3069,19 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
T.assert(3 === db.selectValue('select count(*) from t'));
|
||||
db.close();
|
||||
T.assert(1 === u1.getFileCount());
|
||||
db = new DbCtor(dbName);
|
||||
db = new u2.OpfsSAHPoolDb(dbName);
|
||||
T.assert(1 === u1.getFileCount());
|
||||
db.close();
|
||||
T.assert(1 === u1.getFileCount())
|
||||
.assert(true === u1.unlink(dbName))
|
||||
.assert(false === u1.unlink(dbName))
|
||||
.assert(0 === u1.getFileCount());
|
||||
|
||||
if(0){
|
||||
/* Enable this block to inspect vfs's contents via the dev
|
||||
console or OPFS Explorer browser extension. The
|
||||
following bits will remove them. */
|
||||
return;
|
||||
}
|
||||
T.assert(true === await u2.removeVfs())
|
||||
.assert(false === await u1.removeVfs())
|
||||
.assert(!sqlite3.capi.sqlite3_vfs_find(sahPoolConfig.name));
|
||||
|
Reference in New Issue
Block a user