Skip to content

Caveats

Heyang Zhou edited this page Aug 6, 2022 · 2 revisions

This page documents various behaviors of mvsqlite that are a little different from SQLite. These differences do not cause correctness issues, but may confuse some applications a bit.

The "database is locked" error

To keep compatibility with applications targeting upstream SQLite, mvsqlite enables pessimistic locking by default - when a transaction takes a RESERVED or higher lock on a database, it acquires a one-minute lock lease from mvstore to prevent another transaction from writing to the database. At this point, we have the chance to fail gracefully and return a "database is locked" error if multiple clients want to acquire lock on the same DB. This is a best-effort mechanism to prevent conflict on commit (which causes the process to abort).

Apps should always set busy_timeout = 0 (which is the default) when running with mvsqlite, because on a "database is locked" error it is not possible to retry later and succeed with the same transaction.

No ABA-style idempotency

In case of network errors and crashes, mvsqlite implements AA-style idempotency. Continuously retrying the same commit will keep returning the same successful result. But in case the global commit order is A-B-A, the second attempt of the A commit will conflict and fail.

This means that, in a very rare circumstance as described below:

mvstore crashed during commit, just between FDB commit success and returning the result to the client. Then, another client acquired the database lock, wrote to the database, and committed successfully. Now, the first client retries the commit.

The first client will get a commit conflict and abort. This is the expected behavior, since unbounded idempotency requires too much overhead.

Transaction size and time limit

Currently the max transaction size in mvsqlite is ~390MB and the time limit is 1 hour.

Read latency

SQLite does synchronous "disk" I/O. While we can (and do) concurrently execute write operations, reads from FoundationDB block the SQLite thread.

This is probably fine if you don't expect to get very I/O intensive on a single database, but you may want to enable coroutine in the IoEngine config if you have an event loop outside, so that network I/O won't block the thread.

Clone this wiki locally