diff --git a/ext/wasm/api/extern-post-js.js b/ext/wasm/api/extern-post-js.js index 768696508e..67b32e8912 100644 --- a/ext/wasm/api/extern-post-js.js +++ b/ext/wasm/api/extern-post-js.js @@ -1,6 +1,9 @@ /* extern-post-js.js must be appended to the resulting sqlite3.js - file. It gets its name from being used as the value for - the --extern-post-js=... Emscripten flag. */ + file. It gets its name from being used as the value for the + --extern-post-js=... Emscripten flag. Note that this code, unlike + most of the associated JS code, runs outside of the + Emscripten-generated module init scope, in the current + global scope. */ (function(){ /** In order to hide the sqlite3InitModule()'s resulting Emscripten diff --git a/ext/wasm/api/sqlite3-api-opfs.js b/ext/wasm/api/sqlite3-api-opfs.js index 9f53024548..3f27941e8b 100644 --- a/ext/wasm/api/sqlite3-api-opfs.js +++ b/ext/wasm/api/sqlite3-api-opfs.js @@ -15,14 +15,17 @@ asynchronous Origin-Private FileSystem (OPFS) APIs using a second Worker, implemented in sqlite3-opfs-async-proxy.js. This file is intended to be appended to the main sqlite3 JS deliverable somewhere - after sqlite3-api-glue.js and before sqlite3-api-cleanup.js. + after sqlite3-api-oo1.js and before sqlite3-api-cleanup.js. */ 'use strict'; self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ /** - installOpfsVfs() returns a Promise which, on success, installs - an sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs - which accept a VFS. It uses the Origin-Private FileSystem API for + installOpfsVfs() returns a Promise which, on success, installs an + sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs + which accept a VFS. It is intended to be called via + sqlite3ApiBootstrap.initializersAsync or an equivalent mechanism. + + The installed VFS uses the Origin-Private FileSystem API for all file storage. On error it is rejected with an exception explaining the problem. Reasons for rejection include, but are not limited to: @@ -48,31 +51,31 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ proxying OPFS's synchronous API via the synchronous interface required by the sqlite3_vfs API. - - This function may only be called a single time and it must be - called from the client, as opposed to the library initialization, - in case the client requires a custom path for this API's - "counterpart": this function's argument is the relative URI to - this module's "asynchronous half". When called, this function removes - itself from the sqlite3 object. + - This function may only be called a single time. When called, this + function removes itself from the sqlite3 object. - The argument may optionally be a plain object with the following - configuration options: + All arguments to this function are for internal/development purposes + only. They do not constitute a public API and may change at any + time. - - proxyUri: as described above + The argument may optionally be a plain object with the following + configuration options: - - verbose (=2): an integer 0-3. 0 disables all logging, 1 enables - logging of errors. 2 enables logging of warnings and errors. 3 - additionally enables debugging info. + - proxyUri: as described above - - sanityChecks (=false): if true, some basic sanity tests are - run on the OPFS VFS API after it's initialized, before the - returned Promise resolves. + - verbose (=2): an integer 0-3. 0 disables all logging, 1 enables + logging of errors. 2 enables logging of warnings and errors. 3 + additionally enables debugging info. - On success, the Promise resolves to the top-most sqlite3 namespace - object and that object gets a new object installed in its - `opfs` property, containing several OPFS-specific utilities. + - sanityChecks (=false): if true, some basic sanity tests are + run on the OPFS VFS API after it's initialized, before the + returned Promise resolves. + + On success, the Promise resolves to the top-most sqlite3 namespace + object and that object gets a new object installed in its + `opfs` property, containing several OPFS-specific utilities. */ -const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ +const installOpfsVfs = function callee(options){ if(!self.SharedArrayBuffer || !self.Atomics || !self.FileSystemHandle || @@ -84,9 +87,9 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ new Error("This environment does not have OPFS support.") ); } - const options = (asyncProxyUri && 'object'===asyncProxyUri) ? asyncProxyUri : { - proxyUri: asyncProxyUri - }; + if(!options || 'object'!==typeof options){ + options = Object.create(null); + } const urlParams = new URL(self.location.href).searchParams; if(undefined===options.verbose){ options.verbose = urlParams.has('opfs-verbose') ? 3 : 2; @@ -113,7 +116,6 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ const log = (...args)=>logImpl(2, ...args); const warn = (...args)=>logImpl(1, ...args); const error = (...args)=>logImpl(0, ...args); - //warn("The OPFS VFS feature is very much experimental and under construction."); const toss = function(...args){throw new Error(args.join(' '))}; const capi = sqlite3.capi; const wasm = capi.wasm; @@ -158,9 +160,6 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ s.count = s.time = 0; s = metrics.s11n.deserialize = Object.create(null); s.count = s.time = 0; - //[ // timed routines which are not in state.opIds - // 'xFileControl' - //].forEach((k)=>r(metrics[k] = Object.create(null))); } }/*metrics*/; const promiseReject = function(err){ @@ -223,32 +222,36 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ cases. We should probably have one SAB here with a single slot for locking a per-file initialization step and then allocate a separate SAB like the above one for each file. That will - require a bit of acrobatics but should be feasible. + require a bit of acrobatics but should be feasible. The most + problematic part is that xOpen() would have to use + postMessage() to communicate its SharedArrayBuffer, and mixing + that approach with Atomics.wait/notify() gets a bit messy. */ const state = Object.create(null); state.verbose = options.verbose; state.littleEndian = (()=>{ const buffer = new ArrayBuffer(2); - new DataView(buffer).setInt16(0, 256, true /* littleEndian */); + new DataView(buffer).setInt16(0, 256, true /* ==>littleEndian */); // Int16Array uses the platform's endianness. return new Int16Array(buffer)[0] === 256; })(); - /** Whether the async counterpart should log exceptions to - the serialization channel. That produces a great deal of - noise for seemingly innocuous things like xAccess() checks - for missing files, so this option may have one of 3 values: + /** + Whether the async counterpart should log exceptions to + the serialization channel. That produces a great deal of + noise for seemingly innocuous things like xAccess() checks + for missing files, so this option may have one of 3 values: - 0 = no exception logging + 0 = no exception logging - 1 = only log exceptions for "significant" ops like xOpen(), - xRead(), and xWrite(). + 1 = only log exceptions for "significant" ops like xOpen(), + xRead(), and xWrite(). - 2 = log all exceptions. + 2 = log all exceptions. */ state.asyncS11nExceptions = 1; - /* Size of file I/O buffer block. 64k = max sqlite3 page size. */ - state.fileBufferSize = - 1024 * 64; + /* Size of file I/O buffer block. 64k = max sqlite3 page size, and + xRead/xWrite() will never deal in blocks larger than that. */ + state.fileBufferSize = 1024 * 64; state.sabS11nOffset = state.fileBufferSize; /** The size of the block in our SAB for serializing arguments and @@ -258,7 +261,8 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ */ state.sabS11nSize = opfsVfs.$mxPathname * 2; /** - The SAB used for all data I/O (files and arg/result s11n). + The SAB used for all data I/O between the synchronous and + async halves (file i/o and arg/result s11n). */ state.sabIO = new SharedArrayBuffer( state.fileBufferSize/* file i/o block */ @@ -297,7 +301,13 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ state.opIds.mkdir = i++; state.opIds['opfs-async-metrics'] = i++; state.opIds['opfs-async-shutdown'] = i++; - state.sabOP = new SharedArrayBuffer(i * 4/*sizeof int32*/); + /* The retry slot is used by the async part for wait-and-retry + semantics. Though we could hypothetically use the xSleep slot + for that, doing so might lead to undesired side effects. */ + state.opIds.retry = i++; + state.sabOP = new SharedArrayBuffer( + i * 4/* ==sizeof int32, noting that Atomics.wait() and friends + can only function on Int32Array views of an SAB. */); opfsUtil.metrics.reset(); } /** @@ -338,9 +348,12 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ state.s11n.serialize(...args); Atomics.store(state.sabOPView, state.opIds.rc, -1); Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx); - Atomics.notify(state.sabOPView, state.opIds.whichOp) /* async thread will take over here */; + Atomics.notify(state.sabOPView, state.opIds.whichOp) + /* async thread will take over here */; const t = performance.now(); - Atomics.wait(state.sabOPView, state.opIds.rc, -1); + Atomics.wait(state.sabOPView, state.opIds.rc, -1) + /* When this wait() call returns, the async half will have + completed the operation and reported its results. */; const rc = Atomics.load(state.sabOPView, state.opIds.rc); metrics[op].wait += performance.now() - t; if(rc && state.asyncS11nExceptions){ @@ -352,17 +365,22 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ const initS11n = ()=>{ /** - ACHTUNG: this code is 100% duplicated in the other half of this - proxy! The documentation is maintained in the "synchronous half". + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ACHTUNG: this code is 100% duplicated in the other half of + this proxy! The documentation is maintained in the + "synchronous half". + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! This proxy de/serializes cross-thread function arguments and output-pointer values via the state.sabIO SharedArrayBuffer, using the region defined by (state.sabS11nOffset, state.sabS11nOffset]. Only one dataset is recorded at a time. - This is not a general-purpose format. It only supports the range - of operations, and data sizes, needed by the sqlite3_vfs and - sqlite3_io_methods operations. + This is not a general-purpose format. It only supports the + range of operations, and data sizes, needed by the + sqlite3_vfs and sqlite3_io_methods operations. Serialized + data are transient and this serialization algorithm may + change at any time. The data format can be succinctly summarized as: @@ -386,7 +404,8 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ using their TextEncoder/TextDecoder representations. It would arguably make more sense to store them as Int16Arrays of their JS character values, but how best/fastest to get that - in and out of string form us an open point. + in and out of string form is an open point. Initial + experimentation with that approach did not gain us any speed. Historical note: this impl was initially about 1% this size by using using JSON.stringify/parse(), but using fit-to-purpose @@ -583,9 +602,11 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ toss("Member",name," is not a function pointer. Signature =",sigN); } const memKey = tgt.memberKey(name); - //log("installMethod",tgt, name, sigN); const fProxy = 0 - // We can remove this proxy middle-man once the VFS is working + /** This middle-man proxy is only for use during development, to + confirm that we always pass the proper number of + arguments. We know that the C-level code will always use the + correct argument count. */ ? callee.argcProxy(func, sigN) : func; const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true)); @@ -606,7 +627,6 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ const mTimeStart = (op)=>{ opTimer.start = performance.now(); opTimer.op = op; - //metrics[op] || toss("Maintenance required: missing metrics for",op); ++metrics[op].count; }; const mTimeEnd = ()=>( @@ -619,8 +639,15 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ */ const ioSyncWrappers = { xCheckReservedLock: function(pFile,pOut){ - // Exclusive lock is automatically acquired when opened - //warn("xCheckReservedLock(",arguments,") is a no-op"); + /** + As of late 2022, only a single lock can be held on an OPFS + file. We have no way of checking whether any _other_ db + connection has a lock except by trying to obtain and (on + success) release a sync-handle for it, but doing so would + involve an inherent race condition. For the time being, + pending a better solution, we simply report whether the + given pFile instance has a lock. + */ const f = __openFiles[pFile]; wasm.setMemValue(pOut, f.lockMode ? 1 : 0, 'i32'); return 0; @@ -673,14 +700,17 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ return rc; }, xRead: function(pFile,pDest,n,offset64){ - /* int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst) */ mTimeStart('xRead'); const f = __openFiles[pFile]; let rc; try { rc = opRun('xRead',pFile, n, Number(offset64)); - if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){ - // set() seems to be the fastest way to copy this... + if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){ + /** + Results get written to the SharedArrayBuffer f.sabView. + Because the heap is _not_ a SharedArrayBuffer, we have + to copy the results. TypedArray.set() seems to be the + fastest way to copy this. */ wasm.heap8u().set(f.sabView.subarray(0, n), pDest); } }catch(e){ @@ -713,7 +743,6 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ return rc; }, xWrite: function(pFile,pSrc,n,offset64){ - /* int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst) */ mTimeStart('xWrite'); const f = __openFiles[pFile]; let rc; @@ -779,28 +808,6 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ //xSleep is optionally defined below xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){ mTimeStart('xOpen'); - if(!f._){ - f._ = { - fileTypes: { - SQLITE_OPEN_MAIN_DB: 'mainDb', - SQLITE_OPEN_MAIN_JOURNAL: 'mainJournal', - SQLITE_OPEN_TEMP_DB: 'tempDb', - SQLITE_OPEN_TEMP_JOURNAL: 'tempJournal', - SQLITE_OPEN_TRANSIENT_DB: 'transientDb', - SQLITE_OPEN_SUBJOURNAL: 'subjournal', - SQLITE_OPEN_SUPER_JOURNAL: 'superJournal', - SQLITE_OPEN_WAL: 'wal' - }, - getFileType: function(filename,oflags){ - const ft = f._.fileTypes; - for(let k of Object.keys(ft)){ - if(oflags & capi[k]) return ft[k]; - } - warn("Cannot determine fileType based on xOpen() flags for file",filename); - return '???'; - } - }; - } if(0===zName){ zName = randomFilename(); }else if('number'===typeof zName){ @@ -1084,16 +1091,13 @@ const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){ promiseReject(e); error("Unexpected message from the async worker:",data); break; - } - }; - + }/*switch(data.type)*/ + }/*W.onmessage()*/; })/*thePromise*/; return thePromise; }/*installOpfsVfs()*/; installOpfsVfs.defaultProxyUri = - //self.location.pathname.replace(/[^/]*$/, "sqlite3-opfs-async-proxy.js"); "sqlite3-opfs-async-proxy.js"; -//console.warn("sqlite3.installOpfsVfs.defaultProxyUri =",sqlite3.installOpfsVfs.defaultProxyUri); self.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ if(sqlite3.scriptInfo && !sqlite3.scriptInfo.isWorker){ return; diff --git a/ext/wasm/api/sqlite3-opfs-async-proxy.js b/ext/wasm/api/sqlite3-opfs-async-proxy.js index 5b29aa3ea5..254da7ee5d 100644 --- a/ext/wasm/api/sqlite3-opfs-async-proxy.js +++ b/ext/wasm/api/sqlite3-opfs-async-proxy.js @@ -10,7 +10,7 @@ *********************************************************************** - An Worker which manages asynchronous OPFS handles on behalf of a + A Worker which manages asynchronous OPFS handles on behalf of a synchronous API which controls it via a combination of Worker messages, SharedArrayBuffer, and Atomics. It is the asynchronous counterpart of the API defined in sqlite3-api-opfs.js. @@ -25,8 +25,12 @@ 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. + + This file represents an implementation detail of a larger piece of + code, and not a public interface. Its details may change at any time + and are not intended to be used by any client-level code. */ -'use strict'; +"use strict"; const toss = function(...args){throw new Error(args.join(' '))}; if(self.window === self){ toss("This code cannot run from the main thread.", @@ -133,8 +137,8 @@ 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. + handle object (which must be a valid handle object, as created by + xOpen()), lazily opening 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 @@ -150,7 +154,7 @@ const getSyncHandle = async (fh)=>{ let i = 1, ms = 300; for(; true; ms *= ++i){ try { - //if(1===i) toss("Just testing."); + //if(i<3) toss("Just testing."); //TODO? A config option which tells it to throw here //randomly every now and then, for testing purposes. fh.syncHandle = await fh.fileHandle.createSyncAccessHandle(); @@ -163,7 +167,7 @@ const getSyncHandle = async (fh)=>{ } warn("Error getting sync handle. Waiting",ms, "ms and trying again.",fh.filenameAbs,e); - Atomics.wait(state.sabOPView, state.opIds.xSleep, 0, ms); + Atomics.wait(state.sabOPView, state.opIds.retry, 0, ms); } } log("Got sync handle for",fh.filenameAbs,'in',performance.now() - t,'ms'); @@ -305,7 +309,7 @@ const vfsAsyncImpls = { storeAndNotify('xAccess', rc); mTimeEnd(); }, - xClose: async function(fid){ + xClose: async function(fid/*sqlite3_file pointer*/){ const opName = 'xClose'; mTimeStart(opName); const fh = __openFiles[fid]; @@ -364,7 +368,7 @@ const vfsAsyncImpls = { wTimeEnd(); return rc; }, - xFileSize: async function(fid){ + xFileSize: async function(fid/*sqlite3_file pointer*/){ mTimeStart('xFileSize'); const fh = __openFiles[fid]; let sz; @@ -381,7 +385,8 @@ const vfsAsyncImpls = { storeAndNotify('xFileSize', sz); mTimeEnd(); }, - xLock: async function(fid,lockType){ + xLock: async function(fid/*sqlite3_file pointer*/, + lockType/*SQLITE_LOCK_...*/){ mTimeStart('xLock'); const fh = __openFiles[fid]; let rc = 0; @@ -397,7 +402,8 @@ const vfsAsyncImpls = { storeAndNotify('xLock',rc); mTimeEnd(); }, - xOpen: async function(fid/*sqlite3_file pointer*/, filename, flags){ + xOpen: async function(fid/*sqlite3_file pointer*/, filename, + flags/*SQLITE_OPEN_...*/){ const opName = 'xOpen'; mTimeStart(opName); const deleteOnClose = (state.sq3Codes.SQLITE_OPEN_DELETEONCLOSE & flags); @@ -440,7 +446,7 @@ const vfsAsyncImpls = { } mTimeEnd(); }, - xRead: async function(fid,n,offset){ + xRead: async function(fid/*sqlite3_file pointer*/,n,offset64){ mTimeStart('xRead'); let rc = 0, nRead; const fh = __openFiles[fid]; @@ -448,7 +454,7 @@ const vfsAsyncImpls = { wTimeStart('xRead'); nRead = (await getSyncHandle(fh)).read( fh.sabView.subarray(0, n), - {at: Number(offset)} + {at: Number(offset64)} ); wTimeEnd(); if(nRead < n){/* Zero-fill remaining bytes */ @@ -464,7 +470,7 @@ const vfsAsyncImpls = { storeAndNotify('xRead',rc); mTimeEnd(); }, - xSync: async function(fid,flags/*ignored*/){ + xSync: async function(fid/*sqlite3_file pointer*/,flags/*ignored*/){ mTimeStart('xSync'); const fh = __openFiles[fid]; let rc = 0; @@ -480,7 +486,7 @@ const vfsAsyncImpls = { storeAndNotify('xSync',rc); mTimeEnd(); }, - xTruncate: async function(fid,size){ + xTruncate: async function(fid/*sqlite3_file pointer*/,size){ mTimeStart('xTruncate'); let rc = 0; const fh = __openFiles[fid]; @@ -497,7 +503,8 @@ const vfsAsyncImpls = { storeAndNotify('xTruncate',rc); mTimeEnd(); }, - xUnlock: async function(fid,lockType){ + xUnlock: async function(fid/*sqlite3_file pointer*/, + lockType/*SQLITE_LOCK_...*/){ mTimeStart('xUnlock'); let rc = 0; const fh = __openFiles[fid]; @@ -514,7 +521,7 @@ const vfsAsyncImpls = { storeAndNotify('xUnlock',rc); mTimeEnd(); }, - xWrite: async function(fid,n,offset){ + xWrite: async function(fid/*sqlite3_file pointer*/,n,offset64){ mTimeStart('xWrite'); let rc; wTimeStart('xWrite'); @@ -524,7 +531,7 @@ const vfsAsyncImpls = { rc = ( n === (await getSyncHandle(fh)) .write(fh.sabView.subarray(0, n), - {at: Number(offset)}) + {at: Number(offset64)}) ) ? 0 : state.sq3Codes.SQLITE_IOERR_WRITE; }catch(e){ error("xWrite():",e,fh); diff --git a/manifest b/manifest index bf748e6b59..a762413d2d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypo\sin\scomment. -D 2022-10-24T18:42:45.118 +C Minor\scleanups\sand\sdoc\simprovements\sin\sthe\sOPFS\ssqlite3_vfs\sproxy. +D 2022-10-25T08:06:17.330 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -478,7 +478,7 @@ F ext/wasm/README.md 1e5b28158b74ab3ffc9d54fcbc020f0bbeb82c2ff8bbd904214c86c70e8 F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 36f413ab4dbb057d2dec938fb366ac0a4c5e85ba14660a8d672f0277602c0fc5 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 F ext/wasm/api/README.md 1350088aee90e959ad9a94fab1bb6bcb5e99d4d27f976db389050f54f2640c78 -F ext/wasm/api/extern-post-js.js efbed835f290b3741259acc5faf68714a60d38e6834e6cfe172d5354c87566d2 +F ext/wasm/api/extern-post-js.js 926d192b72fa808378e5e7843721dc7ba3908c163a0260e06d8aa501c12f5469 F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41 F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1 F ext/wasm/api/post-js-header.js 2e5c886398013ba2af88028ecbced1e4b22dc96a86467f1ecc5ba9e64ef90a8b @@ -486,11 +486,11 @@ F ext/wasm/api/pre-js.js 151e0616614a49f3db19ed544fa13b38c87c108959fbcd4029ea839 F ext/wasm/api/sqlite3-api-cleanup.js 4d07a7524dc9b7b050acfde57163e839243ad2383bd7ee0de0178b1b3e988588 F ext/wasm/api/sqlite3-api-glue.js 6e4e472eb5afc732a695cd7c5ded6dee6ef8b480e61aa0d648a3fc9033c84745 F ext/wasm/api/sqlite3-api-oo1.js ca41ffe58bfbbefc98181081fba0b7af58afcc2770e963558f4f6a408c583fc0 -F ext/wasm/api/sqlite3-api-opfs.js 22d60ba956e873b65e2e0591e239178082bd53a6d563c3c58db7dc03e562e8f7 +F ext/wasm/api/sqlite3-api-opfs.js 62da8b7cac30d4e7bb940762d2ac948b0aeb89704a5a290b74eb268ecbd1a64e F ext/wasm/api/sqlite3-api-prologue.js fa00d55f927e5a4ec51cf2c80f6f0eaed2f4f5774341ecf3d63a0ea4c738f8f5 F ext/wasm/api/sqlite3-api-worker1.js a7f38f03275d6c27ab2aef3e83215d3c97ce09c43e6904df47c3764d9d4572b4 F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3 -F ext/wasm/api/sqlite3-opfs-async-proxy.js 206ce6bbc3c30ad51a37d9c25e3a2712e70b586e0f9a2cf8cb0b9619017c2671 +F ext/wasm/api/sqlite3-opfs-async-proxy.js f04cb1eb483c92bc61fe02749f7afcf17ec803968171aedd7d96faf428c26bcb F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 940d576bda7068ba60492e206d06a3567b8a89a3770700aa88690a6e246a0c78 F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b @@ -2037,8 +2037,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 69d704224e9ed022fcec591beff2ffcc4daf3e7fc586debfdcf00b25c1fddd87 -R e2a88fcf6a9d4446fa629ea861bc8ca4 -U drh -Z ea85a8ca90f8837e6e02f1969966b7f9 +P f65c95658fe4d30817da8de7eb88e823ea1cd8be40e347d626870bad3cc13359 +R 18bf727aa37df31466f2ea66a532842e +U stephan +Z 9cf62ee935cac4cb5c613433da7a1983 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c85389d8a2..125f873da6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f65c95658fe4d30817da8de7eb88e823ea1cd8be40e347d626870bad3cc13359 \ No newline at end of file +48645f7bcacf81c4149f26d20ee1752fbe93a02f96b85bd7e28bfa49322137e5 \ No newline at end of file