# Операции: Redis и SQLite
Дополнение к справочнику ключей/таблиц в [routing-and-store-layout.md](routing-and-store-layout.md). Здесь: **дисциплина префикса**, что затрагивают **`clear_*`**, **совместимость версии Redis** и **резервное копирование SQLite** с **WAL**.
---
## Redis: префикс `lnr_*`
Все ключи брокера и глобальный счётчик используют префикс **`lnr_`** (например `lnr_topic:…`, `lnr_connection:…`, `lnr_unique_key`). Так они визуально отделены от прочих ключей в той же логической базе Redis.
**Операционная рекомендация:** запускайте нагрузки liner в **выделенной логической базе Redis** (`SELECT` / путь в URL вида `redis://host/3`) или на выделенном инстансе, чтобы обслуживание (`KEYS`, `FLUSHDB`, мониторинг) не пересекалось с другими приложениями. Библиотека **не** добавляет настраиваемый префикс поверх `lnr_`.
**Обнаружение:** в продакшене предпочитайте **`SCAN`** с шаблоном `lnr_*`, а не **`KEYS`**.
---
## Redis: что делают `clear_*` и чего **не** делают
Обе операции допустимы только когда **клиент не в running** (см. [using-the-api.md](using-the-api.md)).
### `clear_addresses_of_topic`
**Удаляет** **каталог адресов привязки** только для **исходного топика** этого клиента:
| Бэкенд | Эффект |
|--------|--------|
| **Redis** | **`DEL lnr_topic:{source_topic}:addr`** — весь hash для этой строки топика. |
| **SQLite** | **`DELETE FROM topic_addr WHERE topic = ?`** с `topic = source_topic`. |
**Не удаляет:** целочисленные ключи топиков (`lnr_topic:{topic}:key` / таблица `topic_key`), `lnr_unique_key`, любые ключи `lnr_connection:*`, офлайн-очереди или записи **`…:addr` других топиков**.
После вызова другие клиенты могут ещё **кэшировать** старые адреса, пока не вызовут **`refresh_address_topic`** или не переподключатся.
### `clear_stored_messages`
**Удаляет офлайн-очереди и курсоры ack** для listener’ов, записанных для **этой идентичности sender** (`unique_name` + `source_topic`), и сбрасывает карту listener’ов sender’а.
| Бэкенд | Эффект |
|--------|--------|
| **Redis** | Читает **`lnr_sender:{unique}:{source_topic}:listener`**. Для каждой пары `(addr, listener_topic)` находит **`connection_key`**, затем **`DEL lnr_connection:{id}:messages`** и **`DEL lnr_connection:{id}:mess_number`**. В конце **`DEL`** hash **`lnr_sender:…:listener`**. |
| **SQLite** | Тот же поток через **`sender_listener`** → **`connection_key`** → **`DELETE FROM conn_messages`** и **`DELETE FROM conn_mess_number`** для этих ключей, затем **`DELETE FROM sender_listener`** для этого **`sender_key`**. |
**Не удаляет:**
- **Redis:** `lnr_connection:{composite}:key`, `lnr_connection:{id}:sender`, `lnr_topic:*:addr`, `lnr_topic:*:key`, `lnr_unique_key`, `lnr_sender:*` других клиентов или очереди для **ключей соединения**, недостижимых из списка listener’ов этого sender’а (например после ручного редактирования ключей).
- **SQLite:** строки в **`conn_key_map`**, **`conn_sender`**, **`topic_key`**, **`topic_addr`** или **`seq`**.
То есть **`clear_stored_messages`** — **не** полное «стереть всё состояние liner с сервера»; очищаются **персистентные очереди сообщений и последние номера ack**, привязанные к сохранённому набору listener’ов этого sender’а, плюс эта карта listener’ов.
---
## Redis: совместимость версии сервера
Rust-зависимость **`redis = "0.26.1"`** (см. `Cargo.toml`). Брокер использует обычные команды (`GET`, `SET`, `HSET`, `HGETALL`, `DEL`, `INCR`, `RPUSH`, `LLEN`, `LRANGE`, …).
**Важно:** опустошение офлайн-очереди использует **`LPOP` с count** (`load_messages_for_sender`). Такая форма поддерживается с **Redis 6.2**.
**Практика:** используйте **Redis ≥ 6.2**. Более старые серверы могут ломать этот путь. Redis 7.x обычно подходит; крейт не фиксирует максимальную версию — проверяйте в своей среде.
---
## SQLite: один файл, WAL, бэкап
### Файлы на диске
- **Основной путь к БД** — аргумент `Client::new_sqlite` / `lnr_new_client_sqlite`. Необязательный **`receivers_json`** (последний параметр C / последний аргумент Rust) сидирует **`topic_addr`** и **`topic_key`** (проволочный ключ **1** на пира и для вашего `source_topic`), плюс **`conn_sender`** / **`conn_key_map`** для пиров; см. [backends.md](backends.md) (*Изолированный SQLite*).
- **Режим WAL** — SQLite может создавать **`<db>-wal`** и **`<db>-shm`** рядом с основным файлом, пока открыты соединения. Это нормально.
Библиотека при открытии выставляет **`journal_mode=WAL`** и **`busy_timeout`** (см. [backends.md](backends.md)).
### Зачем останавливать клиентов (или «заморозить») перед копированием
Несколько процессов (**клиент + listener + sender** каждый держат файл, и клиентов может быть несколько) удерживают соединения и могут писать. **Наивное копирование** основного `.sqlite` при активных писателях с включённым WAL может дать **несогласованный** бэкап.
**Консервативная процедура бэкапа:**
1. **Остановите все процессы**, держащие файл БД открытым (все клиенты liner с этим путём и любые оболочки `sqlite3`).
2. Копируйте **основной файл** и при наличии **`-wal`** и **`-shm` вместе**, **либо** копируйте только после того, как WAL полностью checkpoint’нут в основной файл (следующий пункт).
3. Либо с **приостановленным** приложением и одним обслуживающим соединением выполните **`PRAGMA wal_checkpoint(TRUNCATE)`**, чтобы WAL слился и обрезался, затем копируйте **только** основной файл БД.
**Онлайн**-варианты (без полной остановки) включают backup API SQLite (`sqlite3_backup_*` / `.backup` в CLI) с корректным учётом WAL — ориентируйтесь на официальную документацию SQLite для вашего инструмента; liner не экспортирует встроенный backup API.
### Восстановление
Восстановите **основной** файл (и согласованные **`-wal`/`-shm`**, если бэкапили набор) на путь, который используют клиенты, со **совместимой схемой** (та же мажорная версия liner, что создавала таблицы). Смешанные копии (основной с одного момента, WAL с другого) рискуют повредить данные.
---
## См. также
- [routing-and-store-layout.md](routing-and-store-layout.md) — полный справочник ключей/таблиц.
- [backends.md](backends.md) — выбор бэкенда, `SQLITE_BUSY`, bundled SQLite.
- [using-the-api.md](using-the-api.md) — когда разрешены `clear_*` (`run` должен быть выключен).