1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Internal restructuring of the OPFS sqlite3_vfs in order to facilitate certain experimentation and improve error reporting/hints if it cannot be activated. Deprecate the name sqlite3.opfs.OpfsDb, preferring sqlite3.oo1.OpfsDb for consistency with JsStorageDb and any future DB subclasses.

FossilOrigin-Name: 0c5c51f4fb04a4b90c50ec9704cfea9a3fb7d7d0ee55c1b0d4476129188217a6
This commit is contained in:
stephan
2022-11-29 05:25:08 +00:00
parent e6b0154138
commit 04184761de
6 changed files with 919 additions and 876 deletions

View File

@ -76,15 +76,25 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
`opfs` property, containing several OPFS-specific utilities. `opfs` property, containing several OPFS-specific utilities.
*/ */
const installOpfsVfs = function callee(options){ const installOpfsVfs = function callee(options){
if(!self.SharedArrayBuffer || if(!self.SharedArrayBuffer
!self.Atomics || || !self.Atomics){
!self.FileSystemHandle || return Promise.reject(
new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. "+
"The server must emit the COOP/COEP response headers to enable those. "+
"See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep")
);
}else if(self.window===self && self.document){
return Promise.reject(
new Error("The OPFS sqlite3_vfs cannot run in the main thread "+
"because it requires Atomics.wait().")
);
}else if(!self.FileSystemHandle ||
!self.FileSystemDirectoryHandle || !self.FileSystemDirectoryHandle ||
!self.FileSystemFileHandle || !self.FileSystemFileHandle ||
!self.FileSystemFileHandle.prototype.createSyncAccessHandle || !self.FileSystemFileHandle.prototype.createSyncAccessHandle ||
!navigator.storage.getDirectory){ !navigator.storage.getDirectory){
return Promise.reject( return Promise.reject(
new Error("This environment does not have OPFS support.") new Error("Missing required OPFS APIs.")
); );
} }
if(!options || 'object'!==typeof options){ if(!options || 'object'!==typeof options){
@ -134,6 +144,18 @@ const installOpfsVfs = function callee(options){
OPFS-specific sqlite3_vfs evolves. OPFS-specific sqlite3_vfs evolves.
*/ */
const opfsUtil = Object.create(null); const opfsUtil = Object.create(null);
/**
Returns true if _this_ thread has access to the OPFS APIs.
*/
const thisThreadHasOPFS = ()=>{
return self.FileSystemHandle &&
self.FileSystemDirectoryHandle &&
self.FileSystemFileHandle &&
self.FileSystemFileHandle.prototype.createSyncAccessHandle &&
navigator.storage.getDirectory;
};
/** /**
Not part of the public API. Solely for internal/development Not part of the public API. Solely for internal/development
use. use.
@ -1179,12 +1201,16 @@ const installOpfsVfs = function callee(options){
//consideration. //consideration.
if(sqlite3.oo1){ if(sqlite3.oo1){
opfsUtil.OpfsDb = function(...args){ const OpfsDb = function(...args){
const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args);
opt.vfs = opfsVfs.$zName; opt.vfs = opfsVfs.$zName;
sqlite3.oo1.DB.dbCtorHelper.call(this, opt); sqlite3.oo1.DB.dbCtorHelper.call(this, opt);
}; };
opfsUtil.OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype); sqlite3.oo1.OpfsDb =
opfsUtil.OpfsDb /* sqlite3.opfs.OpfsDb => deprecated name -
will be phased out Real Soon */ =
OpfsDb;
OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenSql( sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenSql(
opfsVfs.pointer, opfsVfs.pointer,
[ [
@ -1206,13 +1232,6 @@ const installOpfsVfs = function callee(options){
); );
} }
/**
Potential TODOs:
- Expose one or both of the Worker objects via opfsUtil and
publish an interface for proxying the higher-level OPFS
features like getting a directory listing.
*/
const sanityCheck = function(){ const sanityCheck = function(){
const scope = wasm.scopedAllocPush(); const scope = wasm.scopedAllocPush();
const sq3File = new sqlite3_file(); const sq3File = new sqlite3_file();
@ -1282,6 +1301,11 @@ const installOpfsVfs = function callee(options){
W.onmessage = function({data}){ W.onmessage = function({data}){
//log("Worker.onmessage:",data); //log("Worker.onmessage:",data);
switch(data.type){ switch(data.type){
case 'opfs-unavailable':
/* Async proxy has determined that OPFS is unavailable. There's
nothing more for us to do here. */
promiseReject(new Error(data.payload.join(' ')));
break;
case 'opfs-async-loaded': case 'opfs-async-loaded':
/*Arrives as soon as the asyc proxy finishes loading. /*Arrives as soon as the asyc proxy finishes loading.
Pass our config and shared state on to the async worker.*/ Pass our config and shared state on to the async worker.*/
@ -1308,6 +1332,7 @@ const installOpfsVfs = function callee(options){
warn("Running sanity checks because of opfs-sanity-check URL arg..."); warn("Running sanity checks because of opfs-sanity-check URL arg...");
sanityCheck(); sanityCheck();
} }
if(thisThreadHasOPFS()){
navigator.storage.getDirectory().then((d)=>{ navigator.storage.getDirectory().then((d)=>{
W.onerror = W._originalOnError; W.onerror = W._originalOnError;
delete W._originalOnError; delete W._originalOnError;
@ -1316,6 +1341,9 @@ const installOpfsVfs = function callee(options){
log("End of OPFS sqlite3_vfs setup.", opfsVfs); log("End of OPFS sqlite3_vfs setup.", opfsVfs);
promiseResolve(sqlite3); promiseResolve(sqlite3);
}); });
}else{
promiseResolve(sqlite3);
}
}catch(e){ }catch(e){
error(e); error(e);
promiseReject(e); promiseReject(e);
@ -1334,9 +1362,6 @@ const installOpfsVfs = function callee(options){
installOpfsVfs.defaultProxyUri = installOpfsVfs.defaultProxyUri =
"sqlite3-opfs-async-proxy.js"; "sqlite3-opfs-async-proxy.js";
self.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ self.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
if(sqlite3.scriptInfo && !sqlite3.scriptInfo.isWorker){
return;
}
try{ try{
let proxyJs = installOpfsVfs.defaultProxyUri; let proxyJs = installOpfsVfs.defaultProxyUri;
if(sqlite3.scriptInfo.sqlite3Dir){ if(sqlite3.scriptInfo.sqlite3Dir){

View File

@ -47,6 +47,8 @@
usage of those methods to remove the "await". usage of those methods to remove the "await".
*/ */
"use strict"; "use strict";
const wPost = (type,...args)=>postMessage({type, payload:args});
const installAsyncProxy = function(self){
const toss = function(...args){throw new Error(args.join(' '))}; const toss = function(...args){throw new Error(args.join(' '))};
if(self.window === self){ if(self.window === self){
toss("This code cannot run from the main thread.", toss("This code cannot run from the main thread.",
@ -851,7 +853,6 @@ const waitLoop = async function f(){
}; };
navigator.storage.getDirectory().then(function(d){ navigator.storage.getDirectory().then(function(d){
const wMsg = (type)=>postMessage({type});
state.rootDir = d; state.rootDir = d;
self.onmessage = function({data}){ self.onmessage = function({data}){
switch(data.type){ switch(data.type){
@ -880,7 +881,7 @@ navigator.storage.getDirectory().then(function(d){
initS11n(); initS11n();
metrics.reset(); metrics.reset();
log("init state",state); log("init state",state);
wMsg('opfs-async-inited'); wPost('opfs-async-inited');
waitLoop(); waitLoop();
break; break;
} }
@ -896,5 +897,21 @@ navigator.storage.getDirectory().then(function(d){
break; break;
} }
}; };
wMsg('opfs-async-loaded'); wPost('opfs-async-loaded');
}).catch((e)=>error("error initializing OPFS asyncer:",e)); }).catch((e)=>error("error initializing OPFS asyncer:",e));
}/*installAsyncProxy()*/;
if(!self.SharedArrayBuffer){
wPost('opfs-unavailable', "Missing SharedArrayBuffer API.",
"The server must emit the COOP/COEP response headers to enable that.");
}else if(!self.Atomics){
wPost('opfs-unavailable', "Missing Atomics API.",
"The server must emit the COOP/COEP response headers to enable that.");
}else if(!self.FileSystemHandle ||
!self.FileSystemDirectoryHandle ||
!self.FileSystemFileHandle ||
!self.FileSystemFileHandle.prototype.createSyncAccessHandle ||
!navigator.storage.getDirectory){
wPost('opfs-unavailable',"Missing required OPFS APIs.");
}else{
installAsyncProxy(self);
}

View File

@ -1784,13 +1784,12 @@ self.sqlite3InitModule = sqlite3InitModule;
.t({ .t({
name: 'OPFS sanity checks', name: 'OPFS sanity checks',
test: async function(sqlite3){ test: async function(sqlite3){
const opfs = sqlite3.opfs;
const filename = 'sqlite3-tester1.db'; const filename = 'sqlite3-tester1.db';
const pVfs = capi.sqlite3_vfs_find('opfs'); const pVfs = capi.sqlite3_vfs_find('opfs');
T.assert(pVfs); T.assert(pVfs);
const unlink = (fn=filename)=>wasm.sqlite3_wasm_vfs_unlink(pVfs,fn); const unlink = (fn=filename)=>wasm.sqlite3_wasm_vfs_unlink(pVfs,fn);
unlink(); unlink();
let db = new opfs.OpfsDb(filename); let db = new sqlite3.oo1.OpfsDb(filename);
try { try {
db.exec([ db.exec([
'create table p(a);', 'create table p(a);',
@ -1798,7 +1797,7 @@ self.sqlite3InitModule = sqlite3InitModule;
]); ]);
T.assert(3 === db.selectValue('select count(*) from p')); T.assert(3 === db.selectValue('select count(*) from p'));
db.close(); db.close();
db = new opfs.OpfsDb(filename); db = new sqlite3.oo1.OpfsDb(filename);
db.exec('insert into p(a) values(4),(5),(6)'); db.exec('insert into p(a) values(4),(5),(6)');
T.assert(6 === db.selectValue('select count(*) from p')); T.assert(6 === db.selectValue('select count(*) from p'));
}finally{ }finally{
@ -1806,8 +1805,9 @@ self.sqlite3InitModule = sqlite3InitModule;
unlink(); unlink();
} }
if(1){ if(sqlite3.opfs){
// Sanity-test sqlite3_wasm_vfs_create_file()... // Sanity-test sqlite3_wasm_vfs_create_file()...
const opfs = sqlite3.opfs;
const fSize = 1379; const fSize = 1379;
let sh; let sh;
try{ try{
@ -1824,7 +1824,6 @@ self.sqlite3InitModule = sqlite3InitModule;
if(sh) await sh.close(); if(sh) await sh.close();
unlink(); unlink();
} }
}
// Some sanity checks of the opfs utility functions... // Some sanity checks of the opfs utility functions...
const testDir = '/sqlite3-opfs-'+opfs.randomFilename(12); const testDir = '/sqlite3-opfs-'+opfs.randomFilename(12);
@ -1839,6 +1838,7 @@ self.sqlite3InitModule = sqlite3InitModule;
.assert(!(await opfs.entryExists(testDir)), .assert(!(await opfs.entryExists(testDir)),
"entryExists(",testDir,") should have failed"); "entryExists(",testDir,") should have failed");
} }
}
}/*OPFS sanity checks*/) }/*OPFS sanity checks*/)
;/* end OPFS tests */ ;/* end OPFS tests */

View File

@ -33,9 +33,10 @@
with <code>unlock-asap=0-1</code>. with <code>unlock-asap=0-1</code>.
</p> </p>
<p>Achtung: if it does not start to do anything within a couple of <p>Achtung: if it does not start to do anything within a couple of
seconds, check the dev console: Chrome often fails with "cannot allocate seconds, check the dev console: Chrome sometimes fails to load
WasmMemory" at startup. Closing and re-opening the tab usually resolves the wasm module due to "cannot allocate WasmMemory." Closing and
it. re-opening the tab usually resolves it, but sometimes restarting
the browser is required.
</p> </p>
<div class='input-wrapper'> <div class='input-wrapper'>
<input type='checkbox' id='cb-log-reverse'> <input type='checkbox' id='cb-log-reverse'>

View File

@ -1,5 +1,5 @@
C Add\san\sexplicit\swarning\sabout\sthe\scurrent\sAPI-instability\sof\sthe\ssqlite3.opfs\snamespace,\swhich\smay\sneed\sto\sbe\seliminated\sbased\son\sre-thinking\sof\show\sthe\sOPFS\ssqlite3_vfs\sis\sregistered.\sComment\schanges\sonly\s-\sno\scode. C Internal\srestructuring\sof\sthe\sOPFS\ssqlite3_vfs\sin\sorder\sto\sfacilitate\scertain\sexperimentation\sand\simprove\serror\sreporting/hints\sif\sit\scannot\sbe\sactivated.\sDeprecate\sthe\sname\ssqlite3.opfs.OpfsDb,\spreferring\ssqlite3.oo1.OpfsDb\sfor\sconsistency\swith\sJsStorageDb\sand\sany\sfuture\sDB\ssubclasses.
D 2022-11-29T02:23:12.943 D 2022-11-29T05:25:08.036
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -505,11 +505,11 @@ F ext/wasm/api/pre-js.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f
F ext/wasm/api/sqlite3-api-cleanup.js ecdc69dbfccfe26146f04799fcfd4a6f5790d46e7e3b9b6e9b0491f92ed8ae34 F ext/wasm/api/sqlite3-api-cleanup.js ecdc69dbfccfe26146f04799fcfd4a6f5790d46e7e3b9b6e9b0491f92ed8ae34
F ext/wasm/api/sqlite3-api-glue.js 056f44b82c126358a0175e08a892d56fadfce177b0d7a0012502a6acf67ea6d5 F ext/wasm/api/sqlite3-api-glue.js 056f44b82c126358a0175e08a892d56fadfce177b0d7a0012502a6acf67ea6d5
F ext/wasm/api/sqlite3-api-oo1.js 06ad2079368e16cb9f182c18cd37bdc3932536856dff4f60582d0ca5f6c491a8 F ext/wasm/api/sqlite3-api-oo1.js 06ad2079368e16cb9f182c18cd37bdc3932536856dff4f60582d0ca5f6c491a8
F ext/wasm/api/sqlite3-api-opfs.js 3cdae7e98c500f89f9468a260e2a0e1b528c845a107bf72d368e5222769214d3 F ext/wasm/api/sqlite3-api-opfs.js 583650ffdc1452496df6b9459d018fa2aede221ae6ea0cbbbe83bd2e1bdba966
F ext/wasm/api/sqlite3-api-prologue.js 7fce4c6a138ec3d7c285b7c125cee809e6b668d2cb0d2328a1b790b7037765bd F ext/wasm/api/sqlite3-api-prologue.js 7fce4c6a138ec3d7c285b7c125cee809e6b668d2cb0d2328a1b790b7037765bd
F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
F ext/wasm/api/sqlite3-opfs-async-proxy.js 798383f6b46fd5dac122d6e35962d25b10401ddb825b5c66df1d21e6b1d8aacc F ext/wasm/api/sqlite3-opfs-async-proxy.js b5dd7eda8e74e07453457925a0dd793d7785da720954e0e37e847c5c6e4d9526
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c 8b32787a3b6bb2990cbaba2304bd5b75a9652acbc8d29909b3279019b6cbaef5 F ext/wasm/api/sqlite3-wasm.c 8b32787a3b6bb2990cbaba2304bd5b75a9652acbc8d29909b3279019b6cbaef5
F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b
@ -554,8 +554,8 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac
F ext/wasm/tester1-worker.html 5ef353348c37cf2e4fd0b23da562d3275523e036260b510734e9a3239ba8c987 F ext/wasm/tester1-worker.html 5ef353348c37cf2e4fd0b23da562d3275523e036260b510734e9a3239ba8c987
F ext/wasm/tester1.c-pp.html 74aa9b31c75f12490653f814b53c3dd39f40cd3f70d6a53a716f4e8587107399 F ext/wasm/tester1.c-pp.html 74aa9b31c75f12490653f814b53c3dd39f40cd3f70d6a53a716f4e8587107399
F ext/wasm/tester1.c-pp.js 3b91f192c159088004fba6fe3441edea58421a8b88bccf3dd20978a077648d19 F ext/wasm/tester1.c-pp.js a4b6a165aafcd3b86118efaec6b47c70fbb6c64b5ab86d21ca8c250d42617dfa
F ext/wasm/tests/opfs/concurrency/index.html e8fec75ea6eddc600c8a382da7ea2579feece2263a2fb4417f2cf3e9d451744c F ext/wasm/tests/opfs/concurrency/index.html 2b1cda51d6c786102875a28eba22f0da3eecb732a5e677b0d1ecdb53546d1a62
F ext/wasm/tests/opfs/concurrency/test.js bfc3d7e27b207f0827f12568986b8d516a744529550b449314f5c21c9e9faf4a F ext/wasm/tests/opfs/concurrency/test.js bfc3d7e27b207f0827f12568986b8d516a744529550b449314f5c21c9e9faf4a
F ext/wasm/tests/opfs/concurrency/worker.js 0eff027cbd3a495acb2ac94f57ca9e4d21125ab9fda07d45f3701b0efe82d450 F ext/wasm/tests/opfs/concurrency/worker.js 0eff027cbd3a495acb2ac94f57ca9e4d21125ab9fda07d45f3701b0efe82d450
F ext/wasm/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd72273503ae7d5 F ext/wasm/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd72273503ae7d5
@ -2064,8 +2064,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 46cdd3637d6a206ad2bcf8653cc6f2c7a886a16cc7685c45967938609941a755 P 0cb2fd14179397051a25d066256a553fc198656d5668c7010c016f2b8f495bf4
R 3870d04bfd54da096e986662fe29b1c8 R 115b7898d7b2ce79a9261f36a9b959d1
U stephan U stephan
Z ad4a8c5f45a34a10f588c0c6dc455846 Z f4ff31d5e2499971cf67cb62dbdd0ac3
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
0cb2fd14179397051a25d066256a553fc198656d5668c7010c016f2b8f495bf4 0c5c51f4fb04a4b90c50ec9704cfea9a3fb7d7d0ee55c1b0d4476129188217a6