Pourquoi ce verrou RX-X n'apparaît-il pas dans les événements étendus?

13

Le problème

J'ai une paire de requêtes qui, sous isolement sérialisable, provoquent un verrouillage RX-X. Cependant, lorsque j'utilise des événements étendus pour regarder l'acquisition de verrouillage, l'acquisition de verrouillage RX-X n'apparaît jamais, elle est uniquement publiée. D'où est ce que ça vient?

Le Repro

Voici ma table:

CREATE TABLE dbo.LockTest (
ID int identity,
Junk char(4)
)

CREATE CLUSTERED INDEX CX_LockTest --not unique!
ON dbo.LockTest(ID)

--preload some rows
INSERT dbo.LockTest
VALUES ('data'),('data'),('data')

Voici mon lot de problèmes:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRAN

INSERT dbo.LockTest
VALUES ('bleh')

SELECT *
FROM dbo.LockTest
WHERE ID = SCOPE_IDENTITY()

--ROLLBACK

Je vérifie les verrous détenus par cette session et vois RX-X:

SELECT resource_type, request_mode, request_status, resource_description
FROM sys.dm_tran_locks
WHERE request_session_id = 72 --change SPID!

dm_tran_locks

Mais j'ai également un événement étendu sur lock_acquiredet lock_released. Je le filtre sur l'id_object_id associé approprié ... il n'y a pas de RX-X.

Sortie d'événement étendue

Après avoir exécuté la restauration, je vois RX-X (LAST_MODE) publié, même s'il n'a jamais été acquis.

LAST_MODE

Ce que j'ai essayé

  • J'ai regardé tous les verrous dans les événements étendus - pas de filtrage. Aucun verrou RX-X acquis.

  • J'ai aussi essayé Profiler: mêmes résultats (sauf bien sûr qu'il obtient le bon nom ... pas de "LAST_MODE").

  • J'ai exécuté le XE pour les escalades de verrous - ce n'est pas là.

  • Il n'y a pas de XE spécifiquement pour les conversions, mais j'ai pu confirmer qu'au moins la conversion de verrouillage U en X est capturée par lock_acquired

Il convient également de noter le RI-N qui est acquis mais jamais publié. Mon hypothèse actuelle est que le RX-X est un verrou de conversion, comme décrit ici . Il y a des verrous de plage de clés qui se chevauchent dans mon lot qui semblent devoir être qualifiés pour la conversion, mais le verrou RX-X n'est pas dans la table de conversion.

D'où vient ce verrou et pourquoi n'est-il pas récupéré par les événements étendus?

Forrest
la source

Réponses:

12

L'insert à une rangée acquiert un Xverrou (exclusif) sur la nouvelle rangée.

Les SELECTtentatives pour acquérir un RangeS-Sverrou partagé par plage et partagé ( ).

Cette demande est signalée par l' lock_acquiredévénement étendu en mode = RS_S.

Il est signalé par la classe d'événements Profiler en Lock:Acquiredtant que mode 13 ( LCK_M_RS_S).

Le mode demandé est combiné avec le mode de verrouillage exclusif existant dans Lock::CalculateGrantModein sqlmin.dll. Il n'y a pas de mode combiné de plage partagée, clé exclusive ( RangeS-X), le résultat du calcul est donc plage exclusive, clé exclusive ( RangeX-X), qui se trouve être le mode 15.

Le calcul du mode d'octroi ci-dessus est effectué juste avant que l'événement étendu soit généré par lck_ProduceExtendedEvent<XeSqlPkg::lock_acquired>. Néanmoins, le profileur et les événements étendus enregistrent le mode demandé RangeS-S et non le mode de verrouillage résultant RangeX-X. Cela va à l'encontre de la documentation limitée , qui dit:

Mode | int | Mode résultant après l'acquisition du verrou.

La colonne mode de l'événement étendu ne contient aucune documentation et la description dans les métadonnées est vide. Peut-être que Microsoft lui-même n'était même pas sûr du comportement.

J'ai souvent pensé qu'il serait plus utile que les événements de verrouillage signalent à la fois les modes demandés et résultants , mais ce n'est pas ce que nous avons. L'arrangement actuel rend pratiquement impossible le suivi et la correspondance de l'acquisition et de la libération des verrous.

Il peut y avoir une bonne raison de signaler les verrous de cette façon. S'il ne répond pas à vos besoins, vous pouvez ouvrir un dossier de support auprès de Microsoft ou créer un élément Azure Feedback.


LAST_MODE

Le mystérieux LAST_MODEest quelque chose qu'Erik Darling a déjà remarqué . Il s'agit de la map_keyvaleur la plus élevée dans la liste des modes de verrouillage exposés par sys.dm_xe_map_values:

SELECT
    DXMV.map_key,
    DXMV.map_value
FROM sys.dm_xe_map_values AS DXMV
WHERE 
    DXMV.[name] = N'lock_mode'
ORDER BY
    DXMV.map_key;
╔═════════╦═══════════╗
║ map_key ║ map_value ║
╠═════════╬═══════════╣
║       0 ║ NL        ║
║       1 ║ SCH_S     ║
║       2 ║ SCH_M     ║
║       3 ║ S         ║
║       4 ║ U         ║
║       5 ║ X         ║
║       6 ║ IS        ║
║       7 ║ IU        ║
║       8 ║ IX        ║
║       9 ║ SIU       ║
║      10 ║ SIX       ║
║      11 ║ UIX       ║
║      12 ║ BU        ║
║      13 ║ RS_S      ║
║      14 ║ RS_U      ║
║      15 ║ RI_NL     ║
║      16 ║ RI_S      ║
║      17 ║ RI_U      ║
║      18 ║ RI_X      ║
║      19 ║ RX_S      ║
║      20 ║ RX_U      ║
║      21 ║ LAST_MODE ║
╚═════════╩═══════════╝

La structure de mémoire accessible via le DMV (en utilisant sqlmin!CMapValuesTable) est stockée à partir de l'adresse sqlmin!XeSqlPkg::g_lock_mode. Chaque entrée de 16 octets dans la structure contient le map_keypointeur et un pointeur sur la chaîne renvoyée comme map_valuepar le TVF en streaming.

Les chaînes sont stockées exactement comme indiqué dans le tableau ci-dessus (mais pas dans cet ordre). Il semble être une erreur que l'entrée 21 ait un map_value"LAST_MODE" au lieu du "RX_X" attendu. Erik Darling a signalé le problème sur Azure Feedback .

Paul White 9
la source