--- /dev/null
- 'FileSystemHandle', 'FileSystemFileHandle', 'FileSystemDirectoryHandle'
+/*
+ 2022-05-22
+
+ 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.
+
+ ***********************************************************************
+
+ An experiment for wasmfs/opfs. This file MUST be in the same dir as
+ the sqlite3.js emscripten module or that module won't be able to
+ resolve the relative URIs (importScript()'s relative URI handling
+ is, quite frankly, broken).
+*/
+'use strict';
+
+const toss = function(...args){throw new Error(args.join(' '))};
+/**
+ Posts a message in the form {type,data} unless passed more than 2
+ args, in which case it posts {type, data:[arg1...argN]}.
+*/
+const wMsg = function(type,data){
+ postMessage({
+ type,
+ data: arguments.length<3
+ ? data
+ : Array.prototype.slice.call(arguments,1)
+ });
+};
+
+const stdout = function(...args){
+ wMsg('stdout',args);
+ console.log(...args);
+};
+const stderr = function(...args){
+ wMsg('stderr',args);
+ console.error(...args);
+};
+
+const log = console.log.bind(console);
+const warn = console.warn.bind(console);
+const error = console.error.bind(console);
+
+
+const initOpfsBits = async function(sqlite3){
+ if(!self.importScripts || !self.FileSystemFileHandle){
+ //|| !self.FileSystemFileHandle.prototype.createSyncAccessHandle){
+ // ^^^ sync API is not required with WASMFS/OPFS backend.
+ warn("OPFS is not available in this environment.");
+ return;
+ }else if(!sqlite3.capi.wasm.bigIntEnabled){
+ error("OPFS requires BigInt support but sqlite3.capi.wasm.bigIntEnabled is false.");
+ return;
+ }
+ //warn('self.FileSystemFileHandle =',self.FileSystemFileHandle);
+ //warn('self.FileSystemFileHandle.prototype =',self.FileSystemFileHandle.prototype);
+ const capi = sqlite3.capi,
+ wasm = capi.wasm;
+ const sqlite3_vfs = capi.sqlite3_vfs
+ || toss("Missing sqlite3.capi.sqlite3_vfs object.");
+ const sqlite3_file = capi.sqlite3_file
+ || toss("Missing sqlite3.capi.sqlite3_file object.");
+ const sqlite3_io_methods = capi.sqlite3_io_methods
+ || toss("Missing sqlite3.capi.sqlite3_io_methods object.");
+ const StructBinder = sqlite3.StructBinder || toss("Missing sqlite3.StructBinder.");
+ const debug = console.debug.bind(console),
+ log = console.log.bind(console);
+ warn("UNDER CONSTRUCTION: setting up OPFS VFS...");
+
+ const pDVfs = capi.sqlite3_vfs_find(null)/*pointer to default VFS*/;
+ const dVfs = pDVfs
+ ? new sqlite3_vfs(pDVfs)
+ : null /* dVfs will be null when sqlite3 is built with
+ SQLITE_OS_OTHER. Though we cannot currently handle
+ that case, the hope is to eventually be able to. */;
+ const oVfs = new sqlite3_vfs();
+ const oIom = new sqlite3_io_methods();
+ oVfs.$iVersion = 2/*yes, two*/;
+ oVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
+ oVfs.$mxPathname = 1024/*sure, why not?*/;
+ oVfs.$zName = wasm.allocCString("opfs");
+ oVfs.ondispose = [
+ '$zName', oVfs.$zName,
+ 'cleanup dVfs', ()=>(dVfs ? dVfs.dispose() : null)
+ ];
+ if(dVfs){
+ oVfs.$xSleep = dVfs.$xSleep;
+ oVfs.$xRandomness = dVfs.$xRandomness;
+ }
+ // All C-side memory of oVfs is zeroed out, but just to be explicit:
+ oVfs.$xDlOpen = oVfs.$xDlError = oVfs.$xDlSym = oVfs.$xDlClose = null;
+
+ /**
+ Pedantic sidebar about oVfs.ondispose: the entries in that array
+ are items to clean up when oVfs.dispose() is called, but in this
+ environment it will never be called. The VFS instance simply
+ hangs around until the WASM module instance is cleaned up. We
+ "could" _hypothetically_ clean it up by "importing" an
+ sqlite3_os_end() impl into the wasm build, but the shutdown order
+ of the wasm engine and the JS one are undefined so there is no
+ guaranty that the oVfs instance would be available in one
+ environment or the other when sqlite3_os_end() is called (_if_ it
+ gets called at all in a wasm build, which is undefined).
+ */
+
+ /**
+ Installs a StructBinder-bound function pointer member of the
+ given name and function in the given StructType target object.
+ It creates a WASM proxy for the given function and arranges for
+ that proxy to be cleaned up when tgt.dispose() is called. Throws
+ on the slightest hint of error (e.g. tgt is-not-a StructType,
+ name does not map to a struct-bound member, etc.).
+
+ Returns a proxy for this function which is bound to tgt and takes
+ 2 args (name,func). That function returns the same thing,
+ permitting calls to be chained.
+
+ If called with only 1 arg, it has no side effects but returns a
+ func with the same signature as described above.
+ */
+ const installMethod = function callee(tgt, name, func){
+ if(!(tgt instanceof StructBinder.StructType)){
+ toss("Usage error: target object is-not-a StructType.");
+ }
+ if(1===arguments.length){
+ return (n,f)=>callee(tgt,n,f);
+ }
+ if(!callee.argcProxy){
+ callee.argcProxy = function(func,sig){
+ return function(...args){
+ if(func.length!==arguments.length){
+ toss("Argument mismatch. Native signature is:",sig);
+ }
+ return func.apply(this, args);
+ }
+ };
+ callee.removeFuncList = function(){
+ if(this.ondispose.__removeFuncList){
+ this.ondispose.__removeFuncList.forEach(
+ (v,ndx)=>{
+ if('number'===typeof v){
+ try{wasm.uninstallFunction(v)}
+ catch(e){/*ignore*/}
+ }
+ /* else it's a descriptive label for the next number in
+ the list. */
+ }
+ );
+ delete this.ondispose.__removeFuncList;
+ }
+ };
+ }/*static init*/
+ const sigN = tgt.memberSignature(name);
+ if(sigN.length<2){
+ toss("Member",name," is not a function pointer. Signature =",sigN);
+ }
+ const memKey = tgt.memberKey(name);
+ //log("installMethod",tgt, name, sigN);
+ const fProxy = 1
+ // We can remove this proxy middle-man once the VFS is working
+ ? callee.argcProxy(func, sigN)
+ : func;
+ const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
+ tgt[memKey] = pFunc;
+ if(!tgt.ondispose) tgt.ondispose = [];
+ if(!tgt.ondispose.__removeFuncList){
+ tgt.ondispose.push('ondispose.__removeFuncList handler',
+ callee.removeFuncList);
+ tgt.ondispose.__removeFuncList = [];
+ }
+ tgt.ondispose.__removeFuncList.push(memKey, pFunc);
+ return (n,f)=>callee(tgt, n, f);
+ }/*installMethod*/;
+
+ /**
+ Map of sqlite3_file pointers to OPFS handles.
+ */
+ const __opfsHandles = Object.create(null);
+
+ /**
+ Generates a random ASCII string len characters long, intended for
+ use as a temporary file name.
+ */
+ const randomFilename = function f(len=16){
+ if(!f._chars){
+ f._chars = "abcdefghijklmnopqrstuvwxyz"+
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+
+ "012346789";
+ f._n = f._chars.length;
+ }
+ const a = [];
+ let i = 0;
+ for( ; i < len; ++i){
+ const ndx = Math.random() * (f._n * 64) % f._n | 0;
+ a[i] = f._chars[ndx];
+ }
+ return a.join('');
+ };
+
+ const rootDir = await navigator.storage.getDirectory();
+ log("rootDir =",rootDir);
+
+ ////////////////////////////////////////////////////////////////////////
+ // Set up OPFS VFS methods...
+ let inst = installMethod(oVfs);
+ inst('xOpen', function(pVfs, zName, pFile, flags, pOutFlags){
+ const f = new sqlite3_file(pFile);
+ f.$pMethods = oIom.pointer;
+ __opfsHandles[pFile] = f;
+ f.opfsHandle = null /* TODO */;
+ if(flags & capi.SQLITE_OPEN_DELETEONCLOSE){
+ f.deleteOnClose = true;
+ }
+ f.filename = zName ? wasm.cstringToJs(zName) : 'sqlite3-xOpen-'+randomFilename();
+ error("OPFS sqlite3_vfs::xOpen is not yet full implemented.");
+ return capi.SQLITE_IOERR;
+ })
+ ('xFullPathname', function(pVfs,zName,nOut,pOut){
+ /* Until/unless we have some notion of "current dir"
+ in OPFS, simply copy zName to pOut... */
+ const i = wasm.cstrncpy(pOut, zName, nOut);
+ return i<nOut ? 0 : capi.SQLITE_CANTOPEN
+ /*CANTOPEN is required by the docs but SQLITE_RANGE would be a closer match*/;
+ })
+ ('xAccess', function(pVfs,zName,flags,pOut){
+ error("OPFS sqlite3_vfs::xAccess is not yet implemented.");
+ let fileExists = 0;
+ switch(flags){
+ case capi.SQLITE_ACCESS_EXISTS: break;
+ case capi.SQLITE_ACCESS_READWRITE: break;
+ case capi.SQLITE_ACCESS_READ/*docs say this is never used*/:
+ default:
+ error("Unexpected flags value for sqlite3_vfs::xAccess():",flags);
+ return capi.SQLITE_MISUSE;
+ }
+ wasm.setMemValue(pOut, fileExists, 'i32');
+ return 0;
+ })
+ ('xDelete', function(pVfs, zName, doSyncDir){
+ error("OPFS sqlite3_vfs::xDelete is not yet implemented.");
+ // https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/file_system_access/file_system_handle.idl
+ // ==> remove()
+ return capi.SQLITE_IOERR;
+ })
+ ('xGetLastError', function(pVfs,nOut,pOut){
+ debug("OPFS sqlite3_vfs::xGetLastError() has nothing sensible to return.");
+ return 0;
+ })
+ ('xCurrentTime', function(pVfs,pOut){
+ /* If it turns out that we need to adjust for timezone, see:
+ https://stackoverflow.com/a/11760121/1458521 */
+ wasm.setMemValue(pOut, 2440587.5 + (new Date().getTime()/86400000),
+ 'double');
+ return 0;
+ })
+ ('xCurrentTimeInt64',function(pVfs,pOut){
+ // TODO: confirm that this calculation is correct
+ wasm.setMemValue(pOut, (2440587.5 * 86400000) + new Date().getTime(),
+ 'i64');
+ return 0;
+ });
+ if(!oVfs.$xSleep){
+ inst('xSleep', function(pVfs,ms){
+ error("sqlite3_vfs::xSleep(",ms,") cannot be implemented from "+
+ "JS and we have no default VFS to copy the impl from.");
+ return 0;
+ });
+ }
+ if(!oVfs.$xRandomness){
+ inst('xRandomness', function(pVfs, nOut, pOut){
+ const heap = wasm.heap8u();
+ let i = 0;
+ for(; i < nOut; ++i) heap[pOut + i] = (Math.random()*255000) & 0xFF;
+ return i;
+ });
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Set up OPFS sqlite3_io_methods...
+ inst = installMethod(oIom);
+ inst('xClose', async function(pFile){
+ warn("xClose(",arguments,") uses await");
+ const f = __opfsHandles[pFile];
+ delete __opfsHandles[pFile];
+ if(f.opfsHandle){
+ await f.opfsHandle.close();
+ if(f.deleteOnClose){
+ // TODO
+ }
+ }
+ f.dispose();
+ return 0;
+ })
+ ('xRead', /*i(ppij)*/function(pFile,pDest,n,offset){
+ /* int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst) */
+ try {
+ const f = __opfsHandles[pFile];
+ const heap = wasm.heap8u();
+ const b = new Uint8Array(heap.buffer, pDest, n);
+ const nRead = f.opfsHandle.read(b, {at: offset});
+ if(nRead<n){
+ // MUST zero-fill short reads (per the docs)
+ heap.fill(0, dest + nRead, n - nRead);
+ }
+ return 0;
+ }catch(e){
+ error("xRead(",arguments,") failed:",e);
+ return capi.SQLITE_IOERR_READ;
+ }
+ })
+ ('xWrite', /*i(ppij)*/function(pFile,pSrc,n,offset){
+ /* int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst) */
+ try {
+ const f = __opfsHandles[pFile];
+ const b = new Uint8Array(wasm.heap8u().buffer, pSrc, n);
+ const nOut = f.opfsHandle.write(b, {at: offset});
+ if(nOut<n){
+ error("xWrite(",arguments,") short write!");
+ return capi.SQLITE_IOERR_WRITE;
+ }
+ return 0;
+ }catch(e){
+ error("xWrite(",arguments,") failed:",e);
+ return capi.SQLITE_IOERR_WRITE;
+ }
+ })
+ ('xTruncate', /*i(pj)*/async function(pFile,sz){
+ /* int (*xTruncate)(sqlite3_file*, sqlite3_int64 size) */
+ try{
+ warn("xTruncate(",arguments,") uses await");
+ const f = __opfsHandles[pFile];
+ await f.opfsHandle.truncate(sz);
+ return 0;
+ }
+ catch(e){
+ error("xTruncate(",arguments,") failed:",e);
+ return capi.SQLITE_IOERR_TRUNCATE;
+ }
+ })
+ ('xSync', /*i(pi)*/async function(pFile,flags){
+ /* int (*xSync)(sqlite3_file*, int flags) */
+ try {
+ warn("xSync(",arguments,") uses await");
+ const f = __opfsHandles[pFile];
+ await f.opfsHandle.flush();
+ return 0;
+ }catch(e){
+ error("xSync(",arguments,") failed:",e);
+ return capi.SQLITE_IOERR_SYNC;
+ }
+ })
+ ('xFileSize', /*i(pp)*/async function(pFile,pSz){
+ /* int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize) */
+ try {
+ warn("xFileSize(",arguments,") uses await");
+ const f = __opfsHandles[pFile];
+ const fsz = await f.opfsHandle.getSize();
+ capi.wasm.setMemValue(pSz, fsz,'i64');
+ return 0;
+ }catch(e){
+ error("xFileSize(",arguments,") failed:",e);
+ return capi.SQLITE_IOERR_SEEK;
+ }
+ })
+ ('xLock', /*i(pi)*/function(pFile,lockType){
+ /* int (*xLock)(sqlite3_file*, int) */
+ // Opening a handle locks it automatically.
+ warn("xLock(",arguments,") is a no-op");
+ return 0;
+ })
+ ('xUnlock', /*i(pi)*/function(pFile,lockType){
+ /* int (*xUnlock)(sqlite3_file*, int) */
+ // Opening a handle locks it automatically.
+ warn("xUnlock(",arguments,") is a no-op");
+ return 0;
+ })
+ ('xCheckReservedLock', /*i(pp)*/function(pFile,pOut){
+ /* int (*xCheckReservedLock)(sqlite3_file*, int *pResOut) */
+ // Exclusive lock is automatically acquired when opened
+ warn("xCheckReservedLock(",arguments,") is a no-op");
+ wasm.setMemValue(pOut,1,'i32');
+ return 0;
+ })
+ ('xFileControl', /*i(pip)*/function(pFile,op,pArg){
+ /* int (*xFileControl)(sqlite3_file*, int op, void *pArg) */
+ debug("xFileControl(",arguments,") is a no-op");
+ return capi.SQLITE_NOTFOUND;
+ })
+ ('xDeviceCharacteristics',/*i(p)*/function(pFile){
+ /* int (*xDeviceCharacteristics)(sqlite3_file*) */
+ debug("xDeviceCharacteristics(",pFile,")");
+ return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
+ });
+ // xSectorSize may be NULL
+ //('xSectorSize', function(pFile){
+ // /* int (*xSectorSize)(sqlite3_file*) */
+ // log("xSectorSize(",pFile,")");
+ // return 4096 /* ==> SQLITE_DEFAULT_SECTOR_SIZE */;
+ //})
+
+ const rc = capi.sqlite3_vfs_register(oVfs.pointer, 0);
+ if(rc){
+ oVfs.dispose();
+ toss("sqlite3_vfs_register(OPFS) failed with rc",rc);
+ }
+ capi.sqlite3_vfs_register.addReference(oVfs, oIom);
+ warn("End of (very incomplete) OPFS setup.", oVfs);
+ //oVfs.dispose()/*only because we can't yet do anything with it*/;
+
+}/*initOpfsBits()*/;
+
+(async function(){
+ importScripts('sqlite3.js');
+
+ const test1 = function(db){
+ db.exec("create table if not exists t(a);")
+ .transaction(function(db){
+ db.prepare("insert into t(a) values(?)")
+ .bind(new Date().getTime())
+ .stepFinalize();
+ stdout("Number of values in table t:",
+ db.selectValue("select count(*) from t"));
+ });
+ };
+
+ const runTests = async function(Module){
+ //stdout("Module",Module);
+ self._MODULE = Module /* this is only to facilitate testing from the console */;
+ const sqlite3 = Module.sqlite3,
+ capi = sqlite3.capi,
+ oo = sqlite3.oo1,
+ wasm = capi.wasm;
+ stdout("Loaded sqlite3:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
+
+ if(1){
+ let errCount = 0;
+ [
+ 'FileSystemHandle', 'FileSystemFileHandle', 'FileSystemDirectoryHandle',
++ 'FileSystemSyncAccessHandle'
+ ].forEach(function(n){
+ const f = self[n];
+ if(f){
+ warn(n,f);
+ warn(n+'.prototype',f.prototype);
+ }else{
+ stderr("MISSING",n);
+ ++errCount;
+ }
+ });
+ if(errCount) return;
+ }
++ warn('self',self);
+ await initOpfsBits(sqlite3);
+
+ if(1) return;
+
+ let persistentDir;
+ if(1){
+ persistentDir = '';
+ }else{
+ persistentDir = capi.sqlite3_web_persistent_dir();
+ if(persistentDir){
+ stderr("Persistent storage dir:",persistentDir);
+ }else{
+ stderr("No persistent storage available.");
+ return;
+ }
+ }
+ const startTime = performance.now();
+ let db;
+ try {
+ db = new oo.DB(persistentDir+'/foo.db');
+ stdout("DB filename:",db.filename,db.fileName());
+ const banner1 = '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>',
+ banner2 = '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<';
+ [
+ test1
+ ].forEach((f)=>{
+ const n = performance.now();
+ stdout(banner1,"Running",f.name+"()...");
+ f(db, sqlite3, Module);
+ stdout(banner2,f.name+"() took ",(performance.now() - n),"ms");
+ });
+ }finally{
+ if(db) db.close();
+ }
+ stdout("Total test time:",(performance.now() - startTime),"ms");
+ };
+
+ sqlite3InitModule(self.sqlite3TestModule).then(runTests);
+})();
--- /dev/null
- if(argv.indexOf('--nosync')>=0){
- log2('error',"WARNING: --nosync flag is known to cause this test to fail.");
- }
+<!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>speedtest1-kvvfs.wasm</title>
+ </head>
+ <body>
+ <header id='titlebar'><span>speedtest1-kvvfs.wasm</span></header>
+ <div>See also: <a href='speedtest1-worker.html'>A Worker-thread variant of this page.</a></div>
+ <!-- emscripten bits -->
+ <figure id="module-spinner">
+ <div class="spinner"></div>
+ <div class='center'><strong>Initializing app...</strong></div>
+ <div class='center'>
+ On a slow internet connection this may take a moment. If this
+ message displays for "a long time", intialization may have
+ failed and the JavaScript console may contain clues as to why.
+ </div>
+ </figure>
+ <div class="emscripten" id="module-status">Downloading...</div>
+ <div class="emscripten">
+ <progress value="0" max="100" id="module-progress" hidden='1'></progress>
+ </div><!-- /emscripten bits -->
+ <div class='warning'>This page starts running the main exe when it loads, which will
+ block the UI until it finishes! Adding UI controls to manually configure and start it
+ are TODO.</div>
+ </div>
+ <div class='warning'>Achtung: running it with the dev tools open may
+ <em>drastically</em> slow it down. For faster results, keep the dev
+ tools closed when running it!
+ </div>
+ <div>Output is delayed/buffered because we cannot update the UI while the
+ speedtest is running. Output will appear below when ready...
+ <div id='test-output'></div>
+ <script src="common/whwasmutil.js"></script>
+ <script src="common/SqliteTestUtil.js"></script>
+ <script src="speedtest1-kvvfs.js"></script>
+ <script>(function(){
+ const eOut = document.querySelector('#test-output');
+ const log2 = function(cssClass,...args){
+ const ln = document.createElement('div');
+ if(cssClass) ln.classList.add(cssClass);
+ ln.append(document.createTextNode(args.join(' ')));
+ eOut.append(ln);
+ };
+ const logList = [
+ ] /* We can't update DOM while speedtest and kvvfs only works
+ in the main thread, so we queue up main()-time output
+ into logList. */;
+ const dumpLogList = function(){
+ logList.forEach((v)=>log2('',v));
+ logList.length = 0;
+ };
+ const log = (...args)=>{
+ console.log(...args);
+ logList.push(args.join(' '));
+ };
+ const logErr = function(...args){
+ console.error(...args);
+ logList.push('ERROR: '+args.join(' '));
+ };
+
+ const guessStorageSize = function(which=''){
+ let sz = 0;
+ const prefix = 'kvvfs-'+which;
+ [localStorage,sessionStorage].forEach((s)=>{
+ let i;
+ for(i = 0; i < s.length; ++i){
+ const k = s.key(i);
+ if(k.startsWith(prefix)){
+ sz += k.length;
+ sz += s.getItem(k).length;
+ }
+ }
+ });
+ return sz;
+ };
+ const clearStorage = function(){
+ sessionStorage.clear();
+ localStorage.clear();
+ };
+ const runTests = function(EmscriptenModule){
+ console.log("Module inited.",EmscriptenModule);
+
+ const wasm = {
+ exports: EmscriptenModule.asm,
+ alloc: (n)=>EmscriptenModule._malloc(n),
+ dealloc: (m)=>EmscriptenModule._free(m),
+ memory: EmscriptenModule.asm.memory || EmscriptenModule.wasmMemory
+ };
+ log2('warning',"Clearing session/local storage before test starts.");
+ clearStorage();
+ //console.debug('wasm =',wasm);
+ self.WhWasmUtilInstaller(wasm);
+ const scope = wasm.scopedAllocPush();
+ const dbFile = 0 ? "session" : "local";
+ const urlArgs = self.SqliteTestUtil.processUrlArgs();
+ const argv = ["speedtest1", "--size", "5"];
+ if(urlArgs.flags){
+ // transform flags=a,b,c to ["--a", "--b", "--c"]
+ argv.push(...(urlArgs.flags.split(',').map((v)=>'--'+v)));
+ }else{
+ argv.push(
+ "--singlethread",
+ "--nomutex",
+ //"--nosync",
+ "--nomemstat"
+ // ,"--sqlonly"
+ );
+ //argv.push("--memdb" /* note that memdb trumps the filename arg */);
+ }
+ argv.push("--big-transactions"/*important for tests 410 and 510!*/,
+ dbFile);
+ if(argv.indexOf('--memdb')>=0){
+ log2('error',"WARNING: --memdb flag trumps db filename.");
+ }
+ console.log("argv =",argv);
+ // These log messages are not emitted to the UI until after main() returns. Fixing that
+ // requires moving the main() call and related cleanup into a timeout handler.
+ log2('',"Starting native app:\n ",argv.join(' '));
+ log2('',"This will take a while and the browser might warn about the runaway JS.",
+ "Give it time...");
+ logList.length = 0;
+ new Promise(function(resolve,reject){
+ setTimeout(function(){
+ try {
+ wasm.xCall('__main_argc_argv', argv.length,
+ wasm.scopedAllocMainArgv(argv));
+ }catch(e){
+ reject(e);
+ }
+ resolve();
+ }, 50);
+ }).finally(function(){
+ wasm.scopedAllocPop(scope);
+ logList.unshift("Done running native main(). Output:");
+ dumpLogList();
+ log2('',"Approximate",dbFile,"storage usage:",guessStorageSize(),"bytes");
+ log2('warning',"Clearing",dbFile,"storage.");
+ clearStorage(dbFile);
+ });
+ }/*runTests()*/;
+
+ self.sqlite3TestModule.print = log;
+ self.sqlite3TestModule.printErr = logErr;
+ sqlite3Speedtest1InitModule(self.sqlite3TestModule).then(function(M){
+ setTimeout(()=>runTests(M), 100);
+ });
+ })();
+ </script>
+ </body>
+</html>
- C Add\sbatch-runner-kvvfs.html,\sa\skvvfs-specific\sbuild\sof\sbatch-runner.html.\sReduce\sthe\sspeedtest1\s--size\sX\svalue\sfor\sthe\sbatch\slist\sgeneration\sto\s5\sso\sthat\sthe\skvvfs\sbatch\srunner\scan\shandle\sit.
- D 2022-09-16T02:30:49.153
-C Fix\sos_kv.c\sso\sthat\sit\suses\sSQLITE_FCNTL_SYNC\sand\shence\nworks\seven\swith\sPRAGMA\ssynchronous=OFF.
-D 2022-09-16T11:37:01.212
++C Merge\skv-vfs\sbranch\sinto\sfiddle-opfs\sbranch\sfor\s[21915af560b1|synchronous=off\sfix].\sRemove\ssome\sduplicate\sdebug\soutput\sin\sOPFS\stest\scode.
++D 2022-09-16T11:45:09.066
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/wasm/jaccwabyt/jaccwabyt.md 447cc02b598f7792edaa8ae6853a7847b8178a18ed356afacbdbf312b2588106
F ext/wasm/jaccwabyt/jaccwabyt_test.c 39e4b865a33548f943e2eb9dd0dc8d619a80de05d5300668e9960fff30d0d36f
F ext/wasm/jaccwabyt/jaccwabyt_test.exports 5ff001ef975c426ffe88d7d8a6e96ec725e568d2c2307c416902059339c06f19
-F ext/wasm/kvvfs.make 7cc9cf10e744c3ba523c3eaf5c4af47028f3a5bb76db304ea8044a9b2a9d496f
-F ext/wasm/kvvfs1.html 2acb241a6110a4ec581adbf07a23d5fc2ef9c7142aa9d60856732a102abc5016
-F ext/wasm/kvvfs1.js 46afaf4faba041bf938355627bc529854295e561f49db3a240c914e75a529338
-F ext/wasm/testing1.html 0bf3ff224628c1f1e3ed22a2dc1837c6c73722ad8c0ad9c8e6fb9e6047667231
-F ext/wasm/testing1.js cba7134901a965743fa9289d82447ab71de4690b1ee5d06f6cb83e8b569d7943
-F ext/wasm/testing2.html 73e5048e666fd6fb28b6e635677a9810e1e139c599ddcf28d687c982134b92b8
-F ext/wasm/testing2.js d37433c601f88ed275712c1cfc92d3fb36c7c22e1ed8c7396fb2359e42238ebc
+F ext/wasm/kvvfs.make 4b2ba6d061f3a52da9f5812f86f4faa80fb4d9456a152f6b0585dccd667a4e22
+F ext/wasm/kvvfs1.html 13bb24190bfb276a57b228499519badcc1bf39ed07e4b37bc2a425ce6418fed1
+F ext/wasm/kvvfs1.js ec1c1d071bb055711f9151df05616111432cf3e6bf7ac7f8dcbcfb56c9d9ed48
+F ext/wasm/scratchpad-opfs-worker.html 5fdda167571264300f388847d34f00b77dd48984a8dba2ee9c099c3ffa05db66
+F ext/wasm/scratchpad-opfs-worker.js cf6c4554d3b099c1a50013e50d19b3dc60e183511b4b4dbe7fabc2b9d3360567
- F ext/wasm/scratchpad-opfs-worker2.js 2424d7d7b8801fc143f6540fbdd8a96f3f2e5b811f0f545714d06147ccce58bf
++F ext/wasm/scratchpad-opfs-worker2.js 8c980370bbd5a262d96af8627c443936e11b87d0263a02123769d5953fc146da
+F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06
+F ext/wasm/scratchpad-wasmfs-main.js 69e960e9161f6412fd0c30f355d4112f1894d6609eb431e2d16d207d1380518e
- F ext/wasm/speedtest1-kvvfs.html ad08e2018c67cde7c459f692122a7d675b54a3709726c094ecbeed230f36abd3
++F ext/wasm/speedtest1-kvvfs.html 6e6e918d44b819a9ea1a146f260bd69022bdccd854439ee2d8c646f5073c2ea8
+F ext/wasm/speedtest1-wasmfs.html 6a67a6812f03a2058eb5c6ad0c8dea4bf749d0160ed9d6b826dabe7b766c3cf7
+F ext/wasm/speedtest1-worker.html d8881ae802d15fb8adb94049265173e99f350e07e1d4e6f9e1cbd8969fe63a04
+F ext/wasm/speedtest1-worker.js fb5d282c0b8aed18daf41c57f768cbf434f8137dbff707d53dcedcd7d4cb60ef
+F ext/wasm/speedtest1.html fbb8e4d1639028443f3687a683be660beca6927920545cf6b1fdf503104591c0
+F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x
+F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0
+F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5
+F ext/wasm/sqlite3-worker1-promiser.js 92b8da5f38439ffec459a8215775d30fa498bc0f1ab929ff341fc3dd479660b9
+F ext/wasm/sqlite3-worker1.js 0c1e7626304543969c3846573e080c082bf43bcaa47e87d416458af84f340a9e
+F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893
+F ext/wasm/testing-worker1-promiser.js 63448fddfd3b8c89ff667d17c8b31c6c2259dd4647ebbbd28f3a921c48e924da
+F ext/wasm/testing1.html 50575755e43232dbe4c2f97c9086b3118eb91ec2ee1fae931e6d7669fb17fcae
+F ext/wasm/testing1.js 7cd8ab255c238b030d928755ae8e91e7d90a12f2ae601b1b8f7827aaa4fb258e
+F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3
+F ext/wasm/testing2.js 25584bcc30f19673ce13a6f301f89f8820a59dfe044e0c4f2913941f4097fe3c
+F ext/wasm/wasmfs.make 21a5cf297954a689e0dc2a95299ae158f681cae5e90c10b99d986097815fd42d
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
F src/os.c 0eb831ba3575af5277e47f4edd14fdfc90025c67eb25ce5cda634518d308d4e9
F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
- F src/os_kv.c d4909b439043183f9b6aec65528a7433cee49d41cca95b9a3a4c8fb6bbedc0c2
+ F src/os_kv.c 554a2c109f8810b743af2eed4ba732d18dfdbc4d073e3a9bd8b8e828215a9692
F src/os_setup.h 0711dbc4678f3ac52d7fe736951b6384a0615387c4ba5135a4764e4e31f4b6a6
F src/os_unix.c 0fa91925f0b8831fc0156a9c04d39d86f85baf9eef66c98712395e1715cb75cc
-F src/os_win.c e9454cb141908e8eef2102180bad353a36480612d5b736e4c2bd5777d9b25a34
+F src/os_win.c 8d129ae3e59e0fa900e20d0ad789e96f2e08177f0b00b53cdda65c40331e0902
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 6176d9752eb580419e8fef4592dc417a6b00ddfd43ee22f818819bf8840ceee8
F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P ad0677e8abcc077636d1cf1d8485be4943506382581edf832e6b8a2021560040
- R 6eaf6290c7f1da025383bc24b7d47eee
-P e334449912d5176e355d02024a07ed867741f71c9d10ce6744ca800414bf3eeb
-R a55522768af3f3b5d07199ad1dd4c789
-U drh
-Z d50c7a05ab573e361ead585b4e643b32
++P d8df25920a047d5cf2093cc6233128c5e6057a9104d0c4397e643645bd646fe1 21915af560b111aeeaee751790356151a5f063c2fc703dd4b35b22dc393409fb
++R 9d036c771fee3f8c011441c0aa641532
+U stephan
- Z 5b7d05db593e0eeb6d33327ff3472ed8
++Z 6c79830061a07791b98ec477a66ca0ad
# Remove this line to create a well-formed Fossil manifest.