Files
UniversalContainer/docs/architecture.md
T
Efim Beshmenev aea6e330e3 Realisation v1
2026-08-11 22:19:34 +03:00

6.0 KiB
Raw Blame History

Архитектура

Представления

AdaptiveSequence<T> хранит variant<vector<T>, TieredStorage<T>>. Векторный режим предназначен для random/sequential read и append. Tiered-режим состоит из независимо выделенных циклических leaf-блоков (RingBlock) и многоуровневого каталога весов. Каталог строит только необходимое число уровней до заданного максимума; поиск спускается по уровням, а отдельный Fenwick index восстанавливает логическую позицию stable ID.

Текущий TieredStorage — сегментированный исследовательский вариант, а не полная реализация implicit tiered vector с offsets на каждом внутреннем узле. Offsets реально используются внутри leaf, но split/merge меняет массив дескрипторов leaf и перестраивает каталог. Это важное ограничение: некоторые uniform-edit результаты отражают O(number_of_leaves) обслуживание split, а не теоретическую границу полноценного tiered vector.

Адаптивное решение

Storage и policy разделены. Контейнер передаёт OperationSample, policy возвращает:

struct AdaptationDecision {
    StorageMode target;
    TieredConfig tiered_config;
    double expected_saving;
};

Для каждого окна оцениваются vector и все tiered-кандидаты. Главная форма модели edit-cost:

vector: fixed + move_unit * sizeof(T) * (N - position)

tiered: fixed
      + move_unit * sizeof(T) * distance_inside_leaf
      + directory_unit * locality_multiplier * N / leaf
      + lookup(levels)

Первая переменная часть tiered растёт с leaf, вторая — с N/leaf. Поэтому минимум сдвигается к большим блокам при росте N. Для близких последовательных edit-позиций directory multiplier уменьшается: горячая область не создаёт split во множестве разных leaf, и policy выбирает меньший блок.

Для каждого leaf вычисляется минимально достаточная глубина при текущих N и fanout. Сравниваются три альтернативы: остаться, перейти в другое представление, либо перестроить tiered с другой геометрией. Решение требует:

(current_cost - candidate_cost) * forecast
    > rebuild_cost * safety_factor

Для vector→tiered, tiered→vector и tiered→tiered используются разные safety factor. Дополнительно действуют minimum residency, минимальное улучшение shape, EWMA и два подтверждающих окна. После перехода статистическое окно начинается заново. Все коэффициенты находятся в AdaptationConfig и могут заменяться другой policy.

Почему чтение по умолчанию не перестраивает storage

ReadAdaptationMode::deferred лишь записывает статистику. Pending-решение выполняется на следующей мутации или при явном adapt_now(). Это сохраняет важный контракт: обычное чтение не инвалидирует уже выданную ссылку.

eager_nonconst оставлен только как benchmark-эксперимент. Он может выполнить переход вокруг non-const operator[], добавляет проверку в горячий read path и имеет более слабую семантику. Первые измерения не оправдали его как default.

Для read-only фазы, после которой мутаций нет, вызывающий код может поставить явную maintenance point:

values.adapt_now();

Инвалидация

  • const-чтение и сбор статистики в deferred mode ничего не инвалидируют;
  • set() не меняет логические позиции, но ссылка на заменённое значение не должна использоваться как ссылка на старый объект;
  • любая структурная операция в auto mode может также выполнить rebuild, поэтому инвалидирует все references, pointers и iterators;
  • conversion, shape rebuild, force_*, reserve, clear и make_contiguous() инвалидируют всё позиционное;
  • stable ID переживает shifts, split и смену представления; он перестаёт быть живым только после удаления элемента или clear().

Debug-проверка iterator хранит structural generation и бросает logic_error после инвалидирования.

Hash index

AdaptiveSequence<T, true> использует open-addressed flat table value -> {head_id,count}. Дубликаты связаны через компактные intrusive links в ID metadata. find_one означает любой экземпляр. find_all возвращает логически отсортированные позиции и потому может стоить O(k log k), тогда как find_all_ids возвращает unordered stable IDs за O(k).