pg_locks
La vue pg_locks
fournit un accès aux informations
concernant les verrous détenus par les transactions actives
sur le serveur de bases de données. Voir le Chapitre 13
pour une discussion plus importante sur les verrous.
pg_locks
contient une ligne par objet verrouillable
actif, type de verrou demandé et processus associé. Un même
objet verrouillable peut apparaître plusieurs fois si plusieurs
processus ont posé ou attendent des verrous sur celui-ci. Toutefois, un
objet qui n'est pas actuellement verrouillé n'apparaît pas.
Il existe plusieurs types distincts d'objets verrouillables : les
relations complètes (tables, par exemple), les pages individuelles de
relations, des tuples individuels de relations, les identifiants de
transaction (virtuels et permanents) et les objets généraux de la base de
données (identifiés par l'OID de la classe et l'OID de l'objet, de la même
façon que dans pg_description
ou
pg_depend
). De plus, le droit d'étendre une
relation est représenté comme un objet verrouillable distinct, tout comme
le droit de mettre à jour
pg_database
.datfrozenxid
.
Et enfin, les verrous informatifs peuvent être pris sur les numéros qui ont
la signification définie par l'utilisateur.
Tableau 51.74. Colonnes de pg_locks
Nom | Type | Références | Description |
---|---|---|---|
locktype | text |
Type de l'objet verrouillable :
relation ,
extend ,
frozenid ,
page ,
tuple ,
transactionid ,
virtualxid ,
object ,
userlock ou
advisory
| |
database | oid |
| L'OID de la base de données dans laquelle existe l'objet à verrouiller, 0 si la cible est un objet partagé ou NULL si l'objet est un identifiant de transaction |
relation | oid |
| L'OID de la relation visée par le verrouillage, ou NULL si la cible n'est ni une relation ni une partie de relation |
page | integer | Le numéro de page visé par le verrouillage à l'intérieur de cette relation ou NULL si la cible n'est pas un tuple ou une page de relation | |
tuple | smallint | Le numéro du tuple dans la page, ciblé par le verrouillage, ou NULL si la cible n'est pas un tuple | |
virtualxid | text | L'identifiant virtuel de transaction visé par le verrouillage, ou NULL si la cible n'est pas un identifiant virtuel de transaction | |
transactionid | xid | L'identifiant de transaction ciblé par le verrouillage ou NULL si la cible n'est pas un identifiant de transaction | |
classid | oid |
| L'OID du catalogue système contenant la cible du verrouillage ou NULL si la cible n'est pas un objet général de la base de données |
objid | oid | n'importe quelle colonne OID | L'OID de la cible du verrouillage dans son catalogue système ou NULL si la cible n'est pas un objet général de la base de données |
objsubid | smallint |
Numéro de la colonne ciblée par le verrou
(classid et objid
font référence à la table elle-même), ou 0 si la cible est un
autre objet de la base de données, ou NULL si l'objet n'est pas
un objet de la base de données.
| |
virtualtransaction | text | L'identifiant virtuel de la transaction qui détient ou attend le verrou. | |
pid | integer | L'identifiant du processus serveur qui détient ou attend le verrou. NULL si le verrou est possédé par une transaction préparée. | |
mode | text | Nom du type de verrou détenu ou attendu par ce processus (voir la Section 13.3.1 et Section 13.2.3) | |
granted | boolean | True si le verrou est détenu,
false s'il est attendu | |
fastpath | boolean | True si le verrou a été obtenu grâce au
raccourci, false s'il a été obtenu via la table
principale des verrous |
granted
est true
sur une ligne
représentant un verrou tenu par le processus indiqué. False indique que le
processus attend l'acquisition de ce verrou, ce qui implique qu'au moins un
autre processus détient ou est en attente d'un verrou en conflit sur le
même objet. Le processus en attente dormira jusqu'à ce que l'autre verrou
soit relâché (ou qu'une situation de deadlock soit détecté). Un processus
seul ne peut attendre qu'au plus un verrou à la fois.
Au cours de l'exécution d'une transaction, un processus serveur détient un verrou exclusif sur l'identifiant virtuel de transaction. Si un identifiant permanent est affecté à la transaction (ce qui arrive normalement seulement si la transaction modifie l'état de la base), il détient aussi un verrou exclusif sur l'identifiant permanent de transaction jusqu'à sa fin. Quand un processus a besoin d'attendre la fin d'une autre transaction, il le fait en tentant d'acquérir un verrou partagé sur l'identfiant virtuel ou permanent de cette autre transaction . Ceci ne réussira que quand l'autre transaction se termine et relâche son verrou.
Bien que les lignes constituent un type d'objet verrouillable, les informations sur les verrous de niveau ligne sont stockées sur disque, et non en mémoire. Ainsi, les verrous de niveau ligne n'apparaissent normalement pas dans cette vue. Si un processus attend un verrou de niveau ligne, elle apparaît sur la vue comme en attente de l'identifiant permanent de la transaction actuellement détentrice de ce verrou de niveau ligne.
Les verrous consultatifs peuvent être acquis par des clés constituées soit
d'une seule valeur bigint
, soit de deux valeurs
integer
. Une clé bigint
est affichée avec
sa moitié haute dans la colonne classid
, sa
partie basse dans la colonne objid
et
objsubid
à 1. La valeur bigint
originale
peut être recréée avec l'expression (classid::bigint << 32) |
objid::bigint
.
Les clés integer
sont
affichées avec la première clé dans la colonne
classid
, la
deuxième clé dans la colonne objid
et
objsubid
à 2. La signification réelle des clés
est laissée à l'utilisateur. Les verrous consultatifs sont locaux à chaque base,
la colonne database
a donc un sens dans ce cas.
Bien qu'il soit possible d'obtenir des informations sur les processus
bloquant d'autres processus en joignant la vue
pg_locks
avec elle-même, c'est très difficile à
réaliser correctement dans le détail. Une telle requête devrait intégrer
toutes les informations sur les conflits des modes de verrous. Pire, la vue
pg_locks
n'expose pas d'informations sur les
processus en avance des autres dans les queues d'attente de verrous, pas
plus que des informations sur les processus exécutés en parallèle pour
d'autres sessions clientes. Il est préférable d'utiliser la fonction
pg_blocking_pids()
(voir Tableau 9.60) pour identifier les processus
bloqués par d'autres processus.
pg_locks
fournit une vue globale de tous les verrous
du cluster, pas seulement de ceux de la base en cours d'utilisation. Bien que
la colonne relation
puisse être jointe avec
pg_class
.oid
pour identifier
les relations verrouillées, ceci ne fonctionne correctement qu'avec les
relations de la base accédée (celles pour lesquelles la colonne
database
est l'OID de la base actuelle ou 0).
La vue pg_locks
affiche des données provenant
du gestionnaire de verrous standards et du gestionnaire de verrous de
prédicats, qui sont des systèmes autrement séparés ;
de plus, le gestionnaire de verrous standards sous-divise ses verrous en
verrous réguliers et en verrous rapides (fast-path).
Cette donnée n'est pas garantie comme étant entièrement cohérente. Quand
la vue est exécutée, les données des verrous fast-path (avec
fastpath
= true
) sont
récupérées à partir de chaque processus, un à la fois, sans geler
l'état du gestionnaire des verrous. Donc il est possible que des verrous
soient pris ou relachés pendant la récupération de l'information.
Néanmoins, notez que ces verrous sont connus pour ne pas entrer en conflit
avec les autres verrous déjà détenus. Après que tous les processus serveurs
aient été interrogés pour connaître leur verrous fast-path, le reste du
gestionnaire des verrous standards est verrouillé de manière unitaire et une
image cohérente de tous les verrous restants est collectée en une seule
opération atomique. Après avoir déverrouille le gestionnaire de verrous
standards, le gestionnaire de verrous de prédicats est verrouillé de la
même manière et tous les verrous de prédicats sont récupérés en une action
atomique. Du coup, avec l'exception des verrous fast-path, chaque gestionnaire
de verrous délivrera un état cohérent des résultats mais, comme nous ne
verrouillons pas les deux gestionnaires de verrous simultanément, il est
possible que les verrous soient pris ou relachés après avoir interrogé du
gestionnaire de verrous standards et avant avoir interrogé le gestionnaire
des verrous de prédicats.
Verrouiller le gestionnaire de verrous standards ou de prédicats peut avoir un impact sur les performances de la base de données si cette vue est fréquemment interrogée. Les verrous sont bloqués le temps minimum nécessaire pour obtenir les données des gestionnaires de verrous mais cela n'élimine pas complètement la possibilité d'un impact sur les performances.
La colonne
pid
peut être jointe à la colonne
pid
de la vue pg_stat_activity
pour obtenir plus
d'informations sur la session qui détient ou attend un verrou,
par exemple :
SELECT * FROM pg_locks pl LEFT JOIN pg_stat_activity psa ON pl.pid = psa.pid;
.
De plus, si des transactions préparées sont utilisées, la colonne
virtualtransaction
peut être jointe à la colonne
transaction
de la vuepg_prepared_xacts
pour obtenir plus d'informations
sur les transactions préparées qui détiennent des verrous. (Une
transaction préparée ne peut jamais être en attente d'un verrou mais elle
continue à détenir les verrous qu'elle a acquis pendant son exécution.)
Par exemple :
SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx ON pl.virtualtransaction = '-1/' || ppx.transaction;