Для задачи написания **memtable** в key-value базе данных:
**Однозначный выбор: `seize`.**
### Почему `seize` лучше для Memtable?
В контексте БД есть один критический сценарий: **Iterators (Range Scans)**.
Memtable — это не просто хеш-мапа для точечных чтений. Ты будешь делать по ней итераторы (сканирование диапазона ключей) или создавать снапшоты.
1. **Проблема `sdd` (и чистого Epoch-based):**
Если у тебя есть поток, который делает долгий скан (iterator) по memtable, он держит "эпоху". Пока этот поток читает (даже если он медленный), `sdd` **не может освободить ни один удаленный узел** во всей структуре. Если в это время идет активная запись (heavy write workload), у тебя произойдет взрывной рост потребления RAM (memory bloat), потому что сборщик мусора полностью заблокирован одним читателем.
2. **Преимущество `seize`:**
Благодаря алгоритму Hyaline, долгий читатель (итератор) защищает только те конкретные узлы (батчи), на которые он смотрит, и не блокирует глобальную очистку остальных удаленных объектов. Для БД, где важна стабильность latency и предсказуемое потребление памяти при смешанной нагрузке (Read+Write), это критически важно.
---
### Сравнение DX (Developer Experience) и Эргономики
**Победитель по DX: `seize**`.
Он ощущается как современный, переосмысленный `crossbeam-epoch`. API чище, меньше бойлерплейта, и он лучше документирован как *самостоятельная библиотека*, а не как "движок для другой либы".
#### 1. Инициализация и структуры
В `seize` ты работаешь с `Collector`. Это интуитивно понятно:
```rust
// Seize: Создаем коллектор, который можно клонировать и шарить
let collector = seize::Collector::new();
// В lock-free структуре
struct MyMemtable {
collector: seize::Collector,
// ...
}
```
В `sdd` API чуть более сырой, так как он заточен под внутренности `scc`. Там часто приходится жонглировать `sdd::Guard` чуть более явно, и документация предполагает, что ты глубоко понимаешь контекст `scc`.
#### 2. Защита указателей (Guard)
Оба используют паттерн Guard, но `seize` ведет себя более "Растово":
**Seize:**
```rust
let guard = self.collector.enter();
// Получаем atomic pointer
let ptr = some_atomic.load(Ordering::Acquire, &guard);
// Разыменовываем безопасно
let value = unsafe { guard.deref(ptr) }; // Возвращает ссылку &T
```
`seize` имеет очень приятный метод `map`, который позволяет безопасно проецировать лайфтайм гарда на данные, что удобно для итераторов.
**Sdd:**
Также использует `sdd::Guard`, но API методов иногда требует передачи `&Guard` параметром там, где этого не ожидаешь, или возвращает специфические типы, заточенные под оптимизацию, что немного усложняет написание своего кода с нуля.
#### 3. Удаление (Retiring)
Самая важная часть для твоей реализации Lock-Free SkipList или Tree.
**Seize:**
```rust
// Просто и понятно: удаляем, когда никто не смотрит
unsafe { self.collector.retire(ptr, seize::reclaim::boxed::<Node>) };
```
У `seize` очень удобная система кастомных реклеймеров (если ты аллоцируешь не через `Box`, а через свой арена-аллокатор, что популярно в БД, это легко настроить).
### Резюме
Ты пишешь базу данных, а значит тебе нужны **стабильные Latency** и **устойчивость к долгим чтениям** (scan/iter).
* Используй **`seize`**. Это даст тебе лучшую гарантию от OOM (Out Of Memory) при долгих транзакциях чтения и более приятный API для написания сложной структуры вроде SkipList.
* **`sdd`** стоит брать только в том случае, если ты *точно* знаешь, что у тебя не будет долгих итераторов, и тебе нужно выжать последние наносекунды на простых `get/put` операциях (как в кэше). Но для полноценной memtable это риск.