7.6.9.1 Услуга блокировки
Дистрибутивы MySQL предоставляют интерфейс блокировки, доступный на двух уровнях:
На уровне SQL, как набор загружаемых функций, каждая из которых отображает вызовы к службам.
Как C-языковой интерфейс, вызываемый в качестве плагина из серверных плагинов или загружаемых функций.
Для получения общей информации о службах плагинов, см. Раздел 7.6.9, «Службы плагинов MySQL». Для получения общей информации о загружаемых функциях, см. Добавление загружаемой функции.
Интерфейс блокировки имеет следующие характеристики:
-
Блокировки имеют три атрибута: пространство имен блокировки, имя блокировки и режим блокировки:
Блокировки идентифицируются по сочетанию пространства имен и имени блокировки. Пространство имен позволяет различным приложениям использовать одни и те же имена блокировок без конфликтов, создавая блокировки в отдельных пространствах имен. Например, если приложения A и B используют пространства имен
ns1иns2соответственно, каждое приложение может использовать имена блокировокlock1иlock2без взаимных помех.Режим блокировки может быть чтение или запись. Блокировки чтения — общие: если сессия имеет блокировку чтения для данного идентификатора блокировки, другие сессии могут получить блокировку чтения для того же идентификатора. Блокировки записи — исключительные: если сессия имеет блокировку записи для данного идентификатора блокировки, другие сессии не могут получить блокировку чтения или записи для того же идентификатора.
Пространство имен и имена блокировок должны быть не-
NULL, непустыми и иметь максимальную длину 64 символа. Пространство имен или имя блокировки, заданные какNULL, пустая строка или строка длиной более 64 символов, приведут к ошибке.Интерфейс блокировки обрабатывает имена пространства имен и блокировок как двоичные строки, поэтому сравнения чувствительны к регистру.
Интерфейс блокировки предоставляет функции для получения блокировок и освобождения блокировок. Для вызова этих функций не требуется особый привилегий. Проверка привилегий является обязанностью вызывающего приложения.
Блокировки могут ожидать освобождения, если они не доступны немедленно. Вызовы получения блокировки принимают целое значение тайм-аута, которое указывает количество секунд ожидания получения блокировок перед отказом. Если тайм-аут истечет без успешного получения блокировки, произойдет ошибка. Если тайм-аут равен 0, ожидания нет, и вызов приведет к ошибке, если блокировки не могут быть получены немедленно.
Интерфейс блокировки обнаруживает тупиковую ситуацию между вызовами получения блокировок в разных сессиях. В этом случае служба блокировки выбирает вызывающего и завершает его запрос получения блокировки с ошибкой. Эта ошибка не приводит к откату транзакций. Для выбора сессии в случае тупиковой ситуации служба блокировки предпочитает сессии, которые держат блокировки чтения, перед сессиями, которые держат блокировки записи.
Сессия может получить несколько блокировок с помощью одного вызова получения блокировок. Для данного вызова получение блокировок является атомным: вызов успешен, если все блокировки получены. Если получение любой блокировки завершается неудачей, вызов не получает ни одной блокировки и терпит неудачу, обычно с ошибкой или .
Сессия может получить несколько блокировок для одного и того же идентификатора блокировки (сочетание пространства имен и имени блокировки). Эти экземпляры блокировки могут быть блокировками чтения, блокировками записи или комбинацией обоих типов.
Блокировки, полученные в рамках сессии, явно освобождаются путем вызова функции освобождения блокировок или неявно при завершении сессии (как нормальном, так и аномальном). Блокировки не освобождаются при подтверждении или откате транзакций.
В рамках сессии все блокировки для данного пространства имен при освобождении освобождаются вместе.
Интерфейс, предоставляемый службой блокировки, отличается от интерфейса, предоставляемого GET_LOCK() и связанными SQL-функциями (см. Раздел 14.14, «Функции блокировки»). Например, GET_LOCK() не реализует пространства имен и предоставляет только исключительные блокировки, а не отдельные блокировки чтения и записи.
7.6.9.1.1 C-интерфейс службы блокировки
В этом разделе описывается использование C-языкового интерфейса службы блокировки. Чтобы использовать интерфейс функций, см. Раздел 7.6.9.1.2, «Интерфейс функций службы блокировки». Для общих характеристик интерфейса службы блокировки, см. Раздел 7.6.9.1, «Служба блокировки». Для получения общей информации о службах плагинов, см. Раздел 7.6.9, «Службы плагинов 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. Подробности см. в Мониторинг службы блокировки.
7.6.9.1.2 Интерфейс функций сервиса блокировки
В этом разделе описано использование интерфейса сервиса блокировки, предоставляемого его загружаемыми функциями. Для использования интерфейса на языке C см. Раздел 7.6.9.1.1, «Интерфейс сервиса блокировки C». Общие характеристики интерфейса сервиса блокировки см. в Разделе 7.6.9.1, «Сервис блокировки». Общие сведения о загружаемых функциях см. в Добавление загружаемой функции.
Установка или удаление интерфейса функций сервиса блокировки
Процедуры сервиса блокировки, описанные в Разделе 7.6.9.1.1, «Интерфейс сервиса блокировки C», устанавливать не нужно, так как они встроены в сервер. Это не относится к загружаемым функциям, которые отображаются на вызовы процедур сервиса: эти функции необходимо установить перед использованием. В этом разделе описывается как это сделать. Общие сведения об установке загружаемых функций см. в Разделе 7.7.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.