aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/wasm/GNUmakefile2
-rw-r--r--ext/wasm/batch-runner-sahpool.html86
-rw-r--r--ext/wasm/batch-runner-sahpool.js341
-rw-r--r--ext/wasm/batch-runner.js24
-rw-r--r--ext/wasm/demo-123.js15
-rw-r--r--ext/wasm/speedtest1-worker.html2
-rw-r--r--manifest22
-rw-r--r--manifest.uuid2
8 files changed, 470 insertions, 24 deletions
diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile
index c0cab212d..3ef478612 100644
--- a/ext/wasm/GNUmakefile
+++ b/ext/wasm/GNUmakefile
@@ -854,7 +854,7 @@ dir.sql := sql
speedtest1 := ../../speedtest1
speedtest1.c := ../../test/speedtest1.c
speedtest1.sql := $(dir.sql)/speedtest1.sql
-speedtest1.cliflags := --size 25 --big-transactions
+speedtest1.cliflags := --size 10 --big-transactions
$(speedtest1):
$(MAKE) -C ../.. speedtest1
$(speedtest1.sql): $(speedtest1) $(MAKEFILE)
diff --git a/ext/wasm/batch-runner-sahpool.html b/ext/wasm/batch-runner-sahpool.html
new file mode 100644
index 000000000..ad7e7b540
--- /dev/null
+++ b/ext/wasm/batch-runner-sahpool.html
@@ -0,0 +1,86 @@
+<!doctype html>
+<html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
+ <link rel="stylesheet" href="common/testing.css"/>
+ <title>sqlite3-api batch SQL runner for the SAHPool VFS</title>
+ </head>
+ <body>
+ <header id='titlebar'><span>sqlite3-api batch SQL runner for the SAHPool VFS</span></header>
+ <div>
+ <span class='input-wrapper'>
+ <input type='checkbox' class='disable-during-eval' id='cb-reverse-log-order' checked></input>
+ <label for='cb-reverse-log-order' id='lbl-reverse-log-order'>Reverse log order</label>
+ </span>
+ </div>
+ <div id='test-output' class='reverse'></div>
+ <script>
+ (function(){
+ const E = (sel)=>document.querySelector(sel);
+
+ const eOut = E('#test-output');
+ const log2 = function(cssClass,...args){
+ let ln;
+ if(1 || cssClass){
+ ln = document.createElement('div');
+ if(cssClass) ln.classList.add(cssClass);
+ ln.append(document.createTextNode(args.join(' ')));
+ }else{
+ // This doesn't work with the "reverse order" option!
+ ln = document.createTextNode(args.join(' ')+'\n');
+ }
+ eOut.append(ln);
+ };
+ const log = (...args)=>{
+ //console.log(...args);
+ log2('', ...args);
+ };
+ const logErr = function(...args){
+ console.error(...args);
+ log2('error', ...args);
+ };
+ const logWarn = function(...args){
+ console.warn(...args);
+ log2('warning', ...args);
+ };
+
+ const cbReverseLog = E('#cb-reverse-log-order');
+ const lblReverseLog = E('#lbl-reverse-log-order');
+ if(cbReverseLog.checked){
+ lblReverseLog.classList.add('warning');
+ eOut.classList.add('reverse');
+ }
+ cbReverseLog.addEventListener('change', function(){
+ if(this.checked){
+ eOut.classList.add('reverse');
+ lblReverseLog.classList.add('warning');
+ }else{
+ eOut.classList.remove('reverse');
+ lblReverseLog.classList.remove('warning');
+ }
+ }, false);
+
+ const w = new Worker('batch-runner-sahpool.js?sqlite3.dir=jswasm');
+ w.onmessage = function(msg){
+ msg = msg.data;
+ switch(msg.type){
+ case 'stdout': log(...msg.data); break;
+ case 'warn': logWarn(...msg.data); break;
+ case 'error': logErr(...msg.data); break;
+ default:
+ logErr("Unhandled worker message type:",msg);
+ break;
+ }
+ };
+ })();
+ </script>
+ <style>
+ #test-output {
+ white-space: break-spaces;
+ overflow: auto;
+ }
+ </style>
+ </body>
+</html>
diff --git a/ext/wasm/batch-runner-sahpool.js b/ext/wasm/batch-runner-sahpool.js
new file mode 100644
index 000000000..dfa5044a9
--- /dev/null
+++ b/ext/wasm/batch-runner-sahpool.js
@@ -0,0 +1,341 @@
+/*
+ 2023-11-30
+
+ The author disclaims copyright to this source code. In place of a
+ legal notice, here is a blessing:
+
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+
+ ***********************************************************************
+
+ A basic batch SQL runner for the SAHPool VFS. This file must be run in
+ a worker thread. This is not a full-featured app, just a way to get some
+ measurements for batch execution of SQL for the OPFS SAH Pool VFS.
+*/
+'use strict';
+
+const wMsg = function(msgType,...args){
+ postMessage({
+ type: msgType,
+ data: args
+ });
+};
+const toss = function(...args){throw new Error(args.join(' '))};
+const warn = (...args)=>{ wMsg('warn',...args); };
+const error = (...args)=>{ wMsg('error',...args); };
+const log = (...args)=>{ wMsg('stdout',...args); }
+let sqlite3;
+const urlParams = new URL(globalThis.location.href).searchParams;
+const cacheSize = (()=>{
+ if(urlParams.has('cachesize')) return +urlParams.get('cachesize');
+ return 200;
+})();
+
+
+/** Throws if the given sqlite3 result code is not 0. */
+const checkSqliteRc = (dbh,rc)=>{
+ if(rc) toss("Prepare failed:",sqlite3.capi.sqlite3_errmsg(dbh));
+};
+
+const sqlToDrop = [
+ "SELECT type,name FROM sqlite_schema ",
+ "WHERE name NOT LIKE 'sqlite\\_%' escape '\\' ",
+ "AND name NOT LIKE '\\_%' escape '\\'"
+].join('');
+
+const clearDbSqlite = function(db){
+ // This would be SO much easier with the oo1 API, but we specifically want to
+ // inject metrics we can't get via that API, and we cannot reliably (OPFS)
+ // open the same DB twice to clear it using that API, so...
+ const rc = sqlite3.wasm.exports.sqlite3_wasm_db_reset(db.handle);
+ log("reset db rc =",rc,db.id, db.filename);
+};
+
+const App = {
+ db: undefined,
+ cache:Object.create(null),
+ log: log,
+ warn: warn,
+ error: error,
+ metrics: {
+ fileCount: 0,
+ runTimeMs: 0,
+ prepareTimeMs: 0,
+ stepTimeMs: 0,
+ stmtCount: 0,
+ strcpyMs: 0,
+ sqlBytes: 0
+ },
+ fileList: undefined,
+ execSql: async function(name,sql){
+ const db = this.db;
+ const banner = "========================================";
+ this.log(banner,
+ "Running",name,'('+sql.length,'bytes)');
+ const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
+ let pStmt = 0, pSqlBegin;
+ const metrics = db.metrics = Object.create(null);
+ metrics.prepTotal = metrics.stepTotal = 0;
+ metrics.stmtCount = 0;
+ metrics.malloc = 0;
+ metrics.strcpy = 0;
+ if(this.gotErr){
+ this.error("Cannot run SQL: error cleanup is pending.");
+ return;
+ }
+ // Run this async so that the UI can be updated for the above header...
+ const endRun = ()=>{
+ metrics.evalSqlEnd = performance.now();
+ metrics.evalTimeTotal = (metrics.evalSqlEnd - metrics.evalSqlStart);
+ this.log("metrics:",JSON.stringify(metrics, undefined, ' '));
+ this.log("prepare() count:",metrics.stmtCount);
+ this.log("Time in prepare_v2():",metrics.prepTotal,"ms",
+ "("+(metrics.prepTotal / metrics.stmtCount),"ms per prepare())");
+ this.log("Time in step():",metrics.stepTotal,"ms",
+ "("+(metrics.stepTotal / metrics.stmtCount),"ms per step())");
+ this.log("Total runtime:",metrics.evalTimeTotal,"ms");
+ this.log("Overhead (time - prep - step):",
+ (metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms");
+ this.log(banner,"End of",name);
+ this.metrics.prepareTimeMs += metrics.prepTotal;
+ this.metrics.stepTimeMs += metrics.stepTotal;
+ this.metrics.stmtCount += metrics.stmtCount;
+ this.metrics.strcpyMs += metrics.strcpy;
+ this.metrics.sqlBytes += sql.length;
+ };
+
+ const runner = function(resolve, reject){
+ ++this.metrics.fileCount;
+ metrics.evalSqlStart = performance.now();
+ const stack = wasm.scopedAllocPush();
+ try {
+ let t, rc;
+ let sqlByteLen = sql.byteLength;
+ const [ppStmt, pzTail] = wasm.scopedAllocPtr(2);
+ t = performance.now();
+ pSqlBegin = wasm.scopedAlloc( sqlByteLen + 1/*SQL + NUL*/) || toss("alloc(",sqlByteLen,") failed");
+ metrics.malloc = performance.now() - t;
+ metrics.byteLength = sqlByteLen;
+ let pSql = pSqlBegin;
+ const pSqlEnd = pSqlBegin + sqlByteLen;
+ t = performance.now();
+ wasm.heap8().set(sql, pSql);
+ wasm.poke(pSql + sqlByteLen, 0);
+ //log("SQL:",wasm.cstrToJs(pSql));
+ metrics.strcpy = performance.now() - t;
+ let breaker = 0;
+ while(pSql && wasm.peek8(pSql)){
+ wasm.pokePtr(ppStmt, 0);
+ wasm.pokePtr(pzTail, 0);
+ t = performance.now();
+ rc = capi.sqlite3_prepare_v2(
+ db.handle, pSql, sqlByteLen, ppStmt, pzTail
+ );
+ metrics.prepTotal += performance.now() - t;
+ checkSqliteRc(db.handle, rc);
+ pStmt = wasm.peekPtr(ppStmt);
+ pSql = wasm.peekPtr(pzTail);
+ sqlByteLen = pSqlEnd - pSql;
+ if(!pStmt) continue/*empty statement*/;
+ ++metrics.stmtCount;
+ t = performance.now();
+ rc = capi.sqlite3_step(pStmt);
+ capi.sqlite3_finalize(pStmt);
+ pStmt = 0;
+ metrics.stepTotal += performance.now() - t;
+ switch(rc){
+ case capi.SQLITE_ROW:
+ case capi.SQLITE_DONE: break;
+ default: checkSqliteRc(db.handle, rc); toss("Not reached.");
+ }
+ }
+ resolve(this);
+ }catch(e){
+ if(pStmt) capi.sqlite3_finalize(pStmt);
+ this.gotErr = e;
+ reject(e);
+ }finally{
+ capi.sqlite3_exec(db.handle,"rollback;",0,0,0);
+ wasm.scopedAllocPop(stack);
+ }
+ }.bind(this);
+ const p = new Promise(runner);
+ return p.catch(
+ (e)=>this.error("Error via execSql("+name+",...):",e.message)
+ ).finally(()=>{
+ endRun();
+ });
+ },
+
+ /**
+ Loads batch-runner.list and populates the selection list from
+ it. Returns a promise which resolves to nothing in particular
+ when it completes. Only intended to be run once at the start
+ of the app.
+ */
+ loadSqlList: async function(){
+ const infile = 'batch-runner.list';
+ this.log("Loading list of SQL files:", infile);
+ let txt;
+ try{
+ const r = await fetch(infile);
+ if(404 === r.status){
+ toss("Missing file '"+infile+"'.");
+ }
+ if(!r.ok) toss("Loading",infile,"failed:",r.statusText);
+ txt = await r.text();
+ }catch(e){
+ this.error(e.message);
+ throw e;
+ }
+ App.fileList = txt.split(/\n+/).filter(x=>!!x);
+ this.log("Loaded",infile);
+ },
+
+ /** Fetch ./fn and return its contents as a Uint8Array. */
+ fetchFile: async function(fn, cacheIt=false){
+ if(cacheIt && this.cache[fn]) return this.cache[fn];
+ this.log("Fetching",fn,"...");
+ let sql;
+ try {
+ const r = await fetch(fn);
+ if(!r.ok) toss("Fetch failed:",r.statusText);
+ sql = new Uint8Array(await r.arrayBuffer());
+ }catch(e){
+ this.error(e.message);
+ throw e;
+ }
+ this.log("Fetched",sql.length,"bytes from",fn);
+ if(cacheIt) this.cache[fn] = sql;
+ return sql;
+ }/*fetchFile()*/,
+
+ /**
+ Converts this.metrics() to a form which is suitable for easy conversion to
+ CSV. It returns an array of arrays. The first sub-array is the column names.
+ The 2nd and subsequent are the values, one per test file (only the most recent
+ metrics are kept for any given file).
+ */
+ metricsToArrays: function(){
+ const rc = [];
+ Object.keys(this.dbs).sort().forEach((k)=>{
+ const d = this.dbs[k];
+ const m = d.metrics;
+ delete m.evalSqlStart;
+ delete m.evalSqlEnd;
+ const mk = Object.keys(m).sort();
+ if(!rc.length){
+ rc.push(['db', ...mk]);
+ }
+ const row = [k.split('/').pop()/*remove dir prefix from filename*/];
+ rc.push(row);
+ row.push(...mk.map((kk)=>m[kk]));
+ });
+ return rc;
+ },
+
+ metricsToBlob: function(colSeparator='\t'){
+ const ar = [], ma = this.metricsToArrays();
+ if(!ma.length){
+ this.error("Metrics are empty. Run something.");
+ return;
+ }
+ ma.forEach(function(row){
+ ar.push(row.join(colSeparator),'\n');
+ });
+ return new Blob(ar);
+ },
+
+ /**
+ Fetch file fn and eval it as an SQL blob. This is an async
+ operation and returns a Promise which resolves to this
+ object on success.
+ */
+ evalFile: async function(fn){
+ const sql = await this.fetchFile(fn);
+ return this.execSql(fn,sql);
+ }/*evalFile()*/,
+
+ /**
+ Fetches the handle of the db associated with
+ this.e.selImpl.value, opening it if needed.
+ */
+ initDb: function(){
+ const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
+ const stack = wasm.scopedAllocPush();
+ let pDb = 0;
+ const d = Object.create(null);
+ d.filename = "/batch.db";
+ try{
+ const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
+ const ppDb = wasm.scopedAllocPtr();
+ const rc = capi.sqlite3_open_v2(d.filename, ppDb, oFlags, this.PoolUtil.vfsName);
+ pDb = wasm.peekPtr(ppDb)
+ if(rc) toss("sqlite3_open_v2() failed with code",rc);
+ capi.sqlite3_exec(pDb, "PRAGMA cache_size="+cacheSize, 0, 0, 0);
+ this.log("cache_size =",cacheSize);
+ }catch(e){
+ if(pDb) capi.sqlite3_close_v2(pDb);
+ throw e;
+ }finally{
+ wasm.scopedAllocPop(stack);
+ }
+ d.handle = pDb;
+ this.log("Opened db:",d.filename,'@',d.handle);
+ return d;
+ },
+
+ closeDb: function(){
+ if(this.db.handle){
+ this.sqlite3.capi.sqlite3_close_v2(this.db.handle);
+ this.db.handle = undefined;
+ }
+ },
+
+ run: async function(sqlite3){
+ delete this.run;
+ this.sqlite3 = sqlite3;
+ const capi = sqlite3.capi, wasm = sqlite3.wasm;
+ this.log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
+ this.log("WASM heap size =",wasm.heap8().length);
+ let timeStart;
+ sqlite3.installOpfsSAHPoolVfs({
+ clearOnInit: true, initialCapacity: 4,
+ name: 'batch-sahpool',
+ verbosity: 2
+ }).then(PoolUtil=>{
+ App.PoolUtil = PoolUtil;
+ App.db = App.initDb();
+ })
+ .then(async ()=>this.loadSqlList())
+ .then(async ()=>{
+ timeStart = performance.now();
+ for(let i = 0; i < App.fileList.length; ++i){
+ const fn = App.fileList[i];
+ await App.evalFile(fn);
+ if(App.gotErr) throw App.gotErr;
+ }
+ })
+ .then(()=>{
+ App.metrics.runTimeMs = performance.now() - timeStart;
+ App.log("total metrics:",JSON.stringify(App.metrics, undefined, ' '));
+ App.log("Reload the page to run this again.");
+ App.closeDb();
+ App.PoolUtil.removeVfs();
+ })
+ .catch(e=>this.error("ERROR:",e));
+ }/*run()*/
+}/*App*/;
+
+let sqlite3Js = 'sqlite3.js';
+if(urlParams.has('sqlite3.dir')){
+ sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
+}
+importScripts(sqlite3Js);
+globalThis.sqlite3InitModule().then(async function(sqlite3_){
+ log("Done initializing. Running batch runner...");
+ sqlite3 = sqlite3_;
+ App.run(sqlite3_);
+});
diff --git a/ext/wasm/batch-runner.js b/ext/wasm/batch-runner.js
index ff287a66e..e7a322b7f 100644
--- a/ext/wasm/batch-runner.js
+++ b/ext/wasm/batch-runner.js
@@ -72,7 +72,6 @@
App.logHtml("reset db rc =",rc,db.id, db.filename);
};
-
const E = (s)=>document.querySelector(s);
const App = {
e: {
@@ -91,6 +90,15 @@
db: Object.create(null),
dbs: Object.create(null),
cache:{},
+ metrics: {
+ fileCount: 0,
+ runTimeMs: 0,
+ prepareTimeMs: 0,
+ stepTimeMs: 0,
+ stmtCount: 0,
+ strcpyMs: 0,
+ sqlBytes: 0
+ },
log: console.log.bind(console),
warn: console.warn.bind(console),
cls: function(){this.e.output.innerHTML = ''},
@@ -117,7 +125,6 @@
"Running",name,'('+sql.length,'bytes) using',db.id);
const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm;
let pStmt = 0, pSqlBegin;
- const stack = wasm.scopedAllocPush();
const metrics = db.metrics = Object.create(null);
metrics.prepTotal = metrics.stepTotal = 0;
metrics.stmtCount = 0;
@@ -142,6 +149,11 @@
this.logHtml("Overhead (time - prep - step):",
(metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms");
this.logHtml(banner,"End of",name);
+ this.metrics.prepareTimeMs += metrics.prepTotal;
+ this.metrics.stepTimeMs += metrics.stepTotal;
+ this.metrics.stmtCount += metrics.stmtCount;
+ this.metrics.strcpyMs += metrics.strcpy;
+ this.metrics.sqlBytes += sql.length;
};
let runner;
@@ -214,7 +226,9 @@
}.bind(this);
}else{/*sqlite3 db...*/
runner = function(resolve, reject){
+ ++this.metrics.fileCount;
metrics.evalSqlStart = performance.now();
+ const stack = wasm.scopedAllocPush();
try {
let t;
let sqlByteLen = sql.byteLength;
@@ -269,7 +283,7 @@
let p;
if(1){
p = new Promise(function(res,rej){
- setTimeout(()=>runner(res, rej), 50)/*give UI a chance to output the "running" banner*/;
+ setTimeout(()=>runner(res, rej), 0)/*give UI a chance to output the "running" banner*/;
});
}else{
p = new Promise(runner);
@@ -401,7 +415,7 @@
});
return new Blob(ar);
},
-
+
downloadMetrics: function(){
const b = this.metricsToBlob();
if(!b) return;
@@ -576,6 +590,8 @@
const timeTotal = performance.now() - timeStart;
who.logHtml("Run-remaining time:",timeTotal,"ms ("+(timeTotal/1000/60)+" minute(s))");
who.clearStorage();
+ App.metrics.runTimeMs = timeTotal;
+ who.logHtml("Total metrics:",JSON.stringify(App.metrics,undefined,' '));
}, false);
}/*run()*/
}/*App*/;
diff --git a/ext/wasm/demo-123.js b/ext/wasm/demo-123.js
index 8e03ee80f..9f90ca756 100644
--- a/ext/wasm/demo-123.js
+++ b/ext/wasm/demo-123.js
@@ -20,7 +20,7 @@
the main (UI) thread.
*/
let logHtml;
- if(self.window === self /* UI thread */){
+ if(globalThis.window === globalThis /* UI thread */){
console.log("Running demo from main UI thread.");
logHtml = function(cssClass,...args){
const ln = document.createElement('div');
@@ -250,7 +250,7 @@
}/*demo1()*/;
log("Loading and initializing sqlite3 module...");
- if(self.window!==self) /*worker thread*/{
+ if(globalThis.window!==globalThis) /*worker thread*/{
/*
If sqlite3.js is in a directory other than this script, in order
to get sqlite3.js to resolve sqlite3.wasm properly, we have to
@@ -262,19 +262,20 @@
that's not needed.
URL arguments passed as part of the filename via importScripts()
- are simply lost, and such scripts see the self.location of
+ are simply lost, and such scripts see the globalThis.location of
_this_ script.
*/
let sqlite3Js = 'sqlite3.js';
- const urlParams = new URL(self.location.href).searchParams;
+ const urlParams = new URL(globalThis.location.href).searchParams;
if(urlParams.has('sqlite3.dir')){
sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js;
}
importScripts(sqlite3Js);
}
- self.sqlite3InitModule({
- // We can redirect any stdout/stderr from the module
- // like so...
+ globalThis.sqlite3InitModule({
+ /* We can redirect any stdout/stderr from the module like so, but
+ note that doing so makes use of Emscripten-isms, not
+ well-defined sqlite APIs. */
print: log,
printErr: error
}).then(function(sqlite3){
diff --git a/ext/wasm/speedtest1-worker.html b/ext/wasm/speedtest1-worker.html
index 3adf8f2ee..8c9a77dc5 100644
--- a/ext/wasm/speedtest1-worker.html
+++ b/ext/wasm/speedtest1-worker.html
@@ -350,7 +350,7 @@
eControls.classList.remove('hidden');
break;
case 'stdout': log(msg.data); break;
- case 'stdout': logErr(msg.data); break;
+ case 'stderr': logErr(msg.data); break;
case 'run-start':
eControls.disabled = true;
log("Running speedtest1 with argv =",msg.data.join(' '));
diff --git a/manifest b/manifest
index 9f44093bf..d6a02fa19 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C New\sJSON\stest\scases\sshowing\sinsert\sor\sset\swith\smissing\ssubstructure.
-D 2023-11-30T16:16:10.846
+C Add\sa\sbasic\sbatch-mode\sSQL\srunner\sfor\sthe\sSAH\sPool\sVFS,\sfor\suse\sin\scomparing\sit\sagainst\sWebSQL.\sBring\sthe\sWebSQL\sbatch\srunner\sup\sto\sdate,\snoting\sthat\sit\scannot\srun\swithout\saddition\sof\san\s"origin\strial"\sactivation\skey\sfrom\sGoogle\sbecause\sthat's\snow\sthe\sonly\sway\sto\senable\sWebSQL\sin\sChrome\s(that\spart\sis\snot\schecked\sin\sbecause\sthat\skey\sis\sprivate).\sMinor\scode-adjacent\scleanups.
+D 2023-11-30T20:34:24.440
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -568,7 +568,7 @@ F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
-F ext/wasm/GNUmakefile 0e362f3fc04eab6628cbe4f1e35f4ab4a200881f6b5f753b27fb45eabeddd9d2
+F ext/wasm/GNUmakefile 57439eec2b8b4d4074e5d861e93aab3f32bb0f44339a2b472c23f4e638b7e8a3
F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
F ext/wasm/README.md a8a2962c3aebdf8d2104a9102e336c5554e78fc6072746e5daf9c61514e7d193
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
@@ -598,8 +598,10 @@ F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 46c4afa6c50d7369252c104f274ad977a97e91cc
F ext/wasm/api/sqlite3-wasm.c d0e09eb5ed3743c00294e30019e591c3aa150572ae7ffe8a8994568a7377589f
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 569d4e859968e65f55dec5fac0b879828a23c8b179162cc7812fec19f844dd21
F ext/wasm/api/sqlite3-worker1.c-pp.js a541112aa51e16705f13a99bb943c64efe178aa28c86704a955f8fd9afe4ba37
+F ext/wasm/batch-runner-sahpool.html e9a38fdeb36a13eac7b50241dfe7ae066fe3f51f5c0b0151e7baee5fce0d07a7
+F ext/wasm/batch-runner-sahpool.js 54a3ac228e6c4703fe72fb65c897e19156263a51fe9b7e21d2834a45e876aabd
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
-F ext/wasm/batch-runner.js 0dad6a02ad796f1003d3b7048947d275c4d6277f63767b8e685c27df8fdac93e
+F ext/wasm/batch-runner.js 05ec254f5dbfe605146d9640b3db17d6ef8c3fbef6aa8396051ca72bb5884e3f
F ext/wasm/c-pp.c 6d80d8569d85713effe8b0818a3cf51dc779e3f0bf8dc88771b8998552ee25b4
F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
@@ -607,7 +609,7 @@ F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a7
F ext/wasm/common/whwasmutil.js 4c64594eecc7af4ae64259e95a71ba2a7edf118881aaff0bba86d0c7164e78e4
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
-F ext/wasm/demo-123.js 38aa8faec4d0ace1c973bc8a7a1533584463ebeecd4c420daa7d9687beeb9cb5
+F ext/wasm/demo-123.js c7b3cca50c55841c381a9ca4f9396e5bbdc6114273d0b10a43e378e32e7be5bf
F ext/wasm/demo-jsstorage.html 409c4be4af5f207fb2877160724b91b33ea36a3cd8c204e8da1acb828ffe588e
F ext/wasm/demo-jsstorage.js 44e3ae7ec2483b6c511384c3c290beb6f305c721186bcf5398ca4e00004a06b8
F ext/wasm/demo-worker1-promiser.html 1de7c248c7c2cfd4a5783d2aa154bce62d74c6de98ab22f5786620b3354ed15f
@@ -630,7 +632,7 @@ F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
F ext/wasm/speedtest1-wasmfs.html 0e9d335a9b5b5fafe6e1bc8dc0f0ca7e22e6eb916682a2d7c36218bb7d67379d
F ext/wasm/speedtest1-wasmfs.mjs ac5cadbf4ffe69e9eaac8b45e8523f030521e02bb67d654c6eb5236d9c456cbe
-F ext/wasm/speedtest1-worker.html e33e2064bda572c0c3ebaec7306c35aa758d9d27e245d67e807f8cc4a9351cc5
+F ext/wasm/speedtest1-worker.html 864b65ed78ce24847a348c180e7f267621a02ca027068a1863ec1c90187c1852
F ext/wasm/speedtest1-worker.js 4d2ea70a3c24e05bdca78025202841f33d298c4fa9541a0070c3228661f89ecd
F ext/wasm/speedtest1.html ff048b4a623aa192e83e143e48f1ce2a899846dd42c023fdedc8772b6e3f07da
F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x
@@ -2143,8 +2145,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 263f6d3a7784ef7d032dbf7a3265aca8dd70bf50797f28f6b2e8ddb6a301f83a
-R 0e9b3f433035365e3e741a55f5ab0daf
-U drh
-Z 72d2be7125d7371db00777b78c0fb9f8
+P 6802b6459d0d16c961ff41d240a6c88287f197d8f609090f79308707490a49c2
+R 0685d189d0b0c5921f2e4eda3787211e
+U stephan
+Z 5692f67161061876d9b3bcabcb3928cc
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index fcbc7b3b7..98d7aac12 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-6802b6459d0d16c961ff41d240a6c88287f197d8f609090f79308707490a49c2 \ No newline at end of file
+883990e7938c1f63906300a6113f0fadce143913b7c384e8aeb5f886f0be7c62 \ No newline at end of file