WL#8161: Locking service for read/write named locks
Affects: Server-5.7
—
Status: Complete
WL#6940 "Server version token and check" requires a way to protect global and session version token lists. This WL is about providing a locking service for satisfying this requirement. This locking service will be implemented as a set of functions that will be available through a plugin serice as well as a set of UDFs. Both the plugin service and the UDFs will be provided by this WL.
F1: A lock is identified by a name which is a combination of two strings: (namespace, lock_name). The maximum length of each of the strings shall be 64 characters. The "namespace" part is designed to e.g. allow different plugins to use this locking service without interfering with each other. In case of invalid name, ER_LOCKING_SERVICE_WRONG_NAME error shall be reported to the diagnostics area (DA) of the connection. F2: Binary comparison will be used for name matching. (Names given via the UDF interface are already converted to binary) F3: These locks shall be separate from existing locks in the server (e.g. current types of metadata locks - including user-level locks). F4: Each lock can be taken in two modes: Read and write. For a given name: Read and read is compatible, other combinations are not. F5: Both read and write locks shall not be released on commit/rollback of transactions. F6: Both read and write locks shall be released on disconnect. F7: It shall be possible to acquire multiple read locks atomically. It shall also be possible to take multiple write locks atomically. Acquiring a combination of read and write locks atomically is not required. Note that if the names of locks to be taken by the UDF implementation is given as an expression (e.g. a column name reference), the locks will be taken one by one and thus not atomically. The order the locks are taken in this case, depends on how the expression is evaluated. This is a limitation of the current UDF implementation. F8: It shall be possible to release all locks taken. There is no need for releasing individual locks. (This will only affect locks taken by F6). F9: The functions available for UDFs and the plugin service shall have the same functionality: - Acquire one or more read locks by name - Acquire one or more write locks by name - Release all locks F10: Maximum value lock wait timeout (in seconds) shall be supplied by the caller. If timeout happens, ER_LOCK_WAIT_TIMEOUT shall be reported to the diagnostics area (DA) of the connection. A negative timeout will be interpreted as "infinite" timeout - similar to what currently happens for user-level locks. F11: In case of deadlock, a connection with pending read locks is preferable as victim over a connection with pending write locks. Read lock shall be treated as normal DML locks in this respect, and write locks shall be treated as normal DDL locks. In case of deadlock, ER_LOCKING_SERVICE_DEADLOCK (new error) shall be reported to the diagnostics area (DA) of the connection. The ER_LOCK_DEADLOCK shall not be used since it implies transaction rollback. NF1: Privilege checking shall be be the responsibility of the caller. NF2: Other than F6, acquiring and releasing of locks are always explicit. NF3: No checking if a lock with the given name is already held will be done before lock acquisition. This means it is possible to take a lock on the same name twice. Note to documentation: Because of the limitation listed in F7, it is not recommended to use expressions as arguments to the UDFs. This means e.g. avoiding INSERT ... SELECT ... UDF ... FROM ... WHERE ... as the order the locks are taken will depend on the data in the table and how the query is optimized. Especially in the case of error, it can result in an unpredictable number of locks taken.
I-1: Plugin service interface: /** Types of locking service locks. LOCK_SERVICE_READ is compatible with LOCKING_SERVICE_READ. All other combinations are incompatible. */ enum enum_locking_service_lock_type { LOCKING_SERVICE_READ, LOCKING_SERVICE_WRITE }; extern struct mysql_locking_service_st { /** Acquire locking service locks. @param opaque_thd Thread handle. @param lock_namespace Namespace of the locks to acquire. @param lock_names Array of names of the locks to acquire. @param lock_num Number of elements in 'lock_names'. @param lock_type Lock type to acquire. LOCKING_SERVICE_READ or _WRITE. @param lock_timeout Number of seconds to wait before giving up. @retval 1 Acquisition failed, error has been reported in the DA. @retval 0 Acquisition sucessfull, all locks acquired. */ int (*mysql_acquire_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, ulong lock_timeout); /** Release all lock service locks taken by the given connection in the given namespace. @param opaque_thd Thread handle. @param lock_namespace Namespace of the locks to release. @retval 1 Release failed, error has been reported in the DA. @retval 0 Release sucessfull, all locks acquired. */ int (*mysql_release_locks)(MYSQL_THD opaque_thd, const char* lock_namespace); } *mysql_locking_service; I-2: UDFs service_get_read_lock(lock_namespace, (lock_name, ...), lock_timeout) service_get_write_lock(lock_namespace, (lock_name, ...), lock_timeout) service_release_locks(lock_namespace) All these functions RETURNS INT - with similar meaning as the plugin interface above.
Copyright (c) 2000, 2024, Oracle Corporation and/or its affiliates. All rights reserved.