- Estrategia de bloqueos MDL en GreatSQL
En GreatSQL, la gestión de bloqueos de metadatos se centraliza en la clase MDL_lock_strategy. Esta clasifica los bloqueos según su alcance: los de scope se aplican a objetos globales como GLOBAL, COMMIT, TABLESPACE o BACKUP_LOCK, mientras que los de object se refieren a tablas del diccionario de datos (DD). El siguiente análisis se centra en estos últimos.
Para cada tabla, el motor mantiene tres estructuras de control:
m_fast_path_state: bitmap que cuenta los bloqueos obtenidos por la ruta rápida (fast path).m_granted: cola de bloqueos ya concedidos mediante la ruta lenta (slow path).m_waiting: cola de bloqueos pendientes de conceder.
Los bloqueos se dividen en dos grupos según su impacto:
- Ruta rápida (unobtrusive):
S,SH,SRySW. Se contabilizan enm_fast_path_statesin almacenar información individual. - Ruta lenta (obtrusive):
SU,SRO,SNW,SNRWyX. Se gestionan a través de las colasm_grantedym_waiting.
- Niveles de política y prevención de inanición
La concesión de un bloqueo se evalúa en MDL_lock::can_grant_lock. Se requiere que no haya bloqueos incompatibles en m_granted ni bloqueos de mayor prioridad en m_waiting.
Para evitar que los bloqueos de baja prioridad esperan indefinidamente, el motor alterna entre cuatro matrices de compatibilidad en la cola de espera:
m_granted_incompatible: matriz base sobre la colam_granted.m_waiting_incompatible[0]: política normal de espera.m_waiting_incompatible[1]: se activa cuandom_piglet_lock_count >= max_write_lock_count.m_waiting_incompatible[2]: se activa cuandom_hog_lock_count >= max_write_lock_count.m_waiting_incompatible[3]: se activa cuando la suma de bloqueos hog y piglet alcanza el umbral.
Los tipos hog (X, SNRW, SNW) son muy incompatibles y tienden a acaparar la tabla; los piglet (SW) tienen una priordiad intermedia. El contador correspondiente determina cuándo se eleva o se reduce la política activa.
- Semántica de los modos de bloqueo
Los modos más relevantes para objetos de tabla son:
S: lectura de metadatos sin lectura de filas.SH: lectura de metadatos con prioridad sobre operaciones de escritura.SR: lectura de metadatos y de filas dentro de una transacción.SW: lectura de metadatos y actualización de filas.SWLP: comoSW, pero con prioridad reducida.SU: bloqueo actualizable; permite lectura/escritura concurrrente y puede ascender aSNW,SNRoX.SRO: solo lectura de metadatos y filas; bloquea modificaciones y DDL.SNW: bloquea escrituras ajenas; puede ascender aX.SNRW: bloquea lecturas y escrituras ajenas.X: bloqueo exclusivo para modificaciones de esquema y datos.
- Efecto práctico de
max_write_lock_count
Cuando varios hilos compiten por la misma tabla, el valor de max_write_lock_count decide cuál matriz de espera está activa y, por tanto, qué solicitud se atiende primero.
Para ilustrarlo, se crea una tabla de ejemplo con nombres de columna distintos:
CREATE TABLE `datos` (
`id` int NOT NULL,
`txt` varchar(100) DEFAULT NULL,
`ts` timestamp(3) NULL DEFAULT NULL,
`obs` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO datos (id, txt, ts, obs) VALUES
(1, 'aaaa', '2021-01-19 03:14:07.123', 'init'),
(2, NULL, '2022-01-19 03:14:07.123', NULL),
(3, 'bbbb', NULL, NULL),
(4, NULL, NULL, NULL),
(15,'cccc', '2025-01-19 03:14:07.123','last');
4.1. Caso: max_write_lock_count = 100
Con seis sesiones concurrentes y el umbral alto, el contador m_piglet_lock_count no supera el límite, por lo que se mantiene la política 0. Bajo esta política, SW tiene mayor prioridad que SRO. Cuando la primera sesión confirma su transacción, los bloqueos SW pendientes se conceden antes que las lecturas SRO restantes.
4.2. Caso: max_write_lock_count = 1
Tras la concesión de varios bloqueos SRO, el contador de piglet alcanza el umbral y la política de espera asciende a 1. En esta política, SW tiene menor prioridad que SRO, por lo que, tras el COMMIT de la primera sesión, los bloqueos SRO en espera se conceden antes que los SW. Cuando ya no quedan SRO pendientes, la estrategia vuelve a bajar a 0.
El estado de los bloqueos se puede observar con una consulta como la siguiente:
SELECT *
FROM performance_schema.metadata_locks
WHERE object_schema = 'demo'
AND object_name = 'datos';
El resultado mostrará, tras la escalada de política, varios bloqueos SHARED_READ_ONLY en estado GRANTED mientras un SHARED_WRITE permanece en estado PENDING.
- Momentos de cambio de política
La función MDL_lock::reschedule_waiters reevalúa la política activa cuando ocurre alguno de estos eventos:
- Se elimina un ticket de
m_grantedom_waiting. - Otro hilo solicita un bloqueo que provoca una escalada de la estrategia.
- Un bloqueo se libera o se degrada.
- Consideraciones operativas
El parámetro max_write_lock_count actúa como regulador de la inanición de bloqueos. Disminuirlo permite que los bloqueos de menor prioridad avancen antes, pero puede retrasar operaciones de mayor prioridad y alterar el rendimiento de cargas concurrentes. Incrementarlo mantiene el orden habitual a favor de los bloqueos más agresivos. La elección del valor debe ajustarse al comportamiento esperado de cada carga de trabajo.