aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/wasm/GNUmakefile2
-rw-r--r--ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js148
-rw-r--r--ext/wasm/api/sqlite3-worker1-promiser.c-pp.js4
-rw-r--r--ext/wasm/index.html4
-rw-r--r--ext/wasm/tester1.c-pp.js19
-rw-r--r--ext/wasm/tests/opfs/sahpool/index.html31
-rw-r--r--ext/wasm/tests/opfs/sahpool/sahpool-pausing.js183
-rw-r--r--ext/wasm/tests/opfs/sahpool/sahpool-worker.js104
-rw-r--r--manifest24
-rw-r--r--manifest.uuid2
10 files changed, 483 insertions, 38 deletions
diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile
index c9852e389..572a3cd33 100644
--- a/ext/wasm/GNUmakefile
+++ b/ext/wasm/GNUmakefile
@@ -103,7 +103,7 @@ else
ifeq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
$(info ==============================================================)
$(info == Development build. Make one of (dist, snapshot) for a)
- $(info == smaller release build.)
+ $(info == smaller and faster release build.)
$(info ==============================================================)
endif
endif
diff --git a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
index 6551b5c89..e1e7b45b8 100644
--- a/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
+++ b/ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js
@@ -501,22 +501,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
currently-opened client-specified filenames. */
getFileNames(){
const rc = [];
- const iter = this.#mapFilenameToSAH.keys();
- for(const n of iter) rc.push(n);
+ for(const n of this.#mapFilenameToSAH.keys()) rc.push(n);
return rc;
}
-// #createFileObject(sah,clientName,opaqueName){
-// const f = Object.assign(Object.create(null),{
-// clientName, opaqueName
-// });
-// this.#mapSAHToMeta.set(sah, f);
-// return f;
-// }
-// #unmapFileObject(sah){
-// this.#mapSAHToMeta.delete(sah);
-// }
-
/**
Adds n files to the pool's capacity. This change is
persistent across settings. Returns a Promise which resolves
@@ -557,8 +545,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
/**
- Releases all currently-opened SAHs. The only legal
- operation after this is acquireAccessHandles().
+ Releases all currently-opened SAHs. The only legal operation
+ after this is acquireAccessHandles() or (if this is called from
+ pauseVfs()) either of isPaused() or unpauseVfs().
*/
releaseAccessHandles(){
for(const ah of this.#mapSAHToName.keys()) ah.close();
@@ -568,17 +557,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
/**
- Opens all files under this.vfsDir/this.#dhOpaque and acquires
- a SAH for each. returns a Promise which resolves to no value
- but completes once all SAHs are acquired. If acquiring an SAH
- throws, SAHPool.$error will contain the corresponding
- exception.
+ Opens all files under this.vfsDir/this.#dhOpaque and acquires a
+ SAH for each. Returns a Promise which resolves to no value but
+ completes once all SAHs are acquired. If acquiring an SAH
+ throws, this.$error will contain the corresponding Error
+ object.
+
+ If it throws, it releases any SAHs which it may have
+ acquired before the exception was thrown, leaving the VFS in a
+ well-defined but unusable state.
If clearFiles is true, the client-stored state of each file is
cleared when its handle is acquired, including its name, flags,
and any data stored after the metadata block.
*/
- async acquireAccessHandles(clearFiles){
+ async acquireAccessHandles(clearFiles=false){
const files = [];
for await (const [name,h] of this.#dhOpaque){
if('file'===h.kind){
@@ -832,12 +825,18 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Removes this object's sqlite3_vfs registration and shuts down
this object, releasing all handles, mappings, and whatnot,
including deleting its data directory. There is currently no
- way to "revive" the object and reaquire its resources.
+ way to "revive" the object and reaquire its
+ resources. Similarly, there is no recovery strategy if removal
+ of any given SAH fails, so such errors are ignored by this
+ function.
This function is intended primarily for testing.
Resolves to true if it did its job, false if the
VFS has already been shut down.
+
+ @see pauseVfs()
+ @see unpauseVfs()
*/
async removeVfs(){
if(!this.#cVfs.pointer || !this.#dhOpaque) return false;
@@ -853,13 +852,77 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
);
this.#dhVfsRoot = this.#dhVfsParent = undefined;
}catch(e){
- sqlite3.config.error(this.vfsName,"removeVfs() failed:",e);
+ sqlite3.config.error(this.vfsName,"removeVfs() failed with no recovery strategy:",e);
/*otherwise ignored - there is no recovery strategy*/
}
return true;
}
+ /**
+ "Pauses" this VFS by unregistering it from SQLite and
+ relinquishing all open SAHs, leaving the associated files
+ intact. If this object is already paused, this is a
+ no-op. Returns this object.
+
+ This function throws if SQLite has any opened file handles
+ hosted by this VFS, as the alternative would be to invoke
+ Undefined Behavior by closing file handles out from under the
+ library. Similarly, automatically closing any database handles
+ opened by this VFS would invoke Undefined Behavior in
+ downstream code which is holding those pointers.
+
+ If this function throws due to open file handles then it has
+ no side effects. If the OPFS API throws while closing handles
+ then the VFS is left in an undefined state.
+
+ @see isPaused()
+ @see unpauseVfs()
+ */
+ pauseVfs(){
+ if(this.#mapS3FileToOFile_.size>0){
+ sqlite3.SQLite3Error.toss(
+ capi.SQLITE_MISUSE, "Cannot pause VFS",
+ this.vfsName,"because it has opened files."
+ );
+ }
+ if(this.#mapSAHToName.size>0){
+ capi.sqlite3_vfs_unregister(this.vfsName);
+ this.releaseAccessHandles();
+ }
+ return this;
+ }
+
+ /**
+ Returns true if this pool is currently paused else false.
+
+ @see pauseVfs()
+ @see unpauseVfs()
+ */
+ isPaused(){
+ return 0===this.#mapSAHToName.size;
+ }
+
+ /**
+ "Unpauses" this VFS, reacquiring all SAH's and (if successful)
+ re-registering it with SQLite. This is a no-op if the VFS is
+ not currently paused.
+
+ The returned Promise resolves to this object. See
+ acquireAccessHandles() for how it behaves if it throws due to
+ SAH acquisition failure.
+
+ @see isPaused()
+ @see pauseVfs()
+ */
+ async unpauseVfs(){
+ if(0===this.#mapSAHToName.size){
+ return this.acquireAccessHandles(false).
+ then(()=>capi.sqlite3_vfs_register(this.#cVfs, 0),this);
+ }
+ return this;
+ }
+
//! Documented elsewhere in this file.
exportFile(name){
const sah = this.#mapFilenameToSAH.get(name) || toss("File not found:",name);
@@ -984,6 +1047,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
async removeVfs(){ return this.#p.removeVfs() }
+ pauseVfs(){ this.#p.pauseVfs(); return this; }
+ async unpauseVfs(){ return this.#p.unpauseVfs().then(()=>this); }
+ isPaused(){ return this.#p.isPaused() }
+
}/* class OpfsSAHPoolUtil */;
/**
@@ -1217,6 +1284,41 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Clears all client-defined state of all SAHs and makes all of them
available for re-use by the pool. Results are undefined if any such
handles are currently in use, e.g. by an sqlite3 db.
+
+ APIs specific to the "pause" capability (added in version 3.49):
+
+ Summary: "pausing" the VFS disassociates it from SQLite and
+ relinquishes its SAHs so that they may be opened by another
+ instance of this VFS (running in a separate tab/page or Worker).
+ "Unpausing" it takes back control, if able.
+
+ - pauseVfs()
+
+ "Pauses" this VFS by unregistering it from SQLite and
+ relinquishing all open SAHs, leaving the associated files intact.
+ This enables pages/tabs to coordinate semi-concurrent usage of
+ this VFS. If this object is already paused, this is a
+ no-op. Returns this object. Throws if SQLite has any opened file
+ handles hosted by this VFS. If this function throws due to open
+ file handles then it has no side effects. If the OPFS API throws
+ while closing handles then the VFS is left in an undefined state.
+
+ - isPaused()
+
+ Returns true if this VFS is paused, else false.
+
+ - [async] unpauseVfs()
+
+ Restores the VFS to an active state after having called
+ pauseVfs() on it. This is a no-op if the VFS is not paused. The
+ returned Promise resolves to this object on success. A rejected
+ Promise means there was a problem reacquiring the SAH handles
+ (possibly because they're in use by another instance or have
+ since been removed). Generically speaking, there is no recovery
+ strategy for that type of error, but if the problem is simply
+ that the OPFS files are locked, then a later attempt to unpause
+ it, made after the concurrent instance releases the SAHs, may
+ recover from the situation.
*/
sqlite3.installOpfsSAHPoolVfs = async function(options=Object.create(null)){
options = Object.assign(Object.create(null), optionDefaults, (options||{}));
diff --git a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
index 55e497ead..c043fd148 100644
--- a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
+++ b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
@@ -335,8 +335,8 @@ sqlite3Worker1Promiser.v2 = function(config){
/**
When built as a module, we export sqlite3Worker1Promiser.v2()
instead of sqlite3Worker1Promise() because (A) its interface is more
- conventional for ESM usage and (B) the ESM option export option for
- this API did not exist until v2 was created, so there's no backwards
+ conventional for ESM usage and (B) the ESM export option for this
+ API did not exist until v2 was created, so there's no backwards
incompatibility.
*/
export default sqlite3Worker1Promiser.v2;
diff --git a/ext/wasm/index.html b/ext/wasm/index.html
index a3d41f1a9..fb8a58560 100644
--- a/ext/wasm/index.html
+++ b/ext/wasm/index.html
@@ -119,6 +119,10 @@
<li><a href='tests/opfs/concurrency/index.html'>OPFS concurrency</a>
tests using multiple workers.
</li>
+ <li><a href='tests/opfs/sahpool/index.html'>OPFS SAHPool cooperative semi-concurrency</a>
+ demonstrates usage of the OPFS SAHPool VFS's "pause" feature to coordinate
+ access to a database.
+ </li>
</ul>
</li>
<li><strong>WASMFS</strong>-specific tests which require that
diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js
index 28d61de07..8638845a7 100644
--- a/ext/wasm/tester1.c-pp.js
+++ b/ext/wasm/tester1.c-pp.js
@@ -3189,8 +3189,25 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
db.close();
T.assert(1 === u1.getFileCount());
db = new u2.OpfsSAHPoolDb(dbName);
- T.assert(1 === u1.getFileCount());
+ T.assert(1 === u1.getFileCount())
+ .mustThrowMatching(
+ ()=>u1.pauseVfs(),
+ (err)=>{
+ return capi.SQLITE_MISUSE===err.resultCode
+ && /^SQLITE_MISUSE: Cannot pause VFS /.test(err.message);
+ },
+ "Cannot pause VFS with opened db."
+ );
db.close();
+ T.assert( u2===u2.pauseVfs() )
+ .assert( u2.isPaused() )
+ .assert( 0===capi.sqlite3_vfs_find(u2.vfsName) )
+ .mustThrowMatching(()=>new u2.OpfsSAHPoolDb(dbName),
+ /.+no such vfs: .+/,
+ "VFS is not available")
+ .assert( u2===await u2.unpauseVfs() )
+ .assert( u2===await u1.unpauseVfs(), "unpause is a no-op if the VFS is not paused" )
+ .assert( 0!==capi.sqlite3_vfs_find(u2.vfsName) );
const fileNames = u1.getFileNames();
T.assert(1 === fileNames.length)
.assert(dbName === fileNames[0])
diff --git a/ext/wasm/tests/opfs/sahpool/index.html b/ext/wasm/tests/opfs/sahpool/index.html
new file mode 100644
index 000000000..f3d07f456
--- /dev/null
+++ b/ext/wasm/tests/opfs/sahpool/index.html
@@ -0,0 +1,31 @@
+<!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/emscripten.css"/>
+ <link rel="stylesheet" href="../../../common/testing.css"/>
+ <title>sqlite3 tester: OpfsSAHPool Pausing</title>
+ <style></style>
+ </head>
+ <body><h1 id='color-target'></h1>
+
+ <p>
+ This page provides a <em>very basic</em> demonstration of
+ "pausing" and "unpausing" the OPFS SAHPool VFS such that
+ multiple pages or workers can use it by coordinating which
+ handler may have it open at any given time.
+ </p>
+ <div class='input-wrapper'>
+ <input type='checkbox' id='cb-log-reverse'>
+ <label for='cb-log-reverse'>Reverse log order?</label>
+ </div>
+ <div id='test-output'></div>
+ <script>(function(){
+ document.querySelector('h1').innerHTML =
+ document.querySelector('title').innerHTML;
+ })();</script>
+ <script src="sahpool-pausing.js"></script>
+ </body>
+</html>
diff --git a/ext/wasm/tests/opfs/sahpool/sahpool-pausing.js b/ext/wasm/tests/opfs/sahpool/sahpool-pausing.js
new file mode 100644
index 000000000..1aa98d3cb
--- /dev/null
+++ b/ext/wasm/tests/opfs/sahpool/sahpool-pausing.js
@@ -0,0 +1,183 @@
+/*
+ 2025-01-31
+
+ 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.
+
+ ***********************************************************************
+
+ These tests are specific to the opfs-sahpool VFS and are limited to
+ demonstrating its pause/unpause capabilities.
+
+ Most of this file is infrastructure for displaying results to the
+ user. Search for runTests() to find where the work actually starts.
+*/
+'use strict';
+(function(){
+ let logClass;
+
+ const mapToString = (v)=>{
+ switch(typeof v){
+ case 'number': case 'string': case 'boolean':
+ case 'undefined': case 'bigint':
+ return ''+v;
+ default: break;
+ }
+ if(null===v) return 'null';
+ if(v instanceof Error){
+ v = {
+ message: v.message,
+ stack: v.stack,
+ errorClass: v.name
+ };
+ }
+ return JSON.stringify(v,undefined,2);
+ };
+ const normalizeArgs = (args)=>args.map(mapToString);
+ const logTarget = document.querySelector('#test-output');
+ logClass = function(cssClass,...args){
+ const ln = document.createElement('div');
+ if(cssClass){
+ for(const c of (Array.isArray(cssClass) ? cssClass : [cssClass])){
+ ln.classList.add(c);
+ }
+ }
+ ln.append(document.createTextNode(normalizeArgs(args).join(' ')));
+ logTarget.append(ln);
+ };
+ const cbReverse = document.querySelector('#cb-log-reverse');
+ //cbReverse.setAttribute('checked','checked');
+ const cbReverseKey = 'tester1:cb-log-reverse';
+ const cbReverseIt = ()=>{
+ logTarget.classList[cbReverse.checked ? 'add' : 'remove']('reverse');
+ //localStorage.setItem(cbReverseKey, cbReverse.checked ? 1 : 0);
+ };
+ cbReverse.addEventListener('change', cbReverseIt, true);
+ /*if(localStorage.getItem(cbReverseKey)){
+ cbReverse.checked = !!(+localStorage.getItem(cbReverseKey));
+ }*/
+ cbReverseIt();
+
+ const log = (...args)=>{
+ //console.log(...args);
+ logClass('',...args);
+ }
+ const warn = (...args)=>{
+ console.warn(...args);
+ logClass('warning',...args);
+ }
+ const error = (...args)=>{
+ console.error(...args);
+ logClass('error',...args);
+ };
+
+ const toss = (...args)=>{
+ error(...args);
+ throw new Error(args.join(' '));
+ };
+
+ const endOfWork = (passed=true)=>{
+ const eH = document.querySelector('#color-target');
+ const eT = document.querySelector('title');
+ if(passed){
+ log("End of work chain. If you made it this far, you win.");
+ eH.innerText = 'PASS: '+eH.innerText;
+ eH.classList.add('tests-pass');
+ eT.innerText = 'PASS: '+eT.innerText;
+ }else{
+ eH.innerText = 'FAIL: '+eH.innerText;
+ eH.classList.add('tests-fail');
+ eT.innerText = 'FAIL: '+eT.innerText;
+ }
+ };
+
+ const nextHandlerQueue = [];
+
+ const nextHandler = function(workerId,...msg){
+ log(workerId,...msg);
+ (nextHandlerQueue.shift())();
+ };
+
+ const postThen = function(W, msgType, callback){
+ nextHandlerQueue.push(callback);
+ W.postMessage({type:msgType});
+ };
+
+ /**
+ Run a series of operations on an sahpool db spanning two workers.
+ This would arguably be more legible with Promises, but creating a
+ Promise-based communication channel for this purpose is left as
+ an exercise for the reader. An example of such a proxy can be
+ found in the SQLite source tree:
+
+ https://sqlite.org/src/file/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
+ */
+ const runPyramidOfDoom = function(W1, W2){
+ postThen(W1, 'vfs-acquire', function(){
+ postThen(W1, 'db-init', function(){
+ postThen(W1, 'db-query', function(){
+ postThen(W1, 'vfs-pause', function(){
+ postThen(W2, 'vfs-acquire', function(){
+ postThen(W2, 'db-query', function(){
+ postThen(W2, 'vfs-remove', endOfWork);
+ });
+ });
+ });
+ });
+ });
+ });
+ };
+
+ const runTests = function(){
+ log("Running opfs-sahpool pausing tests...");
+ const wjs = 'sahpool-worker.js?sqlite3.dir=../../../jswasm';
+ const W1 = new Worker(wjs+'&workerId=w1'),
+ W2 = new Worker(wjs+'&workerId=w2');
+ W1.workerId = 'w1';
+ W2.workerId = 'w2';
+ let initCount = 0;
+ const onmessage = function({data}){
+ //log("onmessage:",data);
+ switch(data.type){
+ case 'vfs-acquired':
+ nextHandler(data.workerId, "VFS acquired");
+ break;
+ case 'vfs-paused':
+ nextHandler(data.workerId, "VFS paused");
+ break;
+ case 'vfs-unpaused':
+ nextHandler(data.workerId, 'VFS unpaused');
+ break;
+ case 'vfs-removed':
+ nextHandler(data.workerId, 'VFS removed');
+ break;
+ case 'db-inited':
+ nextHandler(data.workerId, 'db initialized');
+ break;
+ case 'query-result':
+ nextHandler(data.workerId, 'query result', data.payload);
+ break;
+ case 'log':
+ log(data.workerId, ':', ...data.payload);
+ break;
+ case 'error':
+ error(data.workerId, ':', ...data.payload);
+ endOfWork(false);
+ break;
+ case 'initialized':
+ log(data.workerId, ': Worker initialized',...data.payload);
+ if( 2===++initCount ){
+ runPyramidOfDoom(W1, W2);
+ }
+ break;
+ }
+ };
+ W1.onmessage = W2.onmessage = onmessage;
+ };
+
+ runTests();
+})();
diff --git a/ext/wasm/tests/opfs/sahpool/sahpool-worker.js b/ext/wasm/tests/opfs/sahpool/sahpool-worker.js
new file mode 100644
index 000000000..592f15955
--- /dev/null
+++ b/ext/wasm/tests/opfs/sahpool/sahpool-worker.js
@@ -0,0 +1,104 @@
+/*
+ 2025-01-31
+
+ 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.
+
+ ***********************************************************************
+
+ This file is part of sahpool-pausing.js's demonstration of the
+ pause/unpause feature of the opfs-sahpool VFS.
+*/
+const searchParams = new URL(self.location.href).searchParams;
+const workerId = searchParams.get('workerId');
+const wPost = (type,...args)=>postMessage({type, workerId, payload:args});
+const log = (...args)=>wPost('log',...args);
+let capi, wasm, S, poolUtil;
+
+const sahPoolConfig = {
+ name: 'opfs-sahpool-pausable',
+ clearOnInit: false,
+ initialCapacity: 3
+};
+
+importScripts(searchParams.get('sqlite3.dir') + '/sqlite3.js');
+
+const sqlExec = function(sql){
+ const db = new poolUtil.OpfsSAHPoolDb('/my.db');
+ try{
+ return db.exec(sql);
+ }finally{
+ db.close();
+ }
+};
+
+const clog = console.log.bind(console);
+globalThis.onmessage = function({data}){
+ clog(workerId+": onmessage:",data);
+ switch(data.type){
+ case 'vfs-acquire':
+ if( poolUtil ){
+ poolUtil.unpauseVfs().then(()=>wPost('vfs-unpaused'));
+ }else{
+ S.installOpfsSAHPoolVfs(sahPoolConfig).then(pu=>{
+ poolUtil = pu;
+ wPost('vfs-acquired');
+ });
+ }
+ break;
+ case 'db-init':
+ try{
+ sqlExec([
+ "DROP TABLE IF EXISTS mytable;",
+ "CREATE TABLE mytable(a);",
+ "INSERT INTO mytable(a) VALUES(11),(22),(33)"
+ ]);
+ wPost('db-inited');
+ }catch(e){
+ wPost('error',e.message);
+ }
+ break;
+ case 'db-query': {
+ const rc = sqlExec({
+ sql: 'select * from mytable order by a',
+ rowMode: 'array',
+ returnValue: 'resultRows'
+ });
+ wPost('query-result',rc);
+ break;
+ }
+ case 'vfs-remove':
+ poolUtil.removeVfs().then(()=>wPost('vfs-removed'));
+ break;
+ case 'vfs-pause':
+ poolUtil.pauseVfs();
+ wPost('vfs-paused');
+ break;
+ }
+};
+
+const hasOpfs = ()=>{
+ return globalThis.FileSystemHandle
+ && globalThis.FileSystemDirectoryHandle
+ && globalThis.FileSystemFileHandle
+ && globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle
+ && navigator?.storage?.getDirectory;
+};
+if( !hasOpfs() ){
+ wPost('error',"OPFS not detected");
+}else{
+ globalThis.sqlite3InitModule().then(async function(sqlite3){
+ S = sqlite3;
+ capi = S.capi;
+ wasm = S.wasm;
+ log("sqlite3 version:",capi.sqlite3_libversion(),
+ capi.sqlite3_sourceid());
+ //return sqlite3.installOpfsSAHPoolVfs(sahPoolConfig).then(pu=>poolUtil=pu);
+ }).then(()=>{
+ wPost('initialized');
+ });
+}
diff --git a/manifest b/manifest
index 820f3bc2d..aa980f3b5 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C configure:\swhen\srunning\sproj-check-function-in-lib,\sstrip\s-Werror\sfrom\sCFLAGS\sfor\sthe\sduration\sof\sthe\stest.\sThis\senables\sCFLAGS='-Wall\s-Werror'\sand\sthe\slike\sto\sbe\spassed\sto\sconfigure\swithout\sbreaking\sthese\sconfigure-time\schecks.
-D 2025-02-20T03:27:47.397
+C Add\sthe\spause/unpause\scapability\sto\sthe\sopfs-sahpool\sVFS,\sas\sdiscussed\sin\s[forum:fe8cdb8431c|forum\sthread\sfe8cdb8431c].\sSummary:\sthis\sgives\sclients\sa\sway\sto\seke\ssome\sdegree\sof\smulti-page/tab/Worker\sconcurrency\sout\sof\sthis\sVFS\sbut\srequires\sthat\scoordination\sto\sbe\simplemented\sclient-side,\se.g.\svia\sa\sSharedWorker\sor\sWebLocks.
+D 2025-02-20T04:14:26.736
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
@@ -619,7 +619,7 @@ F ext/session/sqlite3session.c 52a680dbb03c4734748b215d95987fb4d95ab23baaf053a01
F ext/session/sqlite3session.h aa5de3ec8ef0e5313e9f65dafd69e8ba292d170f07b57da9200c040068dab061
F ext/session/test_session.c 12e0a2c15fd60f92da4bb29c697c9177ff0c0dbcdc5129a54c47e999f147937a
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
-F ext/wasm/GNUmakefile 06e0556e9840fd3d8870997025c2507ace9ba7bf11195f770295fc7947dfc1b5
+F ext/wasm/GNUmakefile 7889f9c5bab69233a65109e2bd00d627cab7470060e1b13b37781ac1b127f6c6
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
F ext/wasm/README.md b89605f65661cf35bf034ff6d43e448cc169b8017fc105d498e33b81218b482c
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
@@ -645,11 +645,11 @@ F ext/wasm/api/sqlite3-api-worker1.c-pp.js f646a65257973b8c4481f8a6a216370b85644
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 3774befd97cd1a5e2895c8225a894aad946848c6d9b4028acc988b5d123475af
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
-F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js bb5e96cd0fd6e1e54538256433f1c60a4e3095063c4d1a79a8a022fc59be9571
+F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js ce59229719220d64f491081bb2b423cea61cff171abcc7ac4ffc2f3687d27788
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 9b86ca2d8276cf919fbc9ba2a10e9786033b64f92c2db844d951804dee6c4b4e
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js e809739d71e8b35dfe1b55d24d91f02d04239e6aef7ca1ea92a15a29e704f616
F ext/wasm/api/sqlite3-wasm.c 6f9d8529072d072359cd22dc5dfb0572c524684686569cfbd0f9640d7619fc10
-F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 46f303ba8ddd1b2f0a391798837beddfa72e8c897038c8047eda49ce7d5ed46b
+F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc65debfe43b81fc39fb25c40ad0cc1946bd82580fbf644351107b544d6177ee
F ext/wasm/api/sqlite3-worker1.c-pp.js 5e8706c2c4af2a57fbcdc02f4e7ef79869971bc21bb8ede777687786ce1c92d5
F ext/wasm/batch-runner-sahpool.html e9a38fdeb36a13eac7b50241dfe7ae066fe3f51f5c0b0151e7baee5fce0d07a7
F ext/wasm/batch-runner-sahpool.js 54a3ac228e6c4703fe72fb65c897e19156263a51fe9b7e21d2834a45e876aabd
@@ -677,7 +677,7 @@ F ext/wasm/fiddle/fiddle-worker.js 850e66fce39b89d59e161d1abac43a181a4caa89ddeea
F ext/wasm/fiddle/fiddle.js b444a5646a9aac9f3fc06c53d78af5e1912eb235d69a8e6010723e4eb0e9d4a1
F ext/wasm/fiddle/index.html c79b1741cbeba78f88af0a84cf5ec7de87a909a6a8d10a369b1f4824c66c2088
F ext/wasm/index-dist.html 56132399702b15d70c474c3f1952541e25cb0922942868f70daf188f024b3730
-F ext/wasm/index.html e4bbffdb3d40eff12b3f9c7abedef91787e2935620b7f8d40f2c774b80ad8fa9
+F ext/wasm/index.html bcaa00eca521b372a6a62c7e7b17a870b0fcdf3e418a5921df1fd61e5344080d
F ext/wasm/jaccwabyt/jaccwabyt.js 1264710db3cfbcb6887d95665b7aeba60c1126eaef789ca4cf1a4a17d5bc7f54
F ext/wasm/jaccwabyt/jaccwabyt.md 59a20df389abcc3606eb4eaea7fb7ba14504beb3e345dbea9b99a0618ba3bec8
F ext/wasm/mkwasmbuilds.c baf6636e139e2c1e3b56e8dc26073ec80f6d14ae1876b023985315f43ccf312b
@@ -696,10 +696,13 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
-F ext/wasm/tester1.c-pp.js 05a0143c44a4114aad0ed40ce73c528febc3e0d6b69f48a51c895d7030015b74
+F ext/wasm/tester1.c-pp.js f3a3cbf0207287c4caa9f84b4e2934804e4b5720c71eaf143f33c8122bd3c9f2
F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
+F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca01385e2732294b53f4c842328
+F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
+F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
F ext/wasm/wasmfs.make 68999f5bd8c489239592d59a420f8c627c99169bbd6fa16a404751f757b9f702
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
F main.mk 323e71cd79e49c9e33d39b6558694a71c08973d9ac3ee4f211aa32e58bd876f5
@@ -2207,8 +2210,9 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 628407f03d4bfb7499f0e6e2197089edf859380a3c4e6fecc517390327718141
-R 0566dfd2338327afb5cc1d164e7ce94d
+P 4ae9d6c642295e3a0c1732dacf7c18ecacd39d3e74e38381ac5531c8396f5f1c e205cdc468e02eefdeb8d391d921aa2d4d28a8b7b87036d6d937a9928261a413
+R 224600d4f738e50568ab6b26e5819abb
+T +closed e205cdc468e02eefdeb8d391d921aa2d4d28a8b7b87036d6d937a9928261a413 Closed\sby\sintegrate-merge.
U stephan
-Z b470bbb1231ec7883dd8df58ba06834f
+Z 8b67a5570124816c376abd5faa1b9b7a
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index d915946f6..5a2129b96 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-4ae9d6c642295e3a0c1732dacf7c18ecacd39d3e74e38381ac5531c8396f5f1c
+b5dbd521951e129b4dec69f191a872500dbf387b34a8479ad58b053ffcccbab9