Architecture d’Async\Pool

Cet article decrit la conception interne du pool de ressources universel. Si vous cherchez un guide d’utilisation, consultez Async\Pool. Pour la couche specifique a PDO, consultez Architecture du PDO Pool.

Structure de donnees

Le pool est implemente en deux couches : une structure ABI publique dans le noyau PHP et une structure interne etendue dans l’extension async.

Structures de donnees du pool

Deux chemins de creation

Un pool peut etre cree depuis du code PHP (via le constructeur Async\Pool) ou depuis une extension C (via l’API interne).

Chemin Fonction Callbacks Utilise par
PHP zend_async_pool_create() zend_fcall_t* (PHP callable) Code utilisateur
API C zend_async_pool_create_internal() pointeurs de fonctions PDO, autres extensions

La difference reside dans handler_flags. Lorsque le drapeau est active, le pool appelle la fonction C directement, contournant le surcout de l’appel d’un callable PHP via zend_call_function().

Acquire : obtention d’une ressource

acquire() -- Algorithme interne

Attente d’une ressource

Lorsque toutes les ressources sont occupees et que max_size est atteint, la coroutine se suspend via ZEND_ASYNC_SUSPEND(). Le mecanisme d’attente est similaire aux canaux :

  1. Une structure zend_async_pool_waiter_t est creee
  2. Le waiter est ajoute a la file FIFO waiters
  3. Un callback de reveil est enregistre
  4. Si un timeout est defini – un timer est enregistre
  5. ZEND_ASYNC_SUSPEND() – la coroutine cede le controle

Le reveil se produit lorsqu’une autre coroutine appelle release().

Release : retour d’une ressource

release() -- Algorithme interne

Healthcheck : surveillance en arriere-plan

Si healthcheckInterval > 0, un timer periodique est demarre lors de la creation du pool. Le timer est integre au reacteur via ZEND_ASYNC_NEW_TIMER_EVENT.

Healthcheck -- Verification periodique

Le healthcheck verifie uniquement les ressources libres. Les ressources occupees ne sont pas affectees. Si, apres la suppression des ressources mortes, le total descend en dessous de min, le pool cree des remplacements.

Tampon circulaire

Les ressources libres sont stockees dans un tampon circulaire – un buffer en anneau a capacite fixe. La capacite initiale est de 8 elements, etendue au besoin.

Les operations push et pop s’executent en O(1). Le tampon utilise deux pointeurs (head et tail), permettant l’ajout et l’extraction efficaces de ressources sans deplacer d’elements.

Integration avec le systeme d’evenements

Le pool herite de zend_async_event_t et implemente un ensemble complet de gestionnaires d’evenements :

Gestionnaire Fonction
add_callback Enregistrer un callback (pour les waiters)
del_callback Supprimer un callback
start Demarrer l’evenement (NOP)
stop Arreter l’evenement (NOP)
dispose Nettoyage complet : liberer la memoire, detruire les callbacks

Cela permet :

Ramasse-miettes

Le wrapper PHP du pool (async_pool_obj_t) implemente un get_gc personnalise qui enregistre toutes les ressources du buffer libre comme racines GC. Cela empeche la collecte prematuree des ressources libres qui n’ont pas de references explicites depuis le code PHP.

Circuit Breaker

Le pool implemente l’interface CircuitBreaker avec trois etats :

Etats du Circuit Breaker

Les transitions peuvent etre manuelles ou automatiques via CircuitBreakerStrategy :

Close : arret du pool

Lorsque le pool est ferme :

  1. L’evenement du pool est marque comme CLOSED
  2. Le timer de healthcheck est arrete
  3. Toutes les coroutines en attente sont reveillees avec une PoolException
  4. Toutes les ressources libres sont detruites via le destructeur
  5. Les ressources occupees continuent de vivre – elles seront detruites lors du release

API C pour les extensions

Les extensions (PDO, Redis, etc.) utilisent le pool a travers des macros :

Macro Fonction
ZEND_ASYNC_NEW_POOL(...) Creer un pool avec des callbacks C
ZEND_ASYNC_NEW_POOL_OBJ(pool) Creer un wrapper PHP pour le pool
ZEND_ASYNC_POOL_ACQUIRE(pool, result, timeout) Acquerir une ressource
ZEND_ASYNC_POOL_RELEASE(pool, resource) Liberer une ressource
ZEND_ASYNC_POOL_CLOSE(pool) Fermer le pool

Toutes les macros appellent des pointeurs de fonctions enregistres par l’extension async au chargement. Cela garantit l’isolation : le noyau PHP ne depend pas de l’implementation specifique du pool.

Sequence : cycle complet Acquire-Release

Cycle complet acquire -> utilisation -> release

Et ensuite ?