Pools
L’un des points les plus importants à comprendre concernant l’API d’Apache est la notion de pool. Il s’agit d’un ensemble de ressources regroupées (descripteurs de fichiers, mémoire, processus fils, sockets, tubes de communication, etc.) qui seront libérées lorsque le pool est supprimé. Quasiment toutes les ressources utilisées par Apache se trouvent dans des pools et leur utilisation ne doit être évitée qu’après mûre reflexion.
Une fonctionnalité intéressante des ressources des pools est que la plupart d’entre elles ne peuvent être libérées qu’en supprimant le pool. Les pools peuvent contenir des sous-pools qui, eux-mêmes, peuvent contenir des sous-sous-pools, etc. Lorsqu’un pool est supprimé, tous ses sous-pools le sont aussi.
Assez naturellement, Apache crée un pool lorsqu’il démarre, à partir duquel d’autres pools seront créés. Les informations sur la configuration sont stockées dans ce pool (elles sont donc détruites et recréées lorsque le serveur est relancé par un kill ). Le niveau de pool suivant est créé pour chaque connexion reçue par Apache et supprimé à la fin de celle-ci. Comme une connexion peut s’étendre sur plusieurs requêtes, un nouveau pool est créé (et supprimé) pour chaque requête. Au cours du traitement d’une requête, les différents modules créent leurs propres pools ; certains produisent également des sous-requêtes, qui sont passées aux mécanismes de l’API comme s’il s’agissait de vraies requêtes. On a accès à chacun de ces pools via les structures qui leur correspondent (la structure de connexion, la structure de requête, etc.).
Sachant tout cela, nous pouvons établir de façon plus précise les moments où vous ne devez pas utiliser un pool : lorsque la durée de vie de la ressource en question ne correspond pas à celle d’un pool. Si vous avez besoin d’un stockage temporaires (ou de fichiers, etc.), vous pouvez créer un sous-pool dans un pool approprié (le pool de requête est le candidat le plus fréquent) et le supprimer lorsque vous n’en avez plus besoin : les durées de vie plus courtes que celle du pool peuvent être gérées facilement. Le seul exemple à notre connaissance où il n’existait pas de pool approprié dans Apache 1.3 était pour le code de gestion des listeners ( copy_listeners() et close_unused_listeners() dans http_main.c ), qui avait une durée de vie plus longue que le pool de plus haut niveau ! Cependant, l’introduction des modèles de processus enfichables dans Apache 2.x a changé cela : il existe maintenant un pool approprié, le pool de processus, qui réside dans process_rec, documenté dans include/httpd.h.
Cela dit, tout n’est pas perdu -- Apache 2.0 nous donne à la fois un nouvel exemple et une nouvelle excuse pour ne pas utiliser les pools. L’excuse : lorsque l’utilisation d’un pool créerait soit une consommation excessive de mémoire, soit trop de création et de destruction de pools. L’exemple : les bucket brigades (ou, plus précisément, les buckets ), qui sont présentées plus loin.
Les pools présentent un certain nombre d’avantages, dont le plus évident est que les modules peuvent utiliser des ressources sans devoir se soucier du moment et du moyen de les libérer. Ainsi, lorsque Apache traite une condition d’erreur, il se contente de se sortir d’affaire, détruisant le pool associé à la requête erronée et confiant dans le fait que tout sera proprement nettoyé. Comme chaque instance d’Apache peut traiter de nombreuses requêtes, cette fonctionnalité est vitale pour la fiabilité du serveur. Ce n’est pas une surprise : les pools interviennent dans quasiment tous les aspects de l’API d’Apache, comme nous le verrons dans ce chapitre. Ils sont du type apr_pool_t, défini dans srclib/apr/include/apr_pools.h.
Comme de nombreux autres aspects d’Apache, les pools sont configurables : vous pouvez ajouter votre propre gestion de ressource à un pool, ce qui consiste essentiellement à enregistrer des fonctions de nettoyage (voir l’API pool dans srclib/apr/include/apr_pools.h ).