June 23, 2024

Hermitage: Testing transaction isolation levels

Hermitage is an attempt to nail down precisely what different database systems actually mean with their isolation levels. It's a suite of tests that simulates various concurrency issues — some common, some more obscure — and documents how different databases handle those situations.

The SQL standard tried to define four isolation levels (read uncommitted, read committed, repeatable read and serializable), but its definition is flawed.

https://github.com/ept/hermitage

… let alone any expectation of consistency in DBMS vendors' definitions.

Hermitage's collection of precise literature definitions of isolation levels and anomalies that happen in systems is a handy reference.

The project also provides examples of manually testing each anomaly on various DBMSs, like a lightweight Jepsen run by hand. It's fascinating how clearly a few simple queries run by hand can illustrate a DBMS's ability (or not) to implement complex behavior.

Most of the examples have to be literally run by hand. The FoundationDB examples, however, use a simple bash script to test across two processes with tmux, which I reproduce here for quick reference. (It's also kind of funny, in a wow sense, that FDB is the only DBMS in the project that only implements the strongest level, serializability).

Here's the setup and prompt driver support:

tmux kill-session -t SQL || true
tmux new-session -d -n SQL -s SQL "fdbsqlcli test | tee /tmp/SQL0.out"
tmux split-window -h -t SQL "fdbsqlcli test | tee /tmp/SQL1.out"

count_prompts()
{
  grep "=>" /tmp/SQL$1.out | wc -l
}

wait_for_prompts()
{
  until [ $2 -ne $(count_prompts $1) ]; do
    echo -n '.'
  done
}

tell()
{
  BEFORE=$(count_prompts $1)
  tmux send-keys -t $1 "$2\\;" c-M
  wait_for_prompts $1 $BEFORE
}

And here's one example test:

echo "Running g0 test."
tell 0 "begin"
tell 1 "begin"
tell 0 "update test set value = 11 where id = 1"
tell 1 "update test set value = 12 where id = 1"
tell 0 "update test set value = 21 where id = 2"
tell 0 "commit"
tell 0 "select * from test"
tell 1 "update test set value = 22 where id = 2"
tell 1 "commit" # Rejected with ERROR: FoundationDB commit aborted: 1020 - not_committed
tell 0 "select * from test" # Shows 1 => 11, 2 => 21
tell 1 "select * from test" # Shows 1 => 11, 2 => 21

RSS

Creative Commons License This work is licensed under a Creative Commons Attribution 4.0 International License.