Closed StabbarN closed 6 years ago
Seems to be a websql bug in webkit. Would it be possible to put all tables into a single database instead?
One database is only for logging purposes. We wanted to split log data from business data so that the logs were stored even tho the transaction was aborted. It’s certainly possible but it would be nice to have multiple databases.
Another thing you could try would be to wait with opening the two at the same time:
dbTwo.open = Dexie.override(dbTwo.open, origFunc => function(){
return dbOne.open().then(()=>origFunc.apply(this, arguments));
});
Essentially this code avoids opening race conditions without sacrificing the autoOpen feature.
But this assumes the race condition bug occurs in the opening of the database only.
NOTE: Keep the explicit function as a function and do not convert it to a lambda arrow, as it needs to preserve the this context from caller
I see. If you choose to go for the single DB option and move the logs table back to the first DB, just make sure your logger can be called from within other transactions in the same db.
export function log(msg): void {
db.transaction('rw!', db.logs, ()=>{
return db.logs.add({msg});
}).catch(err => {
console.error(`Unable to log message to DB: ${err}. Message not logged: ${msg}. `);
});
}
Note that the sample does not return the transaction promise, as a caller typically do not need to wait for it to finish. And if the caller is within another transaction, waiting for this transaction would make that transaction commit too early.
That would probably be a good enough solution.
We might not need two databases. I was thinking about another solution, but yours is probably better. My solution was to change
db.transaction("rw", db[storeName1], db[logStoreName], () => {
...
logStoreName.put(...)
}
to
db.transaction("rw", db[storeName1], () => {
...
logStoreName.put(...)
}
, that is, stop listing db[logStoreName]
to the transaction.
If the transaction is aborted then the log would be stored anyway. But as I said earlier, your's solution is more elegant and uses "!" in a nifty way.
Yes, you would need to put the call in its own transaction (with 'rw!' or 'rw?') as it would otherwise fail due to using a table that is not included in current transaction.
http://dexie.org/docs/Dexie/Dexie.transaction()#specify-reusage-of-parent-transaction
Sounds like you got pointed in the right direction, so closing, but feel free to reopen or comment further as needed...
We are seeing the following exceptions:
undefined unable to begin transaction (5 database is locked)
andThe operation failed for reasons unrelated to the database itself and not covered by any other errors. (unable to commit transaction (5 database is locked))--(1)
Those exceptions started to trouble us after we begun using two database instances instead of one:
It seems to occur most often when we manually reload the page from Javascript
window.location.reload()
.We tried to explicitly close both databases before reload:
but to no avail. We have also made sure that no large transaction in Dexie is ongoing when reload.
See also https://stackoverflow.com/questions/34018829/websql-database-is-locked and https://github.com/pouchdb/pouchdb/issues/6324
We can see that two different databases with extension .sqlite are created and used.
Hiding the app doesn't resolve the problem but force closing it does help (force close: https://support.apple.com/en-us/HT201330 ).
Shim is active in UIWebView on iOS 9.x and 10.x and the exceptions are only thrown on these two platforms. We use latest Dexie, IndexedDBShim version 3.7.0, node 10.9, babel 7.
Any idea how to prevent these locks or where the problem may emerge? @dfahlander, the creator of Dexie, do you have any suggestion?