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 и 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.