Перейти к содержанию

Файберы, потоки и многозадачность

Общие сведения

Данный раздел содержит описание модели кооперативной многозадачности в Picodata. Эти сведения помогут разработчикам создавать расширения для Picodata на языке Rust.

См. также:

Файберы и устройство потоков

Внутри основного процесса picodata существует несколько потоков ОС:

  • tx thread — основной поток для выполнения SQL-команд и в целом логики, связанной с действиями пользователя. tx thread большую часть времени выполняется на одном и том же ядре ЦП, редко совершает операции ввода/вывода (I/O) и, соответственно, реже привлекает внимание планировщика ОС
  • некоторое количество вспомогательных потоков (например, WAL, поток репликации и т.д.), в большей степени связанных с операциями ввода/вывода накопителя или сети

Понятие файбера относится к реализации кооперативной многозадачности в Picodata, т.е. к возможности выполнять асинхронно несколько операций внутри одного потока ОС.

Файберы — наборы инструкций, которые также называются легковесными потоками, выполняющимися внутри tx thread и остальных потоков. Активность в СУБД происходит в виде сменяющих друг друга файберов, которые выполняются асинхронно и под управлением внутреннего планировщика Picodata:

Schedulers

Все события внутри tx thread основаны не неблокирующих системных вызовах, за которыми следит libev. Таким образом, в рамках tx thread, Picodata является однопоточной СУБД с собственным легковесным планировщиком. Это обеспечивает лучшую управляемость и решает проблемы, связанные с распределенной природой СУБД.

Каждый файбер исполняет определенный набор инструкций. Как правило, это отдельная полезная функция, например установка сетевого подключения, исполнение пользовательской SQL-команды и т.д. Выполнив свою функцию, файбер инициирует событие переключения — и в этот момент меняет свое состояние.

Состояния файбера

Любой запущенный файбер может быть в одном из следующих состояний:

  • running — исполняется
  • suspended — приостановлен в ожидании какого-то события
  • ready — готов продолжить работу
  • dead — завершен

В каждый момент времени в состоянии running может находиться не более 1 файбера.

Жизненный цикл файбера

Процесс исполнения кода с учетом передачи управления между файберами показан на схеме ниже.

Fibers

Переключения (yields)

Переключением мы называем особое событие в контексте кооперативной многозадачности, при котором управление внутри потока переходит от одного файбера к другому (последний должен быть в состоянии ready).

Передача управления между файберами

Инициатором переключения всегда выступает сам файбер, в коде которого для этого происходит вызов соответствующей функции. В этот момент текущий файбер изменяет свое состояние на suspended или ready, а следующий файбер переходит из состояния ready в состояние running.

При передаче управления используется первым в очереди файбер в состоянии ready. Если очередь из таких файберов заканчивается, управление возвращается циклу событий (event loop).

Избегание блокировок переключения и голодания

Если файбер не передает управление другим файберам в течение долгого времени, это приводит к голоданию (starvation) остальных файберов. Они не смогут продолжить работу и вызовут увеличение latency вплоть до полного зависания инстанса. Гарантированно выйти из ситуации зависания можно путем перезагрузки инстанса.