103 lines
6.0 KiB
Markdown
103 lines
6.0 KiB
Markdown
# Архитектура
|
||
|
||
## Представления
|
||
|
||
`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
|
||
возвращает:
|
||
|
||
```cpp
|
||
struct AdaptationDecision {
|
||
StorageMode target;
|
||
TieredConfig tiered_config;
|
||
double expected_saving;
|
||
};
|
||
```
|
||
|
||
Для каждого окна оцениваются vector и все tiered-кандидаты. Главная форма
|
||
модели edit-cost:
|
||
|
||
```text
|
||
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 с другой геометрией. Решение требует:
|
||
|
||
```text
|
||
(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:
|
||
|
||
```cpp
|
||
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).
|