PostgreSQLLa base de données la plus sophistiquée au monde.

49.4. Considérations pour le verrouillage d'index

Les méthodes d'accès aux index doivent gérer des mises à jour concurrentes de l'index par plusieurs processus. Le système principal PostgreSQL™ obtient AccessShareLock sur l'index lors d'un parcours d'index et RowExclusiveLock quand il le met à jour (ceci incluant le VACUUM simple). Comme ces types de verrous ne sont pas en conflit, la méthode d'accès est responsable de la gestion d'un verrouillage plus précis si nécessaire. Un verrou exclusif sur l'index entier sera seulement pris lors de la création, destruction de l'index, dans une opération REINDEX ou lors d'un VACUUM FULL.

Construire un type d'index qui supporte les mises à jour concurrentes requiert une analyse complète et subtile du comportement requis. Pour les types d'index B-tree et hash, vous pouvez lire les décisions du concept dans src/backend/access/nbtree/README et src/backend/access/hash/README.

En plus des besoins de cohérence interne de l'index, les mises à jour concurrentes créent des problèmes de cohérence entre la table parent (l'en-tête) et l'index. Comme PostgreSQL™ sépare les accès et les mises à jour de l'en-tête de ceux de l'index, il existe des possibilités pour que l'index ne soit pas à jour par rapport à l'en-tête. Nous gérons ce problème avec les règles suivantes :

  • Une nouvelle entrée dans l'en-tête est effectuée avant sa contrepartie dans l'index (du coup, un parcours d'index concurrent pourrait ne pas voir l'entrée dans l'en-tête ; ceci est bon car le lecteur de l'index ne sera pas intéressé par une ligne non validée... voir Section 49.5, « Vérification de l'unicité de l'index »).

  • Quand une entrée de l'en-tête doit être supprimée (par VACUUM), toutes les entrées de l'index doivent d'abord être supprimées.

  • Un parcours d'index doit maintenir un lien sur la page d'index contenant le dernier élément renvoyé par amgettuple, et ambulkdelete ne peut pas supprimer les entrées de pages qui sont liées à d'autres processus. Le besoin de cette règle est expliqué plus bas.

Sans la troisième règle, il est possible qu'un lecteur d'index voit une entrée dans l'index juste avant qu'elle ne soit supprimée par un VACUUM, puis d'arriver à l'entrée correspondante de l'en-tête après qu'elle soit supprimée par le VACUUM. Ceci ne crée pas de problèmes sérieux si ce numéro d'élément est toujours inutilisé quand le lecteur l'atteint car un emplacement d'élément vide sera ignoré par heap_fetch(). Mais que se passe-t'il si un troisième moteur a déjà ré-utilisé l'emplacement de l'élément pour quelque chose d'autre ? Lors de l'utilisation d'une image compatible MVCC, il n'y a pas de problème car le nouvel occupant de l'emplacement est certain d'être trop nouveau pour accepter ou renvoyer une ligne qui, en fait, ne correspond pas aux clés de parcours. Nous pouvons nous défendre contre ce scénario en réclamant que les clés de parcours soient de nouveau vérifiées avec la ligne d'en-tête dans tous les cas mais c'est bien trop coûteux. À la place, nous utilisons un lien sur une page d'index comme un proxy, pour indiquer que le lecteur pourrait toujours être « en parcours » à partir de l'entrée de l'index jusqu'à l'entrée correspondante. Faire bloquer ambulkdelete sur un tel lien nous assure qu'un VACUUM ne peut pas supprimer l'entrée de l'en-tête avant que le lecteur n'en ait terminé avec lui. Cette solution coûte peu en temps d'exécution mais ajoute un délai dans le blocage dans de rares cas où il existe réellement un conflit.

Cette solution requiert que les parcours d'index soient « synchrones » : nous devons récupérer chaque ligne d'en-tête immédiatement après avoir parcouru l'entrée d'index correspondante. Ceci est coûteux pour plusieurs raisons. Un parcours « asynchrone » dans lequel nous récupérons les TID de l'index et dans lequel nous visitons seulement les en-têtes de lignes un peu plus tard, requiert moins de temps de verrouillage de l'index et pourrait autoriser un modèle d'accès à l'en-tête plus efficace. En plus de l'analyse ci-dessus, nous devons utiliser l'approche synchronisée pour les images non compatibles avec MVCC mais un parcours asynchrone est possible pour une requête utilisant une image MVCC.

Dans un parcours d'index amgetmulti, la méthode d'accès n'a pas besoin de garantir la conservation d'un lien à l'index sur aucune des lignes renvoyées, ce qui est impraticable pour toutes sauf la dernière). Du coup, il est plus sage d'utiliser plusieurs parcours avec des images compatibles MVCC.