mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
OPFS VFS now lazily opens its sync access handle, as a step towards experimenting with relinquishing it during idle times to help avoid cross-tab and page-reload locking issues.
FossilOrigin-Name: a984e1ba435731413a541f86c50232bc7d6e33aff6ba4cca90f89188e7b82a2c
This commit is contained in:
@ -24,27 +24,32 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
self.WhWasmUtilInstaller(capi.wasm);
|
||||
delete self.WhWasmUtilInstaller;
|
||||
|
||||
/**
|
||||
Install JS<->C struct bindings for the non-opaque struct types we
|
||||
need... */
|
||||
sqlite3.StructBinder = self.Jaccwabyt({
|
||||
heap: 0 ? wasm.memory : wasm.heap8u,
|
||||
alloc: wasm.alloc,
|
||||
dealloc: wasm.dealloc,
|
||||
functionTable: wasm.functionTable,
|
||||
bigIntEnabled: wasm.bigIntEnabled,
|
||||
memberPrefix: '$'
|
||||
});
|
||||
delete self.Jaccwabyt;
|
||||
|
||||
if(0){
|
||||
/* "The problem" is that the following isn't type-safe.
|
||||
OTOH, nothing about WASM pointers is. */
|
||||
/**
|
||||
Add the `.pointer` xWrap() signature entry to extend the
|
||||
`pointer` arg handler to check for a `pointer` property. This
|
||||
can be used to permit, e.g., passing an sqlite3.oo1.DB instance
|
||||
to a C-style sqlite3_xxx function which takes an `sqlite3*`
|
||||
argument.
|
||||
*/
|
||||
const xPointer = wasm.xWrap.argAdapter('pointer');
|
||||
const adapter = function(v){
|
||||
if(v && v.constructor){
|
||||
const x = v.pointer;
|
||||
if(Number.isInteger(x)) return x;
|
||||
else toss("Invalid (object) type for .pointer-type argument.");
|
||||
/* "The problem" is that the following isn't even remotely
|
||||
type-safe. OTOH, nothing about WASM pointers is. */
|
||||
const argPointer = wasm.xWrap.argAdapter('*');
|
||||
wasm.xWrap.argAdapter('StructType', (v)=>{
|
||||
if(v && v.constructor && v instanceof StructBinder.StructType){
|
||||
v = v.pointer;
|
||||
}
|
||||
return xPointer(v);
|
||||
};
|
||||
wasm.xWrap.argAdapter('.pointer', adapter);
|
||||
} /* ".pointer" xWrap() argument adapter */
|
||||
return (v === (v | 0) /* v is a 32-bit integer */)
|
||||
? argPointer(v)
|
||||
: toss("Invalid (object) type for StructType-type argument.");
|
||||
});
|
||||
}
|
||||
|
||||
if(1){/* Convert Arrays and certain TypedArrays to strings for
|
||||
'flexible-string'-type arguments */
|
||||
@ -605,19 +610,6 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
};
|
||||
}/*wasm.pstack filler*/
|
||||
|
||||
/**
|
||||
Install JS<->C struct bindings for the non-opaque struct types we
|
||||
need... */
|
||||
sqlite3.StructBinder = self.Jaccwabyt({
|
||||
heap: 0 ? wasm.memory : wasm.heap8u,
|
||||
alloc: wasm.alloc,
|
||||
dealloc: wasm.dealloc,
|
||||
functionTable: wasm.functionTable,
|
||||
bigIntEnabled: wasm.bigIntEnabled,
|
||||
memberPrefix: '$'
|
||||
});
|
||||
delete self.Jaccwabyt;
|
||||
|
||||
{/* Import C-level constants and structs... */
|
||||
const cJson = wasm.xCall('sqlite3_wasm_enum_json');
|
||||
if(!cJson){
|
||||
|
@ -371,16 +371,16 @@ self.WhWasmUtilInstaller = function(target){
|
||||
/**
|
||||
Creates a WASM function which wraps the given JS function and
|
||||
returns the JS binding of that WASM function. The signature
|
||||
argument must be the Jaccwabyt-format or Emscripten
|
||||
string must be the Jaccwabyt-format or Emscripten
|
||||
addFunction()-format function signature string. In short: in may
|
||||
have one of the following formats:
|
||||
|
||||
- Emscripten: `x...`, where the first x is a letter representing
|
||||
- Emscripten: `"x..."`, where the first x is a letter representing
|
||||
the result type and subsequent letters represent the argument
|
||||
types. Functions with no arguments have only a single
|
||||
letter. See below.
|
||||
|
||||
- Jaccwabyt: `x(...)` where `x` is the letter representing the
|
||||
- Jaccwabyt: `"x(...)"` where `x` is the letter representing the
|
||||
result type and letters in the parens (if any) represent the
|
||||
argument types. Functions with no arguments use `x()`. See
|
||||
below.
|
||||
@ -451,9 +451,9 @@ self.WhWasmUtilInstaller = function(target){
|
||||
// is not yet documented on MDN.
|
||||
sigToWasm: function(sig){
|
||||
const rc = {parameters:[], results: []};
|
||||
if('v'!==sig[0]) rc.results.push(f._.letterType(sig[0]));
|
||||
if('v'!==sig[0]) rc.results.push(f.sigTypes(sig[0]));
|
||||
for(const x of f._.sigParams(sig)){
|
||||
rc.parameters.push(f._.letterType(x));
|
||||
rc.parameters.push(f._.typeCodes(x));
|
||||
}
|
||||
return rc;
|
||||
},************/
|
||||
|
@ -25,6 +25,13 @@
|
||||
access to the sqlite3 JS/WASM bits, so any bits which it needs (most
|
||||
notably SQLITE_xxx integer codes) have to be imported into it via an
|
||||
initialization process.
|
||||
|
||||
Potential TODOs:
|
||||
|
||||
- When idle for "a long time", close the sync access handle in order
|
||||
to release the lock, then re-open it on demand. Similarly, delay
|
||||
fetching of the sync access handle until we need it. The intent
|
||||
would be to help multi-tab access to a db avoid locking issues.
|
||||
*/
|
||||
'use strict';
|
||||
const toss = function(...args){throw new Error(args.join(' '))};
|
||||
@ -132,6 +139,17 @@ const getDirForFilename = async function f(absFilename, createDirs = false){
|
||||
return [dh, filename];
|
||||
};
|
||||
|
||||
/**
|
||||
Returns the sync access handle associated with the given file
|
||||
handle object (which must be a valid handle object), lazily opening
|
||||
it if needed.
|
||||
*/
|
||||
const getSyncHandle = async (f)=>(
|
||||
f.accessHandle || (
|
||||
f.accessHandle =
|
||||
await f.fileHandle.createSyncAccessHandle()
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
Stores the given value at state.sabOPView[state.opIds.rc] and then
|
||||
@ -294,7 +312,7 @@ const vfsAsyncImpls = {
|
||||
let sz;
|
||||
wTimeStart('xFileSize');
|
||||
try{
|
||||
sz = await fh.accessHandle.getSize();
|
||||
sz = await (await getSyncHandle(fh)).getSize();
|
||||
state.s11n.serialize(Number(sz));
|
||||
sz = 0;
|
||||
}catch(e){
|
||||
@ -322,23 +340,24 @@ const vfsAsyncImpls = {
|
||||
return;
|
||||
}
|
||||
const hFile = await hDir.getFileHandle(filenamePart, {create});
|
||||
const fobj = Object.create(null);
|
||||
/**
|
||||
wa-sqlite, at this point, grabs a SyncAccessHandle and
|
||||
assigns it to the accessHandle prop of the file state
|
||||
object, but only for certain cases and it's unclear why it
|
||||
places that limitation on it.
|
||||
*/
|
||||
fobj.accessHandle = await hFile.createSyncAccessHandle();
|
||||
wTimeEnd();
|
||||
const fobj = Object.assign(Object.create(null),{
|
||||
filenameAbs: filename,
|
||||
filenamePart: filenamePart,
|
||||
dirHandle: hDir,
|
||||
fileHandle: hFile,
|
||||
sabView: state.sabFileBufView,
|
||||
readOnly: create
|
||||
? false : (state.sq3Codes.SQLITE_OPEN_READONLY & flags),
|
||||
deleteOnClose: deleteOnClose
|
||||
});
|
||||
__openFiles[fid] = fobj;
|
||||
fobj.filenameAbs = filename;
|
||||
fobj.filenamePart = filenamePart;
|
||||
fobj.dirHandle = hDir;
|
||||
fobj.fileHandle = hFile;
|
||||
fobj.sabView = state.sabFileBufView;
|
||||
fobj.readOnly = create ? false : (state.sq3Codes.SQLITE_OPEN_READONLY & flags);
|
||||
fobj.deleteOnClose = deleteOnClose;
|
||||
storeAndNotify(opName, 0);
|
||||
}catch(e){
|
||||
wTimeEnd();
|
||||
@ -354,7 +373,7 @@ const vfsAsyncImpls = {
|
||||
try{
|
||||
const fh = __openFiles[fid];
|
||||
wTimeStart('xRead');
|
||||
const nRead = fh.accessHandle.read(
|
||||
const nRead = (await getSyncHandle(fh)).read(
|
||||
fh.sabView.subarray(0, n),
|
||||
{at: Number(offset)}
|
||||
);
|
||||
@ -395,7 +414,7 @@ const vfsAsyncImpls = {
|
||||
wTimeStart('xTruncate');
|
||||
try{
|
||||
affirmNotRO('xTruncate', fh);
|
||||
await fh.accessHandle.truncate(size);
|
||||
await (await getSyncHandle(fh)).truncate(size);
|
||||
}catch(e){
|
||||
error("xTruncate():",e,fh);
|
||||
state.s11n.storeException(2,e);
|
||||
@ -413,8 +432,9 @@ const vfsAsyncImpls = {
|
||||
const fh = __openFiles[fid];
|
||||
affirmNotRO('xWrite', fh);
|
||||
rc = (
|
||||
n === fh.accessHandle.write(fh.sabView.subarray(0, n),
|
||||
{at: Number(offset)})
|
||||
n === (await getSyncHandle(fh))
|
||||
.write(fh.sabView.subarray(0, n),
|
||||
{at: Number(offset)})
|
||||
) ? 0 : state.sq3Codes.SQLITE_IOERR_WRITE;
|
||||
}catch(e){
|
||||
error("xWrite():",e,fh);
|
||||
|
Reference in New Issue
Block a user