aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/sqlite3-opfs-async-proxy.js
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-10-04 17:06:51 +0000
committerstephan <stephan@noemail.net>2022-10-04 17:06:51 +0000
commit9a55773b2f2b5e94afa59ced504e2078af2c565b (patch)
tree126faada6fe7da83fd02d8c55b2ec4df858c695c /ext/wasm/sqlite3-opfs-async-proxy.js
parented3182f233690989b332f64548d03ef9eb791a5c (diff)
downloadsqlite-9a55773b2f2b5e94afa59ced504e2078af2c565b.tar.gz
sqlite-9a55773b2f2b5e94afa59ced504e2078af2c565b.zip
Replace time-based auto-unlock of opfs sync handles with lock acquisition/release via sqlite3_io_methods::xLock/xUnlock().
FossilOrigin-Name: 2625b7cfe1640c1d7e779ec1f37db970541598c0dc3e22e5eecf3c772d95ad40
Diffstat (limited to 'ext/wasm/sqlite3-opfs-async-proxy.js')
-rw-r--r--ext/wasm/sqlite3-opfs-async-proxy.js78
1 files changed, 40 insertions, 38 deletions
diff --git a/ext/wasm/sqlite3-opfs-async-proxy.js b/ext/wasm/sqlite3-opfs-async-proxy.js
index d9310d025..fd4c7f2b8 100644
--- a/ext/wasm/sqlite3-opfs-async-proxy.js
+++ b/ext/wasm/sqlite3-opfs-async-proxy.js
@@ -41,6 +41,9 @@ if(self.window === self){
}else if(!navigator.storage.getDirectory){
toss("This API requires navigator.storage.getDirectory.");
}
+
+//warn("This file is very much experimental and under construction.",self.location.pathname);
+
/**
Will hold state copied to this object from the syncronous side of
this API.
@@ -97,8 +100,6 @@ metrics.dump = ()=>{
console.log("Serialization metrics:",metrics.s11n);
};
-//warn("This file is very much experimental and under construction.",self.location.pathname);
-
/**
Map of sqlite3_file pointers (integers) to metadata related to a
given OPFS file handles. The pointers are, in this side of the
@@ -142,8 +143,7 @@ const getDirForFilename = async function f(absFilename, createDirs = false){
/**
Returns the sync access handle associated with the given file
handle object (which must be a valid handle object), lazily opening
- it if needed. Timestamps the handle for use in relinquishing it
- during idle time.
+ it if needed.
In order to help alleviate cross-tab contention for a dabase,
if an exception is thrown while acquiring the handle, this routine
@@ -177,13 +177,12 @@ const getSyncHandle = async (fh)=>{
}
log("Got sync handle for",fh.filenameAbs,'in',performance.now() - t,'ms');
}
- fh.syncHandleTime = performance.now();
return fh.syncHandle;
};
const closeSyncHandle = async (fh)=>{
if(fh.syncHandle){
- //warn("Closing sync handle for",fh.filenameAbs);
+ log("Closing sync handle for",fh.filenameAbs);
const h = fh.syncHandle;
delete fh.syncHandle;
return h.close();
@@ -239,6 +238,7 @@ const wTimeEnd = ()=>(
*/
let flagAsyncShutdown = false;
+
/**
Asynchronous wrappers for sqlite3_vfs and sqlite3_io_methods
methods. Maintenance reminder: members are in alphabetical order
@@ -373,6 +373,20 @@ const vfsAsyncImpls = {
storeAndNotify('xFileSize', sz);
mTimeEnd();
},
+ xLock: async function(fid,lockType){
+ mTimeStart('xLock');
+ const fh = __openFiles[fid];
+ let rc = 0;
+ if( !fh.syncHandle ){
+ try { await getSyncHandle(fh) }
+ catch(e){
+ state.s11n.storeException(1,e);
+ rc = state.sq3Codes.SQLITE_IOERR;
+ }
+ }
+ storeAndNotify('xLock',rc);
+ mTimeEnd();
+ },
xOpen: async function(fid/*sqlite3_file pointer*/, filename, flags){
const opName = 'xOpen';
mTimeStart(opName);
@@ -473,6 +487,23 @@ const vfsAsyncImpls = {
storeAndNotify('xTruncate',rc);
mTimeEnd();
},
+ xUnlock: async function(fid,lockType){
+ mTimeStart('xUnlock');
+ let rc = 0;
+ const fh = __openFiles[fid];
+ if( state.sq3Codes.SQLITE_LOCK_NONE===lockType
+ && fh.syncHandle ){
+ try { await closeSyncHandle(fh) }
+ catch(e){
+ state.s11n.storeException(1,e);
+ rc = state.sq3Codes.SQLITE_IOERR;
+ /* Maybe we want to not report this? "Destructors do not
+ throw." */
+ }
+ }
+ storeAndNotify('xUnlock',rc);
+ mTimeEnd();
+ },
xWrite: async function(fid,n,offset){
mTimeStart('xWrite');
let rc;
@@ -495,7 +526,7 @@ const vfsAsyncImpls = {
storeAndNotify('xWrite',rc);
mTimeEnd();
}
-};
+}/*vfsAsyncImpls*/;
const initS11n = ()=>{
/**
@@ -617,21 +648,7 @@ const waitLoop = async function f(){
We need to wake up periodically to give the thread a chance
to do other things.
*/
- const waitTime = 500;
- /**
- relinquishTime defines the_approximate_ number of ms after which
- a db sync access handle will be relinquished so that we do not
- hold a persistent lock on it. When the following loop times out
- while waiting, every (approximate) increment of this value it
- will relinquish any db handles which have been idle for at least
- this much time.
-
- Reaquisition of a sync handle seems to take an average of
- 0.6-0.9ms on this dev machine but takes anywhere from 1-3ms every
- once in a while (maybe 1 time in 5 or 10). Outliers as long as
- 7ms have been witnessed, but they're rare.
- */
- const relinquishTime = 500;
+ const waitTime = 1000;
let lastOpTime = performance.now();
let now;
while(!flagAsyncShutdown){
@@ -639,21 +656,6 @@ const waitLoop = async function f(){
if('timed-out'===Atomics.wait(
state.sabOPView, state.opIds.whichOp, 0, waitTime
)){
- if(relinquishTime &&
- (lastOpTime + relinquishTime <= (now = performance.now()))){
- for(const fh of Object.values(__openFiles)){
- if(fh.syncHandle && (
- now - relinquishTime >= fh.syncHandleTime
- )){
- log("Relinquishing for timeout:",fh.filenameAbs);
- await closeSyncHandle(fh)
- /* Testing shows that we have to wait on this async
- op to finish, else we might try to re-open it
- before the close has run. The FS layer does not
- retain the order those operations, apparently. */;
- }
- }
- }
continue;
}
lastOpTime = performance.now();
@@ -719,4 +721,4 @@ navigator.storage.getDirectory().then(function(d){
}
};
wMsg('opfs-async-loaded');
-}).catch((e)=>error(e));
+}).catch((e)=>error("error initializing OPFS asyncer:",e));