Prolly опубликовала Rust-крейт для content-addressed словарей на prolly-деревьях

Prolly опубликовала Rust-крейт для content-addressed словарей на prolly-деревьях

Prolly, это Rust-крейт (пакет называется prolly-map, импорт выглядит как prolly::{Config, Prolly}), который даёт примитивы для content-addressed («контент-адресуемого») хранения на основе prolly-деревьев: неизменяемый упорядоченный словарь ключ-значение поверх байтовых ключей и значений, где структура узлов детерминированно выводится из содержимого. Это даёт структурное разделение данных между версиями, эффективные diff и merge, а также массовую загрузку.

Основная единица API, Tree: лёгкий персистентный хендл, который хранит корневой CID (content identifier, контент-идентификатор узла, опционален) и конфигурацию чанкинга/кодирования. Сами узлы дерева живут в подключаемом хранилище (Store). Любая операция (put, delete, batch) клонирует и переписывает только затронутый путь или поддерево, записывает новые content-addressed узлы и возвращает новый хендл Tree, старый хендл остаётся рабочим, пока хранилище не удалило нужные ему узлы.

Весь код работы с хранилищем реализован один раз в едином async-first движке без привязки к конкретному рантайму. Асинхронный тип AsyncProlly<S: AsyncStore> использует этот движок напрямую; синхронный Prolly<S: Store> прогоняет ту же логику через встроенный адаптер и, по описанию проекта, не создаёт рантайм, не паркует поток и не диспетчеризует вызовы хранилища в Tokio.

CID каждого узла, это SHA-256-хеш детерминированного байтового представления узла, а разбиение на чанки детерминированно и использует границы по xxHash64. Из-за этого неизменившиеся узлы сохраняют тот же CID между версиями, что даёт структурное разделение, эффективный diff (за счёт отбрасывания одинаковых CID) и трёхстороннее слияние с поддержкой кастомных резолверов конфликтов, а также CRDT-подобные (CRDT, бесконфликтные реплицируемые типы данных) стратегии слияния без конфликтов.

Хранилище подключается через трейт Store: из коробки есть память, SQLite и опциональный RocksDB. Отдельно заявлена «первоклассная» нативная асинхронная поддержка для PostgreSQL, MySQL, Redis, Turso, DynamoDB, Cosmos DB и Spanner, с синхронными фасадами для блокирующих приложений. Есть отдельный адаптер prolly-store-turso, встраивающий нативный асинхронный движок Turso Database для локального хранения и опционально открывающий push/pull с Turso Cloud за отдельным флагом Cargo (feature) с именем sync.

Поверх базового Tree в проекте описаны два фасада более высокого уровня. VersionedMap, транзакционно-безопасная управляемая карта с автоматическими head-указателями, неизменяемыми версиями, выводимыми из содержимого, закреплёнными (pinned) чтениями, доказательствами, сравнением и слиянием версий, резервным копированием и синхронизацией, типизированными кодеками, подписками на изменения, транзакциями между несколькими картами, ограниченной по объёму историей и точечной сборкой мусора. IndexedMap, строгий координатор неуникальных вторичных индексов с публикацией единственного корня атомарно, конечными бюджетами операций, поддержкой разрежённых и множественных значений в индексируемых полях, тремя режимами проекции (KeysOnly/Include/All), точными историческими снимками, устойчивыми закреплениями, безопасной сборкой мусора, структурированной диагностикой и проверяемой ограниченной передачей данных; работает одинаково и в синхронном, и в асинхронном движке.

Отдельный слой API, доказательства (proofs): можно доказать значение или отсутствие одного ключа, нескольких ключей сразу с общими узлами доказательства, целый диапазон, всё под логическим префиксом, страницу курсора или страницу diff между двумя корнями. Проверка пересчитывает CID узлов и сверяет ссылки на дочерние узлы, не обращаясь к самому хранилищу. Канонические байты доказательства можно обернуть в конверт HMAC-SHA256 для обнаружения подмены, привязки к контексту приложения, идентификаторов ключей, nonce и сроков действия, проверка конверта и вложенного доказательства делается одним вызовом.

Для векторного поиска в проекте есть детерминированная ProximityMap, приближённый поиск ближайших соседей (ANN) с точным поиском, отфильтрованным best-first-поиском, локализованным каноническим copy-on-write, вынесением переполняющих векторов во внешнее хранилище, ускорением через SQ8/PQ/HNSW, асинхронным и SIMD-исполнением, типизированной репликацией и сборкой мусора, доказательствами, привязанными к дескриптору индекса. Пример semantic_rag.rs строит полностью офлайновую 1536-мерную ProximityMap, которая хранит корпус и именованный дескриптор в SQLite, переживает перезапуск процесса и на выходе выдаёт ранжированные цитаты для RAG-ответа плюс готовый для LLM блок контекста.

В каталоге примеров, 18 файлов: журнал событий агента (append-heavy), фоновая компакция с учётом retention, базовые операции с картой, массовое построение дерева со статистикой, diff и конфликт-свободное трёхстороннее слияние, резолверы с учётом удалений, вторичные индексы (включая indexed_map_real_world.rs, 14 продакшн-паттернов индексов для статуса, клиента, арендатора, времени, разрежённых и множественных полей, покрывающих, путевых, геопространственных, текстовых и исторических индексов), материализованные представления, CRDT-слияния, память диалогов агента с публикацией через CAS, детерминированные снимки RAG-индекса для воспроизводимых ответов и отката, индексация документов и чанков с векторным «сайдкаром», использование фасада VersionedMap, значения с провенансом (источник, парсер, эмбеддинг, модель, родительский чанк, CID), вынос blob-данных с их сборкой мусора и Git-подобные снимки файловой системы.

Отдельно упомянута интеграция prolly-gluesql, превращающая целую базу GlueSQL в одно транзакционное Prolly-дерево с устойчивыми ветками, неизменяемыми версиями, вторичными индексами, логическими diff, историческими чтениями и опциональным CLI на SQLite. В браузерном приложении 3rd/prolly-tree-visualizer можно выполнять мутации против настоящей WASM-сборки @crabbuild/prolly-wasm и видеть само дерево, пути поиска, структурные различия и историю хранилища.

Для тех, кто хочет Git-подобный слой репозитория поверх prolly-деревьев, в документации описан пока только предложенный (не реализованный) дизайн отдельного крейта prolly-vcs, с бэкенд-нейтральным KvStore-субстратом для коммитов, ссылок (refs), reflog, патчей, оркестрации слияний, планирования синхронизации и сборки мусора на уровне репозитория. Сам prolly-map намеренно остаётся сфокусирован только на неизменяемых упорядоченных словарях.

Ключевые факты

  • Prolly (крейт prolly-map), Rust-библиотека неизменяемых content-addressed упорядоченных словарей на prolly-деревьях: CID узла = SHA-256 от детерминированных байтов узла, чанкинг, по границам xxHash64
  • Один async-first движок работает и как асинхронный AsyncProlly, и как синхронный Prolly через встроенный адаптер, по описанию проекта, без создания рантайма и без диспетчеризации в Tokio на синхронном пути
  • Подключаемое хранилище: память/SQLite/опциональный RocksDB из коробки плюс заявленная нативная асинхронная поддержка PostgreSQL, MySQL, Redis, Turso, DynamoDB, Cosmos DB и Spanner
  • Встроенные проверяемые доказательства (single/multi-key, range, prefix, cursor-page, diff-page) с опциональным HMAC-SHA256-конвертом для защиты от подмены при обмене между сторонами
  • Детерминированная ProximityMap для приближённого поиска соседей (ANN) с ускорением SQ8/PQ/HNSW; пример semantic_rag.rs строит офлайновую 1536-мерную версию поверх SQLite; отдельно, 18 готовых примеров, включая 14 продакшн-паттернов вторичных индексов

Почему это важно

Prolly объединяет в одной Rust-библиотеке то, что разработчики баз данных, систем версионирования и RAG-пайплайнов обычно собирают вручную: content-addressed хранение (как в Git или IPFS) поверх обычного упорядоченного словаря ключ-значение. Детерминированный CID узла и детерминированный чанкинг по xxHash64 означают, что одинаковое содержимое всегда даёт одинаковую структуру дерева, отсюда структурное разделение между версиями, дешёвый diff и предсказуемое трёхстороннее слияние без отдельной базы данных как обязательного слоя.

Кому это важно

В первую очередь, Rust-разработчикам, которые строят собственные хранилища, системы, похожие на контроль версий, или агентные/RAG-пайплайны и которым нужен проверяемый, синхронизируемый, content-addressed индекс. Отдельно это интересно командам, которым важен async-first движок, но которые не хотят тянуть асинхронный рантайм в синхронный код, а также тем, кто строит полностью офлайновый и воспроизводимый векторный поиск для RAG (пример semantic_rag.rs на SQLite без сети).

Как это применить

Крейт подключается как обычная Rust-зависимость (пакет prolly-map, импорт prolly::{Config, Prolly}); дальше выбирается Store, память для тестов, SQLite или RocksDB, либо один из нативных асинхронных адаптеров для конкретной СУБД. Базовые операции put/delete/batch работают напрямую через Tree, а для истории версий и автоматической сборки мусора удобнее фасад VersionedMap; для неуникальных вторичных индексов, IndexedMap. Составные ключи с корректным побайтовым порядком строятся через KeyBuilder (push_u64, push_timestamp_millis и т.д.), а для обмена данными без доверенного доступа к хранилищу используются доказательства (prove_key, prove_range и другие). В каталоге examples/, 18 готовых к запуску сценариев (cargo run --example ...), а браузерный prolly-tree-visualizer позволяет наглядно посмотреть на реальное дерево.

Можно ли доверять

Материал, это документация самого проекта (README на GitHub), опубликованная на Hacker News; за примерно пять часов пост набрал 23 балла и не получил ни одного комментария, то есть независимого обсуждения или проверки заявленных возможностей пока не было. В тексте нет даты релиза, номера версии, лицензии, каких-либо бенчмарков производительности и сравнения с другими content-addressed или CRDT-библиотеками, а также не названа организация, которая ведёт проект, только имена крейта и структура репозитория. Заявленный Git-подобный слой prolly-vcs в тексте прямо назван лишь предложенным дизайном, а не реализованным кодом.

Риски и подводные камни

Из-за отсутствия в источнике версии и лицензии решение о зависимости от крейта требует отдельной проверки самого репозитория. Широкий заявленный набор возможностей, доказательства, ANN-индекс, нативные асинхронные адаптеры сразу под семь СУБД, задел под VCS-слой, типичен для раннего проекта с одним репозиторием и пока нулевым обсуждением, что повышает риск незрелости или нестабильности отдельных частей. Сравнения с устоявшимися альтернативами в Rust-экосистеме источник не даёт, так что оценить реальные преимущества и ограничения Prolly по одной документации нельзя. Слой prolly-vcs использовать нельзя уже сейчас, по тексту это лишь предложенный дизайн, а не рабочий код.