Files
ARSV/articles/for-asvk/plan.md
T
2026-08-11 03:58:29 +03:00

7.4 KiB
Raw Blame History

Исследование алгоритма разрешения зависимостей в ALT RPM

Замысел и структура статьи

Статья будет как решение одной формальной задачи. В ALT RPM пакет-потребитель задаёт множество требуемых символов R (Requires), а пакет-поставщик - множество предоставляемых символов P (Provides). Зависимость выполнима тогда и только тогда, когда


R \subseteq P.

Явное перечисление тысяч ELF-, Python- и файловых символов раздувает RPM-метаданные, поэтому множества представлены компактными set-строками.

1. Постановка задачи и данные ALT Linux

Ввести обозначения для bpp(b), множеств, хэш функций(H), длин строк и т.д.

Проверяемое программой условие имеет вид


H_b(R)\subseteq H_b(P).

Отмечаем вероятностную природу: из R\subseteq P следует H_b(R)\subseteq H_b(P), поэтому коллизия не создаёт ложного отказа. Обратное неверно: отсутствующий символ может совпасть по хешу с символом из P и дать ложное принятие зависимости.

(Представить данные ниже табличкой) Привести срез Sisyphus x86_64 + noarch: 47 367 пакетов, 14 761 Provides-отношение и 68 857 Requires-отношений. Для 68 198 реально сопоставимых пар медианы равны p=480, r=13, p/r=28.1; p75 - 1886, 37 и 80; p90 - 6219, 104 и 257. В 92.4% пар выполняется p/r\ge 4. Это к теме, почему рассматриваем разреженные множества.

2. Устройство существующей set:-строки

Даём схему формата:

массив строк
  | (Jenkins OAAT)
  v
массив хэшей
  | (qsort)
  v
отсортированный массив хэшей
  | (вычисление разницы между элементами)
  v
массив delta
  | (Rice-Golomb преобразование)
  v
битовый массив
  | (base62 преобразование)
  v
set-строка

Нужно отдельно разобрать заголовок, диапазоны bpp и Mshift, внешний префикс set: и роль Base62: строка должна оставаться допустимым токеном версии RPM. Полезна небольшая иллюстрация на 5-8 символах: исходные имена, хеши, отсортированный массив, дельты, биты кода и итоговая строка. Но. Это много альт-специфики, может настолько глубоко не стоит (хотя и не очень глубоко)

2.1. Хеширование и вероятность коллизий

! Всё ещё нет нормального анализа коллизий

Текущий код использует 32-битный Jenkins OAAT и оставляет b бит. Для модели равномерного независимого хеширования ожидаемое число столкнувшихся пар среди n различных символов равно

(будет мудрёная формула, теория)

В статье формулы дополняем разными табличками по реальным данным из Sisyphus: распределения p,r,b, ожидаемые коллизии, реальные.

(Другие хэши идут далее)

2.2. Кодирование Golomb-Rice

Для отсортированных значений 0\le x_1<\dots<x_n<N определить \delta_1=x_1, \delta_i=x_i-x_{i-1}.

Занимаеи столько и столько бит. В реализации параметр выбирается из b и n приблизительно как


m=b-\lfloor\log_2 n\rfloor-1

с ограничением допустимым диапазоном формата. При средней дельте \mathbb E\delta\approx 2^b/n это даёт ожидаемую длину порядка

...

2.3. Base62

Пояснить экзотичность Base62, его алфавит, принцип кодирования, Z-escape,

3. Построение set:-строк в set.c

(фактически его можно в 2 упихать)

Рассказать путь set_new() - set_add() - set_fini() и отдельно объяснить сложные участки:

(а тут и нет сложного, всё в cmp запихали) Можно рассказать о слитом энкодере, но это есть в переписанной части

В оригинальном варианте используется qsort()

Записать итоговую сложность построения:

...

И доп памяти:

...

4. Сравнение set:-строк

4.1. Обратное декодирование

Кратко пройти обратную цепочку:

set-строка
  | (обратное base62 преобразование)
  v
битовый массив
  | (обратное Rice-Golomb преобразование)
  v
массив delta
  | (вычисление изначальных значений)
  v
массив хэшей

Если bpp различается, более точное множество проецируется на меньшее число бит, после чего снова удаляются дубликаты. (btw, тут есть сортировка слиянием, интересный момент)

4.2. Кэш декодированных множеств

В исходном set.c кэш содержит 256 записей (CACHE_SIZE=256), при вытеснении использует позицию 243 (PIVOT_SIZE=243), free() и два memmove(). Ключ включает короткий fingerprint, а окончательная проверка требует сравнения строки.

  • что именно кэшируется;
  • стоимость линейного поиска, strcmp, перемещений и аллокаций;
  • слабое повторное использование при потоке десятков тысяч различных пар;

(всё надо сильно короче расписывать)

4.3. Проверка включения и «прыжок» по массивам

После декодирования задача сводится к двум возрастающим массивам. Базовый вариант

рассказ про IFLT4 и IFLT8

Худшая асимптотика остаётся


T_{\subseteq}(p,r)=O(p+r),

Полная сложность алгоритма холодного сравнения:

...

При попадании в кэш:

...