Найти в Дзене
10 подписчиков

Где-то три года назад я хотел построить свой лунапарк (пытался найти какой-нибудь референс на концепцию, пролистал до начала канала, не нашёл ничего конкретного, только сумбурный бред размазанный тонким слоем по постам). Рабочее название того лунапарка было Prism, сейчас переименовал его в Diffbelt, упростил концепцию и... за двое суток реализовал прототип.


... прототип правда ну совсем урезаный, работает только в in-memory виде, транзакционность только на уровне всей базы, но мой простенький тест проходит и слава Коту.

«я джва года ждал», суть такова:

◾️ Это база данных

◾️ key-value, иммутабельная, версионированная

◾️ База состоит из набора коллекций

◾️ Коллекции состоят из:

◾️ ◾️ Набора из записей вида {key, value, generationId}

◾️ ◾️ Идентификатора текущего и следующего поколения

◾️ ◾️ Набора reader'ов

◾️ Reader'ы это {readerId, generationId, collectionId}

◾️ Коллекции бывают двух видов:

◾️ ◾️ «Автоматические» — коллекции для добавления исходных данных, в них после запросов на мутации (добавление/изменение/удаление ключей) через какое-то время следующее поколение сменит текущее и будет запланировано следующее

◾️ ◾️ «Ручные» — производные коллекции, в которых можно&нужно управлять созданием поколений самостоятельно

🔻 В ручных коллекциях мы можем завести сколько нужно reader'ов указывающих на другие коллекции (будем называть их зависимостями), которые запомнят текущее поколение тех коллекций

◾️ Затем мы можем попросить ручную коллекцию начать новое поколение

◾️ Когда поколение начато, мы можем вычитать коллекции-зависимости целиком и записать в ручную коллекцию некоторый результат являющийся производным от содержимого коллекций-зависимостей

◾️ Когда закончили вычитывать зависимости и записали всё что хотели — можем закоммитить поколение, после чего чтения из этой коллекции будут отображать новые данные

🔸 После того, как в коллекциях-зависимостях произошли какие-то изменения, мы можем снова начать новое поколение

◾️ После чего просим дать нам diff'ы коллекций-зависимостей начиная с generationId сохранённого в соответствующем reader'е до актуального

◾️ Накатываем diff'ы на новое поколение

◾️ Коммитим поколение, но на этот раз говорим «а ещё вместе с коммитом обнови вот эти reader'ы на такие вот generationId»

◾️ Ну и теперь когда мы будем повторять с пункта 🔸, мы будем накатывать только те изменения, которых мы ещё не видели

◾️ Если в какой-то из моментов мы покрешились по каким-то причинам, то мы можем просто выкинуть начатое поколение и начать заново (мы знаем, на каком состоянии мы были до этого и никакие данные не затирались)

◾️ Если мы знаем что у нас вообще данные неконсистентны потому что у нас всю жизнь баг в коде сидел — можем радикально начать с пункта 🔻 и пересчитать все данные по-новой (удалив всё в новом поколении, а затем добавив правильно посчитанное)

◾️ Данные старых поколений удаляются тогда, когда на них не указывает ни один из reader'ов (этого я втираю, ещё не реализовал, но должно быть так)

Занудновато получилось, вот кейс который я в первом тесте написал:

◾️ Есть коллекция A в которой ключи это секунды, а значения это числа

◾️ Есть коллекция B в которой ключи это (секунды - (секунды % 60)), т.е. каждая минута, а значения — сумма чисел из коллекции A за такой интервал

◾️ У коллекции B есть reader коллекции A

◾️ Когда мы что-то добавляем в коллекцию A, через какое-то время это консистентно отображается на коллекцию B

◾️ Происходит это процессом, который наблюдает за изменениями идентификатора поколения A и когда видит, что он стал посвежее — стартует всю эту штуку с 🔸, смотрит на то какие числа были добавлены/изменены/удалены, вычисляет разницу за минуту и применяет изменения

◾️ Больше занудства: причём изменения он применяет поточно и идемпотентно, когда посчитал разницу из диффа для минутного диапазона он берёт значение из старой версии, меняет её и сохраняет в новую (т.е. тут допускается покрешиться где-то посередине чтения диффа, а затем повторить с момента который мы последним помним что точно корректно обработали)

Надеюсь более или менее понятно, что оно умеет.

#diffbelt
3 минуты