(fourni
par )
Cache en mémoire vive
Maintenant que nous avons défini la structure de base de notre
bibliothèque, il est temps d'implémenter les fonctionnalités
de stockage. Avant de continuer, je voudrais indiquer deux
choses : la première est que cette bibliothèque est prévue
pour tenir dans un seul fichier. Nous verrons plus loin pourquoi,
mais il suffit de dire qu'un seul fichier à inclure est une
bonne politique. Par conséquent, chaque fonction est préfixée
avec 'cache_', même si cela
conduit à des redondances comme l'horrible cache_cache().
Nous souhaitons ici réduire le risque de conflit avec les
autres fonctions de votre projet. Deuxièmement, la chaîne
'cache_' n'apparaît jamais
ailleurs que dans un nom de fonction : cela vous permet de
modifier facilement ce préfixe avec une autre valeur par un
simple rechercher/remplacer dans la bibliothèque.
Commençons notre implémentation avec le code concernant la
mémoire partagée : vous pouvez voir au listing
2. Comme je l'ai mentionné auparavant, shm est une extension
native aux systèmes Unix, mais elle est disponible sur de
nombreux autres systèmes, sous d'autres noms. Sur Windows,
vous profiterez de cette fonctionnalité si vous utilisez PHP
comme module du serveur Web, IIS ou Apache.
Utiliser
la mémoire partagée est très simple, étant donné qu'elle se
comporte en pratique comme un fichier, mais avec différents
noms de fonctions: on ouvre un segment de mémoire, on y lit
ou écrit, et on le referme. C'est classique.
Comme avec la plupart des opérations reliées à des objets
partagés, comme nous le verrons ultérieurement avec les fichiers,
il existe un problème d'accès simultané lorsque vous manipulez
des données dans un environnement multi-processus : plusieurs
processus peuvent décider d,accéder en même temps à une ressource,
et cela va conduire directement au désastre.
Pour pallier ce problème, la solution la plus simple est d'utiliser
un sémaphore binaire : c'est un sémaphore qui ne peut être
manipulé que par un processus à la fois. Il nous permettra
de poser un verrou exclusif sur une ressource particulière.
Une fois qu'un script a acquis un verrou, aucun autre processus
du système, y compris un processus non-PHP, ne pourra poser
le même verrou. De cette manière, tant que nous pensons à
bien libérer le verrou, nous pouvons être sûr qu'un seul processus
modifie le bloc de mémoire à un moment donné.
Si vous regardez le listing
2, vous noterez que les deux fonctions cache_shm_get_cached_version()
et cache_shm_cache() commencent
par créer un identifiant numérique associé à la ressource
en cache. Cela se fait avec la fonction crc32(),
qui retourne un entier. En réalité, nous devrions nous assurer
que le nombre que nous utilisons est bien unique. Pour ma
part, je n'ai jamais rencontré de situation où crc32()
me retournait deux fois la même valeur avec des contenus différents.
La marge d'erreur est suffisamment petite pour nous passer
d'une vérification supplémentaire. Assurez-vous de ne pas
abuser du nombre de ressources en cache.
La raison de l'utilisation de crc32()
plutôt qu'une fonction plus sécuritaire comme ftok()
est que cette dernière n'est pas disponible sur tous les systèmes
d'exploitation, par exemple Windows. De plus, ftock()
fonctionne avec des fichiers : elle crée un identifiant numérique
à partir de nom de fichier, ce qui revient à utiliser crc32(),
selon moi. En observant le code de plus près, notamment à
la ligne 101 du listing
2, vous verrez que je préfère créer un segment de mémoire
différent pour chaque variable créé. Par conséquent, j'ai
besoin d'une fonction qui soit capable de créer des identifiants
différents pour chaque script ou fichier.
|
Forum |
|
Réagissez
dans les forums
de JDN Développeurs
|
Mon approche est ici différente de celle de PEAR. Les routines
shm de PEARCache créent un bloc de mémoire unique dans lequel
les données sont stockées. Un mécanisme de collecteur supprime
les données trop vieilles. C'est une solution élégante, mais
je crois que mon approche est plus efficace, car, avec PEAR,
si une opération de cache prend du temps, toutes les autres
opérations sont retardées, aussi bien en écriture qu'en lecture.
D'un autre côté, mon approche consomme plus de mémoire et
de pointeurs, ce qui conduit à plus de fragmentation. Cela
reste dès peu probable.
|