jlongster / absurd-sql

sqlite3 in ur indexeddb (hopefully a better backend soon)
MIT License
4.15k stars 101 forks source link

Database locked sometimes #29

Open quolpr opened 2 years ago

quolpr commented 2 years ago

Sometimes I get database is locked when I have two tabs, and sometimes they write to DB simultaneously. I use Microsoft edge(chrome-based browser), and it has the support of the Atomics & SharedBuffer.

And I am curious how it could happen, cause the lock should be handled by IDB 🤔. Or maybe I missed something.

The screenshots from sentry:

image

And stack trace:

Error: database is locked
  at n.handleError(/assets/VaultDb.worker.ee6ed4b1.js:15:55024)
  at e.step(/assets/VaultDb.worker.ee6ed4b1.js:15:50388)
  at n.exec(/assets/VaultDb.worker.ee6ed4b1.js:15:53846)
  at Ri.sqlExec(/assets/VaultDb.worker.ee6ed4b1.js:15:149051)
  at ? (/assets/VaultDb.worker.ee6ed4b1.js:15:149374)
  at Array.forEach(<anonymous>)
  at Ri.insertRecords(/assets/VaultDb.worker.ee6ed4b1.js:15:149281)
  at ? (/assets/VaultDb.worker.ee6ed4b1.js:15:125570)
  at Wo(/assets/VaultDb.worker.ee6ed4b1.js:15:123937)
  at Ri.transaction(/assets/VaultDb.worker.ee6ed4b1.js:15:148788)

I didn't set up the source map, but I still hope that it will help somehow to understand why such error happens

jlongster commented 2 years ago

sqlite throws this error when locking the file fails, so it can't write to it. In absurd-sql, the only reason why locking would fail is if the change byte check fails here:

https://github.com/jlongster/absurd-sql/blob/master/src/sqlite-util.js#L19

This is run from the upgradeExclusive function which is run by the lock method, which tries to take a readonly IDB transaction to a readwrite one:

https://github.com/jlongster/absurd-sql/blob/master/src/indexeddb/worker.js#L110

What can happen is a write commits during this upgrade unfortunately, because we are opening an entirely new IDB transaction. In that case, the lock must fail because the writes that were made to the db happened in a state that doesn't exist anymore.

I'm still recovering context that I had a month ago; I can't remember if I had a solution for this. One blunt solution would be to always use readwrite transactions so we don't have to upgrade, but means only one query could ever run at once.