5.5.6.1 Сервис блокировок
Дистрибутивы MySQL предоставляют интерфейс блокировки, доступный на двух уровнях:
На уровне SQL, как набор загружаемых функций, каждая из которых отображается на вызовы процедур службы.
Как интерфейс на языке C, вызываемый в качестве плагина из серверных плагинов или загружаемых функций.
Для общей информации о службах плагинов, см. Раздел 5.5.6, «Службы плагинов MySQL». Для общей информации о загружаемых функциях, см. Добавление загружаемой функции.
Интерфейс блокировки имеет следующие характеристики:
-
Блокировки имеют три атрибута: пространство имен блокировки, имя блокировки и режим блокировки:
Блокировки идентифицируются по комбинации пространства имен и имени блокировки. Пространство имен позволяет различным приложениям использовать одни и те же имена блокировок без конфликтов, создавая блокировки в разных пространствах имен. Например, если приложения A и B используют пространства имен
ns1иns2соответственно, каждое приложение может использовать имена блокировокlock1иlock2без вмешательства другого приложения.Режим блокировки может быть чтение или запись. Блокировки чтения разделяемые: если у сессии есть блокировка чтения для данного идентификатора блокировки, другие сессии могут получить блокировку чтения для того же идентификатора. Блокировки записи — эксклюзивные: если у сессии есть блокировка записи для данного идентификатора блокировки, другие сессии не могут получить блокировку чтения или записи для этого же идентификатора.
Пространство имен и имена блокировок должны быть не-
NULL, непустыми и иметь максимальную длину 64 символа. Пространство имен или имя блокировки, заданные какNULL, пустая строка или строка длиннее 64 символов, приведут к ошибке.Интерфейс блокировки обрабатывает пространства имен и имена блокировок как двоичные строки, поэтому сравнения чувствительны к регистру.
Интерфейс блокировки предоставляет функции для получения и освобождения блокировок. Для вызова этих функций не требуется специальный привилегии. Проверка привилегий является обязанностью вызывающего приложения.
Блокировки можно ожидать, если они не доступны немедленно. Вызовы получения блокировки принимают целочисленное значение таймаута, указывающее, сколько секунд нужно ждать получения блокировок перед отказом. Если таймаут истечет без успешного получения блокировки, произойдёт ошибка. Если таймаут равен 0, ожидания нет, и вызов выдаст ошибку, если блокировки не могут быть получены немедленно.
Интерфейс блокировки обнаруживает тупик между вызовами получения блокировок в разных сессиях. В этом случае служба блокировки выбирает вызывающего и завершает его запрос получения блокировки с ошибкой. Эта ошибка не приводит к откату транзакций. Для выбора сессии в случае тупика служба блокировки отдает предпочтение сессиям, удерживающим блокировки чтения, перед сессиями, удерживающими блокировки записи.
Сессия может получить несколько блокировок с помощью одного вызова получения блокировок. Для данного вызова получение блокировок является атомарным: вызов успешен, если все блокировки получены. Если получение любой блокировки завершается ошибкой, вызов не получает никаких блокировок и завершается ошибкой, обычно с или ошибкой.
Сессия может получить несколько блокировок для одного и того же идентификатора блокировки (комбинация пространства имен и имени блокировки). Эти экземпляры блокировок могут быть блокировками чтения, блокировками записи или смесью обоих.
Блокировки, полученные в рамках сессии, явно освобождаются путем вызова функции освобождения блокировок или неявно при завершении сессии (нормально или аномально). Блокировки не освобождаются при подтверждении или откате транзакций.
В рамках сессии все блокировки для данного пространства имен при освобождении освобождаются вместе.
Интерфейс, предоставляемый службой блокировок, отличается от интерфейса, предоставляемого функциями GET_LOCK() и связанными SQL-функциями (см. Раздел 12.14, «Функции блокировки»). Например, GET_LOCK() не реализует пространства имен и предоставляет только эксклюзивные блокировки, а не отдельные блокировки чтения и записи.
5.5.6.1.1 Интерфейс службы блокировок на C
В этом разделе описано использование интерфейса службы блокировок на языке C. Чтобы использовать интерфейс функций, см. Раздел 5.5.6.1.2, «Функциональный интерфейс службы блокировок». Общие характеристики интерфейса службы блокировок см. в разделе 5.5.6.1, «Сервис блокировок». Общую информацию о службах плагинов см. в разделе 5.5.6, «Службы плагинов MySQL».
Файлы исходного кода, использующие службу блокировки, должны включать этот заголовочный файл:
#include <mysql/service_locking.h>
Для получения одной или нескольких блокировок вызовите эту функцию:
int mysql_acquire_locking_service_locks(MYSQL_THD opaque_thd,
const char* lock_namespace,
const char**lock_names,
size_t lock_num,
enum enum_locking_service_lock_type lock_type,
unsigned long lock_timeout);
Аргументы имеют следующее значение:
opaque_thd: Дескриптор потока. Если задано какNULL, используется дескриптор текущего потока.lock_namespace: Строка с нулевым завершением, указывающая пространство имен блокировки.lock_names: Массив строк с нулевым завершением, предоставляющий имена блокировок для получения.lock_num: Количество имён в массивеlock_names.lock_type: Режим блокировки, либоLOCKING_SERVICE_READилиLOCKING_SERVICE_WRITEдля получения блокировок чтения или записи соответственно.lock_timeout: Целое число секунд ожидания получения блокировок перед отказом.
Для освобождения блокировок, полученных для данного пространства имен, вызовите эту функцию:
int mysql_release_locking_service_locks(MYSQL_THD opaque_thd,
const char* lock_namespace);
Аргументы имеют следующие значения:
opaque_thd: Дескриптор потока. Если задано какNULL, используется дескриптор текущего потока.lock_namespace: Строка с нулевым завершением, указывающая пространство имен блокировки.
Блокировки, полученные или ожидаемые службой блокировок, можно отслеживать на уровне SQL, используя Performance Schema. Подробности см. в Разделе мониторинга службы блокировки.
5.5.6.1.2 Интерфейс функции сервиса блокировок
В этом разделе описывается, как использовать интерфейс сервиса блокировок, предоставляемый загружаемыми функциями. Чтобы использовать интерфейс на языке C, см. Раздел 5.5.6.1.1, «Интерфейс сервиса блокировок на C». Для общих характеристик интерфейса сервиса блокировок см. Раздел 5.5.6.1, «Сервис блокировок». Для общей информации о загружаемых функциях см. Добавление загружаемой функции.
Установка или удаление интерфейса функции сервиса блокировок
Функции сервиса блокировок, описанные в Разделе 5.5.6.1.1, «Интерфейс сервиса блокировок на C», не нуждаются в установке, так как они встроенные в сервер. То же самое не относится к загружаемым функциям, которые отображаются на вызовах функций сервиса: эти функции необходимо установить перед использованием. В этом разделе описывается, как это сделать. Для общей информации об установке загружаемых функций см. Раздел 5.6.1, «Установка и удаление загружаемых функций».
Функции сервиса блокировок реализованы в файле библиотеки плагинов, расположенном в каталоге, указанном переменной системы plugin_dir. Имя файла — locking_service. Суффикс имени файла отличается в зависимости от платформы (например, .so для Unix-систем, .dll для Windows).
Для установки функций сервиса блокировок используйте оператор CREATE FUNCTION, скорректировав суффикс .so для вашей платформы по мере необходимости:
CREATE FUNCTION service_get_read_locks RETURNS INT
SONAME 'locking_service.so';
CREATE FUNCTION service_get_write_locks RETURNS INT
SONAME 'locking_service.so';
CREATE FUNCTION service_release_locks RETURNS INT
SONAME 'locking_service.so';
Если функции используются на сервере источника репликации, установите их и на всех серверах репликации, чтобы избежать проблем с репликацией.
После установки функции остаются установленными до их удаления. Для их удаления используйте оператор DROP FUNCTION:
DROP FUNCTION service_get_read_locks;
DROP FUNCTION service_get_write_locks;
DROP FUNCTION service_release_locks;
Использование интерфейса функции сервиса блокировок
Перед использованием функций сервиса блокировок установите их в соответствии с инструкциями в разделе Установка или удаление интерфейса функции сервиса блокировок.
Для получения одной или нескольких блокировок чтения вызовите эту функцию:
mysql> SELECT service_get_read_locks('mynamespace', 'rlock1', 'rlock2', 10);
+---------------------------------------------------------------+
| service_get_read_locks('mynamespace', 'rlock1', 'rlock2', 10) |
+---------------------------------------------------------------+
| 1 |
+---------------------------------------------------------------+
Первый аргумент — пространство имен блокировки. Последний аргумент — целочисленная временная метка, указывающая, сколько секунд ожидать получения блокировок перед отказом. Аргументы между ними — имена блокировок.
В приведенном примере функция получает блокировки с идентификаторами блокировок (mynamespace, rlock1) и (mynamespace, rlock2).
Для получения записей блокировок вместо блокировок чтения вызовите эту функцию:
mysql> SELECT service_get_write_locks('mynamespace', 'wlock1', 'wlock2', 10);
+----------------------------------------------------------------+
| service_get_write_locks('mynamespace', 'wlock1', 'wlock2', 10) |
+----------------------------------------------------------------+
| 1 |
+----------------------------------------------------------------+
В этом случае идентификаторы блокировок — (mynamespace, wlock1) и (mynamespace, wlock2).
Для освобождения всех блокировок для пространства имен используйте эту функцию:
mysql> SELECT service_release_locks('mynamespace');
+--------------------------------------+
| service_release_locks('mynamespace') |
+--------------------------------------+
| 1 |
+--------------------------------------+
Каждая функция блокировки возвращает ненулевое значение при успехе. Если функция завершается ошибкой, происходит ошибка. Например, возникает следующая ошибка, потому что имена блокировок не могут быть пустыми:
mysql> SELECT service_get_read_locks('mynamespace', '', 10);
ERROR 3131 (42000): Incorrect locking service lock name ''.
Сессия может получить несколько блокировок для одного и того же идентификатора блокировки. Пока другая сессия не имеет записи блокировки для идентификатора, сессия может получить любое количество блокировок чтения или записи. Каждый запрос на блокировку для идентификатора получает новую блокировку. Следующие операторы получают три записи блокировок с одинаковым идентификатором, а затем три блокировки чтения для того же идентификатора:
SELECT service_get_write_locks('ns', 'lock1', 'lock1', 'lock1', 0);
SELECT service_get_read_locks('ns', 'lock1', 'lock1', 'lock1', 0);
Если вы изучите таблицу Performance Schema metadata_locks в этот момент, вы обнаружите, что сессия содержит шесть различных блокировок с одинаковым (ns, lock1) идентификатором. (Для получения подробностей см. Мониторинг сервиса блокировок.)
Поскольку сессия содержит по крайней мере одну запись блокировки для (ns, lock1), ни одна другая сессия не может получить блокировку для нее, ни чтение, ни запись. Если сессия содержала только блокировки чтения для идентификатора, другие сессии могли получить блокировки чтения, но не записи.
Блокировки для одного вызова приобретения блокировки получают атомарно, но атомарность не сохраняется между вызовами. Таким образом, для оператора, такого как следующий, где service_get_write_locks() вызывается один раз на строку набора результатов, атомарность сохраняется для каждого отдельного вызова, но не для всего оператора:
SELECT service_get_write_locks('ns', 'lock1', 'lock2', 0) FROM t1 WHERE ... ;
Поскольку сервис блокировок возвращает отдельную блокировку для каждого успешного запроса на заданный идентификатор блокировки, один оператор может получить большое количество блокировок. Например:
INSERT INTO ... SELECT service_get_write_locks('ns', t1.col_name, 0) FROM t1;
Такие операторы могут иметь определенные неблагоприятные последствия. Например, если оператор завершается частично и откатывается, блокировки, полученные до момента сбоя, все еще существуют. Если предполагается, что существует соответствие между вставленными строками и полученными блокировками, это намерение не выполняется. Кроме того, если важно, чтобы блокировки предоставлялись в определенном порядке, помните, что порядок набора результатов может отличаться в зависимости от того, какой план выполнения выбирает оптимизатор. По этим причинам лучше всего ограничить приложения одним вызовом приобретения блокировки на оператор.
Мониторинг сервиса блокировок
Сервис блокировок реализован с использованием механизма блокировок метаданных MySQL Server, поэтому вы можете отслеживать полученные или ожидаемые блокировки сервиса блокировок, просматривая таблицу Performance Schema metadata_locks.
Сначала включите инструмент для блокировки метаданных:
mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
-> WHERE NAME = 'wait/lock/metadata/sql/mdl';
Затем получите некоторые блокировки и проверьте содержимое таблицы metadata_locks:
mysql> SELECT service_get_write_locks('mynamespace', 'lock1', 0);
+----------------------------------------------------+
| service_get_write_locks('mynamespace', 'lock1', 0) |
+----------------------------------------------------+
| 1 |
+----------------------------------------------------+
mysql> SELECT service_get_read_locks('mynamespace', 'lock2', 0);
+---------------------------------------------------+
| service_get_read_locks('mynamespace', 'lock2', 0) |
+---------------------------------------------------+
| 1 |
+---------------------------------------------------+
mysql> SELECT OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_STATUS
-> FROM performance_schema.metadata_locks
-> WHERE OBJECT_TYPE = 'LOCKING SERVICE'\G
*************************** 1. row ***************************
OBJECT_TYPE: LOCKING SERVICE
OBJECT_SCHEMA: mynamespace
OBJECT_NAME: lock1
LOCK_TYPE: EXCLUSIVE
LOCK_STATUS: GRANTED
*************************** 2. row ***************************
OBJECT_TYPE: LOCKING SERVICE
OBJECT_SCHEMA: mynamespace
OBJECT_NAME: lock2
LOCK_TYPE: SHARED
LOCK_STATUS: GRANTED
У блокировок сервиса блокировок есть значение OBJECT_TYPE равное LOCKING SERVICE. Это отличается, например, от блокировок, полученных с помощью функции GET_LOCK(), у которых значение OBJECT_TYPE равно USER
LEVEL LOCK.
Пространство имен блокировки, имя и режим отображаются в столбцах OBJECT_SCHEMA, OBJECT_NAME и LOCK_TYPE. Блокировки чтения и записи имеют значения LOCK_TYPE, равные SHARED и EXCLUSIVE соответственно.
Значение LOCK_STATUS равно GRANTED для полученной блокировки, PENDING для блокировки, за которой ведется ожидание. Вы увидите PENDING, если одна сессия имеет запись блокировки, а другая сессия пытается получить блокировку с тем же идентификатором.
Справочник функций интерфейса службы блокировки
SQL-интерфейс службы блокировки реализует загружаемые функции, описанные в этом разделе. Примеры использования см. в разделе об использовании интерфейса функций службы блокировки.
Функции обладают следующими характеристиками:
Значение возвращаемого значения отлично от нуля при успехе. В противном случае возникает ошибка.
Имя пространства имен и блокировки должно быть непустым, не
NULLи иметь максимальную длину 64 символа.Значения тайм-аута должны быть целыми числами, указывающими количество секунд ожидания приобретения блокировок перед отказом с ошибкой. Если тайм-аут равен 0, ожидание не происходит, и функция возвращает ошибку, если блокировки не могут быть приобретены немедленно.
Доступны следующие функции службы блокировки:
-
service_get_read_locks(namespace,lock_name[,lock_name] ...,timeout)Приобретает одну или несколько блокировок чтения (совместных) в заданном пространстве имен с использованием заданных имен блокировок, завершаясь с ошибкой при истечении тайм-аута, если блокировки не были приобретены в течение заданного значения тайм-аута.
-
service_get_write_locks(namespace,lock_name[,lock_name] ...,timeout)Приобретает одну или несколько блокировок записи (исключительных) в заданном пространстве имен с использованием заданных имен блокировок, завершаясь с ошибкой при истечении тайм-аута, если блокировки не были приобретены в течение заданного значения тайм-аута.
-
service_release_locks(namespace)Для данного пространства имен высвобождает все блокировки, которые были приобретены в текущей сессии с помощью
service_get_read_locks()иservice_get_write_locks().Отсутствие блокировок в пространстве имен не является ошибкой.
© 2025 Oracle
Licensed under the GPLv2 License.