1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

Expand the worker1 'exec' op handling for per-row callbacks for API-level consistency and smooth some edges between worker1 core and worker1-promiser. Add worker1 'config-get' message to fetch the serializable parts of the sqlite3.config state. Improve the 'open' op's handling of the 'persistent' option (noting that we cannot yet test that case from a worker).

FossilOrigin-Name: 509f8839201ec1ea4863bd31493e6c29a0721ca6340755bb96656b828758fea7
This commit is contained in:
stephan
2022-08-24 18:39:46 +00:00
parent 9c765e7945
commit 3734401a95
7 changed files with 264 additions and 142 deletions

View File

@ -27,7 +27,7 @@
manipulated via a Promise-based interface and returns a factory
function which returns Promises for communicating with the worker.
This proxy has an _almost_ identical interface to the normal
worker API, with any exceptions noted below.
worker API, with any exceptions documented below.
It requires a configuration object with the following properties:
@ -127,26 +127,34 @@
- exec's {callback: STRING} option does not work via this
interface (it triggers an exception), but {callback: function}
does and works exactly like the STRING form does in the Worker:
the callback is called one time for each row of the result set
and once more, at the end, passed only `null`, to indicate that
the callback is called one time for each row of the result set,
passed the same worker message format as the worker API emits:
{type:typeString, row:VALUE, rowNumber:1-based-#}
Where `typeString` is an internally-synthesized message type string
used temporarily for worker message dispatching. It can be ignored
by all client code except that which tests this API. The `row`
property contains the row result in the form implied by the
`rowMode` option (defaulting to `'array'`). The `rowNumber` is a
1-based integer value incremented by 1 on each call into th
callback.
At the end of the result set, the same event is fired with
(row=undefined, rowNumber=null) to indicate that
the end of the result set has been reached. Note that the rows
arrive via worker-posted messages, with all the implications
of that.
TODO?: a config option which causes it to queue up events to fire
one at a time and flush the event queue on the first error. The
main use for this is test runs which must fail at the first error.
*/
self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){
// Inspired by: https://stackoverflow.com/a/52439530
let idNumber = 0;
const handlerMap = Object.create(null);
const noop = function(){};
const err = config.onerror || noop;
const debug = config.debug || noop;
const idTypeMap = config.generateMessageId ? undefined : Object.create(null);
const genMsgId = config.generateMessageId || function(msg){
return msg.type+'#'+(++idNumber);
return msg.type+'#'+(idTypeMap[msg.type] = (idTypeMap[msg.type]||0) + 1);
};
const toss = (...args)=>{throw new Error(args.join(' '))};
if('function'===typeof config.worker) config.worker = config.worker();
@ -162,7 +170,7 @@ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){
}
msgHandler = handlerMap[ev.type] /* check for exec per-row callback */;
if(msgHandler && msgHandler.onrow){
msgHandler.onrow(ev.row);
msgHandler.onrow(ev);
return;
}
if(config.onunhandled) config.onunhandled(arguments[0]);
@ -183,13 +191,10 @@ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){
default:
break;
}
try {
msgHandler.resolve(ev);
}catch(e){
msgHandler.reject(e);
}
try {msgHandler.resolve(ev)}
catch(e){msgHandler.reject(e)}
}/*worker.onmessage()*/;
return function(/*(msgType, msgArgs) || (msg)*/){
return function(/*(msgType, msgArgs) || (msgEnvelope)*/){
let msg;
if(1===arguments.length){
msg = arguments[0];
@ -206,15 +211,29 @@ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){
msg.departureTime = performance.now();
const proxy = Object.create(null);
proxy.message = msg;
let cbId /* message handler ID for exec on-row callback proxy */;
let rowCallbackId /* message handler ID for exec on-row callback proxy */;
if('exec'===msg.type && msg.args){
if('function'===typeof msg.args.callback){
cbId = genMsgId(msg)+':row';
rowCallbackId = msg.messageId+':row';
proxy.onrow = msg.args.callback;
msg.args.callback = cbId;
handlerMap[cbId] = proxy;
msg.args.callback = rowCallbackId;
handlerMap[rowCallbackId] = proxy;
}else if('string' === typeof msg.args.callback){
toss("exec callback may not be a string when using the Promise interface.");
/**
Design note: the reason for this limitation is that this
API takes over worker.onmessage() and the client has no way
of adding their own message-type handlers to it. Per-row
callbacks are implemented as short-lived message.type
mappings for worker.onmessage().
We "could" work around this by providing a new
config.fallbackMessageHandler (or some such) which contains
a map of event type names to callbacks. Seems like overkill
for now, seeing as the client can pass callback functions
to this interface (whereas the string-form "callback" is
needed for the over-the-Worker interface).
*/
}
}
//debug("requestWork", msg);
@ -225,7 +244,7 @@ self.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig){
debug("Posting",msg.type,"message to Worker dbId="+(config.dbId||'default')+':',msg);
config.worker.postMessage(msg);
});
if(cbId) p = p.finally(()=>delete handlerMap[cbId]);
if(rowCallbackId) p = p.finally(()=>delete handlerMap[rowCallbackId]);
return p;
};
}/*sqlite3Worker1Promiser()*/;