Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I implement file locking in a VFS? #5

Closed
rhashimoto opened this issue May 8, 2021 · 0 comments
Closed

How do I implement file locking in a VFS? #5

rhashimoto opened this issue May 8, 2021 · 0 comments
Labels
faq Frequently asked question

Comments

@rhashimoto
Copy link
Owner

rhashimoto commented May 8, 2021

The example VFS classes that access shareable storage (IndexedDB and OPFS) use the Web Locks API to implement locking. As of December 2021, this API is supported on all the evergreen browsers (Safari recently fixed this Worker bug which should ship in 15.6, but didn't so hopefully the next one).

Although the SQLite locking model allows shared read locks - i.e. multiple database connections can read the same database at the same time to enhance performance - the example classes do not support this so both read and write transactions take an exclusive lock. There is a drop-in replacement locking class, WebLocksShared, which does support the full locking model including shared reads. To use it, you will need to modify the VFS code by changing the import:

import { WebLocksExclusive as WebLocks } from './WebLocks.js';

to this:

import { WebLocksShared as WebLocks } from './WebLocks.js';

If you use a locking implementation that returns SQLITE_BUSY, like WebLocksShared, you must also handle this result in your application code (wa-sqlite throws an Error with code property SQLITE_BUSY and message property "database is locked"). From the SQLite docs for sqlite3_step:

SQLITE_BUSY means that the database engine was unable to acquire the database locks it needs to do its job. If the statement is a COMMIT or occurs outside of an explicit transaction, then you can retry the statement. If the statement is not a COMMIT and occurs within an explicit transaction then you should rollback the transaction before continuing.

Failure to do this will risk deadlock if you have concurrent access (e.g. multiple browser tabs). This added responsibility for applications is the reason why WebLocksShared is not the default implementation in the examples.

The alternative mechanisms to support locking without the Web Locks API are not great. The best of these probably is using a service worker as a central resource to manage locks. You can look at the edit history of this entry for this and other ideas. One important detail is that implementing the full SQLite locking model (i.e. including shared reads) requires upgradeable locks, i.e. from shared to exclusive, and if the upgrade fails the lock state should remain shared.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
faq Frequently asked question
Projects
None yet
Development

No branches or pull requests

1 participant