Generic cleanups in the OPFS sync/async proxy.

FossilOrigin-Name: f36bddbe54c3acbfaa958042e4d24724f130bdca551401033f9bc63f3da73492
This commit is contained in:
stephan 2022-09-17 21:13:26 +00:00
parent 0731554629
commit e6f8a09532
4 changed files with 70 additions and 32 deletions

View File

@ -10,10 +10,10 @@
***********************************************************************
A EXTREMELY INCOMPLETE and UNDER CONSTRUCTION experiment for OPFS: a
Worker which manages asynchronous OPFS handles on behalf of a
synchronous API which controls it via a combination of Worker
messages, SharedArrayBuffer, and Atomics.
An INCOMPLETE and UNDER CONSTRUCTION experiment for OPFS: a Worker
which manages asynchronous OPFS handles on behalf of a synchronous
API which controls it via a combination of Worker messages,
SharedArrayBuffer, and Atomics.
Highly indebted to:
@ -109,8 +109,8 @@ const getDirForPath = async function f(absFilename, createDirs = false){
*/
const storeAndNotify = (opName, value)=>{
log(opName+"() is notify()ing w/ value:",value);
Atomics.store(state.opBuf, state.opIds[opName], value);
Atomics.notify(state.opBuf, state.opIds[opName]);
Atomics.store(state.opSABView, state.opIds[opName], value);
Atomics.notify(state.opSABView, state.opIds[opName]);
};
const isInt32 = function(n){
@ -294,8 +294,8 @@ navigator.storage.getDirectory().then(function(d){
state.verbose = opt.verbose ?? 2;
state.fileBufferSize = opt.fileBufferSize;
state.fbInt64Offset = opt.fbInt64Offset;
state.opSab = opt.opSab;
state.opBuf = new Int32Array(state.opSab);
state.opSAB = opt.opSAB;
state.opSABView = new Int32Array(state.opSAB);
state.opIds = opt.opIds;
state.sq3Codes = opt.sq3Codes;
Object.keys(vfsAsyncImpls).forEach((k)=>{

View File

@ -10,10 +10,20 @@
***********************************************************************
A EXTREMELY INCOMPLETE and UNDER CONSTRUCTION experiment for OPFS.
An INCOMPLETE and UNDER CONSTRUCTION experiment for OPFS.
This file holds the synchronous half of an sqlite3_vfs
implementation which proxies, in a synchronous fashion, the
asynchronous OPFS APIs using a second Worker.
asynchronous OPFS APIs using a second Worker, implemented
in sqlite3-opfs-async-proxy.js.
Summary of how this works:
This file uses the sqlite3.StructBinder-created struct wrappers for
sqlite3_vfs, sqlite3_io_methods, ans sqlite3_file to set up a
conventional sqlite3_vfs (except that it's implemented in JS). The
methods which require OPFS APIs use a separate worker (hereafter called the
OPFS worker) to access that functionality. This worker and that one
use SharedBufferArray
*/
'use strict';
/**
@ -36,6 +46,16 @@ const initOpfsVfs = function(sqlite3){
};
warn("This file is very much experimental and under construction.",self.location.pathname);
if(self.window===self ||
!self.SharedBufferArray ||
!self.FileSystemHandle ||
!self.FileSystemDirectoryHandle ||
!self.FileSystemFileHandle ||
!self.FileSystemFileHandle.prototype.createSyncAccessHandle ||
!navigator.storage.getDirectory){
warn("This environment does not have OPFS support.");
}
const capi = sqlite3.capi;
const wasm = capi.wasm;
const sqlite3_vfs = capi.sqlite3_vfs
@ -44,7 +64,6 @@ const initOpfsVfs = function(sqlite3){
|| toss("Missing sqlite3.capi.sqlite3_file object.");
const sqlite3_io_methods = capi.sqlite3_io_methods
|| toss("Missing sqlite3.capi.sqlite3_io_methods object.");
const StructBinder = sqlite3.StructBinder || toss("Missing sqlite3.StructBinder.");
const W = new Worker("sqlite3-opfs-async-proxy.js");
const wMsg = (type,payload)=>W.postMessage({type,payload});
@ -72,7 +91,7 @@ const initOpfsVfs = function(sqlite3){
state.opIds.xSync = i++;
state.opIds.xTruncate = i++;
state.opIds.xWrite = i++;
state.opSab = new SharedArrayBuffer(i * 4);
state.opSAB = new SharedArrayBuffer(i * 4/*sizeof int32*/);
}
state.sq3Codes = Object.create(null);
@ -91,13 +110,13 @@ const initOpfsVfs = function(sqlite3){
const isWorkerErrCode = (n)=>!!state.sq3Codes._reverse[n];
const opStore = (op,val=-1)=>Atomics.store(state.opBuf, state.opIds[op], val);
const opWait = (op,val=-1)=>Atomics.wait(state.opBuf, state.opIds[op], val);
const opStore = (op,val=-1)=>Atomics.store(state.opSABView, state.opIds[op], val);
const opWait = (op,val=-1)=>Atomics.wait(state.opSABView, state.opIds[op], val);
/**
Runs the given operation in the async worker counterpart, waits
for its response, and returns the result which the async worker
writes to the given op's index in state.opBuf. The 2nd argument
writes to the given op's index in state.opSABView. The 2nd argument
must be a single object or primitive value, depending on the
given operation's signature in the async API counterpart.
*/
@ -105,7 +124,7 @@ const initOpfsVfs = function(sqlite3){
opStore(op);
wMsg(op, args);
opWait(op);
return Atomics.load(state.opBuf, state.opIds[op]);
return Atomics.load(state.opSABView, state.opIds[op]);
};
const wait = (ms,value)=>{
@ -151,16 +170,17 @@ const initOpfsVfs = function(sqlite3){
opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
opfsVfs.$mxPathname = 1024/*sure, why not?*/;
opfsVfs.$zName = wasm.allocCString("opfs");
// All C-side memory of opfsVfs is zeroed out, but just to be explicit:
opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null;
opfsVfs.ondispose = [
'$zName', opfsVfs.$zName,
'cleanup dVfs', ()=>(dVfs ? dVfs.dispose() : null)
'cleanup default VFS wrapper', ()=>(dVfs ? dVfs.dispose() : null),
'cleanup opfsIoMethods', ()=>opfsIoMethods.dispose()
];
if(dVfs){
opfsVfs.$xSleep = dVfs.$xSleep;
opfsVfs.$xRandomness = dVfs.$xRandomness;
}
// All C-side memory of opfsVfs is zeroed out, but just to be explicit:
opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null;
/**
Pedantic sidebar about opfsVfs.ondispose: the entries in that array
are items to clean up when opfsVfs.dispose() is called, but in this
@ -383,7 +403,7 @@ const initOpfsVfs = function(sqlite3){
const dbFile = "/sanity/check/file";
let rc = vfsSyncWrappers.xOpen(opfsVfs.pointer, dbFile,
fid, openFlags, pOut);
log("open rc =",rc,"state.opBuf[xOpen] =",state.opBuf[state.opIds.xOpen]);
log("open rc =",rc,"state.opSABView[xOpen] =",state.opSABView[state.opIds.xOpen]);
if(isWorkerErrCode(rc)){
error("open failed with code",rc);
return;
@ -399,7 +419,7 @@ const initOpfsVfs = function(sqlite3){
log("xSleep()ing before close()ing...");
opRun('xSleep',1500);
rc = ioSyncWrappers.xClose(fid);
log("xClose rc =",rc,"opBuf =",state.opBuf);
log("xClose rc =",rc,"opSABView =",state.opSABView);
log("Deleting file:",dbFile);
opRun('xDelete', dbFile);
}finally{
@ -416,13 +436,31 @@ const initOpfsVfs = function(sqlite3){
/*Pass our config and shared state on to the async worker.*/
wMsg('init',state);
break;
case 'inited':
case 'inited':{
/*Indicates that the async partner has received the 'init',
so we now know that the state object is no longer subject to
being copied by a pending postMessage() call.*/
state.opBuf = new Int32Array(state.opSab);
try {
const rc = capi.sqlite3_vfs_register(opfsVfs.pointer, opfsVfs.$zName);
if(rc){
opfsVfs.dispose();
toss("sqlite3_vfs_register(OPFS) failed with rc",rc);
}
if(opfsVfs.pointer !== capi.sqlite3_vfs_find("opfs")){
toss("BUG: sqlite3_vfs_find() failed for just-installed OPFS VFS");
}
capi.sqlite3_vfs_register.addReference(opfsVfs, opfsIoMethods);
state.opSABView = new Int32Array(state.opSAB);
if(self.location && +self.location.port > 1024){
log("Running sanity check for dev mode...");
sanityCheck();
}
warn("End of (very incomplete) OPFS setup.", opfsVfs);
}catch(e){
error(e);
}
break;
}
default:
error("Unexpected message from the async worker:",data);
break;

View File

@ -1,5 +1,5 @@
C Add\sthe\sremaining\svfs/io_methods\swrappers\sto\sthe\sOPFS\ssync/async\sproxy,\sbut\smost\sare\snot\syet\stested.
D 2022-09-17T20:50:12.684
C Generic\scleanups\sin\sthe\sOPFS\ssync/async\sproxy.
D 2022-09-17T21:13:26.228
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -523,7 +523,7 @@ F ext/wasm/speedtest1.html fbb8e4d1639028443f3687a683be660beca6927920545cf6b1fdf
F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x
F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0
F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5
F ext/wasm/sqlite3-opfs-async-proxy.js 62024877ad13fdff1834581ca1951ab58bda431e4d548aaaf4506ea54f0ed2de
F ext/wasm/sqlite3-opfs-async-proxy.js ceb5e3a190bfd42d25fc137b3aaf09adf6469b5f1e33528a64ce7ff74e5ef5b1
F ext/wasm/sqlite3-worker1-promiser.js 92b8da5f38439ffec459a8215775d30fa498bc0f1ab929ff341fc3dd479660b9
F ext/wasm/sqlite3-worker1.js 0c1e7626304543969c3846573e080c082bf43bcaa47e87d416458af84f340a9e
F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893
@ -534,7 +534,7 @@ F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c2
F ext/wasm/testing2.js 25584bcc30f19673ce13a6f301f89f8820a59dfe044e0c4f2913941f4097fe3c
F ext/wasm/wasmfs.make 21a5cf297954a689e0dc2a95299ae158f681cae5e90c10b99d986097815fd42d
F ext/wasm/x-sync-async.html 717b0d3bee96e49cbd36731bead497ab27a8bf3a3b23dd11e40e61d4ac9e8b80
F ext/wasm/x-sync-async.js 05c0b49adae0600c5ad12f3325e0873ab1f07b99c2bb017f32b50a4f701490f1
F ext/wasm/x-sync-async.js c99a6f98a8b0ccb43b2883a1bc1da42d0d84b26b5d4fd99d2f053ffe209a0a1f
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
@ -2030,8 +2030,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 38da059b472415da52f57de7332fbeb8a91e3add1f4be3ff9c1924b52672f77c
R 8887512b2075b067b4aa7969d08f1316
P 44db9132145b3072488ea91db53f6c06be74544beccad5fd07efd22c0f03dc04
R 75c9aa6717389505aa78f157abdf6d44
U stephan
Z 1bf4c438e48bd1dc1717362060b2f357
Z 6a0a0bcb470dbb44e9d0c87c09f1fedd
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
44db9132145b3072488ea91db53f6c06be74544beccad5fd07efd22c0f03dc04
f36bddbe54c3acbfaa958042e4d24724f130bdca551401033f9bc63f3da73492