# Нежурналируемые таблицы в SQL

## Описание

Задача этого ADR - описать механизм нежурналируемых таблиц в пикодате и проблемы связанные с реализацией. Реализованы они будут как эквивалент *(насколько возможно приближенный)* `UNLOGGED` таблиц постгреса.

На [сайте документации постгреса](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-UNLOGGED) написано следующее:
> ...Data written to unlogged tables **is not written to the write-ahead log**, which makes them considerably faster than ordinary tables. However, they are not crash-safe: an unlogged table is **automatically truncated after a crash or unclean shutdown**. The contents of an unlogged table are also **not replicated to standby servers**. Any indexes created on an unlogged table are automatically unlogged as well.
> 
> This form is not supported for partitioned tables. (Помарка: этот момент мы опустим)

Из чего мы приходим к выводу, что для нежурналируемых таблиц можно использовать [`data-temporary` спейсы тарантула](https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_schema/space_create/#lua-data.space_opts.temporary):
> Space contents are temporary: **changes are not stored in the write-ahead log** and there is **no replication**.
>
> **Note**
>
> Vinyl does not support temporary spaces.

## Проблемы

В любой момент времени таблица **должна** хранить данные только на одном инстансе репликасета, и чтение должно происходить только с него, чтобы таблица имела свойство линеаризируемости. Рассмотрим несколько ситуаций, в которых могут возникнуть проблемы:

1. При двух фейловерах, пользователи могут увидеть, что данные были, потом пропали и позже вернулись. Представим следующий сюжет:
   - В репликасете два инстанса: `A`, `B`, на всех них создана `UNLOGGED` таблица `t` (для удобства, назовем конкретные спейсы с данными на инстансе `t_A`, `t_B` соответственно), но только мастер `A` держит (в `t_A`) записи.
   - Если мастер `A` отключится от репликасета (**не из-за краша**, а, например, из-за сетевого таймаута) и произойдет фейловер, то новым мастером станет `B`, у которого пустой спейс `t_B`. При чтении `t`, будут выдаваться записи из `t_B` - поведение ожидаемо. Однако:
   - Если предыдущий мастер `A` восстановится в репликасет, и произойдет еще один фейловер (неважно по какой причине), то новым мастером станет `A`, и давно записанные (и уже скорее всего неактуальные) данные из `t_A` будут представлены пользователю при чтении из `t`.

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

## Реализация

Для создания таблицы, в параметры создание тарантулового спейса прокидывается параметр `data-temporary = true`, предварительно проверив, что движок хранения не винил и она не распределена глобально.

Краевые случаи, описанные выше, предлагается решать так:
1. В код с демоутом старого мастера будет добавлен транкейт всех нежурналируемых таблиц. Поиск таких таблиц можно производить с помощью фильтрации с поиском по колонке `opts` в `_pico_table`.
    > Для корректной работы, нужно проверить, что файбер, освобождающий память таблицы достаточно йилдит, чтобы не убить инстанс *(см [этот комментарий](https://git.picodata.io/core/picodata/-/merge_requests/2626#note_193613))*
2. В рамках МРа [!2598](https://git.picodata.io/core/picodata/-/merge_requests/2598) была добавлена опция предпочтения чтения с мастера/реплики - нужно будет добавить условие, что если таблица в запросе нежурналируема, он должен быть отправлен на мастер, иначе - вернуть ошибку.