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

Correct opfs-sahpool VFS after the pebkac involving the previous speedtest1 runs. Make that VFS explicitly opt-in to avoid certain unfortunate locking situations.

FossilOrigin-Name: 41bf1fe31f2f3d0daa2bac25dc57262a4b90f22fed6fa97e4e92467c32ae02dc
This commit is contained in:
stephan
2023-07-15 19:08:58 +00:00
parent eadabc6513
commit 38d1db9b79
5 changed files with 698 additions and 620 deletions

View File

@ -53,16 +53,43 @@
*/ */
'use strict'; 'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const installOpfsVfs = async function(sqlite3){ const toss = sqlite3.util.toss;
let vfsRegisterResult = undefined;
/**
installOpfsSAHPoolVfs() asynchronously initializes the
OPFS SyncAccessHandle Pool VFS. It returns a Promise
which either resolves to the sqlite3 object or rejects
with an Error value.
Initialization of this VFS is not automatic because its
registration requires that it lock all resources it
will potentially use, even if client code does not want
to use them. That, in turn, can lead to locking errors
when, for example, one page in a given origin has loaded
this VFS but does not use it, then another page in that
origin tries to use the VFS. If the VFS were automatically
registered, the second page would fail to load the VFS
due to OPFS locking errors.
On calls after the first this function immediately returns a
resolved or rejected Promise. If called while the first call is
still pending resolution, a rejected promise with a descriptive
error is returned.
*/
sqlite3.installOpfsSAHPoolVfs = async function(){
if(sqlite3===vfsRegisterResult) return Promise.resolve(sqlite3);
else if(undefined!==vfsRegisterResult){
return Promise.reject(vfsRegisterResult);
}
if(!globalThis.FileSystemHandle || if(!globalThis.FileSystemHandle ||
!globalThis.FileSystemDirectoryHandle || !globalThis.FileSystemDirectoryHandle ||
!globalThis.FileSystemFileHandle || !globalThis.FileSystemFileHandle ||
!globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle ||
!navigator?.storage?.getDirectory){ !navigator?.storage?.getDirectory){
return Promise.reject(new Error("Missing required OPFS APIs.")); return Promise.reject(vfsRegisterResult = new Error("Missing required OPFS APIs."));
} }
return new Promise(async function(promiseResolve, promiseReject_){ vfsRegisterResult = new Error("VFS initialization still underway.");
const verbosity = 2; const verbosity = 2 /*3+ == everything*/;
const loggers = [ const loggers = [
sqlite3.config.error, sqlite3.config.error,
sqlite3.config.warn, sqlite3.config.warn,
@ -74,17 +101,19 @@ const installOpfsVfs = async function(sqlite3){
const log = (...args)=>logImpl(2, ...args); const log = (...args)=>logImpl(2, ...args);
const warn = (...args)=>logImpl(1, ...args); const warn = (...args)=>logImpl(1, ...args);
const error = (...args)=>logImpl(0, ...args); const error = (...args)=>logImpl(0, ...args);
const toss = sqlite3.util.toss;
const capi = sqlite3.capi; const capi = sqlite3.capi;
const wasm = sqlite3.wasm; const wasm = sqlite3.wasm;
const opfsIoMethods = new capi.sqlite3_io_methods(); const opfsIoMethods = new capi.sqlite3_io_methods();
const opfsVfs = new capi.sqlite3_vfs() const opfsVfs = new capi.sqlite3_vfs()
.addOnDispose(()=>opfsIoMethods.dispose()); .addOnDispose(()=>opfsIoMethods.dispose());
const promiseReject = (err)=>{ const promiseReject = (err)=>{
opfsVfs.dispose(); error("rejecting promise:",err);
return promiseReject_(err); //opfsVfs.dispose();
vfsRegisterResult = err;
return Promise.reject(err);
}; };
const promiseResolve =
()=>Promise.resolve(vfsRegisterResult = sqlite3);
// Config opts for the VFS... // Config opts for the VFS...
const SECTOR_SIZE = 4096; const SECTOR_SIZE = 4096;
const HEADER_MAX_PATH_SIZE = 512; const HEADER_MAX_PATH_SIZE = 512;
@ -113,6 +142,7 @@ const installOpfsVfs = async function(sqlite3){
? new capi.sqlite3_vfs(pDVfs) ? new capi.sqlite3_vfs(pDVfs)
: null /* dVfs will be null when sqlite3 is built with : null /* dVfs will be null when sqlite3 is built with
SQLITE_OS_OTHER. */; SQLITE_OS_OTHER. */;
opfsIoMethods.$iVersion = 1;
opfsVfs.$iVersion = 2/*yes, two*/; opfsVfs.$iVersion = 2/*yes, two*/;
opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
opfsVfs.$mxPathname = HEADER_MAX_PATH_SIZE; opfsVfs.$mxPathname = HEADER_MAX_PATH_SIZE;
@ -358,13 +388,14 @@ const installOpfsVfs = async function(sqlite3){
(or no) value to clear it. (or no) value to clear it.
*/ */
storeErr: function(e){ storeErr: function(e){
if(e) error(e);
return this.$error = e; return this.$error = e;
}, },
/** /**
Pops this object's Error object and returns Pops this object's Error object and returns
it (a falsy value if no error is set). it (a falsy value if no error is set).
*/ */
popErr: function(e){ popErr: function(){
const rc = this.$error; const rc = this.$error;
this.$error = undefined; this.$error = undefined;
return rc; return rc;
@ -377,7 +408,9 @@ const installOpfsVfs = async function(sqlite3){
*/ */
const ioSyncWrappers = { const ioSyncWrappers = {
xCheckReservedLock: function(pFile,pOut){ xCheckReservedLock: function(pFile,pOut){
log('xCheckReservedLock');
SAHPool.storeErr(); SAHPool.storeErr();
wasm.poke32(pOut, 1);
return 0; return 0;
}, },
xClose: function(pFile){ xClose: function(pFile){
@ -385,15 +418,15 @@ const installOpfsVfs = async function(sqlite3){
const file = SAHPool.mapIdToFile.get(pFile); const file = SAHPool.mapIdToFile.get(pFile);
if(file) { if(file) {
try{ try{
log(`xClose ${file.path}`); log(`xClose ${file}`);
if(file.sq3File) file.sq3File.dispose();
file.sah.flush(); file.sah.flush();
SAHPool.mapIdToFile.delete(pFIle); SAHPool.mapIdToFile.delete(pFile);
if(file.flags & capi.SQLITE_OPEN_DELETEONCLOSE){ if(file.flags & capi.SQLITE_OPEN_DELETEONCLOSE){
SAHPool.deletePath(file.path); SAHPool.deletePath(file.path);
} }
}catch(e){ }catch(e){
SAHPool.storeErr(e); SAHPool.storeErr(e);
error("xClose() failed:",e.message);
return capi.SQLITE_IOERR; return capi.SQLITE_IOERR;
} }
} }
@ -406,24 +439,29 @@ const installOpfsVfs = async function(sqlite3){
return capi.SQLITE_NOTFOUND; return capi.SQLITE_NOTFOUND;
}, },
xFileSize: function(pFile,pSz64){ xFileSize: function(pFile,pSz64){
const file = SAHPool.mapIdToFile(pFile); log(`xFileSize`);
const file = SAHPool.mapIdToFile.get(pFile);
const size = file.sah.getSize() - HEADER_OFFSET_DATA; const size = file.sah.getSize() - HEADER_OFFSET_DATA;
//log(`xFileSize ${file.path} ${size}`); //log(`xFileSize ${file.path} ${size}`);
wasm.poke64(pSz64, BigInt(size)); wasm.poke64(pSz64, BigInt(size));
return 0; return 0;
}, },
xLock: function(pFile,lockType){ xLock: function(pFile,lockType){
log(`xLock ${lockType}`);
SAHPool.storeErr(); SAHPool.storeErr();
let rc = capi.SQLITE_IOERR; const file = SAHPool.mapIdToFile.get(pFile);
return rc; file.lockType = lockType;
return 0;
}, },
xRead: function(pFile,pDest,n,offset64){ xRead: function(pFile,pDest,n,offset64){
log(`xRead ${n}@${offset64}`);
SAHPool.storeErr(); SAHPool.storeErr();
const file = SAHPool.mapIdToFile.get(pFile); const file = SAHPool.mapIdToFile.get(pFile);
log(`xRead ${file.path} ${n} ${offset64}`); log(`xRead ${file.path} ${n} ${offset64}`);
try { try {
const nRead = file.sah.read( const nRead = file.sah.read(
pDest, {at: HEADER_OFFSET_DATA + offset64} wasm.heap8u().subarray(pDest, pDest+n),
{at: HEADER_OFFSET_DATA + Number(offset64)}
); );
if(nRead < n){ if(nRead < n){
wasm.heap8u().fill(0, pDest + nRead, pDest + n); wasm.heap8u().fill(0, pDest + nRead, pDest + n);
@ -436,10 +474,11 @@ const installOpfsVfs = async function(sqlite3){
return capi.SQLITE_IOERR; return capi.SQLITE_IOERR;
} }
}, },
xSectorSize: function(pFile){ /*xSectorSize: function(pFile){
return SECTOR_SIZE; return SECTOR_SIZE;
}, },*/
xSync: function(pFile,flags){ xSync: function(pFile,flags){
log(`xSync ${flags}`);
SAHPool.storeErr(); SAHPool.storeErr();
const file = SAHPool.mapIdToFile.get(pFile); const file = SAHPool.mapIdToFile.get(pFile);
//log(`xSync ${file.path} ${flags}`); //log(`xSync ${file.path} ${flags}`);
@ -453,6 +492,7 @@ const installOpfsVfs = async function(sqlite3){
} }
}, },
xTruncate: function(pFile,sz64){ xTruncate: function(pFile,sz64){
log(`xTruncate ${sz64}`);
SAHPool.storeErr(); SAHPool.storeErr();
const file = SAHPool.mapIdToFile.get(pFile); const file = SAHPool.mapIdToFile.get(pFile);
//log(`xTruncate ${file.path} ${iSize}`); //log(`xTruncate ${file.path} ${iSize}`);
@ -465,16 +505,20 @@ const installOpfsVfs = async function(sqlite3){
return capi.SQLITE_IOERR; return capi.SQLITE_IOERR;
} }
}, },
/**xUnlock: function(pFile,lockType){ xUnlock: function(pFile,lockType){
return capi.SQLITE_IOERR; log('xUnlock');
},*/ const file = SAHPool.mapIdToFile.get(pFile);
file.lockType = lockType;
return 0;
},
xWrite: function(pFile,pSrc,n,offset64){ xWrite: function(pFile,pSrc,n,offset64){
SAHPool.storeErr(); SAHPool.storeErr();
const file = SAHPool.mapIdToFile(pFile); const file = SAHPool.mapIdToFile.get(pFile);
//log(`xWrite ${file.path} ${n} ${offset64}`); log(`xWrite ${file.path} ${n} ${offset64}`);
try{ try{
const nBytes = file.sah.write( const nBytes = file.sah.write(
pSrc, { at: HEADER_OFFSET_DATA + Number(offset64) } wasm.heap8u().subarray(pSrc, pSrc+n),
{ at: HEADER_OFFSET_DATA + Number(offset64) }
); );
return nBytes === n ? 0 : capi.SQLITE_IOERR; return nBytes === n ? 0 : capi.SQLITE_IOERR;
}catch(e){ }catch(e){
@ -491,6 +535,7 @@ const installOpfsVfs = async function(sqlite3){
*/ */
const vfsSyncWrappers = { const vfsSyncWrappers = {
xAccess: function(pVfs,zName,flags,pOut){ xAccess: function(pVfs,zName,flags,pOut){
log(`xAccess ${wasm.cstrToJs(zName)}`);
SAHPool.storeErr(); SAHPool.storeErr();
try{ try{
const name = this.getPath(zName); const name = this.getPath(zName);
@ -511,6 +556,7 @@ const installOpfsVfs = async function(sqlite3){
return 0; return 0;
}, },
xDelete: function(pVfs, zName, doSyncDir){ xDelete: function(pVfs, zName, doSyncDir){
log(`xDelete ${wasm.cstrToJs(zName)}`);
SAHPool.storeErr(); SAHPool.storeErr();
try{ try{
SAHPool.deletePath(SAHPool.getPath(zName)); SAHPool.deletePath(SAHPool.getPath(zName));
@ -522,10 +568,12 @@ const installOpfsVfs = async function(sqlite3){
} }
}, },
xFullPathname: function(pVfs,zName,nOut,pOut){ xFullPathname: function(pVfs,zName,nOut,pOut){
log(`xFullPathname ${wasm.cstrToJs(zName)}`);
const i = wasm.cstrncpy(pOut, zName, nOut); const i = wasm.cstrncpy(pOut, zName, nOut);
return i<nOut ? 0 : capi.SQLITE_CANTOPEN; return i<nOut ? 0 : capi.SQLITE_CANTOPEN;
}, },
xGetLastError: function(pVfs,nOut,pOut){ xGetLastError: function(pVfs,nOut,pOut){
log(`xGetLastError ${nOut}`);
const e = SAHPool.popErr(); const e = SAHPool.popErr();
if(e){ if(e){
const scope = wasm.scopedAllocPush(); const scope = wasm.scopedAllocPush();
@ -543,31 +591,35 @@ const installOpfsVfs = async function(sqlite3){
}, },
//xSleep is optionally defined below //xSleep is optionally defined below
xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){ xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){
log(`xOpen ${wasm.cstrToJs(zName)} ${flags}`);
try{ try{
// First try to open a path that already exists in the file system. // First try to open a path that already exists in the file system.
const path = (zName && wasm.peek8(zName)) const path = (zName && wasm.peek8(zName))
? SAHPool.getPath(name) ? SAHPool.getPath(zName)
: getRandomName(); : getRandomName();
let ah = SAHPool.mapPathToSAH.get(path); let sah = SAHPool.mapPathToSAH.get(path);
if(!ah && (flags & capi.SQLITE_OPEN_CREATE)) { if(!sah && (flags & capi.SQLITE_OPEN_CREATE)) {
// File not found so try to create it. // File not found so try to create it.
if(SAHPool.getFileCount() < SAHPool.getCapacity()) { if(SAHPool.getFileCount() < SAHPool.getCapacity()) {
// Choose an unassociated OPFS file from the pool. // Choose an unassociated OPFS file from the pool.
ah = SAHPool.availableSAH.keys()[0]; [sah] = SAHPool.availableSAH.keys();
SAHPool.setAssociatedPath(ah, path, flags); SAHPool.setAssociatedPath(sah, path, flags);
}else{ }else{
// File pool is full. // File pool is full.
toss('SAH pool is full. Cannot create file',path); toss('SAH pool is full. Cannot create file',path);
} }
} }
if(!ah){ if(!sah){
toss('file not found:',path); toss('file not found:',path);
} }
// Subsequent methods are only passed the file pointer, so // Subsequent methods are only passed the file pointer, so
// map the relevant info we need to that pointer. // map the relevant info we need to that pointer.
const file = { path, flags, ah }; const file = {path, flags, sah};
SAHPool.mapIdToFile.set(pFile, file); SAHPool.mapIdToFile.set(pFile, file);
wasm.poke32(pOutFlags, flags); wasm.poke32(pOutFlags, flags);
file.sq3File = new capi.sqlite3_file(pFile);
file.sq3File.$pMethods = opfsIoMethods.pointer;
file.lockType = capi.SQLITE_LOCK_NONE;
return 0; return 0;
}catch(e){ }catch(e){
SAHPool.storeErr(e); SAHPool.storeErr(e);
@ -592,17 +644,16 @@ const installOpfsVfs = async function(sqlite3){
}; };
} }
if(!opfsVfs.$xSleep){ if(!opfsVfs.$xSleep){
vfsSyncWrappers.xSleep = function(pVfs,ms){ vfsSyncWrappers.xSleep = (pVfs,ms)=>0;
return 0;
};
} }
/** /**
Ensure that the client has a "fully-sync" SAH impl, Ensure that the client has a "fully-sync" SAH impl,
else reject the promise. Returns true on success, else reject the promise. Returns true on success,
else false. else a value intended to be returned via the containing
function's Promise result.
*/ */
if(!(async ()=>{ const apiVersionCheck = await (async ()=>{
try { try {
const dh = await navigator.storage.getDirectory(); const dh = await navigator.storage.getDirectory();
const fn = '.opfs-sahpool-sync-check-'+getRandomName(); const fn = '.opfs-sahpool-sync-check-'+getRandomName();
@ -617,14 +668,13 @@ const installOpfsVfs = async function(sqlite3){
} }
return true; return true;
}catch(e){ }catch(e){
promiseReject(e); return e;
return false;
} }
})()){ })();
return; if(true!==apiVersionCheck){
return promiseReject(apiVersionCheck);
} }
return SAHPool.isReady = SAHPool.reset().then(async ()=>{
SAHPool.isReady = SAHPool.reset().then(async ()=>{
if(SAHPool.$error){ if(SAHPool.$error){
throw SAHPool.$error; throw SAHPool.$error;
} }
@ -634,9 +684,11 @@ const installOpfsVfs = async function(sqlite3){
//log("vfs list:",capi.sqlite3_js_vfs_list()); //log("vfs list:",capi.sqlite3_js_vfs_list());
sqlite3.vfs.installVfs({ sqlite3.vfs.installVfs({
io: {struct: opfsIoMethods, methods: ioSyncWrappers}, io: {struct: opfsIoMethods, methods: ioSyncWrappers},
vfs: {struct: opfsVfs, methods: vfsSyncWrappers} vfs: {struct: opfsVfs, methods: vfsSyncWrappers},
applyArgcCheck: true
}); });
//log("vfs list:",capi.sqlite3_js_vfs_list()); log("opfsVfs",opfsVfs,"opfsIoMethods",opfsIoMethods);
log("vfs list:",capi.sqlite3_js_vfs_list());
if(sqlite3.oo1){ if(sqlite3.oo1){
const OpfsSAHPoolDb = function(...args){ const OpfsSAHPoolDb = function(...args){
const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args); const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args);
@ -683,15 +735,7 @@ const installOpfsVfs = async function(sqlite3){
); );
}/*extend sqlite3.oo1*/ }/*extend sqlite3.oo1*/
log("VFS initialized."); log("VFS initialized.");
promiseResolve(sqlite3); return promiseResolve();
}).catch(promiseReject); }).catch(promiseReject);
})/*return Promise*/; }/*installOpfsSAHPoolVfs()*/;
}/*installOpfsVfs()*/;
globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
return installOpfsVfs(sqlite3).catch((e)=>{
sqlite3.config.warn("Ignoring inability to install opfs-sahpool sqlite3_vfs:",
e.message, e);
});
}/*sqlite3ApiBootstrap.initializersAsync*/);
}/*sqlite3ApiBootstrap.initializers*/); }/*sqlite3ApiBootstrap.initializers*/);

View File

@ -236,6 +236,7 @@ const installOpfsVfs = function callee(options){
? new sqlite3_vfs(pDVfs) ? new sqlite3_vfs(pDVfs)
: null /* dVfs will be null when sqlite3 is built with : null /* dVfs will be null when sqlite3 is built with
SQLITE_OS_OTHER. */; SQLITE_OS_OTHER. */;
opfsIoMethods.$iVersion = 1;
opfsVfs.$iVersion = 2/*yes, two*/; opfsVfs.$iVersion = 2/*yes, two*/;
opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof; opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
opfsVfs.$mxPathname = 1024/*sure, why not?*/; opfsVfs.$mxPathname = 1024/*sure, why not?*/;

View File

@ -71,20 +71,48 @@
self.onmessage = function(msg){ self.onmessage = function(msg){
msg = msg.data; msg = msg.data;
switch(msg.type){ switch(msg.type){
case 'run': runSpeedtest(msg.data || []); break; case 'run':
try {
runSpeedtest(msg.data || []);
}catch(e){
mPost('error',e);
}
break;
default: default:
logErr("Unhandled worker message type:",msg.type); logErr("Unhandled worker message type:",msg.type);
break; break;
} }
}; };
const sahpSanityChecks = function(sqlite3){
log("Attempting OpfsSAHPoolDb sanity checks...");
const db = new sqlite3.oo1.OpfsSAHPoolDb('opfs-sahpoool.db');
const fn = db.filename;
db.exec([
'create table t(a);',
'insert into t(a) values(1),(2),(3);'
]);
db.close();
sqlite3.wasm.sqlite3_wasm_vfs_unlink(sqlite3_vfs_find("opfs-sahpool"), fn);
log("SAH sanity checks done.");
};
const EmscriptenModule = { const EmscriptenModule = {
print: log, print: log,
printErr: logErr, printErr: logErr,
setStatus: (text)=>mPost('load-status',text) setStatus: (text)=>mPost('load-status',text)
}; };
self.sqlite3InitModule(EmscriptenModule).then((sqlite3)=>{ log("Initializing speedtest1 module...");
const S = sqlite3; self.sqlite3InitModule(EmscriptenModule).then(async (sqlite3)=>{
const S = globalThis.S = sqlite3;
log("Loaded speedtest1 module. Setting up...");
if(S.installOpfsSAHPoolVfs){
await S.installOpfsSAHPoolVfs().then(()=>{
log("Loaded SAHPool.");
}).catch(e=>{
logErr("Error setting up SAHPool:",e.message);
});
}
App.vfsUnlink = function(pDb, fname){ App.vfsUnlink = function(pDb, fname){
const pVfs = S.wasm.sqlite3_wasm_db_vfs(pDb, 0); const pVfs = S.wasm.sqlite3_wasm_db_vfs(pDb, 0);
if(pVfs) S.wasm.sqlite3_wasm_vfs_unlink(pVfs, fname||0); if(pVfs) S.wasm.sqlite3_wasm_vfs_unlink(pVfs, fname||0);
@ -95,5 +123,10 @@
//else log("Using transient storage."); //else log("Using transient storage.");
mPost('ready',true); mPost('ready',true);
log("Registered VFSes:", ...S.capi.sqlite3_js_vfs_list()); log("Registered VFSes:", ...S.capi.sqlite3_js_vfs_list());
if(0 && S.installOpfsSAHPoolVfs){
sahpSanityChecks(S);
}
}).catch(e=>{
logErr(e);
}); });
})(); })();

View File

@ -1,5 +1,5 @@
C speedtest1\sJS:\sonly\sadd\s--memdb\sflag\sby\sdefault\sif\sno\s--vfs\sis\sprovided. C Correct\sopfs-sahpool\sVFS\safter\sthe\spebkac\sinvolving\sthe\sprevious\sspeedtest1\sruns.\sMake\sthat\sVFS\sexplicitly\sopt-in\sto\savoid\scertain\sunfortunate\slocking\ssituations.
D 2023-07-15T16:30:46.383 D 2023-07-15T19:08:58.138
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
@ -502,8 +502,8 @@ F ext/wasm/api/sqlite3-api-worker1.js 9f32af64df1a031071912eea7a201557fe39b17386
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 961bbc3ccc1fa4e91d6519a96e8811ad7ae60173bd969fee7775dacb6eee1da2 F ext/wasm/api/sqlite3-opfs-async-proxy.js 961bbc3ccc1fa4e91d6519a96e8811ad7ae60173bd969fee7775dacb6eee1da2
F ext/wasm/api/sqlite3-v-helper.js e5c202a9ecde9ef818536d3f5faf26c03a1a9f5192b1ddea8bdabf30d75ef487 F ext/wasm/api/sqlite3-v-helper.js e5c202a9ecde9ef818536d3f5faf26c03a1a9f5192b1ddea8bdabf30d75ef487
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.js ad6ec4e87f47152a871a23bf90b64709094bf04e8ee76671fc6cedd1ce45086d F ext/wasm/api/sqlite3-vfs-opfs-sahpool.js 83388ead4bfc489bee008298ab51948ccb75227795ce8d1634f2eec8e02548f1
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 891f3a18d9ac9b0422b32fd975319dfcd0af5a8ca392f0cce850524e51b49c87 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js a5c3195203e6085d7aa89fae4b84cf3f3eec4ff4f928c6d0e5d3ef8b14cbc1c0
F ext/wasm/api/sqlite3-wasm.c 12a096d8e58a0af0589142bae5a3c27a0c7e19846755a1a37d2c206352fbedda F ext/wasm/api/sqlite3-wasm.c 12a096d8e58a0af0589142bae5a3c27a0c7e19846755a1a37d2c206352fbedda
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f
F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75 F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
@ -540,7 +540,7 @@ F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd84223150
F ext/wasm/speedtest1-wasmfs.html 0e9d335a9b5b5fafe6e1bc8dc0f0ca7e22e6eb916682a2d7c36218bb7d67379d F ext/wasm/speedtest1-wasmfs.html 0e9d335a9b5b5fafe6e1bc8dc0f0ca7e22e6eb916682a2d7c36218bb7d67379d
F ext/wasm/speedtest1-wasmfs.mjs ac5cadbf4ffe69e9eaac8b45e8523f030521e02bb67d654c6eb5236d9c456cbe F ext/wasm/speedtest1-wasmfs.mjs ac5cadbf4ffe69e9eaac8b45e8523f030521e02bb67d654c6eb5236d9c456cbe
F ext/wasm/speedtest1-worker.html bbcf1e7fd79541040c1a7ca2ebf1cb7793ddaf9900d6bde1784148f11b807c34 F ext/wasm/speedtest1-worker.html bbcf1e7fd79541040c1a7ca2ebf1cb7793ddaf9900d6bde1784148f11b807c34
F ext/wasm/speedtest1-worker.js 13b57c4a41729678a1194014afec2bd5b94435dcfc8d1039dfa9a533ac819ee1 F ext/wasm/speedtest1-worker.js 4de92e4e6718b8bd1cdecb75af62739d1115fa66656a700b0b51822c848948f5
F ext/wasm/speedtest1.html ff048b4a623aa192e83e143e48f1ce2a899846dd42c023fdedc8772b6e3f07da F ext/wasm/speedtest1.html ff048b4a623aa192e83e143e48f1ce2a899846dd42c023fdedc8772b6e3f07da
F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x
F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0 F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0
@ -2044,8 +2044,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 fff68e9f25a57045e9d636b02ffa073cf1b984b2587d4fce10f6e35c9988469c P 676ffe6280c1ce787b04d0cdb4a0664229c6125c601af4b18d1bfa125aac3675
R 30945b34df9134e0f98668ba08cfc13f R bca4913f68935c8abed9e461aac753fd
U stephan U stephan
Z 32f9fd4e9e8f1a70cce170b39e2a4458 Z 2546a1c8fd9c0ca0c4fd392086704b47
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
676ffe6280c1ce787b04d0cdb4a0664229c6125c601af4b18d1bfa125aac3675 41bf1fe31f2f3d0daa2bac25dc57262a4b90f22fed6fa97e4e92467c32ae02dc