|
|
|
|
@ -36,7 +36,8 @@
|
|
|
|
|
|
|
|
|
|
**DB_SYNC_INSTANCE** — одна таблица синхронизации: |
|
|
|
|
- `table_name` — имя SQLite-таблицы (например `msg_GENERAL`) |
|
|
|
|
- `hash` — instance_hash = первые 8 байт SHA256(name || id_be) для маршрутизации сообщений |
|
|
|
|
- `group_id` — идентификатор группы для маршрутизации сообщений |
|
|
|
|
- `sync_gated` — ожидание успешной синхронизации участников; блокирует входящий и исходящий обмен |
|
|
|
|
- `next_id` — автоинкрементный ID записей |
|
|
|
|
- `last_timestamp_ms` — последний использованный timestamp (монотонный) |
|
|
|
|
- `peers[]` — динамический массив SI_PEER (состояние синхронизации с каждым пиром) |
|
|
|
|
@ -50,8 +51,8 @@
|
|
|
|
|
- `verified_pos` — последняя подтверждённая позиция (совпадение хешей) |
|
|
|
|
- `last_peer_count` — последнее известное количество записей у пира |
|
|
|
|
- `sync_state` — 0=idle, 1=syncing, 2=synced |
|
|
|
|
- `sync_start_tb` — время начала синхронизации (для детекции таймаутов) |
|
|
|
|
- `retry_count` — счётчик ретраев (зарезервировано, не используется) |
|
|
|
|
- `sync_start_tb` — время начала/последнего прогресса обмена; устанавливается в обеих ролях |
|
|
|
|
- `retry_count` — число повторов после таймаута |
|
|
|
|
|
|
|
|
|
### 1.2 Структура данных (SQLite) |
|
|
|
|
|
|
|
|
|
@ -128,7 +129,7 @@ chain_hash[0] = SHA256(0x00..00 [32] || id_0 || ts_0 || author_0 || sig_0)
|
|
|
|
|
│ └──────────────┘ └───────────────┘ |
|
|
|
|
│ │ |
|
|
|
|
└─────────────────────────────────────────────┘ |
|
|
|
|
CONN DOWN / ERROR (DB_ERR_NOT_FOUND, DB_ERR_DISABLED) |
|
|
|
|
потеря READY группы / ERROR (NOT_FOUND, DISABLED, NOT_READY) |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### 2.2 Диаграмма протокола синхронизации |
|
|
|
|
@ -137,7 +138,7 @@ chain_hash[0] = SHA256(0x00..00 [32] || id_0 || ts_0 || author_0 || sig_0)
|
|
|
|
|
MASTER (node_id > peer) SLAVE (node_id < peer) |
|
|
|
|
─────────────────────── ────────────────────── |
|
|
|
|
|
|
|
|
|
conn UP → initiate sync |
|
|
|
|
участники синхронизированы + READY группы → initiate sync |
|
|
|
|
│ |
|
|
|
|
├─ INIT_SYNC ──────────────────────────► |
|
|
|
|
│ [my_count:4] │ flush recalc |
|
|
|
|
@ -183,31 +184,29 @@ conn UP → initiate sync
|
|
|
|
|
│ db_sync_init(inst) │ |
|
|
|
|
│ ├─ открывает SQLite (shared или свой chats.db) │ |
|
|
|
|
│ ├─ etcp_bind(inst, 0x20, recv_cb) │ |
|
|
|
|
│ ├─ etcp_add_conn_status_cbk(conn_status) │ |
|
|
|
|
│ └─ запускает peer_check_timer (5s) │ |
|
|
|
|
│ └─ таймер повторов запускается при появлении работы │ |
|
|
|
|
│ │ |
|
|
|
|
│ ... позже, при создании канала ... │ |
|
|
|
|
│ │ |
|
|
|
|
│ db_sync_instance_add(inst, "msg_GENERAL", hash, 1) │ |
|
|
|
|
│ db_sync_instance_add(inst, "msg_GENERAL", group_id) │ |
|
|
|
|
│ ├─ CREATE TABLE IF NOT EXISTS... │ |
|
|
|
|
│ ├─ загружает next_id = MAX(id)+1 │ |
|
|
|
|
│ ├─ db_verify_chain() — проверка целостности цепных хешей │ |
|
|
|
|
│ ├─ запускает TTL-таймер (1 час) │ |
|
|
|
|
│ └─ для всех активных соединений: si_peer_add() + initiate_sync() │ |
|
|
|
|
│ └─ подписка на READY группы; gated=1, сетевого обмена нет │ |
|
|
|
|
├────────────────────────────────────────────────────────────────────────────┤ |
|
|
|
|
│ │ |
|
|
|
|
│ ┌─── DB_SYNC_INSTANCE активен ───────────────────────────────────────────┐│ |
|
|
|
|
│ │ ││ |
|
|
|
|
│ │ conn UP ──► on_conn_up() ││ |
|
|
|
|
│ │ └─ для всех enabled инстансов: ││ |
|
|
|
|
│ │ si_peer_add() → initiate_sync() ││ |
|
|
|
|
│ │ member_sync OK + READY группы → initiate_sync() ││ |
|
|
|
|
│ │ └─ пир должен быть участником именно этой группы ││ |
|
|
|
|
│ │ ││ |
|
|
|
|
│ │ conn DOWN ──► on_conn_down() ││ |
|
|
|
|
│ │ └─ сброс sync_state для всех инстансов ││ |
|
|
|
|
│ │ потеря READY (DOWN/REINIT/LEAVE/ошибка отправки снимка) ││ |
|
|
|
|
│ │ └─ сброс состояния обмена только этой групповой сессии ││ |
|
|
|
|
│ │ ││ |
|
|
|
|
│ │ recv_cb() — приём сообщений ││ |
|
|
|
|
│ │ ├─ извлекает instance_hash, type, payload ││ |
|
|
|
|
│ │ ├─ lazy-register если инстанс не найден ││ |
|
|
|
|
│ │ ├─ извлекает group_id, type, payload ││ |
|
|
|
|
│ │ ├─ проверяет регистрацию, членство, gated и READY ││ |
|
|
|
|
│ │ └─ диспетчеризация по type ││ |
|
|
|
|
│ │ ││ |
|
|
|
|
│ │ peer_check_timer (каждые 5с) ││ |
|
|
|
|
@ -222,6 +221,7 @@ conn UP → initiate sync
|
|
|
|
|
│ └─────────────────────────────────────────────────────────────────────────┘│ |
|
|
|
|
│ │ |
|
|
|
|
│ db_sync_instance_remove(si) │ |
|
|
|
|
│ ├─ снимает подписку на готовность группы │ |
|
|
|
|
│ ├─ отменяет таймеры │ |
|
|
|
|
│ ├─ освобождает peers[] │ |
|
|
|
|
│ └─ сдвигает массив instances[] (таблица БД не удаляется) │ |
|
|
|
|
@ -245,13 +245,13 @@ conn UP → initiate sync
|
|
|
|
|
|
|
|
|
|
``` |
|
|
|
|
┌─────────────────┬──────────────┬──────────────────────────────┐ |
|
|
|
|
│ svc_id (1 byte) │ hash_be (8) │ payload (variable) │ |
|
|
|
|
│ ETCP_RT_ID=0x20 │ instance_hash│ зависит от type │ |
|
|
|
|
│ svc_id (1 byte) │ group_id (8) │ payload (variable) │ |
|
|
|
|
│ ETCP_RT_ID=0x20 │ big-endian │ зависит от type │ |
|
|
|
|
└─────────────────┴──────────────┴──────────────────────────────┘ |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
**instance_hash** = первые 8 байт `SHA256(table_name || id_be)` в big-endian. |
|
|
|
|
Это позволяет приёмной стороне найти `DB_SYNC_INSTANCE` по хешу. |
|
|
|
|
**group_id** — идентификатор группы в big-endian. Приёмная сторона находит |
|
|
|
|
зарегистрированную таблицу этой группы; входящий пакет не создаёт таблицы или callbacks. |
|
|
|
|
|
|
|
|
|
### 3.2 Типы сообщений |
|
|
|
|
|
|
|
|
|
@ -263,7 +263,7 @@ conn UP → initiate sync
|
|
|
|
|
| `DB_MSG_PUSH` | 0x05 | →Peers | Рассылка новой записи всем synced-пирам | |
|
|
|
|
| `DB_MSG_ACK_PUSH` | 0x06 | →Author | Подтверждение получения PUSH | |
|
|
|
|
| `DB_MSG_SYNC_DONE` | 0x07 | ↔ | Завершение синхронизации | |
|
|
|
|
| `DB_MSG_ERROR` | 0x08 | ↔ | Ошибка (NOT_FOUND, DISABLED) | |
|
|
|
|
| `DB_MSG_ERROR` | 0x08 | ↔ | Ошибка (NOT_FOUND, DISABLED, NOT_READY) | |
|
|
|
|
| `DB_MSG_REQUEST_SYNC` | 0x09 | Slave→Master | Запрос на инициацию синхронизации | |
|
|
|
|
|
|
|
|
|
### 3.3 DB_MSG_INIT_SYNC (0x01) |
|
|
|
|
@ -416,10 +416,18 @@ tp=10 → entry[0]: pos=9 (tp - 1)
|
|
|
|
|
Коды ошибок: |
|
|
|
|
| #define | Value | Значение | |
|
|
|
|
|---------|-------|----------| |
|
|
|
|
| `DB_ERR_NOT_FOUND` | 0x01 | Инстанс с таким hash не найден | |
|
|
|
|
| `DB_ERR_NOT_FOUND` | 0x01 | Таблица этой группы не зарегистрирована | |
|
|
|
|
| `DB_ERR_DISABLED` | 0x02 | Инстанс существует, но disabled | |
|
|
|
|
| `DB_ERR_NOT_READY` | 0x03 | Участники или групповая сессия ещё не готовы | |
|
|
|
|
|
|
|
|
|
При получении ERROR сбрасывается `sync_state` пира в 0. |
|
|
|
|
При получении ERROR сбрасываются `sync_state` и ожидание ответа; планируется повтор. |
|
|
|
|
Ошибка отправки также возвращает обмен в IDLE. Обе роли ждут прогресс не более 15 секунд; |
|
|
|
|
таймер повторов работает с периодом 5 секунд, пока есть несинхронизированные READY-пиры. |
|
|
|
|
Появление нового READY запускает обмен независимо от того, работал ли таймер. |
|
|
|
|
|
|
|
|
|
При JOIN запись connection-узла из JOIN_INFO_RESP применяется через `member_sync_apply_record()`: |
|
|
|
|
подписи проверяются, модель и Merkle-индекс обновляются в одной транзакции. JOIN_READY |
|
|
|
|
подтверждает вступление, но история разблокируется только после успешного member_sync. |
|
|
|
|
|
|
|
|
|
### 3.10 DB_MSG_REQUEST_SYNC (0x09) |
|
|
|
|
|
|
|
|
|
|