Le module amcheck
fournit des fonctions vous permettant
de vérifier la cohérence logique de la structure des relations. Si la structure
semble valide, aucune erreur n'est levée.
Les fonctions vérifient diverses propriétés invariantes
dans la structure de la représentation de certains relations. La justesse des
fonctions permettant l'accès aux données durant les parcours d'index et
d'autres opérations importantes reposent sur le fait que ces propriétés
invariantes sont toujours vraies. Par exemple, certaines fonctions
vérifient, entre autres choses, que toutes les pages d'index B-Tree ont leurs
éléments dans un ordre « logique » (par exemple, pour des index
B-Tree sur un type text
, les lignes de l'index devraient être
triées dans l'ordre alphabétique défini par la collation). Si, pour une
raison ou une autre, cette propriété invariante spécifique n'est plus vérifiée,
il faut s'attendre à ce que des recherches binaires sur la page affectée
renseignent de manière erronée les parcours d'index, avec pour conséquence
des résultats de requêtes SQL erronés.
La vérification est réalisée en utilisant les même procédures que celles utilisées par les parcours d'index eux-mêmes, qui peuvent très bien être du code utilisateur pour une classe d'opérateur. Par exemple, la vérification d'index B-Tree s'appuie sur les comparaisons faites avec une ou plusieurs routines pour la fonction de support 1. Voir Section 37.16.3 pour plus de détail sur les fonctions de support des classes d'opérateur.
Les fonctions du module amcheck
ne peuvent être
exécutées que par des super utilisateurs.
bt_index_check(index regclass, heapallindexed boolean) returns void
bt_index_check
vérifie que sa cible, un index B-Tree,
respecte un éventail de propriétés invariables. Exemple d'utilisation :
test=# SELECT bt_index_check(index => c.oid, heapallindexed => i.indisunique), c.relname, c.relpages FROM pg_index i JOIN pg_opclass op ON i.indclass[0] = op.oid JOIN pg_am am ON op.opcmethod = am.oid JOIN pg_class c ON i.indexrelid = c.oid JOIN pg_namespace n ON c.relnamespace = n.oid WHERE am.amname = 'btree' AND n.nspname = 'pg_catalog' -- Ignore les tables temporaires, qui peuvent appartenir à d'autres sessions AND c.relpersistence != 't' -- La fonction peut renvoyer une erreur si cela est omis : AND c.relkind = 'i' AND i.indisready AND i.indisvalid ORDER BY c.relpages DESC LIMIT 10; bt_index_check | relname | relpages ----------------+---------------------------------+---------- | pg_depend_reference_index | 43 | pg_depend_depender_index | 40 | pg_proc_proname_args_nsp_index | 31 | pg_description_o_c_o_index | 21 | pg_attribute_relid_attnam_index | 14 | pg_proc_oid_index | 10 | pg_attribute_relid_attnum_index | 9 | pg_amproc_fam_proc_index | 5 | pg_amop_opr_fam_index | 5 | pg_amop_fam_strat_index | 5 (10 rows)
Cet exemple montre une session qui vérifie les 10 plus gros index du
catalogue de la base de données « test ». La vérification de
la présence des lignes de la table dans l'index est demandée
pour le sous-ensemble des index uniques.
Puisqu'aucune erreur n'est retournée, tous les index testés semblent
être cohérents au niveau logique. Bien évidemment, cette requête
pourrait être facilement modifiée pour appeler
bt_index_check
sur chacun des index présents dans
la base de données pour lesquels la vérification est supportée.
bt_index_check
acquiert un
AccessShareLock
sur l'index cible ainsi que sur la
relation à laquelle il appartient. Ce niveau de verrouillage est le
même que celui acquis sur les relations lors d'une simple requête
SELECT
. bt_index_check
ne
vérifie pas les propriétés invariantes qui englobent les relations
enfant/parent, mais vérifiera la présence de toutes les lignes de la
table et des lignes d'index à l'intérieur de l'index quand
heapallindexed
vaut true
.
Quand il faut lancer un test de recherche de corruption,
de routine et pas trop lourd, sur un environnement de production,
l'utilisation de bt_index_check
offre généralement
le meilleur compromis entre vérification minutieuse et impact
limité sur les performances et la disponibilité de l'application.
bt_index_parent_check(index regclass, heapallindexed boolean, rootdescend boolean) returns void
bt_index_parent_check
teste que sa cible, un index
B-Tree, respecte un certain nombre de propriétés invariantes. En option,
quand l'argument heapallindexed
vaut
true
, la fonction vérifie la présence de toutes les
lignes dans la table, et la présence de tous les liens dans la structure
de l'index. Quand l'argument optionel rootdescend
vaut true
, la vérification recherche de nouveau les
lignes au niveau des feuilles en réalisant une nouvelle recherche à partir
de la racine pour chaque ligne. Les vérifications réalisables par
bt_index_parent_check
sont un sur-ensemble des
vérifications réalisées par bt_index_check
.
On peut voir bt_index_parent_check
comme une version
plus minutieuse de bt_index_check
:
contrairement à bt_index_check
,
bt_index_parent_check
vérifie également les
propriétés invariantes qui englobent les relations parent/enfant.
bt_index_parent_check
respecte la convention habituelle qui consiste à retourner une erreur si
une incohérence ou tout autre problème est détecté.
Un verrou de type ShareLock
est requis sur l'index
ciblé par bt_index_parent_check
(un
ShareLock
est également acquis sur la relation
associée). Ces verrous empêchent des modifications concurrentes par des
commandes INSERT
, UPDATE
et
DELETE
. Les verrous empêchent également la relation
associée d'être traitée de manière concurrente par
VACUUM
, ainsi que toute autre commande d'administration.
Il est à noter que cette fonction ne conserve les verrous
uniquement que durant son exécution et non pas durant l'intégralité de la
transaction.
La vérification supplémentaire qu'opère
bt_index_parent_check
est plus apte à détecter
différents cas pathologiques. Ces cas peuvent impliquer une classe
d'opérateur B-Tree implémentée de manière incorrecte utilisée pour
l'index vérifié, ou, hypothétiquement, des bugs non encore découverts
dans le code de la méthode d'accès associée à cet index B-Tree. Il est à
noter que bt_index_parent_check
ne peut pas être
utilisé lorsque le mode Hot Standby est activé (c'est-à-dire, sur un
serveur secondaire disponible en lecture seule), contrairement à
bt_index_check
.
heapallindexed
Quand l'argument heapallindexed
des fonctions de
vérification est à true
, une phase de vérification
supplémentaire est opérée sur la table associée à l'index cible.
Elle consiste en une opération CREATE INDEX
« bidon » qui vérifie la présence de tous les nouveaux
enregistrements hypothétiques d'index dans une structure de
récapitulation temporaire et en mémoire (elle est construite au besoin
durant la première phase de la vérification). Cette structure de
récapitulation prend l'« empreinte digitale » de chaque
enregistrement rencontré dans l'index cible. Le principe directeur
derrière la vérification heapallindexed
est qu'un
nouvel index équivalent à l'index cible existant ne doit avoir que des entrées
que l'on peut trouver dans la structure existante.
La phase heapallindexed
supplémentaire a un coût
significatif : typiquement, la vérification peut être plusieurs fois
plus longue. Cependant il n'y a pas de changement quant aux verrous acquis
au niveau de la table quand on opère une vérification
heapallindexed
.
La structure de récapitulation est limitée en taille par
maintenance_work_mem
. Pour s'assurer que la probabilité de
rater une incohérence ne dépasse 2 % pour chaque enregistrement qui
devrait être dans l'index, il faut environ 2 octets de mémoire par
enregistrement. Quand moins de mémoire est disponible par enregistrement,
la probabilité de manquer une incohérence augmente lentement. Cette
approche limite significativement le coût de la vérification, tout en
réduisant légèrement la probabilité de détecter un problème, particulièrement
sur les installations où la vérification est traitée comme une opération de
maintenance de routine. Tout enregistrement absent ou déformé a une nouvelle
chance d'être détecté avec chaque lancement de la vérification.
amcheck
efficacement
amcheck
peut être efficace pour détecter différents
types de modes d'échec que les sommes de contrôle de
page n'arriveront jamais à détecter. Cela inclut :
Les incohérences dans la structure causées par des implémentations incorrectes de classe d"opérateur.
Cela inclue également des problèmes causés par le changement des règles de
comparaison des collations du système d'exploitation. Les comparaisons
des données d'un type ayant une collation comme text
doivent
être immuables (tout comme toutes les autres comparaisons utilisées pour
les parcours d'index B-Tree doivent être immuables), ce qui implique que
les règles de collation du système d'exploitation ne doivent jamais changer.
Bien que cela soit rare, des mises à jour des règles des collations du
système d'exploitation peuvent causer ces problèmes. Plus généralement,
une incohérence dans l'ordre de collation entre un serveur primaire et son
réplicat est impliqué, peut-être parce que la version
majeure du système d'exploitation utilisée est
incohérente. De telles incohérences ne surviendront généralement que sur
des serveurs secondaires, et ne pourront par conséquent être détectées que
là.
Si un tel problème survient, il se peut que cela n'affecte pas chaque index qui utilise le tri d'une collation affectée, tout simplement car les valeurs indexées pourraient avoir le même ordre de tri absolu indépendamment des incohérences comportementales. Voir Section 23.1 et Section 23.2 pour plus de détails sur comment PostgreSQL utilise les locales et collations du système d'exploitation.
Les incohérences dans la structure entre les index et les tables indexées
(lorsque la vérification heapallindexed
est
réalisée).
Il n'y a pas de vérification avec la table initiale en temps normal. Les symptômes d'une corruption de la table peuvent être subtils.
La corruption causée par un hypothétique bug non encore découvert dans le code de la méthode d'accès dans PostgreSQL, dans le code effectuant le tri ou le code de gestion transactionnelle.
La vérification automatique de l'intégrité structurelle des index joue un
rôle dans les tests généraux des fonctionnalités de
PostgreSQL, nouvelles ou proposées,
qui pourraient possiblement permettre l'introduction d'incohérences
logiques. La vérification de la
structure de la table et des informations de visibilité et de statut des
transactions associées joue un rôle similaire. Une stratégie de test
évidente est d'appeler les fonctions d'amcheck
de
manière continue en même temps que les tests de régression standard sont
lancés. Voir Section 32.1 pour plus de détails sur comment lancer les
tests.
Les failles dans le système de fichiers ou dans le sous-système de stockage quand les sommes de contrôles ne sont pas activées.
Il est à noter que amcheck
n'examine une page que
telle qu'elle se présente dans un tampon en mémoire partagée lors de la
vérification, et qu'en accédant au bloc dans la mémoire partagée.
Par conséquent, amcheck
n'examine
pas forcément les données lues depuis le système de fichiers au moment de
la vérification. Notez que si les sommes de contrôles sont activées,
amcheck
peut lever une erreur de somme de contrôle
incorrecte quand un bloc corrompu est lu vers un tampon.
Les corruptions causée par une RAM défaillante, et plus largement le sous-système mémoire et le système d'exploitation.
PostgreSQL ne protège pas contre les erreurs mémoire corrigibles, et il est supposé que vous utilisez de la mémoire RAM de standard industriel ECC (Error Correcting Codes ) ou avec une meilleure protection. Cependant, la mémoire ECC n'est typiquement immunisée que contre les erreurs d'un seul bit, et il ne faut pas partir du principe que ce type de mémoire fournit une protection absolue contre les défaillances provoquant une corruption de la mémoire.
Quand la vérification heapallindexed
est réalisée,
il y a une chance fortement accrue de détecter des erreurs d'un bit car
l'égalité binaire stricte est testée et les attributs indexés de la table
sont testés.
De manière générale, amcheck
ne peut que prouver la
présence d'une corruption ; il ne peut pas en prouver l'absence.
Aucune erreur concernant une corruption remontée par
amcheck
ne devrait être un faux positif.
amcheck
remonte des erreurs dans le cas où des
conditions, par définition, ne devraient jamais arriver, et par conséquent
une analyse minutieuse des erreurs remontées par amcheck
est souvent nécessaire.
Il n'y a pas de méthode générale pour réparer les problèmes que
amcheck
détecte. Une explication de la cause principale
menant à ce que la propriété invariante soit violée devrait être étudiée.
pageinspect peut jouer un rôle utile dans le
diagnostic de la corruption qu'amcheck
détecte. Un
REINDEX
peut échouer à réparer la corruption.