
Фреймворк тестирования транзакционной корректности на основе Jepsen для DuckDB, обнаруживающий аномалии изоляции, такие как нарушения G2-item и SSI, с помощью рандомизированных рабочих нагрузок и проверки Elle.
Тесты Jepsen для базы данных DuckDB. Выполняются локально, а не на удалённом кластере. Тест создаёт набор локальных процессов, которые открывают файл DuckDB локально и взаимодействуют с ним через STDIN/STDOUT.
Это ранний прототип. Он запускается, выполняет транзакции, проверяет их корректность и сообщает об ошибках, но я не уверен, что эти ошибки реальны.
Вам понадобится JDK (21+), Git, Gnuplot, Graphviz, а также Leiningen. В отличие от большинства тестов Jepsen, этот выполняется полностью локально; вам не нужен кластер машин, SSH-ключи и т.д.
sudo apt install openjdk leiningen gnuplot graphviz
brew install openjdk leiningen gnuplot graphviz
Чтобы запустить тест, попробуйте:
lein run test
DuckDB по умолчанию использует (как я подозреваю) Strong SI, и именно это проверяет тест. Однако он допускает G2-item, что является нарушением Repeatable Read. Чтобы продемонстрировать это, попробуйте:
lein run test --time-limit 10 --expected-consistency-model serializable --max-writes-per-key 8
Мы запрашиваем тест на десять секунд, чтобы искать нарушения сериализуемости, и (чтобы сгенерировать маленькие, читаемые примеры) записывать только 8 элементов на ключ. Примеры G2-item должны быть доступны в store/latest/elle/G2-item.
Доступно несколько опций настройки. Справка по различным опциям доступна через lein run test --help.
Результаты тестов записываются в store/<test-name>/<date>/ и симлинкуются как store/latest. Каждая из этих директорий с тестом самодостаточна; вы можете копировать её, архивировать, анализировать позже, удалять и так далее. Также можно запустить веб-сервер для просмотра результатов.
lein run serve
Доступна REPL; см. lein repl.
Тестовый фреймворк находится в этой директории; его файл проекта — project.clj, исходный код — в src/ и так далее.
Тестовый фреймворк запускает отдельную программу, "локальный узел", которая встраивает библиотеку DuckDB и выполняет транзакции против неё. Тестовый фреймворк генерирует случайные транзакции для заданной нагрузки, отправляет их по HTTP на локальный узел и журналирует результаты этих транзакций, проверяя в конце наличие различных аномалий транзакций. Мы ищем Strong Snapshot Isolation с помощью проверяющего компонента Elle (https://github.com/jepsen-io/elle).
Локальный узел имеет небольшой HTTP-сервер, который принимает абстрактные транзакции (например, "прочитать ключ x, затем установить y в 5") от тестового фреймворка и преобразует их в транзакции, выполняемые через JDBC-драйвер DuckDB.
Мы можем внедрить один тип сбоя: завершение процессов.
У нас есть две рабочие нагрузки.
Первая, append, выполняет транзакции, которые добавляют уникальные целые числа в списки и читают содержимое этих списков. Каждый список находится в одной строке, распределённой по нескольким таблицам. Списки идентифицируются по первичному ключу или неиндексированному вторичному ключу. Списки кодируются либо как текстовые поля, либо как списки DuckDB INTEGER[]. Изменение выполняется либо с помощью INSERT ON CONFLICT UPDATE, либо с помощью MERGE INTO.
Вторая, fkey-register, выполняет чтение и запись целочисленных регистров. В DuckDB мы храним эти регистры в двух таблицах. Логическая таблица сопоставляет ключи с физическими идентификаторами с помощью внешнего ключа. Физическая таблица сопоставляет физические идентификаторы со значениями. Для чтения мы используем обычный JOIN между ними. Запись выполняется либо обновлением физической строки, либо созданием новой физической строки и изменением логического указателя на неё. Я только сегодня запустил эту рабочую нагрузку; она работает, но ещё не доработана.
Copyright © 2026 Jepens, LLC
Эта программа и сопутствующие материалы предоставляются на условиях Eclipse Public License 2.0, доступной по адресу https://www.eclipse.org/legal/epl-2.0.
Этот исходный код также может быть предоставлен на следующих вторичных лицензиях, когда для этого выполняются условия, установленные в Eclipse Public License, v. 2.0: GNU General Public License, опубликованная Free Software Foundation, версия 2 Лицензии или (по вашему выбору) любая более поздняя версия, с исключением GNU Classpath Exception, доступным по адресу https://www.gnu.org/software/classpath/license.html.