From 76f794f167ad777fbbf19fbb1d9e4297e98a204a Mon Sep 17 00:00:00 2001
From: Dmitry <b4tm4n@mail.ru>
Date: Sat, 8 Oct 2022 15:39:54 +0300
Subject: [PATCH] data format in README

---
 README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 50 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index 7639a01..203915f 100644
--- a/README.md
+++ b/README.md
@@ -4,12 +4,58 @@
 
 Исходный файл вопросов: `json.zip`, кодировка `UTF-8`.
 
-Выходная база: файл `./db/data.mdb`, формат базы [LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
-
-Работа с базой выполняется с помощью [ledb](https://crates.io/crates/ledb).
-
 При загрузке базы информация о пакете(файле/турнире) дублируется в каждом вопросе.
 
+## Выходной формат данных
+
+Для хранения данных используется [bincode](https://crates.io/crates/bincode) и [zstd](https://crates.io/crates/zstd).
+Данные вопросов в виде структуры сериализуются через `bincode` в бинарные данные и сжимаются `zstd`. Каждый вопрос сериализуется и сжимается отдельно.
+В файле сжатые данные храняться последовательно, после заголовка файла.
+
+### Заголовок файла
+
+В заголовке хранятся только смещения каждого сжатого блока данных, и дополнительно, смещение указывающее на конец файла.
+Смещение указывается в виде 32-битного беззнакового целового числа `u32`, сохраненного в виде 4-х байтов от младшего к старшему ([Little Endian](https://ru.wikipedia.org/wiki/Порядок_байтов#Порядок_от_младшего_к_старшему)).
+
+Пример заголовка:
+
+~~~
+00:  10 00 00 00
+04:  1A 00 00 00
+08:  2E 00 00 00
+0А:  3A 00 00 00
+~~~
+
+данные:
+
+~~~
+10:  00 00 00 00 00 00 00 00 00 00
+1A:  00 00 00 00 00 00 00 00 00 00
+     00 00 00 00 00 00 00 00 00 00
+2E:  00 00 00 00 00 00 00 00 00 00
+     00 00
+3A:  (EOF)
+~~~
+
+В этом примере сохранены 3 записи:
+
+1. смещение **0x10**, длина **10** байт
+2. смещение **0x1A**, длина **20** байт
+3. смещение **0x2E**, длина **12** байт
+
+Размер файла - 58 байт (0x3A), размер заголовка 16 байт (0x10).
+
+### Чтение данных
+
+Пусть размер записи заголовка в байтах = **`M`**, количество записей в файле = **`N`**.
+
+Тогда для того чтобы:
+
+- Найти **`N`**, нужно прочитать первую запись (**`M`** байт) в начале файла и разделить её значение на **`M`**;
+- Найти элемент данных с индексом **`i`**, нужно последовательно прочитать 2 записи (**`M * 2`** байт), начиная c индекса **`i`** (по смещению в файле: **`i * M`**). Смещением будет значение по индексу **`i`**, длинной - разница между значениями по индексам **`i + 1`** и **`i`**.
+
+Далее для каждого вопроса отдельно предполагается распаковка данных через `zstd` и десериализация через `bincode`.
+
 ## Ссылки
 
 - Источник вопросов: http://db.chgk.info