Skip to content

Caveats

Heyang Zhou edited this page Aug 21, 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.

Transactions are optimistic

mvSQLite does not take locks on databases. Instead, it performs optimistic conflict checking at commit time. If a conflict is found, the "database is locked" error is returned from the COMMIT statement. In that case the only reasonable thing to do is ROLLBACK.

Some applications may retry failed COMMIT without checking the error type. This will never succeed when running with mvSQLite.

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 50000 pages (~390MiB with 8KiB page size) 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.