From: stephan Date: Wed, 24 Aug 2022 00:10:45 +0000 (+0000) Subject: Significant restructuring of the Worker #1 request/response object structures to... X-Git-Tag: version-3.40.0~169^2~162 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a9ac2ed069da67cfd540f5a35cbd15acabc9a00e;p=thirdparty%2Fsqlite.git Significant restructuring of the Worker #1 request/response object structures to improve readability and clarity. FossilOrigin-Name: 03b9db9b98cb36faa7de5a8a64d2e13c4aeaadfefb33ac92bb41056f6be3f121 --- diff --git a/ext/wasm/api/sqlite3-api-worker1.js b/ext/wasm/api/sqlite3-api-worker1.js index a7b759851f..2e8d5a25d0 100644 --- a/ext/wasm/api/sqlite3-api-worker1.js +++ b/ext/wasm/api/sqlite3-api-worker1.js @@ -34,7 +34,7 @@ messages and then it posts a message in the form: ``` - {type:'sqlite3-api',data:'worker1-ready'} + {type:'sqlite3-api',result:'worker1-ready'} ``` to let the client know that it has been initialized. Clients may @@ -60,15 +60,6 @@ sqlite3.initWorker1API = function(){ - Support for handling multiple DBs via this interface is under development. - - - Revisit how virtual files are managed. We currently delete DBs - from the virtual filesystem when we close them, for the sake of - saving memory (the VFS lives in RAM). Supporting multiple DBs may - require that we give up that habit. Similarly, fully supporting - ATTACH, where a user can upload multiple DBs and ATTACH them, - also requires the that we manage the VFS entries better. - Related: we most definitely do not want to delete persistent DBs - (e.g. stored on OPFS) when they're closed. */ const toss = (...args)=>{throw new Error(args.join(' '))}; if('function' !== typeof importScripts){ @@ -102,10 +93,9 @@ sqlite3.initWorker1API = function(){ idSeq: 0, idMap: new WeakMap, open: function(arg){ - // TODO: if arg is a filename, look for a db in this.dbs with the + // TODO? if arg is a filename, look for a db in this.dbs with the // same filename and close/reopen it (or just pass it back as is?). if(!arg && this.defaultDb) return this.defaultDb; - //???if(this.defaultDb) this.defaultDb.close(); const db = (Array.isArray(arg) ? new DB(...arg) : new DB(arg)); this.dbs[getDbId(db)] = db; if(!this.defaultDb) this.defaultDb = db; @@ -122,12 +112,12 @@ sqlite3.initWorker1API = function(){ } } }, - post: function(type,data,xferList){ + post: function(msg,xferList){ if(xferList){ - self.postMessage( {type, data}, xferList ); + self.postMessage( msg, xferList ); xferList.length = 0; }else{ - self.postMessage({type, data}); + self.postMessage(msg); } }, /** Map of DB IDs to DBs. */ @@ -167,49 +157,42 @@ sqlite3.initWorker1API = function(){ xfer: [/*Temp holder for "transferable" postMessage() state.*/], /** Proxy for the DB constructor. Expects to be passed a single - object or a falsy value to use defaults. The object may - have a filename property to name the db file (see the DB - constructor for peculiarities and transformations) and/or a - buffer property (a Uint8Array holding a complete database - file's contents). The response is an object: + object or a falsy value to use defaults. The object may have a + filename property to name the db file (see the DB constructor + for peculiarities and transformations). The response is an + object: { filename: db filename (possibly differing from the input), - dbId: an opaque ID value which must be passed to other calls - in this API to tell them which db to use. If it is not - provided to future calls, they will default to - operating on the first-opened db. - - messageId: if the client-sent message included this field, - it is mirrored in the response. + dbId: an opaque ID value which must be passed in the message + envelope to other calls in this API to tell them which + db to use. If it is not provided to future calls, they + will default to operating on the first-opened db. } */ open: function(ev){ - const args = [], data = (ev.data || {}); - if(data.simulateError){ // undocumented internal testing option + const oargs = [], args = (ev.args || {}); + if(args.simulateError){ // undocumented internal testing option toss("Throwing because of simulateError flag."); } - if(data.filename) args.push(data.filename); - const db = wState.open(args); + if(args.filename) oargs.push(args.filename); + const db = wState.open(oargs); return { filename: db.filename, dbId: getDbId(db) }; }, /** - Proxy for DB.close(). If ev.data may either be a boolean or - an object with an `unlink` property. If that value is - truthy then the db file (if the db is currently open) will - be unlinked from the virtual filesystem, else it will be - kept intact. The response object is: + Proxy for DB.close(). ev.args may either be a boolean or an + object with an `unlink` property. If that value is truthy then + the db file (if the db is currently open) will be unlinked from + the virtual filesystem, else it will be kept intact. The + result object is: { filename: db filename _if_ the db is opened when this - is called, else the undefined value, - unlink: boolean. If true, unlink() (delete) the db file - after closing int. Any error while deleting it is - ignored. + is called, else the undefined value } It does not error if the given db is already closed or no db is @@ -222,8 +205,8 @@ sqlite3.initWorker1API = function(){ dbId: db ? getDbId(db) : undefined }; if(db){ - wState.close(db, !!((ev.data && 'object'===typeof ev.data) - ? ev.data.unlink : false)); + wState.close(db, ((ev.args && 'object'===typeof ev.args) + ? !!ev.args.unlink : false)); } return response; }, @@ -242,11 +225,11 @@ sqlite3.initWorker1API = function(){ message type key, in which case a callback function will be applied which posts each row result via: - postMessage({type: thatKeyType, data: theRow}) + postMessage({type: thatKeyType, row: theRow}) And, at the end of the result set (whether or not any result rows were produced), it will post an identical - message with data:null to alert the caller than the result + message with row:null to alert the caller than the result set is completed. The callback proxy must not recurse into this interface, or @@ -264,8 +247,8 @@ sqlite3.initWorker1API = function(){ */ exec: function(ev){ const opt = ( - 'string'===typeof ev.data - ) ? {sql: ev.data} : (ev.data || Object.create(null)); + 'string'===typeof ev.args + ) ? {sql: ev.args} : (ev.args || Object.create(null)); if(undefined===opt.rowMode){ /* Since the default rowMode of 'stmt' is not useful for the Worker interface, we'll default to @@ -286,13 +269,13 @@ sqlite3.initWorker1API = function(){ row as a message of that type. */ const that = this; opt.callback = - (row)=>wState.post(callbackMsgType,row,this.xfer); + (row)=>wState.post({type: callbackMsgType, row:row}, this.xfer); } try { db.exec(opt); if(opt.callback instanceof Function){ opt.callback = callbackMsgType; - wState.post(callbackMsgType, null); + wState.post({type: callbackMsgType, row: null}); } }/*catch(e){ console.warn("Worker is propagating:",e);throw e; @@ -305,7 +288,7 @@ sqlite3.initWorker1API = function(){ return opt; }/*exec()*/, /** - TO(re)DO, once we can abstract away access to the + TO(RE)DO, once we can abstract away access to the JS environment's virtual filesystem. Currently this always throws. @@ -352,73 +335,77 @@ sqlite3.initWorker1API = function(){ form: { type: apiCommand, - dbId: optional DB ID value (else uses a default db handle) - data: apiArguments, + dbId: optional DB ID value (else uses a default db handle), + args: apiArguments, messageId: optional client-specific value } As a rule, these commands respond with a postMessage() of their - own in the same form, but will, if needed, transform the `data` - member to an object and may add state to it. The responses - always have an object-format `data` part. If the inbound `data` - is an object which has a `messageId` property, that property is + own in the form: + + TODO: refactoring is underway. + + The responses always have an object-format `result` part. If the + inbound object has a `messageId` property, that property is always mirrored in the result object, for use in client-side dispatching of these asynchronous results. Exceptions thrown - during processing result in an `error`-type event with a - payload in the form: + during processing result in an `error`-type event with a payload + in the form: - { - message: error string, - errorClass: class name of the error type, + { type: 'error', dbId: DB handle ID, - input: ev.data, - [messageId: if set in the inbound message] + [messageId: if set in the inbound message], + result: { + message: error string, + errorClass: class name of the error type, + input: ev.data + } } The individual APIs are documented in the wMsgHandler object. */ self.onmessage = function(ev){ ev = ev.data; - let response, dbId = ev.dbId, evType = ev.type; + let result, dbId = ev.dbId, evType = ev.type; const arrivalTime = performance.now(); try { if(wMsgHandler.hasOwnProperty(evType) && wMsgHandler[evType] instanceof Function){ - response = wMsgHandler[evType](ev); + result = wMsgHandler[evType](ev); }else{ toss("Unknown db worker message type:",ev.type); } }catch(err){ evType = 'error'; - response = { + result = { message: err.message, errorClass: err.name, input: ev }; if(err.stack){ - response.stack = ('string'===typeof err.stack) + result.stack = ('string'===typeof err.stack) ? err.stack.split('\n') : err.stack; } if(0) console.warn("Worker is propagating an exception to main thread.", - "Reporting it _here_ for the stack trace:",err,response); - } - if(!response.messageId && ev.data - && 'object'===typeof ev.data && ev.data.messageId){ - response.messageId = ev.data.messageId; + "Reporting it _here_ for the stack trace:",err,result); } if(!dbId){ - dbId = response.dbId/*from 'open' cmd*/ + dbId = result.dbId/*from 'open' cmd*/ || getDefaultDbId(); } - if(!response.dbId) response.dbId = dbId; // Timing info is primarily for use in testing this API. It's not part of // the public API. arrivalTime = when the worker got the message. - response.workerReceivedTime = arrivalTime; - response.workerRespondTime = performance.now(); - response.departureTime = ev.departureTime; - wState.post(evType, response, wMsgHandler.xfer); + wState.post({ + type: evType, + dbId: dbId, + messageId: ev.messageId, + workerReceivedTime: arrivalTime, + workerRespondTime: performance.now(), + departureTime: ev.departureTime, + result: result + }, wMsgHandler.xfer); }; - setTimeout(()=>self.postMessage({type:'sqlite3-api',data:'worker1-ready'}), 0); + setTimeout(()=>self.postMessage({type:'sqlite3-api',result:'worker1-ready'}), 0); }.bind({self, sqlite3}); }); diff --git a/ext/wasm/sqlite3-worker1.js b/ext/wasm/sqlite3-worker1.js index 3982ddaa2b..ff024d8215 100644 --- a/ext/wasm/sqlite3-worker1.js +++ b/ext/wasm/sqlite3-worker1.js @@ -14,7 +14,7 @@ sqlite3.js, initializes the module, and postMessage()'s a message after the module is initialized: - {type: 'sqlite3-api', data: 'worker1-ready'} + {type: 'sqlite3-api', result: 'worker1-ready'} This seemingly superfluous level of indirection is necessary when loading sqlite3.js via a Worker. Instantiating a worker with new diff --git a/ext/wasm/testing2.js b/ext/wasm/testing2.js index bcbe7b50de..b051cc04cc 100644 --- a/ext/wasm/testing2.js +++ b/ext/wasm/testing2.js @@ -31,17 +31,6 @@ const warn = console.warn.bind(console); const error = console.error.bind(console); const toss = (...args)=>{throw new Error(args.join(' '))}; - /** Posts a worker message as {type:type, data:data}. */ - const wMsg = function(type,data){ - log("Posting message to worker dbId="+(DbState.id||'default')+':',data); - SW.postMessage({ - type, - dbId: DbState.id, - data, - departureTime: performance.now() - }); - return SW; - }; SW.onerror = function(event){ error("onerror",event); @@ -74,28 +63,37 @@ logHtml("","Total test count:",T.counter+". Total time =",(performance.now() - startTime),"ms"); }; - const logEventResult = function(evd){ + const logEventResult = function(ev){ + const evd = ev.result; logHtml(evd.errorClass ? 'error' : '', - "runOneTest",evd.messageId,"Worker time =", - (evd.workerRespondTime - evd.workerReceivedTime),"ms.", + "runOneTest",ev.messageId,"Worker time =", + (ev.workerRespondTime - ev.workerReceivedTime),"ms.", "Round-trip event time =", - (performance.now() - evd.departureTime),"ms.", - (evd.errorClass ? evd.message : "") + (performance.now() - ev.departureTime),"ms.", + (evd.errorClass ? ev.message : ""), evd ); }; - const runOneTest = function(eventType, eventData, callback){ - T.assert(eventData && 'object'===typeof eventData); + const runOneTest = function(eventType, eventArgs, callback){ + T.assert(eventArgs && 'object'===typeof eventArgs); /* ^^^ that is for the testing and messageId-related code, not a hard requirement of all of the Worker-exposed APIs. */ - eventData.messageId = MsgHandlerQueue.push(eventType,function(ev){ - logEventResult(ev.data); + const messageId = MsgHandlerQueue.push(eventType,function(ev){ + logEventResult(ev); if(callback instanceof Function){ callback(ev); testCount(); } }); - wMsg(eventType, eventData); + const msg = { + type: eventType, + args: eventArgs, + dbId: DbState.id, + messageId: messageId, + departureTime: performance.now() + }; + log("Posting",eventType,"message to worker dbId="+(DbState.id||'default')+':',msg); + SW.postMessage(msg); }; /** Methods which map directly to onmessage() event.type keys. @@ -103,23 +101,23 @@ const dbMsgHandler = { open: function(ev){ DbState.id = ev.dbId; - log("open result",ev.data); + log("open result",ev); }, exec: function(ev){ - log("exec result",ev.data); + log("exec result",ev); }, export: function(ev){ - log("export result",ev.data); + log("export result",ev); }, error: function(ev){ - error("ERROR from the worker:",ev.data); - logEventResult(ev.data); + error("ERROR from the worker:",ev); + logEventResult(ev); }, resultRowTest1: function f(ev){ if(undefined === f.counter) f.counter = 0; - if(ev.data) ++f.counter; - //log("exec() result row:",ev.data); - T.assert(null===ev.data || 'number' === typeof ev.data.b); + if(ev.row) ++f.counter; + //log("exec() result row:",ev.row); + T.assert(null===ev.row || 'number' === typeof ev.row.b); } }; @@ -149,7 +147,7 @@ multi: true, resultRows: [], columnNames: [] }, function(ev){ - ev = ev.data; + ev = ev.result; T.assert(0===ev.resultRows.length) .assert(0===ev.columnNames.length); }); @@ -157,7 +155,7 @@ sql: 'select a a, b b from t order by a', resultRows: [], columnNames: [], }, function(ev){ - ev = ev.data; + ev = ev.result; T.assert(3===ev.resultRows.length) .assert(1===ev.resultRows[0][0]) .assert(6===ev.resultRows[2][1]) @@ -169,7 +167,7 @@ resultRows: [], columnNames: [], rowMode: 'object' }, function(ev){ - ev = ev.data; + ev = ev.result; T.assert(3===ev.resultRows.length) .assert(1===ev.resultRows[0].a) .assert(6===ev.resultRows[2].b) @@ -181,7 +179,7 @@ resultRows: [], //rowMode: 'array', // array is the default in the Worker interface }, function(ev){ - ev = ev.data; + ev = ev.result; T.assert(1 === ev.resultRows.length) .assert(1 === ev.resultRows[0][0]); }); @@ -206,7 +204,7 @@ rowMode: 1, resultRows: [] },function(ev){ - const rows = ev.data.resultRows; + const rows = ev.result.resultRows; T.assert(3===rows.length). assert(6===rows[0]); }); @@ -215,14 +213,14 @@ sql: 'select count(a) from t', resultRows: [] },function(ev){ - ev = ev.data; + ev = ev.result; T.assert(1===ev.resultRows.length) .assert(2===ev.resultRows[0][0]); }); if(0){ // export requires reimpl. for portability reasons. runOneTest('export',{}, function(ev){ - ev = ev.data; + ev = ev.result; T.assert('string' === typeof ev.filename) .assert(ev.buffer instanceof Uint8Array) .assert(ev.buffer.length > 1024) @@ -231,11 +229,11 @@ } /***** close() tests must come last. *****/ runOneTest('close',{unlink:true},function(ev){ - ev = ev.data; + ev = ev.result; T.assert('string' === typeof ev.filename); }); runOneTest('close',{unlink:true},function(ev){ - ev = ev.data; + ev = ev.result; T.assert(undefined === ev.filename); }); }; @@ -276,11 +274,11 @@ filename:'testing2.sqlite3', simulateError: simulateOpenError }, function(ev){ - //log("open result",ev); - T.assert('testing2.sqlite3'===ev.data.filename) - .assert(ev.data.dbId) - .assert(ev.data.messageId); - DbState.id = ev.data.dbId; + log("open result",ev); + T.assert('testing2.sqlite3'===ev.result.filename) + .assert(ev.dbId) + .assert(ev.messageId); + DbState.id = ev.dbId; if(waitForOpen) setTimeout(runTests2, 0); }); if(!waitForOpen) runTests2(); @@ -293,7 +291,7 @@ } ev = ev.data/*expecting a nested object*/; //log("main window onmessage:",ev); - if(ev.data && ev.data.messageId){ + if(ev.result && ev.messageId){ /* We're expecting a queued-up callback handler. */ const f = MsgHandlerQueue.shift(); if('error'===ev.type){ @@ -306,7 +304,7 @@ } switch(ev.type){ case 'sqlite3-api': - switch(ev.data){ + switch(ev.result){ case 'worker1-ready': log("Message:",ev); self.sqlite3TestModule.setStatus(null); diff --git a/manifest b/manifest index ef10d9657a..fc1e6d40bd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Wasm\sbuild\sflag\stweaks\sand\sdocumentation. -D 2022-08-23T17:02:46.959 +C Significant\srestructuring\sof\sthe\sWorker\s#1\srequest/response\sobject\sstructures\sto\simprove\sreadability\sand\sclarity. +D 2022-08-24T00:10:45.121 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -486,7 +486,7 @@ F ext/wasm/api/sqlite3-api-glue.js 67ca83974410961953eeaa1dfed3518530d68381729ed F ext/wasm/api/sqlite3-api-oo1.js f6dcaac3270182471f97efcfda25bd4a4ac1777b8ec52ebd1c6846721160e54c F ext/wasm/api/sqlite3-api-opfs.js 011799db398157cbd254264b6ebae00d7234b93d0e9e810345f213a5774993c0 F ext/wasm/api/sqlite3-api-prologue.js 6e0e7787ed955ea2b6158e0bb7608f63b54236847700d183e49e1f10d0525b8f -F ext/wasm/api/sqlite3-api-worker1.js ceb1fc88d8a3742c069632e88fd05c14d5a79eb86bdb9e12969ec37f64fbf42b +F ext/wasm/api/sqlite3-api-worker1.js c9e4edb89f41a4fa65d136ae180c1bc0beb694eb95f7d9e6936fbb702914c160 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 0d81282eaeff2a6e9fc5c28a388c5c5b45cf25a9393992fa511ac009b27df982 F ext/wasm/common/SqliteTestUtil.js 04156a3b714b1b17a7261d21dd51341a8aeb9880a223e1e7519de98c2cceb414 @@ -508,11 +508,11 @@ F ext/wasm/scratchpad-opfs-main.js 69e960e9161f6412fd0c30f355d4112f1894d6609eb43 F ext/wasm/scratchpad-opfs-worker.html 66c1d15d678f3bd306373d76b61c6c8aef988f61f4a8dd40185d452f9c6d2bf5 F ext/wasm/scratchpad-opfs-worker.js 3ec2868c669713145c76eb5877c64a1b20741f741817b87c907a154b676283a9 F ext/wasm/scratchpad-opfs-worker2.js 5f2237427ac537b8580b1c659ff14ad2621d1694043eaaf41ae18dbfef2e48c0 -F ext/wasm/sqlite3-worker1.js e93fe8e5da7cb56dcf4d1bb0aa44bf681b509e1c56f2a75885c0f408f034c42b +F ext/wasm/sqlite3-worker1.js 0c1e7626304543969c3846573e080c082bf43bcaa47e87d416458af84f340a9e F ext/wasm/testing1.html 528001c7e32ee567abc195aa071fd9820cc3c8ffc9c8a39a75e680db05f0c409 F ext/wasm/testing1.js 2def7a86c52ff28b145cb86188d5c7a49d5993f9b78c50d140e1c31551220955 F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3 -F ext/wasm/testing2.js e16ae385cd24c4a4ec5de6f1c02e621d243e1f179204ac8df31068faa9e31b1a +F ext/wasm/testing2.js f01e8d7b32f6d4790f8352bf8dc17d2b860afa58f6c8ea1f824ef1c0d2068138 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 @@ -2006,8 +2006,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 ea2acc454c012a62556f6d0623d6eff60736d24aa214a64462b423623ef44d47 -R 72b1967923c17320161370eaaa7aa1c3 +P c8eb3aa8e0f487f14791214caf70d1aa03866e01345c7fa1d5607c24c39dde1d +R ea27eb9ac1a6ed815943946a889ca949 U stephan -Z 64cee0eefa2cd9236a38fc28a7dddd9f +Z 3af622548a101a1182c5d00aa6a9dd08 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5d826619c0..9b2d03d93c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c8eb3aa8e0f487f14791214caf70d1aa03866e01345c7fa1d5607c24c39dde1d \ No newline at end of file +03b9db9b98cb36faa7de5a8a64d2e13c4aeaadfefb33ac92bb41056f6be3f121 \ No newline at end of file