Chapitre 51. Fichiers de page

Une description du format de page des fichiers de la base de données.

Cette section fournit un survol du format de page utilisé par les tables et index de PostgreSQL. (Les méthodes d'accès aux index n'ont pas besoin d'utiliser ce format de page. Actuellement, toutes les méthodes d'index utilisent ce format basique mais les données conservées sur les métapages des index ne suivent généralement pas exactement les règles de disposition des éléments.) Les tables TOAST et les séquences sont formatées comme de simples tables.

Dans l'explication suivante, un octet est supposé contenir huit bits. De plus, le terme élément fait référence à une valeur individuelle d'une donnée, stockée sur une page. Dans une table, un élément est une ligne ; dans un index, un élément est une entrée d'index.

Tableau 51-1 affiche la disposition de base d'une page. Il existe cinq parties dans chaque page.

Tableau 51-1. Exemple de disposition d'une page

ÉlémentDescription
PageHeaderData20 octets de long. Contient des informations générales sur la page, dont les pointeurs vers les espaces libres.
ItemIdDataTableau de couples (décalage, longueur) pointant vers les vrais éléments.
Free spaceL'espace non alloué. Toutes les nouvelles lignes sont affectées ici, généralement à partir de la fin.
ItemsLes éléments.
Special SpaceDonnées spécifiques aux méthodes d'accès des index. Des méthodes différentes stockent des données différentes. Vide pour les tables ordinaires.

Les 20 premiers octets de chaque page consistent en un entête de page (PageHeaderData). Son format est détaillé dans Tableau 51-2. Les deux premiers champs concernent les WAL. Ils sont suivis de trois champs d'entier codé sur deux octets (trois fois deux octets, donc), (pd_lower, pd_upper, et pd_special). Ils représentent les décalages d'octets pour le début de l'espace libre, la fin de cet espace libre et le début de l'espace spécial.

Tableau 51-2. Disposition de PageHeaderData

ChampTypeLongueurDescription
pd_lsnXLogRecPtr8 octetsLSN : prochain octet après le dernier octet d'xlog
pd_suiStartUpID4 octetsSUI des dernières modifications (actuellement uniquement utilisé par le << heap AM >>)
pd_lowerLocationIndex2 octetsDécalage du début de l'espace libre.
pd_upperLocationIndex2 octetsDécalage de la fin de l'espace libre.
pd_specialLocationIndex2 octetsDécalage du début de l'espace spécial.
pd_pagesize_versionuint162 octetsInformation sur la taille de la page et le numéro de version de la disposition.

Tous les détails sont disponibles dans src/include/storage/bufpage.h.

L'espace spécial est une région à la fin de la page qui est allouée au moment de l'initialisation de la page et contient des informations spécifiques à une méthode d'accès. Les deux derniers octets de l'entête de la page, pd_pagesize_version, stockent à la fois la taille de la page et un indicateur de version. Depuis PostgreSQL 7.3, le numéro de version est 1 ; les versions précédentes utilisaient le numéro de version 0. (La disposition basique de la page et le format de l'entête n'ont pas changé mais la disposition des entêtes des lignes heap a changé.) La taille de la page est présente essentiellement en tant que vérification croisée ; avoir plus d'une taille de page dans une installation n'est pas supporté.

Après l'entête de page se trouvent les identifiants de l'élément (ItemIdData), chacun nécessitant quatre octets. Un identifiant d'élément contient un décalage d'octets vers le début de l'élément, sa longueur en octets et un ensemble de bits d'attributs qui affectent son interprétation. Les identifiants des nouveaux éléments sont alloués à la volée à partir du début de l'espace libre. Le nombre d'identifiants d'éléments présents se détermine en cherchant pd_lower, qui est incrémenté à chaque allocation d'un nouvel identifiant. Comme un identifiant d'élément n'est jamais déplacé jusqu'à sa libération, son index peut être utilisé sur le long terme pour référencer un élément, même si l'élément lui-même est déplacé dans la page pour compacter l'espace libre. En fait, chaque pointeur vers un élément (ItemPointer, aussi connu sous le nom de CTID) créé par PostgreSQL consiste en un numéro de page et l'index d'un identifiant d'élément.

Les éléments eux-mêmes sont stockés dans l'espace à partir de la fin de l'espace libre. La structure exacte varie en fonction du contenu de la table. Les tables et les séquences toutes deux utilisent une structure nommée HeapTupleHeaderData, décrite ci-dessous.

La section finale est la << section spéciale >> qui peut contenir tout ce que la méthode d'accès souhaite y stocker. Les tables ordinaires ne l'utilisent absolument pas (indiqué en égalant pd_special à la taille de la page).

Toutes les lignes de table sont structurées de la même façon. Il y a un entête de taille fixe (occupant 23 octets sur la plupart des machines) suivi d'un bitmap nul optionnel, d'un champ optionnel d'identifiant de l'objet et des données utilisateur. L'entête est détaillé dans Tableau 51-3. Les données utilisateur réelles (colonnes de la ligne) commencent au décalage indiqué par t_hoff, qui doit toujours être un multiple de la distance MAXALIGN pour la plateforme. Le bitmap nul est présent uniquement si le bit HEAP_HASNULL est positionné dans t_infomask. S'il est présent, il commence juste après l'entête fixé et occupe assez d'octets pour disposer d'un bit par colonne de données (c'est-à-dire l'ensemble des bits de t_natts). Dans cette liste de bits, un bit à 1 indique non nul, un bit à 0 nul. Quand le bitmap n'est pas présent, toutes les colonnes sont supposées non nulles. L'identifiant de l'objet est présent seulement si le bit HEAP_HASOID est activé dans t_infomask. S'il est présent, il apparaît juste avant la limite t_hoff. Tout bit supplémentaire nécessaire pour faire de t_hoff un multiple de MAXALIGN apparaîtra entre le bitmap nul et l'identifiant de l'objet. (Du coup, ceci nous assure que l' identifiant de l'objet est bien aligné.)

Tableau 51-3. Disposition de HeapTupleHeaderData

ChampTypeLongueurDescription
t_xminTransactionId4 octetsinsère le tampon XID
t_cminCommandId4 octetsinsère le tampon CID (couvert avec t_xmax)
t_xmaxTransactionId4 octetssupprime le tampon XID
t_cmaxCommandId4 octetssupprime le tampon CID (couvert avec t_xvac)
t_xvacTransactionId4 octetsXID pour l'opération VACUUM déplaçant la version de la ligne
t_ctidItemPointerData6 octetsTID actuel de cette version de ligne ou de celle plus récente
t_nattsint162 octetsnombre d'attributs
t_infomaskuint162 octetsdifférents drapeaux
t_hoffuint81 bytedécalage des données utilisateur

Tous les détails sont disponibles dans src/include/access/htup.h.

Interpréter les données actuelles peut seulement être fait avec des informations obtenues à partir d'autres tables, principalement pg_attribute. Les champs particuliers sont attlen et attalign. Il n'existe pas de façon d'obtenir directement un attribut particulier, sauf s'il n'y a que des champs de taille fixe et aucun NULL. Tout ceci est emballé dans les fonctions heap_getattr, fastgetattr et heap_getsysattr.

Pour lire les données, vous avez besoin d'examiner chaque attribut. Vérifiez tout d'abord que le champ est NULL en accord avec le bitmap nul. Si c'est le cas, allez au suivant. Puis, assurez-vous que vous avez le bon alignement. Si le champ est un champ de taille fixe, alors tous les octets sont simplement placés. S'il s'agit d'un champ à taille variable (attlen == -1), alors cela devient un peu plus compliqué car il faut utiliser la structure de longueur variable varattrib. Suivant les options, les données peuvent être en ligne, compressées ou dans une autre table (TOAST).