mirror of https://github.com/voidlizard/hbs2
117 lines
5.3 KiB
Plaintext
117 lines
5.3 KiB
Plaintext
|
||
Немного про сборку мусора в HBS2
|
||
|
||
Предпосылки:
|
||
|
||
- В блоках / содержимом транзакций может быть всё, что
|
||
угодно. Например, ссылки. Нет возможности заставить
|
||
разработчиков не делать ссылки изнутри бинарных блоков,
|
||
так же как и нет возможности надёжно отслеживать наличие
|
||
рукояток для сборщика мусора для структур данных.
|
||
|
||
Ведь приложения могут быть сторонними, в том числе
|
||
такими, которые вообще не пользуются Haskell и
|
||
библиотеками hbs2.
|
||
|
||
Простой пример: текстовый документ, который содержит
|
||
ссылки в текстовом виде.
|
||
|
||
|
||
Из этого получается, что мы не можем полагаться на наше
|
||
представление об устройстве блоков, и должны переложить это
|
||
на пользователя.
|
||
|
||
Каким образом:
|
||
|
||
Первая мысль: сделать некие pinned refs, в каждой такой
|
||
ссылке - дерево хэшей блоков, и эти блоки не трогать при
|
||
сборке, если есть pinned ref.
|
||
|
||
При сборке мусора использовать только их.
|
||
|
||
Все, что не pinned --- будет собираться.
|
||
|
||
Минус подхода: как быть с хостами, на которых нет pinned
|
||
ref?
|
||
|
||
Если pinned ref делать локальными. Если их не делать
|
||
локальными, то нужен протокол, который крайне похож на
|
||
refchan/reflog.
|
||
|
||
Выглядит не очень.
|
||
|
||
Другой подход: мы действуем в рамках имеющихся ссылок,
|
||
ссылки парсим, контент распознаём при помощи tryDetect.
|
||
|
||
Количество подобных структур стараемся не увеличивать.
|
||
|
||
Pinned refs для надёжности можно сделать тоже.
|
||
|
||
Далее.
|
||
|
||
Может ли сборщик быть инкрементальным?
|
||
|
||
Или даже так: может ли он быть НЕ инкрементальным?
|
||
|
||
Ссылки обновляются всё время, мы не можем "остановить мир"
|
||
без угрозы потери консистентности.
|
||
|
||
Поэтому, как бы поступить?
|
||
|
||
допустим, началась сборка.
|
||
|
||
storage/refs не трогаем, пускай пишут ссылки.
|
||
|
||
storage/blocks делаем файлом.
|
||
|
||
в нём - ссылка на "текущий" каталог блоков.
|
||
|
||
Когда пошёл процесс GC, создаём новый пустой каталог
|
||
blocks-N, где <<N>> - номер <<поколения>>.
|
||
|
||
устанавливаем sorage/blocks на blocks-N.
|
||
|
||
Новые блоки начинают писаться в него.
|
||
|
||
При чтении делаем две вещи:
|
||
|
||
1. инкрементируем "refcount" для каждого блока
|
||
|
||
2. если через какое-то время T refcount для блока /= 0,
|
||
то переносим его в новое поколение.
|
||
|
||
3. если спустя TBD - refcounf == 0, то блок
|
||
можно удалить?
|
||
|
||
мутноватая тема. спустя какое время?
|
||
|
||
Ок, другой вариант. Делаем клон сторейджа полностью, со
|
||
ссылками. собираем мусов в нём, относительно тех ссылок,
|
||
которые в нём зафиксированы.
|
||
|
||
В процессе работы с новым сторейджем действительно выполняем
|
||
копирование из "старого" поколения в новое, если блок
|
||
оказался востребованным в новом поколении.
|
||
|
||
<<Старая>> копия сторейджа иммутабельна, в смысле новые
|
||
ссылки и блоки не создаются.
|
||
|
||
Когда закончили сборку, то просто добавляем все выжившие
|
||
блоки обратно в новое поколение, а временный каталог для
|
||
сборки прибиваем.
|
||
|
||
Развитие идеи в том, что мы не делаем копий блоков, а
|
||
оперируем только ссылками. тогда, допустим, в начале цикла
|
||
сборки мы устанавливаем всем блокам refcount=0, делаем
|
||
снапшот ссылок, сканируем ссылки из этого снапшота и ищем
|
||
выжившие блоки, потом удаляем те, которые не выжили.
|
||
|
||
В процессе удаления хорошо бы понять, что новых ссылок не
|
||
появилось и они не указывают на блоки, которых у нас нет, а
|
||
так же хорошо бы не удалять блоки в процессе обновления
|
||
ссылки.
|
||
|
||
TO BE CONTINUED...
|
||
|
||
|