title |
---|
Структура файлов |
Здесь описаны файлы, которые использует приложение, и формат их содержимого. Используемые типы данных находится в файле с общими типами данных.
Все указанные файлы располагаются в базовой директории приложения. Корень можно задать через конфигурацию. Если явно не передана, то используется рабочая директория приложения.
Общая структура файловой системы выглядит следующим образом (относительно рабочей директории):
taskflux.settings.json
data
tflux.log
log
xxxxxxxxxxxxxxxxxxx.log
tflux.metadata
tflux.snapshot
temp
Представляет собой одну запись из очереди. Состоит из полей: ID, приоритет и данные записи, идущих друг за другом.
Поле | ID | Приоритет | Данные |
---|---|---|---|
Тип | UInt64 | Int64 | Buffer |
Это файл конфигурации приложения. Конфигурация хранится в формате json. Файл не обязателен, и если отсутствует, то ничего прочитано не будет.
Для хранения записей используется сегментированный лог. В этой директории содержатся сегменты этого лога.
Каждый файл лога именуется xxxxxxxxxxxxxxxxxxx.log
, где xxxxxxxxxxxxxxxxxxx
- это индекс (LSN), с которого
начинаются все записи в логе.
Например:
0000000000000000000.log
- самый первый файл сегмента лога, т.к. он начинается с записи, индекс которой 0;0000000000645261357.log
- сегмент, записи которого начинаются с индекса 645261357.
Длина названия фиксированная - 23 = len(LSN +
.log
)
Это файл лога команд. Команды применяются к приложению для восстановления его состояния. Если этого файла нет, то значит никаких команд не применялось. При старте приложения, этот файл создается.
Дальше команды будут называться
Дельта
- изменение в состоянии приложения.
Общий формат файла:
Маркер файла | Версия | Маркер записи | Терм | Чек-сумма | Данные | Маркер конца файла |
---|---|---|---|---|---|---|
Byte[4] | Int32 | Byte[4] | Int32 | UInt32 | Array<Byte> | Byte[4] |
Поля:
Маркер файла
- специальный маркер для изначальной проверки, что переданный файл является логом. Равен0x12 0x76 0xAD 0x55
;Версия
- версия структуры файла;Маркер записи
- маркер, используемый для проверки того, что дальше идет запись. Равен0xAA 0xF5 0x34 0xC4
;Терм
- терм, которому принадлежит запись;Чек-сумма
- чек-сумма, подсчитанная для данных дельты (следующее поле, без длины). Вычисляется для данных в полеДанные
(без длины);Данные
- содержимое команды, которое мы храним.Маркер конца файла
- маркерные байты, которые означают окончание файла лога. Равен0x00 0x00 0x00 0x00
.
Поля Маркер-записи
, Терм
, Чек-сумма
, Данные
образуют одну запись.
Эти поля идут в файле последовательно друг за другом.
Для их разделения используется маркер записи, а не отдельное поле длины, для большей производительности.
Поле Данные
содержит данные команды, которые будут использоваться для восстановления состояния приложения.
Каждая запись называется Дельта
, т.к. означает дельту изменения состояния (вставка, удаление и т.д.).
Оно содержит в себе как нужный маркер команды, так и необходимые данные.
Структура данных содержится далее, в секции дельта.
Замечание: поле
Данные
должно быть выравнено по границе 4 байт. Если длина содержимого данных не кратна 4 байтам, то в конец добавляются нулевые байты до размера кратного 4 байтам. Примеры:
Длина данных (байты) Дополнение (байты) 1 3 34 2 1024 0 2051 1
Файлы сегментов могут создаваться и удаляться в процессе работы:
- При запуске приложения в первый раз создается файл сегмента
0000000000000000000.log
; - Когда размер файла сегмента превышает указанный лимит, то создается очередной файл
сегмента -
CURRENT LAST LSN + 1
+.log
, гдеCURRENT LAST LSN
- последний LSN текущего сегмента; - При откате незакоммиченных записей лога, файлы могут удаляться, если требуется переписать данные из уже законченного сегмента.
Для файлов сегментов указываются 2 параметра:
soft limit
- мягкая граница размера файла в байтах.hard limit
- жесткая граница размера файла в байтах.
Новые файлы сегментов создаются при соблюдении любого следующего условия:
soft limit < current segment size && commit index == last segment LSN
;hard limit < current segment size
.
Т.е. новый файл создается:
- либо когда мягкий предел размера сегмента превышен и все записи закоммичены;
- либо когда превышен жесткий предел размера сегмента.
Дельта : Изменение в состоянии приложения
На данный момент поддерживаются следующие дельты:
CreateQueue
- Создание очередиDeleteQueue
- Удаление очередиAddRecord
- Добавление записи в очередьRemoveRecord
- Удаление записи из очереди
Для каждого из типа определены собственные форматы данных и маркеры.
Создание новой очереди.
Формат:
Маркер | Название очереди | Реализация | Максимальный размер очереди | Максимальный размер сообщения | Диапазон ключей |
---|---|---|---|---|---|
Byte('C') | QueueName | Int32 | Int32 | Int32 | Nullable<Pair<Int64, Int64>> |
Поле Реализация
содержит код реализации, который нужно использовать
Удаление существующей очереди
Формат:
Маркер | Название очереди |
---|---|
Byte('D') | QueueName |
Добавить в очередь новую запись
Формат:
Маркер | Название очереди | Ключ | Сообщение |
---|---|---|---|
Byte('A') | QueueName | Int64 | Buffer |
Удалить запись из очереди по указанному Id
Маркер | Название очереди | Id |
---|---|---|
Byte('R') | QueueName | UInt64 |
В этом файле хранится готовый слепок приложения - все очереди с их параметрами и записями.
Содержит данные о всех существовавших очередях в приложении на момент создания файла. Порядок хранения очередей не задается - могут идти в любом.
Структура файла:
Маркер | Последний индекс | Последний терм | Состояние | Чек-сумма |
---|---|---|---|---|
Byte[4] | Int32 | Int32 | Buffer | Byte[4] |
Поля:
Маркер
- маркер файла снапшота. Равен0xB6 0x38 0x0F 0xC9
;Последний индекс
- индекс последней примененной команды;Последний терм
- терм последней примененной команды;Состояние
- данные снапшота, представляется массивом байт;Чек-сумма
- чек-сумма, вычисленная по всем данным поляСостояние
(кроме длины);
Само поле Состояние
состоит из сериализованного массива структур QueueData
, т.е. там хранится Array\<QueueData>
.
Эта структура представляет описание одной очереди вместе с ее записями.
Формат структуры QueueData
представлен ниже:
Название очереди | Реализация | Последний ID | Максимальный размер очереди | Максимальный размер сообщения | Диапазон ключей | Данные очереди |
---|---|---|---|---|---|---|
QueueName | Int32 | UInt64 | Int32 | Int32 | Nullable<Pair<Int64, Int64>> | Array<QueueRecord> |
Поле Очередь
содержит повторяющиеся сериализованные значения всех элементов очереди - пара приоритет-нагрузка.
Количество элементов определяется полем Размер очереди
.
Поля:
Название очереди
- название очередиРеализация
- код реализации очередиПоследний ID
- ID последней записи, который был назначен
Замечание: данные в очереди необязательно должны быть в правильной очередности (порядок приоритета), очередь восстанавливается во время старта из этих значений.
В этом файле содержатся метаданные, которые необходимы для корректной работы узла в кластере.
Файл занимает немного места и состоит из нескольких фиксированных по размеру полей.
Структура файла:
Маркер | Версия | Терм | Голос | Чек-сумма |
---|---|---|---|---|
Byte[4] | Int32 | Int32 | Int32 | Byte[4] |
Поля:
Маркер
- специальный маркер файла. Равен0x5A 0x6E 0xA0 0x12
;Версия
- версия файла;Терм
- последний сохраненный терм;Голос
- значение ID узла, за который голосовали последний раз.-1
означает отсутствие голоса. Другие отрицательные значения не принимаются;Чек-сумма
- чек-сумма, вычисленная для файла. Вычисляется по всем полям, кромеМаркер
.
Эта директория необходима для хранения временных файлов. Например:
- Временные файлы лога при создании снапшота;
- Новые снапшоты, которые принимаются от других узлов.
На все файлы накладываются следующие условия:
- Если файл существует на момент старта приложения, то либо файл должен быть в корректном состоянии, либо пуст (размер 0);
- Для расчета чек-суммы (где есть соответствующее поле) используется алгоритм описанный в сетевом протоколе.