# Заморозка и блокировка таблицы

"Заморозка" таблицы полезна, когда вы хотите сделать физическую копию или резервную копию. Она помечает файлы таблицы как замороженные и показывает, где они хранятся. После заморозки вы можете безопасно скопировать эти файлы в другое место. Вы по-прежнему можете добавлять новые документы в замороженную таблицу, пока она не достигнет `rt_mem_limit`, но эти новые данные остаются в памяти и не записываются на диск, пока таблица не будет разморожена. Если таблица превысит `rt_mem_limit`, все изменения приостанавливаются до её разморозки. Если демон неожиданно остановится, любые несохранённые данные будут восстановлены из бинарного лога.

"Блокировка" таблицы полезна для логических резервных копий. Она не останавливает внутренние задачи обслуживания, такие как операции слияния дисковых чанков или запись RAM-чанка на диск. Она блокирует только операции записи. Это означает, что вы не можете вставлять, заменять или обновлять данные в заблокированной таблице. Это полезно для таких инструментов, как `mysqldump`, потому что блокировка гарантирует логическую согласованность данных. Например, без блокировки, если вы замените документ во время дампа, старая версия может уже быть в дампе, а новая версия также может появиться позже, обе с одним и тем же идентификатором документа. Блокировка таблицы предотвращает такую ситуацию.


## Заморозка таблицы
<!-- example freeze -->

```sql
FREEZE tbl1[, tbl2, ...]
```

`FREEZE` подготавливает таблицу реального времени/обычную таблицу для безопасного [резервного копирования](../Securing_and_compacting_a_table/Backup_and_restore.md). В частности, она:
1. Деактивирует уплотнение таблицы. Если таблица в данный момент уплотняется, `FREEZE` корректно прервёт этот процесс.
2. Передаёт текущий RAM-чанк в дисковый чанк.
3. Сбрасывает атрибуты.
4. Отключает неявные операции, которые могут изменить дисковые файлы.
5. Увеличивает счётчик блокировок таблицы.
6. Показывает фактический список файлов, связанных с таблицей.

Если таблица уже заморожена (заблокирована), `FREEZE`:
1. Увеличит счётчик блокировок таблицы.
2. Покажет фактический список файлов, связанных с таблицей.

Встроенный инструмент [manticore-backup](../Securing_and_compacting_a_table/Backup_and_restore.md) использует `FREEZE` для обеспечения согласованности данных. Вы можете сделать то же самое, если хотите создать собственное решение для резервного копирования или вам нужно заморозить таблицы по другим причинам. Просто выполните следующие шаги:
1. Выполните `FREEZE` для таблицы (или нескольких).
2. Захватите вывод команды `FREEZE` и создайте резервную копию указанных файлов.
3. Выполните `UNFREEZE` для таблицы(таблиц) по завершении.

<!-- request Example -->
```sql
FREEZE t;
```

<!-- response Example -->
```sql
+-------------------+---------------------------------+
| file              | normalized                      |
+-------------------+---------------------------------+
| data/t/t.0.spa    | /work/anytest/data/t/t.0.spa    |
| data/t/t.0.spd    | /work/anytest/data/t/t.0.spd    |
| data/t/t.0.spds   | /work/anytest/data/t/t.0.spds   |
| data/t/t.0.spe    | /work/anytest/data/t/t.0.spe    |
| data/t/t.0.sph    | /work/anytest/data/t/t.0.sph    |
| data/t/t.0.sphi   | /work/anytest/data/t/t.0.sphi   |
| data/t/t.0.spi    | /work/anytest/data/t/t.0.spi    |
| data/t/t.0.spm    | /work/anytest/data/t/t.0.spm    |
| data/t/t.0.spp    | /work/anytest/data/t/t.0.spp    |
| data/t/t.0.spt    | /work/anytest/data/t/t.0.spt    |
| data/t/t.meta     | /work/anytest/data/t/t.meta     |
| data/t/t.ram      | /work/anytest/data/t/t.ram      |
| data/t/t.settings | /work/anytest/data/t/t.settings |
+-------------------+---------------------------------+
13 rows in set (0.01 sec)
```

<!-- end -->

Столбец `file` указывает пути к файлам таблицы внутри [data_dir](../Server_settings/Searchd.md#data_dir) запущенного экземпляра. Столбец `normalized` отображает абсолютные пути для тех же файлов. Чтобы создать резервную копию таблицы, просто скопируйте предоставленные файлы без дополнительной подготовки.

Когда таблица заморожена, вы не можете выполнять запросы `UPDATE`; они будут ждать, пока таблица не будет разморожена.

Также запросы `DELETE` и `REPLACE` имеют некоторые ограничения, пока таблица заморожена:
* Если `DELETE` затрагивает документ в текущем RAM-чанке — это разрешено.
* Если `DELETE` затрагивает документ в дисковом чанке, но он был ранее удалён — это разрешено.
* Если `DELETE` изменит фактический дисковый чанк — он будет ждать, пока таблица не будет разморожена.

Ручной `FLUSH` RAM-чанка замороженной таблицы сообщит об "успехе", но реального сохранения не произойдёт.

`DROP`/`TRUNCATE` замороженной таблицы **разрешены**, поскольку эти операции не являются неявными. Мы предполагаем, что если вы усекаете или удаляете таблицу, вам не нужна её резервная копия; следовательно, её не следовало изначально замораживать.

`INSERT` в замороженную таблицу поддерживается, но с ограничением: новые данные будут храниться в оперативной памяти (как обычно) до достижения `rt_mem_limit`; затем новые вставки будут ждать, пока таблица не будет разморожена.

Если вы завершите работу демона с замороженной таблицей, он поведёт себя так, как будто произошло грязное завершение работы (например, `kill -9`): вновь вставленные данные **не** будут сохранены в RAM-чанке на диске, и при перезапуске они будут восстановлены из бинарного лога (если он есть) или потеряны (если ведение бинарного лога отключено).

## Разморозка таблицы

<!-- example unfreeze -->

```sql
UNFREEZE tbl1[, tbl2, ...]
```

Команда `UNFREEZE` уменьшает счётчик блокировок таблицы, и если он достигает нуля, повторно активирует ранее заблокированные операции и возобновляет работу внутренней службы уплотнения. Любые операции, которые ожидали разморозки таблицы, также возобновятся и завершатся нормально.

<!-- request Example -->
```sql
UNFREEZE tbl;
```

<!-- end -->

## Проверка состояния блокировки таблицы

<!-- example show_table_status -->

Вы можете использовать `SHOW table_name STATUS`, чтобы проверить, заморожена ли таблица.

Счётчик блокировок отображается в статусе таблицы в столбце `locked`. Значение ноль указывает, что таблица не заморожена, в то время как ненулевое значение отражает количество активных блокировок. Каждая явная команда `FREEZE` и неявная блокировка (например, когда таблица является частью кластера и процедура репликации выбирает её в качестве донора для реплики) увеличивает счётчик. Каждая команда `UNFREEZE` уменьшает счётчик, в конечном итоге до нуля.

<!-- request Example -->

```sql
SHOW TABLE `foo` STATUS LIKE 'locked';
```

<!-- response Example -->

```sql
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| locked        | 2     |
+---------------+-------+
1 row in set (0,00 sec)
```

<!-- end -->

## Блокировка таблицы

<!-- example lock -->

```sql
lock tables tbl1 read[, tbl2 read, ...]
```

Вы можете явно блокировать таблицы в сеансе SQL-клиента для координации доступа с другими сеансами или для остановки изменения данных другими сеансами, пока вам нужен эксклюзивный доступ. Сеанс может блокировать или разблокировать таблицы только для себя. Он не может блокировать или разблокировать таблицы от имени другого сеанса. Блокировки могут использоваться только в SQL-сеансах, подключённых через протокол MySQL. Пока таблица заблокирована, ни один протокол не может изменять её данные (SQL / HTTP / бинарный). Блокировки также не работают для таблиц, принадлежащих кластеру репликации.


Manticore поддерживает только **чтение (разделяемые)** блокировки. **Запись (эксклюзивные)** блокировки не поддерживаются.

Когда сессия запрашивает блокировку на чтение, Manticore:
1. Проверяет, что соединение использует протокол MySQL.
2. Проверяет, что таблицу можно заблокировать. Это должна быть локальная реального времени или перколяционная таблица и она не должна быть частью кластера репликации.
3. Автоматически снимает все блокировки, которые уже удерживает сессия.
4. Ожидает завершения всех текущих операций вставки, замены, обновления или удаления в таблице.
5. Увеличивает счетчик блокировок на чтение для таблицы (см. [SHOW LOCKS](../Securing_and_compacting_a_table/Freezing_and_locking_a_table.md#SHOW-LOCKS)).

Любая модифицирующая инструкция (DML), такая как `INSERT`, `REPLACE`, `UPDATE`, `DELETE` и `TRUNCATE`, сначала проверяет, заблокирована ли таблица на чтение. Если да, инструкция завершается ошибкой `table is locked`. Инструкции DDL (такие как `CREATE`, `ALTER`, `DROP`) не блокируются блокировками на чтение.


<!-- request Example -->

```sql
--------------
LOCK TABLES tbl READ
--------------

Query OK, 0 rows affected (0.000 sec)

--------------
LOCK TABLES tbl READ, tbl2 WRITE
--------------

Query OK, 0 rows affected, 1 warning (0.000 sec)

--------------
SHOW WARNINGS
--------------

+---------+------+--------------------------------+
| Level   | Code | Message                        |
+---------+------+--------------------------------+
| warning | 1000 | Write lock is not implemented. |
+---------+------+--------------------------------+
1 row in set (0.000 sec)
```

<!-- end -->

## UNLOCK TABLES

<!-- example unlock -->
Команда `UNLOCK TABLES` явно снимает все блокировки таблиц, удерживаемые текущей SQL-сессией.

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

<!-- request Example -->

```sql
UNLOCK TABLES;
```

<!-- end -->


## SHOW LOCKS

<!-- example show_locks -->

Команда `SHOW LOCKS` выводит список всех таблиц, которые в данный момент заблокированы или заморожены.  
Каждая строка показывает тип таблицы, её имя, тип блокировки и счётчик, указывающий, сколько раз эта блокировка была применена.

**Тип блокировки** может быть:
- `read` — таблица защищена блокировкой на чтение. Модифицирующие инструкции будут завершаться ошибкой, пока блокировка не будет снята.
- `freeze` — таблица заморожена. Это останавливает любую операцию, которая записывает данные на диск, пока таблица не будет разморожена.

<!-- request Example -->

```sql
SHOW LOCKS;
```

<!-- response Example -->

```sql
+-----------+------+-----------+-----------------+
| Type      | Name | Lock Type | Additional Info |
+-----------+------+-----------+-----------------+
| rt        | a    | read      | Count: 1        |
| percolate | bar  | freeze    | Count: 3        |
| rt        | foo  | freeze    | Count: 2        |
+-----------+------+-----------+-----------------+
3 rows in set (0,01 sec)
```

<!-- end -->
