Выпущена версия Vitastor 3.2.0

31.08.2026

Это корректирующий релиз, и большая часть исправлений внесена благодаря новому подходу к тестированию: хаос-тесту блочного хранилища, который теперь запускается в CI при каждом изменении.

Также спасибо Юрию Лунёву из MIND Software за другую часть исправлений.

Новые функции

Кроме хаос-теста и исправлений стабильности, в релиз также входит несколько новых функций:

  • Онлайн-изменение размера для ublk, NBD, QEMU и VDUSE, плюс онлайн-расширение на ноде в CSI для всех типов томов. То есть, размер подключённых устройств теперь меняется автоматически после vitastor-cli modify --resize.
  • Хелперы монтирования VitastorFS mount.vitastorfs и mount.vitastorblk — ФС теперь можно монтировать из /etc/fstab.
  • Теперь можно настраивать NFS --readahead в команде монтирования: увеличение ускоряет чтение в 2-3 раза.
  • Снова разрешено использование клиента без io_uring (опция use_sync_send_recv) — при включённом RDMA это ничем не хуже по производительности.
  • Добавлен обработчик пути /healthcheck в мониторе.
  • Серверы NBD, ublk и NFS теперь обрабатывают SIGINT и SIGTERM и завершаются плавно.
  • В CSI теперь используются, а в документации VitastorFS предлагаются безопасные опции монтирования soft,sync.
  • В первую очередь это касается старого хранилища, однако: больше не допускаются ситуации, в которых операции записи могут зависнуть навсегда из-за исчерпании места в журнале. Теперь в таких случаях хранилище возвращает EAGAIN, OSD обрабатывают эту ошибку, а обязанность повторить запрос возлагается на клиента. Исправление меняет логику обработки ошибок на стороне клиента, поэтому при использовании старого хранилища рекомендуется обновить клиентов.

Хаос-тестирование

Блочное хранилище теперь покрыто тестом в стиле DST (детерминистический симуляционный тест), управляемым сидом. Хранилище запускается в симулированной среде: io_uring отдаёт завершения не по порядку и со случайной задержкой, энергозависимый кэш диска при симулированном отключении питания теряет случайное подмножество своего содержимого, а записи, летевшие в этот момент, доезжают целиком, частично (рвутся по границе сектора) или не доезжают вовсе. Само хранилище при этом настоящее — журнал, метаданные, флашер, компактизация, контрольные суммы. Рядом ведётся модель записанных данных и после каждого отключения питания восстановленное состояние сверяется с ней, включая битмапы объектов.

Тест запускает обе реализации хранилища на одной и той же нагрузке в 24 конфигурациях: старое и новое хранилище, серверные и десктопные диски (с конденсаторами и без), двухфазные (EC) и мгновенные (реплицированные) записи, контрольные суммы выключены / включены с блоком 4 КБ / 16 КБ. CI прогоняет 200 сидов на каждой сборке, по процессу на сид, и печатает список упавших сидов — после чего любое падение можно чётко воспроизвести командой test_blockstore_chaos --seed N.

Для понимания масштаба: на хранилище из 3.1.0 текущий хаос-тест падает на 83 сидах из 200 без учёта утечек памяти и строгого запрета одновременной записи одного и того же сектора, а с их учётом - на 97 сидах из 200.

  #  конфигурация                           сломано/всего
  8  v2 fsync=0 csum=16384 instant          4/9
  9  v2 fsync=1 csum=none  instant          1/8
 10  v2 fsync=1 csum=4096  instant          1/8
 12  v1 fsync=0 csum=none  two-phase        8/8
 13  v1 fsync=0 csum=4096  two-phase        8/8
 14  v1 fsync=0 csum=16384 two-phase        8/8
 15  v1 fsync=1 csum=none  two-phase        8/8
 16  v1 fsync=1 csum=4096  two-phase        8/8
 17  v1 fsync=1 csum=16384 two-phase        8/8
 18  v1 fsync=0 csum=none  instant          8/8
 19  v1 fsync=0 csum=4096  instant          8/8
 20  v1 fsync=0 csum=16384 instant          8/8
 21  v1 fsync=1 csum=none  instant          1/8
 22  v1 fsync=1 csum=4096  instant          3/8
 23  v1 fsync=1 csum=16384 instant          8/8

Доминирующие проблемы:

  • Старое хранилище: OSD аварийно завершается с BUG: Unexpected dirty_entry ... unstable state during flush — на каждом сиде всех шести двухфазных (EC) конфигураций — или отказывается стартовать с Fatal error (bug): big_write journal_entry was allocated over another object.
  • Новое хранилище: после отключения питания объект становится нечитаемым с ошибкой контрольной суммы (retval=-33), а в одном случае возвращается с данными другого объекта.

Теперь же все эти проблемы исправлены.

Нужно ли обновляться?

  • Старое хранилище (meta_format 2, OSD, созданные до 3.0) — да, независимо от железа. Оно падало в хаос-тесте во всех конфигурациях, включая рекомендуемые.
  • Диски без конденсаторов, десктопные (immediate_commit=none) — да. В обоих версиях хранилища исправлены значительные баги, связанные с SYNC, такие, как потеря подтверждённых данных при отключении питания.
  • Контрольные суммы с блоком больше 4 КБ (csum_block_size) — да, и это касается обоих хранилищ. Чтения частично записанных блоков могли падать с ложной ошибкой контрольной суммы на совершенно целых данных, а у нового хранилища объект мог стать нечитаемым после отключения питания даже на серверных SSD.
  • Новое хранилище на серверных SSD с конденсаторами, чексуммы выключены или 4 КБ — обновление рекомендуется, но не срочно. Хаос-тест не поймал новое хранилище на падении в этой в конфигурации на 3.1.0, а исправления ниже для неё закрывают более редкие ситуации.

Исправления для конфигурации по умолчанию (серверные SSD, суммы выключены или 4 КБ)

Старое хранилище (meta_format 2):

  • При перезапуске после обрыва журнала на записи, находящейся в начале блока, запись журнала продолжалась некорректно, так, что новые записи не учитывались при повторном быстром перезапуске OSD (раньше полного цикла записи всего журнала).
  • Порядок нескольких одновременных записей в журнал учитывался некорректно, а значит, запись могла подтвердиться раньше успешного журналирования.
  • Две записи одного и того же журнального сектора могли лететь одновременно. Теоретически устройство могло выполнить их в произвольном порядке и повредить журнал.
  • Счётчики занятого места объектов и OSD могли уйти в минус после перезапуска.
  • При остановке OSD метаданные грязной записи освобождались через free, не будучи указателем и портили кучу. Заодно исправлено несколько утечек памяти; тесты теперь гоняются с включённой проверкой на утечки (ранее в CI проверка была отключена).
  • Чтения не работали вообще, вместо этого роняя OSD с ошибкой деления на ноль, при выключенных контрольных суммах и при выключенном inmemory_journal.
  • При выключенном inmemory_journal неизменённый журнальный сектор — или даже суперблок журнала — мог быть перезаписан некорректными данными, после чего OSD отказался бы стартовать.

Новое хранилище (meta_format 3):

  • При отключении питания во время компактификации могли пропадать объекты с базовой записью типа big_intent, если их данные были мутированы, а метаданные не были обновлены. Для серверных SSD данная ситуация редка, но в теории возможна.

Исправления для дисков без конденсаторов (immediate_commit=none)

Старое хранилище:

  • Исправлено несколько зависаний и падений вокруг удалений, откатов и синков — откат версии, под которой лежит более новая незасинканная запись, висел вечно; удаление могло уронить assert во флашере или при записи журнала; удаление одновременно с синком портило внутреннее состояние.
  • Старое хранилище: накат журнала мог воскресить устаревшие записи удалённого объекта или отказаться стартовать с “big_write journal_entry was allocated over another object”.

Новое хранилище:

  • SYNC мог вернуть успех, ничего не сбросив (#77, спасибо Changwei Ye). Если два клиента синкались одновременно, второй забирал счётчик первого и возвращался сразу, поэтому данные, подтверждённые как засинканные, могли потеряться при отключении питания.
  • Запись могла потеряться, а более новая запись того же объекта — уцелеть, и объект оставался на версии, у которой нет предшественника, то есть содержал смесь двух версий. Теперь все ещё не зафиксированные на диске записи одного объекта записываются в тот же метаблок и не могут исчезнуть независимо.
  • Объект мог пропасть целиком после перезапуска, если питание пропадало в середине его компактификации.
  • Новые запросы записи могли просто зависнуть после перезапуска.

Исправления для блока контрольных сумм больше 4 КБ

Только старое хранилище:

  • Чтения частично записанных больших записей сверяли контрольную сумму с данными на диске вместо явного нулевого дополнения, с которым сумма считалась — поэтому чтение могло упасть с ложной ошибкой суммы на целых данных. Без этого исправления падает каждый сид хаос-теста в затронутых конфигурациях.
  • Два падения во время компактификации в fill_partial_checksum_blocks().
  • Падение в read_bitmap() при чтении удалённой версии объекта.
  • Падения с assert(fulfilled == read_op->len) в dequeue_read().

Прочие исправления

  • PG теперь перепириваются при изменении pg_minsize.
  • Исправлен скрипт make-etcd с IPv4 и автоопределение пула в snap-create (и то, и то сломано в 3.1.0).
  • vitastor-dd теперь определяет seekable-ввод и вывод, включая stdin/stdout.
  • В VitastorFS исправлены смещение cookie в READDIR, переполнение стека при длинном READDIR из кэша, добавлено ограничение размера кэша итераторов.
  • Исправлено потенциальное падение при неполном приёме из сокета, в теории в редких случаях возможном даже с используемым флагом MSG_WAITALL.
  • Исправлено падение при инициализации RDMA-CM, когда RDMA-CM недоступен.
  • Исправлено падение клиента при отсутствующей конфигурации пула или PG во время выполнения запроса.
  • Конфигурации, в которых запись метаданных больше meta_block_size, теперь отклоняются при инициализации OSD, а не приводят к делению на ноль в vitastor-disk.
  • Отклоняются вывернутые диапазоны в DESCRIBE; защищён поиск inode при чтении цепочек.
  • Также отклоняется WRITE_STABLE поверх нестабильного WRITE в старом хранилище (неиспользуемый OSD и с неопределённым поведением).
  • Исправлено несколько замечаний UBSan и санитайзеров: отрицательные смещения на диске, арифметика с нулевым указателем, memset нулевой длины по NULL, неинициализированная память.
  • Исправлен ряд краевых случаев в мессенджере: идентификаторы клиентов, outbox_push для уже несуществующего клиента, некорректный начальный EPOLLIN в HTTP-клиенте.

Полный лог коммитов доступен по ссылке на релиз ниже.

Ссылки