From 16c64ca6261ecefb844b4a7a0d43365ec7a75526 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 26 Oct 2026 12:47:54 +0100 Subject: [PATCH] Describe Merkle index ownership and mark old sync plan historical --- src/chat/merkle_tree.h | 15 +++++++++++---- src/chat/merkle_tz.md | 13 ++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/chat/merkle_tree.h b/src/chat/merkle_tree.h index 307d9e11..a41beeeb 100644 --- a/src/chat/merkle_tree.h +++ b/src/chat/merkle_tree.h @@ -1,7 +1,9 @@ /* merkle_tree — производный индекс хешей в SQLite для сравнения записей модели. * В каждом namespace дерево SHA256: корень (уровень 0), 5 уровней по 32 ветви. * Лист выбирается по старшим 25 битам ключа; его содержимое хеширует модель. - * Пустое поддерево имеет нулевой хеш. БД принадлежит вызывающему. */ + * Пустое поддерево имеет нулевой хеш. БД принадлежит вызывающему. + * Таблица merkle_tree_hash общая для всех наборов; движок передаёт namespace dataset:channel. + * Все вызовы в потоке владельца SQLite; db/ns/выходные буферы обязательны. */ #ifndef MERKLE_TREE_H #define MERKLE_TREE_H @@ -17,14 +19,19 @@ * Возвращает число записей (0 = пустой лист), <0 при ошибке. */ typedef int (*merkle_leaf_hash_fn)(void* ctx, const char* ns, uint8_t level, uint64_t prefix, EVP_MD_CTX* hash); -/* Пересоздать пустой индекс; вызывающий затем восстанавливает его из модели. 0/-1. */ +/* DROP/CREATE всей merkle_tree_hash, включая чужие namespace; не создаёт свою транзакцию. + * Вызывающий затем восстанавливает индекс из моделей. 0/-1. */ int merkle_tree_init(sqlite3* db); -/* Прочитать хеш уровня 0..5; отсутствующий узел даёт нулевой хеш. 0/-1. */ +/* Прочитать хеш уровня 0..5 с нормализованным prefix; отсутствующий узел даёт нули. + * 0/-1; при ошибке сохранность выходного hash не гарантируется. */ int merkle_tree_get(sqlite3* db, const char* ns, uint8_t level, uint64_t prefix, uint8_t hash[MT_HASH_SIZE]); -/* Прочитать 32 дочерних хеша узла уровня 0..4; отсутствующие — нули. 0/-1. */ +/* Прочитать 32 дочерних хеша узла уровня 0..4 с нормализованным prefix; отсутствующие — нули. + * Индекс массива — следующие 5 бит ключа. 0/-1; при ошибке выход может быть частичным. */ int merkle_tree_children(sqlite3* db, const char* ns, uint8_t level, uint64_t prefix, uint8_t hashes[MT_BUCKETS][MT_HASH_SIZE]); /* Пересчитать лист ключа и родителей в транзакции вызывающего. + * SHA256(0x4d || level:1 || данные): leaf_hash добавляет данные листа, родитель — 32 дочерних хеша. + * Пустые узлы удаляются; обход прекращается на первом неизменившемся хеше. * 1 = индекс изменился, 0 = прежний хеш, -1 = ошибка (транзакцию нужно откатить). */ int merkle_tree_update(sqlite3* db, const char* ns, uint64_t key, merkle_leaf_hash_fn leaf_hash, void* ctx); /* Оставить старшие level*5 бит ключа, остальные обнулить; уровень 0 — корень. */ diff --git a/src/chat/merkle_tz.md b/src/chat/merkle_tz.md index e53f27c2..141cf9f7 100644 --- a/src/chat/merkle_tz.md +++ b/src/chat/merkle_tz.md @@ -1,10 +1,13 @@ # ТЗ: событийная синхронизация чата (db_sync + merkle_sync) вместо периодического опроса -> **Статус: реализовано.** Это историческое ТЗ. Актуальное описание модулей — в -> `merkle_sync_doc.md` и `member_sync_doc.md` (рядом с исходниками). Ключевые пункты -> реализованы: событийный peer_check (`db_sync_has_pending_work`/`resume`), per-session -> `out_q` с backpressure и отдельный WAL-таймер в merkle_sync, централизованный путь -> «запись → пересчёт → рассылка» в member_sync (коммиты `d62c370`, `d0784a3`, `a4e73ac`, `4e06db7`). +> **Статус: историческое ТЗ прежней реализации, не описание текущего кода.** +> Актуальное описание протокола 3 — в `merkle_sync_doc.md` и `member_sync_doc.md`. +> Текущий merkle_sync использует два pull-прохода, один подготовленный пакет и waiter +> на сессию; out_q, broadcast/push_update, bg_check и отдельного WAL-таймера в нём нет. +> member_sync после commit уведомляет движок об изменении дерева вместо прямого push. +> Упомянутые ниже функции, строки, «текущее состояние» и критерии относятся к старому этапу. +> Аудит db_sync в проверку member/Merkle от 26.10.2026 не входил; его соответствие +> этому историческому ТЗ здесь не подтверждается. ## 1. Цель После завершения первичной репликации синхронизация должна перейти в **событийный режим**: