aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api/sqlite3-api-opfs.js
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-09-20 08:27:57 +0000
committerstephan <stephan@noemail.net>2022-09-20 08:27:57 +0000
commit5e8bb0aa13628208b7baedd720ba4aaaac2cc239 (patch)
treed60d362917c05f78482bf91dae4e7bf428f0255d /ext/wasm/api/sqlite3-api-opfs.js
parent138647a55219b3250cff95bbfc96cc753639ddc4 (diff)
downloadsqlite-5e8bb0aa13628208b7baedd720ba4aaaac2cc239.tar.gz
sqlite-5e8bb0aa13628208b7baedd720ba4aaaac2cc239.zip
An alternative messaging strategy for the OPFS VFS proxy which uses only SharedArrayBuffer and Atomics, instead of worker messages, for communication (only the initial one-time handshake during initialization uses worker messages). It runs speedtest1 approx. 15-20% faster but still 20-ish% slower than WASMFS.
FossilOrigin-Name: a83ee3082d89439ea3ad5737e63e25bebb0f91895aca006ce5fecf5b93a2651a
Diffstat (limited to 'ext/wasm/api/sqlite3-api-opfs.js')
-rw-r--r--ext/wasm/api/sqlite3-api-opfs.js60
1 files changed, 34 insertions, 26 deletions
diff --git a/ext/wasm/api/sqlite3-api-opfs.js b/ext/wasm/api/sqlite3-api-opfs.js
index c6b38fa93..52777c5f3 100644
--- a/ext/wasm/api/sqlite3-api-opfs.js
+++ b/ext/wasm/api/sqlite3-api-opfs.js
@@ -128,7 +128,6 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
// failure is, e.g., that the remote script is 404.
promiseReject(new Error("Loading OPFS async Worker failed for unknown reasons."));
};
- const wMsg = (type,args)=>W.postMessage({type,args});
/**
Generic utilities for working with OPFS. This will get filled out
by the Promise setup and, on success, installed as sqlite3.opfs.
@@ -203,7 +202,6 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
{
let i = 0;
state.opIds.whichOp = i++;
- state.opIds.nothing = i++;
state.opIds.xAccess = i++;
state.rcIds.xAccess = i++;
state.opIds.xClose = i++;
@@ -228,8 +226,9 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
state.rcIds.xWrite = i++;
state.opIds.mkdir = i++;
state.rcIds.mkdir = i++;
+ state.opIds.xFileControl = i++;
+ state.rcIds.xFileControl = i++;
state.sabOP = new SharedArrayBuffer(i * 4/*sizeof int32*/);
- state.opIds.xFileControl = state.opIds.xSync /* special case */;
opfsUtil.metrics.reset();
}
@@ -260,12 +259,17 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
given operation's signature in the async API counterpart.
*/
const opRun = (op,...args)=>{
+ const rcNdx = state.rcIds[op] || toss("Invalid rc ID:",op);
+ const opNdx = state.opIds[op] || toss("Invalid op ID:",op);
+ state.s11n.serialize(...args);
+ Atomics.store(state.sabOPView, rcNdx, -1);
+ Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx);
+ Atomics.notify(state.sabOPView, state.opIds.whichOp) /* async thread will take over here */;
const t = performance.now();
- Atomics.store(state.sabOPView, state.opIds[op], -1);
- wMsg(op, args);
- Atomics.wait(state.sabOPView, state.opIds[op], -1);
+ Atomics.wait(state.sabOPView, rcNdx, -1);
+ const rc = Atomics.load(state.sabOPView, rcNdx);
metrics[op].wait += performance.now() - t;
- return Atomics.load(state.sabOPView, state.opIds[op]);
+ return rc;
};
const initS11n = ()=>{
@@ -297,11 +301,25 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
serialization for simplicy of implementation, but if that
proves imperformant then a lower-level approach will be
created.
+
+ If passed "too much data" (more that the shared buffer size
+ it will either throw or truncate the data (not certain
+ which)). This routine is only intended for serializing OPFS
+ VFS arguments and (in at least one special case) result
+ values, and the buffer is sized to be able to comfortably
+ handle those.
+
+ If passed no arguments then it zeroes out the serialization
+ state.
*/
state.s11n.serialize = function(...args){
- const json = jsonEncoder.encode(JSON.stringify(args));
- viewSz.setInt32(0, json.byteLength, state.littleEndian);
- viewJson.set(json);
+ if(args.length){
+ const json = jsonEncoder.encode(JSON.stringify(args));
+ viewSz.setInt32(0, json.byteLength, state.littleEndian);
+ viewJson.set(json);
+ }else{
+ viewSz.setInt32(0, 0, state.littleEndian);
+ }
};
return state.s11n;
};
@@ -552,9 +570,8 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
const vfsSyncWrappers = {
xAccess: function(pVfs,zName,flags,pOut){
mTimeStart('xAccess');
- wasm.setMemValue(
- pOut, (opRun('xAccess', wasm.cstringToJs(zName)) ? 0 : 1), 'i32'
- );
+ const rc = opRun('xAccess', wasm.cstringToJs(zName));
+ wasm.setMemValue( pOut, (rc ? 0 : 1), 'i32' );
mTimeEnd();
return 0;
},
@@ -687,21 +704,11 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
return 0===opRun('xDelete', fsEntryName, 0, recursive);
};
/**
- Exactly like deleteEntry() but runs asynchronously. This is a
- "fire and forget" operation: it does not return a promise
- because the counterpart operation happens in another thread and
- waiting on that result in a Promise would block the OPFS VFS
- from acting until it completed.
- */
- opfsUtil.deleteEntryAsync = function(fsEntryName,recursive=false){
- wMsg('xDeleteNoWait', [fsEntryName, 0, recursive]);
- };
- /**
Synchronously creates the given directory name, recursively, in
the OPFS filesystem. Returns true if it succeeds or the
directory already exists, else false.
*/
- opfsUtil.mkdir = async function(absDirName){
+ opfsUtil.mkdir = function(absDirName){
return 0===opRun('mkdir', absDirName);
};
/**
@@ -736,7 +743,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
features like getting a directory listing.
*/
- const sanityCheck = async function(){
+ const sanityCheck = function(){
const scope = wasm.scopedAllocPush();
const sq3File = new sqlite3_file();
try{
@@ -791,6 +798,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut);
rc = wasm.getMemValue(pOut,'i32');
if(rc) toss("Expecting 0 from xAccess(",dbFile,") after xDelete().");
+ log("End of OPFS sanity checks.");
}finally{
sq3File.dispose();
wasm.scopedAllocPop(scope);
@@ -803,7 +811,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
switch(data.type){
case 'opfs-async-loaded':
/*Pass our config and shared state on to the async worker.*/
- wMsg('opfs-async-init',state);
+ W.postMessage({type: 'opfs-async-init',args: state});
break;
case 'opfs-async-inited':{
/*Indicates that the async partner has received the 'init',