cache mysql maison

WRInaute accro
Bonjour

J'ai MariaDB récente avec query_cache_size à zéro.

J'ai fait une librairie ORM ( Object Relational Mapping) d'accès MySQL.

Je compte implémenter un cache MySQL maison, tel que les requêtes les plus anciennes soient effacées d'abord.

Mais comment identifier les requêtes MySQL dans le cache, pour les apparier avec celles exécutées dans les fichiers php ?

D'après un hash code ?

Celui de la requête MySQL alpĥabétique ?

Merci beaucoup pour vos réponses.

Amicalement.
 
WRInaute accro
Rebond

Le problème ( me semble-t-il ) , serait de normaliser la rédaction des requêtes MySQL ( avec mon ORM ), pour que deux requêtes de fonctionnalité et paramètres identiques, aient le même hash code ( c'est-à-dire en théorie exactement la même requête alphabétique ).

Comment faire celà
 
WRInaute impliqué
Je compte implémenter un cache MySQL maison, tel que les requêtes les plus anciennes soient effacées d'abord.

Pourquoi se lancer dans un truc pareil ? Tu n'arriveras jamais à optimiser aussi bien que MariaDB qui profite de plus de 20 ans d'optimisations et qui est écrit en C, C++.
Si tu as un problème de perfs, c'est que tu devrais te pencher sur l'écriture des requêtes, les formats de tes colonnes, les index, ou éventuellement la configuration des caches de MariaDB (mais ça, c'est surtout quand on a une grosse base et du trafic).

Comment faire celà
Bah c'est super simple, tu parses la requête, tu écris un optimiseur, et tu finis avec un résultat normalisé. N'oublie pas de tout optimiser, hein. Du genre un LIKE "Salut%", c'est identique à un LIKE "SALUT%" pour une colonne dont le type est insensible à la casse. Ou un WHERE colonnea > colonneb, c'est identique à colonneb < colonnea, ce genre de choses.
Oh, et attention aux requêtes avec des fonctions, comme NOW(). Parce qu'un NOW() au moment de mettre en cache et de l'appel du cache, forcément, ça ne fonctionne plus. Mais bon, tu peux peut-être quand même faire un subset pour le reste de la requête.

Ah oui, et ton idée d'effacer les requêtes les plus anciennes, c'est pas top. Ce qu'il faut faire c'est invalider les caches quand il y a une mise à jour des données (bien sûr), et garder en cache les requêtes les plus fréquentes et/ou les plus lourdes en priorité.
Tu ne vas pas éliminer une requête qui est appelée sur chaque page et qui prend trois secondes si ta limite est de 40 requêtes, juste parce que le reste d'une page a nécessité 40 requêtes prenant 0,01 seconde chacune.

En gros, pour être aussi performant, il faut que tu réécrives un bon gros bout de MariaDB, en suivant exactement sa logique, mais avec un overhead supérieur parce que ton code sera écrit en PHP.

Après, si tu t'ennuies et que ça t'éclate, pourquoi pas, hein..
 
WRInaute accro
+1 @colonies
Tu vas encore réinventer la roue... MySQL/MariaDB ont déjà un cache qui fait pareil.
Lance une requête lourde 2 fois tu verras le temps d'exécution.
 
WRInaute accro
Bonjour colonies et spout

Je croyais que MariaDB à partir de la version 10.1.7 désactivait le cache.

C'est vrai qu'il suffit de mettre query_cache_size > 0 pour qu'il y ait un cache.

Pour ce qui est de la priorité des requêtes à effacer, je voyais un mix des tailles et fréquences des requêtes, et du degré d'ancienneté.

Pour la formule je ne sais pas.

Le tout en RAM/fichier tmpfs. ( ou plusieurs fichiers suivant répertoire du script ).

Comme j'ai fait cet ORM, je peux lui intégrer ce cache et faire l'optimiseur, vu que je parse déjà les instructions MySQL orientées objet.

Je vais me pencher sur le problème de la fragmentation du/des fichiers cache.

Merci beaucoup de votre aide.

Amicalement.
 
WRInaute accro
Pardon

Pour ce qui est de l'ordre dans lequel effacer les requêtes en cache, dans une première approche :

- Ordre croissant : taille
- Ordre croissant : ancienneté
- Ordre croissant : fréquence

Ou bien un ou deux indices composites de tri, calculés par une combinaison linéaire de type : indice_tri = a x + b y + c z / ( a + b + c ), et a, b et c progressivement ajustés par des mesures d'efficacité.

Quelles mesures d'efficacité de timing ?

Peut-être minorer les durées globales des requêtes ?

Merci beaucoup pour vos réponses.

Amicalement.
 
WRInaute accro
Bonjour spout ;)

Comme tout est affaire de pondération.

J'ajusterais les a, b et c par recherches dichotomiques et/ou mesures ?

Je vais faire tourner l'algorithme à la main.

Merci beaucoup de ton aide.

Amicalement.
 
WRInaute accro
Voili, voilou

Donc : Fréquence et ancienneté, c'est la même chose.

Effacement par :

1) Durée réelles des requêtes avant cache,
2) Fréquence/ancienneté.

J'envisage de normaliser les coefficients a et b de la combinaison linéaire, avec les écarts-types et valeurs totales.

De manière à ce que les écarts à la moyenne des composantes a x et b y soient à peu près similaires.

Celà vous paraît-il viable ?

Merci pour votre aide.

Amicalement.
 
WRInaute passionné
Alors je ne comprends rien à ces histoires de math, mais si vous parlez de caches disque (et non mémoire), perso j'ai mis mes fichiers de cache dans des dossiers temporaires qui correspondent chacun à la table principale qui est attaquée par les requêtes (même nom en fait).
Ensuite, quand une donnée est changée dans la table (ou dans une des tables secondaires de ces requêtes), je renomme le dossier (ce qui est instantané, quel que soit le nombre de fichiers), le recrée pour accueillir peu à peu à nouveau les résultats des requêtes.
Et dans une commande shell en parallèle non blocante (mais ça pourrait être un script cron lancé n'importe quand), je supprime l'ancien dossier renommé. Comme ça, la suppression des caches est rapide ! Car supprimer des dizaines de fichiers à chaque changement de données, oui c'est assez lent si le disque est assez utilisé par ailleurs au même moment... Alors que renommer simplement le dossier, j'ai constaté que c'était la solution la plus rapide pour s'en débarrasser sans faire de blocage.
 
WRInaute passionné
Ah donc en mémoire, donc ce que j'ai dit ne compte pas.
Eh bien je me moquerais pas mal de l'ordre ou du nombre de caches à supprimer, puisqu'en RAM c'est ultra-rapide, alors il faut bien faire quelques benches et tout tracer en log pour vérifier, mais si c'est pour gagner quelques millisecondes aucun intérêt de faire de la complexité pour des micro-optimisations. J'attends d'abord de rencontrer un problème de lenteur avant de réfléchir à des solutions :)
 
WRInaute accro
Bonjour rick38

Merci beaucoup beaucoup pour ton aide. ;)

Voici ce que je vais faire :

Mes fichiers temporaires habituels quotidiens en tmpfs,

Le reste comme tu dis, noms de fichiers : TABLE1(_TABLE2)?_date.txt en tmpfs, etc, suppression si nécessaire, du plus ancien au plus récent.

Modification : Voir ci-dessous, plus besoin de dates, suppression dynamique des données.

J'ajoute : 1 timestamp par requête, mis à jour à chaque utilisation cache, et lecture séquentielle des fichiers.

Suppressions : Je pense faire par cron comme tu dis, mapping fichiers en variables indicées, écriture sur fichier intermédiaire tmpfs autre nom, puis renommer le fichier intermédiaire vers fichier départ. Celà en ne supprimant que les données anciennes.

Génial, merci pour ton aide.

Amicalement.
 
WRInaute accro
Je n'arrive toujours pas à imaginer la Rolls de site que tu aurais si tu passais tout ce temps à autre chose que des broutilles :p
 
WRInaute accro
Bon

Je visualise sur mon ordi les ordres MySQL, qui sont très répétitifs.

Je vais suivre l'avis de colonies, et grouper ces trucs.

La fonctionnalité de mon orm maison est presque complète ( pratiquement toutes les instructions MySQL de type Data Manipulation Language ( pas administration ) sont prises en compte ).

Une petite étape de groupage des instructions répétitives faite, je vérifierai la rectitude des codes produits, et après c'est le cache.

Merci beaucoup pour votre aide.

Amicalement.
 
WRInaute accro
Bonjour

Est-ce que ceci est valide en MySQL/MariaDB ?

SELECT COUNT(NUMJO) FROM `COURSES` WHERE `NUMJO` IN (5499, 283, 807, 10955, 253, 3677, 279, 11328) AND `NUMCRS`<'171225' AND `RANG`!='99' GROUP BY `NUMJO`

Merci beaucoup.

Amicalement.
 
WRInaute occasionnel
SELECT COUNT(NUMJO) FROM `COURSES` WHERE `NUMJO` IN (5499, 283, 807, 10955, 253, 3677, 279, 11328) AND `NUMCRS`<'171225' AND `RANG`!='99' GROUP BY `NUMJO`

alors en 2 mots, un moteur de bases de données, son rôle c'est de gérer les données. Donc le but c'est bien que ce ce soit lui qui s'emmerde a stocker les données, les trier, les mettre ou il veut, comme il veut et à optimiser son truc.
Vu de l'utilisateur, en fonction du nombre du volume de données, des accès concurrentiels sur ces mêmes données (parce que quand même le but d'utiliser un moteur de base de données c'est souvent aussi parce que plusieurs personnes vont travailler sur les mêmes données), on a quelques paramètres sur lesquels agir.
En gros beaucoup d'accès, peu de données qui varient pas. En mémoire, en cache autant que faire se peut.
Du volume, on oublie la mémoire.. Il faut trouver la juste balance entre optimisation et brouettisations bug parce qu'on on rien compris.

La requête, ok du sql level 0

En gros ce qui va optimiser une BD, c'est la manière dont sont découpées les tables, les données.
C'est impossible de dire si la requête est bonne sans avoir le schéma de la BD. On sent quand même a plein nez une grosse ftat table bien pourrie
Et les BD relationnelles, elles sont très fortes et très rapides pour faire des jointures entre les tables
Si on a 400 rows dans une flat table, OSEF la base de donnée, elle sert à rien
 
WRInaute accro
Docteur rollback

Celà pourrait dépendre des index et clés étrangères ( FOREIGN KEY ) entre tables.

Le pivots des équijointures sont des foreign keys ?

Merci beaucoup de ton aide; ;)

Amicalement.
 
WRInaute occasionnel
??????? je passe des journées entières à expliquer que l'informatique est simple et que toujours derrière les mots blablabla de toutes les technologies informatiques il y a toujours des notions super simples mais là je comprends rien. Et je ne suis pas docteur, c'est pas assez haut à la fac
 
WRInaute accro
Bonjour rollback

Le fait est qu'au mieux les colonnes NUMJO et NUMCRS sont en index multiples, et quand on sait comment MySQL/MariaDB traite les index...

Code:
MariaDB [turf]> EXPLAIN SELECT COUNT(NUMJO) FROM `COURSES` WHERE `NUMJO` IN (5499, 283, 807, 10955, 253, 3677, 279, 11328) AND `NUMCRS`<'171225' AND `RANG`!='99' GROUP BY `NUMJO`; 
+------+-------------+---------+-------+------------------------------------+----------+---------+------+-------+------------------------------------+
| id   | select_type | table   | type  | possible_keys                      | key      | key_len | ref  | rows  | Extra                              |
+------+-------------+---------+-------+------------------------------------+----------+---------+------+-------+------------------------------------+
|    1 | SIMPLE      | COURSES | range | IX_NUMCRS_NUMCH,IX_NUMJO,IX_NUMCRS | IX_NUMJO | 8       | NULL | 43653 | Using index condition; Using where |
+------+-------------+---------+-------+------------------------------------+----------+---------+------+-------+------------------------------------+
1 row in set (1.004 sec)
MariaDB [turf]>

Quel SGDBR tu me conseillerais ?

PostgreSQL ou autre chose ?

Merci beaucoup de ton aide. ;)

Amicalement.
 
WRInaute impliqué
Moi je te conseillerais de faire confiance à ta DB. Je te l'ai déjà écrit plus haut : tu ne pourras jamais battre son niveau d'optimisation, et si c'est le cas, c'est que soit la structure de tes tables, soit ta config MySQL est en cause. Ou même les deux.
Ce que tu essayes de faire est d'un niveau qui te dépasse. Si si, je t'assure. Et c'est pas une offense, tu t'attaques à un truc où pour faire mieux coté PHP que coté DB, il faudrait que tu sois 10x meilleur que les gens qui écrivent les DB. Toute la communauté. Avec des décennies d'expérience.

Au fait, qu'est-ce qui se passe avec ton système de cache si je change la structure d'une table ?
Bah c'est foireux, à moins de, pour chaque accès, vérifier la structure des tables de la query, en plus de la parser. Et si c'est bon, faire un accès au FS.
Dans tous les cas, tu seras plus lent que MariaDB/MySQL.
Je répète : DANS TOUS LES CAS.
Laisse tomber.
 
WRInaute accro
Pardon

Pour le 1 ) : Il n'y a plus de cache actif ( par défaut ) à partir de MariaDB 1.5.7.

Pour le 2) : Mon cache en RAM, et remise à zéro facile dans ce cas ( rare ).

Amicalement.
 
WRInaute impliqué
Pour le 1 ) : Il n'y a plus de cache actif ( par défaut ) à partir de MariaDB 1.5.7.
Aaaaah, ok. Sauf qu'il n'y a jamais eu de version 1.5.7 de MariaDB, et que ton affirmation est fausse.
Il y a des caches dans MariaDB. Des tas et des tas de caches.

Tu peux commencer par regarder ça :
Code:
SHOW VARIABLES LIKE '%cache%'

Et puis ça :
Code:
SELECT  ENGINE,
        ROUND(SUM(data_length) /1024/1024, 1) AS "Data MB",
        ROUND(SUM(index_length)/1024/1024, 1) AS "Index MB",
        ROUND(SUM(data_length + index_length)/1024/1024, 1) AS "Total MB",
        COUNT(*) "Num Tables"
FROM  INFORMATION_SCHEMA.TABLES
WHERE  table_schema not in ("information_schema", "PERFORMANCE_SCHEMA", "SYS_SCHEMA", "ndbinfo")
GROUP BY  ENGINE;
 
WRInaute accro
Bonjour colonies

Vu sur le site de MariaDB :

Code:
   To see if the cache is enabled, view the query_cache_type server variable. It is enabled by default in MariaDB versions up to 10.1.6, but disabled starting with MariaDB 10.1.7 - if needed enable it by setting query_cache_type to 1.

Donc : 10.1.7 et non pas 1.5.7.

On peut activer le cache.

Le problème, est qu'un cache généraliste tout azimut est moins performant qu'un cache spécialisé.

Amicalement.
 
WRInaute impliqué
Mais il y a un paquet d'autres caches dans MariaDB / MySQL. Le cache de queries n'a pas été désactivé par hasard, c'est parce qu'il peut facilement dégrader les perfs.
https://haydenjames.io/mysql-query-cache-size-performance/

Si tu fais un cache de toutes les queries d'une page d'accueil qui a largement plus d'accès que de mises à jour, et que tu peux invalider le cache manuellement, ça peut valoir le coup (ou même mettre en cache le HTML généré à partir de ces données). Mais pour des queries individuelles, tu vas avoir le même problème qui fait que ce cache a été désactivé : un overhead trop important.

Mais bon... j'ai l'impression que quoi qu'on te dise, tu continueras, donc tu verras tout ça à la fin, en faisant des benchs.
 
WRInaute occasionnel
Je ne vais pas embourber le sujet, je ne suis pas spécialiste de mysql, un peu plus de trucs comme sqlserver ou la crémerie d'en face chez oracle (bien qu'il ont acheté mysql)
Juste une idée d’optimisation, faire des procédures stockées, déjà ca évite de parser le sql a chaque fois...
Et les db sont nulles pour parser le sql... A l'inverse elles aiment bien savoir à l'avance ce qu’elles doivent faire pour pondre un résultat qui peut êrte n'a pas changé, et est là dans une certaine zone pour quelques instants encore...
 
WRInaute accro
Bonjour

J'ai besoin d'aide.

J'obtiens ceci comme résultat de :

SELECT IFNULL(MIN(NUMT),-1) AS TMP_NUMT FROM `TERRAINS` WHERE `NOMT`='Reunion:1:COURSE:1:SIMPLE:TRIO:COUPLES' LIMIT 1 :


Array
(
[TMP_NUMT] => 6765
)


Et mon instruction orm de départ est :

$row = $new_conn->TABLE('TERRAINS')->WHERE(['NOMT', SQLChaine($terrain)])->SELECT($new_conn->RAW('IFNULL(MIN(NUMT), -1) AS TMP_NUMT'))->FIRST();

L'array ci-dessus ( correcte ) est affichée et rendue par FIRST(), mais il semble que $row soit booléen et non une array.

Spout, dans quel ordre sont interprétée les fonctions TABLE, WHERE, SELECT, RAW et FIRST ?

Je croyais que c'était de gauche à droite ?

Merci beaucoup de ton aide.

Respectueusement.
 
WRInaute accro
Je vous demande pardon

C'est simple : La fonction de cache rendait true au lieu de la requête cachée.

Bien amicalement.
 
WRInaute accro
Et voilà

Pour la mise à jour de ma bdd ce soir :

1705 requêtes SQL ( réelles ou cachées ),

1219 dans le cache. ( SQL réelles seulement ).

Donc : 1705 - 1219 = 486 lue sdans le cache.

Des SELECT instantanés cependant, pour les requêtes rapides je peux ne pas faire de cache, en préfixant avec : CACHE(false)->

Cà roule.

Merci beaucoup de votre aide.
 
WRInaute accro
cavemen-wheel-cartoon-300x178.png
 
WRInaute accro
Merci Spout ;)

J'aurais besoin de savoir si mon site est accessible en ipv6 ?

Je ne peux pas rediriger http vers https, car j'ai un certif Letsencrypt, avec renouvellement en http.

Merci beaucoup.
 
WRInaute accro
Ortolojf, vu le nombre de messages, questions concernant ton site et surtout tes problèmes à implémenter des fonctionnalités sur ton serveur, il y a bien longtemps que je me serai tourné vers un système de gestion de serveur.

Pour ma part qui suis une quiche en SSH ( si si le SSH ne m'aime pas :) ), certains du forum pourront en témoigner, je me sers d'une surcouche sur mes serveurs, surcouche qui s'appelle Plesk et qui me permet de gérer efficacement, rapidement et surtout avec compréhension mes serveurs et les sites qui sont dessus. Bon, les puristes te diront que cela rajoute encore une couche intermédiaire à Debian, mais pour ma part cela me permet de ne pas être obligé de me servir de SSH même s’il m'arrive de le faire pour des commandes précises.

Bref, si tu patauges dans la semoule, si tu ne comprends pas trop comment tout cela fonctionne, sers-toi d'un gestionnaire de serveur comme Plesk ou autre, il y en a plusieurs. Et tu pourras par exemple implémenter Letsencrypt en 10 secondes chrono avec gestion des sous-domaines, prise en charge dans la messagerie, etc. Il en sera de même pour la gestion de tes bases de données, de tes abonnements, de tes droits, bref de toutes les questions que tu as posées jusqu'à aujourd'hui, souvent en n’écoutant pas les recommandations de personnes qualifiées soit dit en passant.
 
WRInaute accro
Bon bon

Je ne tiens pas à activer ma connexion ipv6 Free , par mesure de sécurité.

Est-ce mon site est accessible en ipv6 ?

Je te dirais le niveau de complexité de mes programmes PHP, tu frémirais d'horreur. ;)

Pour l'admin je me débrouille.

Amicalement.
 
WRInaute occasionnel
c'est sur plesk c'est bien, un peu payant, les indiens aiment bien Cpanel........ gare aux failles mais il y en a moins que sur un serveur mal géré
 
WRInaute accro
Bon bon...

J'ai pratiquement terminé l'alpha du cache.

L'algorithme est le suivant :

Ouverture du ficher cache en lecture binaire ( "br" ),
Lecture séquentielle,
Fermeture fichier

Hash requête existe ?
Oui : rend le cache,
Non : Lecture Bdd, cache produit,

Ouverture fichier cache en append ( "a+" ),
Ecriture avec fwrite.
Fermeture fichier.
Rend le cache,

Je met aussi un timestamp dans l'enreg.

Une question à propos de fwrite ( un fichier cache par script , fichier binaire ) :
Est-ce que les écritures ( partition tmpfs ) avec fwrite sur un même fichier sont suffisamment instantanées, pour qu'il n'y ait pas de collisions ?

Les fichiers seront binaires, vu la longueur des requêtes/enregs.

Les data sont écrites une ligne ( virtuelle avec délimiteur ), à chaque mise en cache.

Sinon, comment gérer les accès simultanés en écriture ?

Des sémaphores rapides en mémoire ?

Merci.
 
WRInaute accro
Rebond ;)

Une autre question : Qu'est-ce qui est le plus rapide, texte ou binaire ?

1) Lecture séquentielle,

2) Ecriture en append.

Merci beaucoup de vos réponses.

Amicalement.
 
WRInaute impliqué
Ce qui est le plus rapide, c'est utiliser une base de donnée sans ton cache dont l'approche naïve ne peut que dégrader les perfs.
Là tu commences tout juste à te poser la question du système de lock, tu as un fichier monolithique donc un verrou unique pour toutes les tables concernées par ton cache, tu charges toutes les données "au cas où elles pourraient servir", bref, tu perds ton temps et celui de ton serveur, alors qu'il suffisait que tu modifies le my.cnf ou que tu saisisses un
SET GLOBAL query_cache_type = 'ON'
dans phpMyAdmin pour retrouver un système ultra performant qui gère déjà tout ça de manière efficace et fiable, qui gère les transactions, la corruption de données, les insertions différées, et j'en passe.
 
WRInaute accro
Bonjour colonies

J'ai autant de fichiers cache que de scripts.
Environ une petite dizaine.

Ce matin j'ai programmé le dégrossissage des fichiers cache, en effaçant les enregistrements plus ancien que 60 minutes. A lancer par cron.

Je peux aussi utiliser un critère de grosseur de fichier, ou de nombre d'enregistrements.

Sur mon ordi, le cache semble fonctionner.

C'est sûr que je ne peux pas savoir à l'avance si le site sera accéléré ou non, mais les caches seront en RAM ( tmpfs ).

Je teste encore sur l'ordinateur.

J'ai déjà le cache de la Bdd à à 0.

Merci beaucoup beaucoup pour ton aide.

Amicalement.
 
WRInaute occasionnel
une sorte de ramasse miette du cache. Je n'ai pas tout suivi, mais pour quoi un visiteur qui viendrait 60 minute plus tard devrait être plus lent sur une recherche ?Tant qu'il y a de la place en mémoire, on cache, ce n'est pas couteux de garder du cache s'il y a de la place de libre
 
WRInaute accro
Merci beaucoup.

Je peux faire varier la constante de délai.

Pour l'instant j'ai encore à adapter les fonctions agrégats ( mono ou multi colonnes ), qui doivent être triplement indexées par leur noms de colonnes, et valeurs des colonnes et des fonctions.

C'est un problème purement d'orm, pas de cache.

Facile à faire. ;)

Après, je fait un audit du site, puis je teste.

Merci beaucoup à tous pour votre aide. :)

Amicalement.
 
WRInaute accro
Voili, voilou

J'ai une question à poser, pour peaufiner mes fonctions d'agrégats à plusieurs colonnes :

En syntaxe Eloquent version 2, quelle pourrait être la syntaxe d'un group by à deux ou plus colonnes ?

Ceci, avec ou sans des where_in ?

Merci beaucoup de vos réponses.

Respectueusement.
 
WRInaute accro
Merci Spout ;)

En fait, c'était pour les fonctions agrégats à plusieurs colonnes.

Celà est interdit par la norme SQL.

Donc au pire, des group_by sur plusieurs colonnes, donc nécessairement plusieurs fonctions agrégats, donc une fonction select( $conn->raw($sql) )
, avec $sql contenant les fonctions agrégats.

Eventuellement avec un group_by($col1, $col2) avant.

La fonction raw() est entièrement supportée par ma version de Eloquent v2, je vais tester.

Merci beaucoup de ton aide.

Amicalement.
 
WRInaute accro
Voilà c'est fait

Le cache MySQL est enfin en place et fonctionnel, sa mise à jour ( pas à zéro ) a lieu une fois/heure suivant
les timestamp, mais çà n'empêche pas le cache html de fonctionner.

Mon site était down pendant une semaine.

Maintenant le site fonctionne.

Merci de votre aide.

Amicalment.
 
WRInaute accro
Excusez-moi

J'envisage de porter mon cache mysql maison sur mémoire partagée au lieu de fichiers en mode tmpfs.

Cette version utilisera la fonction : shmop_open ( int $key , string $flags , int $mode , int $size )

Mais comment générer une $key unique ?

Habituellement, on utilise pour celà : ftok ( string $pathname , string $proj )

Y a-t-il une autre solution que ftok() ?

Un nombre integer suffisamment aléatoire ?

Cette version ( j'ai fait l'algorithme hier soir ), utilisera ( par script php en amont ) :

1) Un index de blocs de n lignes max chacun,
2) 1 ... p blocs contenant les data.

1 Index de blocs : Exemple de ligne :

KEY_BLOC1 ( 64 octets ) | CACHE_HASH_1 ( 64 octets ) | CACHE_HASH_2 | ..etc...

Séparateur fin de ligne : TOKEN_EOL

Exemple de blocs :

CACHE_HASH | TOKEN_CACHE | $timestamp | TOKEN_CACHE | SQL_CACHE | TOKEN_EOL

C'est du séquentiel indexé.

Merci beaucoup de vos avis.

Amicalement.
 
WRInaute accro
Pardon

Est-ce que random_int() pourrait être utilisé pour shmop_open ( int $key , string $flags , int $mode , int $size ) ?

Code:
$key = random_int (0 , PHP_INT_MAX);
 
WRInaute accro
Bonjour

Pour l'ancienne version de mon cache mysql, je met en log toutes les 20 minutes.

Le log est là : https://www.pronostics-courses.fr/cache_logs.txt

NBRE = nbre de caches par fichier.

AVG, MAX et MIN sont les tailles de chaque enreg/cache.

J'ai besoin, pour allocater les index de fichiers ( et les blocs ) de savoir leurs tailles maximum.

Merci beaucoup de votre aide.

Code:
-------------------------------------------------------------------------------------------------------------------------------------------------
|                    CACHE                    |    NBRE    |    AVG    |    MAX    |    MIN    |
-------------------------------------------------------------------------------------------------------------------------------------------------
| /var/www/html/CACHE/cache_index.txt                                           |    13    |    194    |    535    |    7    |
| /var/www/html/CACHE/cache_aplusbegalix.txt                                    |    151    |    397    |    5803    |    7    |
| /var/www/html/CACHE/php/contact/cache_tmp_enreg.txt                           |    1    |    6    |    6    |    6    |
| /var/www/html/CACHE/php/contact/cache_contact.txt                             |    1    |    6    |    6    |    6    |
| /var/www/html/CACHE/php/stats/cache_affic_stats.txt                           |    1    |    6    |    6    |    6    |
| /var/www/html/CACHE/php/stats/cache_tmp_enreg.txt                             |    1    |    6    |    6    |    6    |
| /var/www/html/CACHE/php/stats/cache_derniers_gagnes.txt                       |    1    |    6    |    6    |    6    |
| /var/www/html/CACHE/php/stats/cache_new_new_affic_stats.txt                   |    1    |    6    |    6    |    6    |
| /var/www/html/CACHE/php/courses_actuelles/cache_statistiques_new_courses.txt  |    5    |    710    |    1083    |    7    |
| /var/www/html/CACHE/php/courses_actuelles/cache_pronostics_new_courses.txt    |    67    |    742    |    6219    |    7    |
| /var/www/html/CACHE/php/courses_actuelles/cache_new_courses.txt               |    2    |    445    |    882    |    7    |
| /var/www/html/CACHE/php/courses_actuelles/cache_tmp_enreg.txt                 |    2    |    445    |    882    |    7    |
| /var/www/html/CACHE/php/courses_nouvelles/cache_pronostics_new_courses.txt    |    16    |    142    |    883    |    7    |
| /var/www/html/CACHE/php/courses_nouvelles/cache_tmp_enreg.txt                 |    2    |    445    |    882    |    7    |
| /var/www/html/CACHE/php/courses_nouvelles/cache_new_courses.txt               |    2    |    445    |    882    |    7    |
| /var/www/html/CACHE/php/courses_nouvelles/cache_statistiques_new_courses.txt  |    3    |    329    |    882    |    7    |
| /var/www/html/CACHE/php/courses_anciennes/cache_old_historique.txt            |    1    |    6    |    6    |    6    |
| /var/www/html/CACHE/php/courses_anciennes/cache_statistiques_old_courses.txt  |    1    |    6    |    6    |    6    |
| /var/www/html/CACHE/php/courses_anciennes/cache_old_courses.txt               |    6    |    222    |    883    |    7    |
| /var/www/html/CACHE/php/courses_anciennes/cache_tmp_enreg.txt                 |    2    |    445    |    882    |    7    |
| /var/www/html/CACHE/php/courses_anciennes/cache_action_old_courses.txt        |    1374    |    257    |    9291    |    7    |
| /var/www/html/CACHE/php/courses_anciennes/cache_pronostics_new_old_courses.txt|    48    |    5074    |    104627    |    7    |
-------------------------------------------------------------------------------------------------------------------------------------------------
 
WRInaute accro
Rebonjour

Voilà les paramètres du système de cache MySQL que je vais faire prochainement.
Ils sont tirés de mes stats.

Ce sont des nombre d'octets.

NBRE_DIGIT_MAX = 343 = nbre de digits de PHP_INT_MAX ( Il y a une erreur )
SIZEOF_CACHE_HASH = 64 = nbre de caractères d'un hash code sha256.

NBRE_ENREGS_TOTAL = nbre de requêtes cachées différentes.Tiré de mes stats de cache.

NBRE_ENREGS_BLOC = calculé à partir de NBRE_ENREGS_TOTAL par une fonction adaptant le nbre de blocs et le nbre d'enregs/bloc.

SIZEOF_AVG_SQL_CACHE = 221 = Taille moyenne d'une requête SQL cachée; tiré de mes stats.

BLOC_LENGTH_INDEX = 414 Taille d'un bloc ( = ligne ) d'index.
NBRE_LIGNE_INDEX = 10 Nbre de lignes dans l'index.
INDEX_LENGTH = 4140 Longueur totale de l'index.
BLOC_LENGTH_MAX = 644 Longueur moyenne d'un bloc de data.

Je suis obligé pour l'open de l'index ( ou des blocs ), de prévoir leur taille.

Merci beaucoup de vos suggestions et avis.

Respectueusement.


Code:
cache_index.txt
        NBRE_ENREGS_TOTAL = 10
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 221
        NBRE_DIGIT_MAX = 343
        SIZEOF_CACHE_HASH = 64
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 10
        INDEX_LENGTH = 4140
        BLOC_LENGTH_MAX = 644
        /**********************************************************/
cache_aplusbegalix.txt
        NBRE_ENREGS_TOTAL = 151
        NBRE_ENREGS_BLOC = 20
        SIZEOF_AVG_SQL_CACHE = 397
        BLOC_LENGTH_INDEX = 1630
        NBRE_LIGNE_INDEX = 8
        INDEX_LENGTH = 13040
        BLOC_LENGTH_MAX = 8363
        /**********************************************************/
php/contact/cache_tmp_enreg.txt
        NBRE_ENREGS_TOTAL = 1
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 6
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 1
        INDEX_LENGTH = 414
        BLOC_LENGTH_MAX = 429
        /**********************************************************/
php/contact/cache_contact.txt
        NBRE_ENREGS_TOTAL = 1
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 6
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 1
        INDEX_LENGTH = 414
        BLOC_LENGTH_MAX = 429
        /**********************************************************/
php/stats/cache_affic_stats.txt
        NBRE_ENREGS_TOTAL = 1
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 6
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 1
        INDEX_LENGTH = 414
        BLOC_LENGTH_MAX = 429
        /**********************************************************/
php/stats/cache_tmp_enreg.txt
        NBRE_ENREGS_TOTAL = 1
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 6
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 1
        INDEX_LENGTH = 414
        BLOC_LENGTH_MAX = 429
        /**********************************************************/
php/stats/cache_derniers_gagnes.txt
        NBRE_ENREGS_TOTAL = 282
        NBRE_ENREGS_BLOC = 20
        SIZEOF_AVG_SQL_CACHE = 371
        BLOC_LENGTH_INDEX = 1630
        NBRE_LIGNE_INDEX = 15
        INDEX_LENGTH = 24450
        BLOC_LENGTH_MAX = 7843
        /**********************************************************/
php/stats/cache_new_new_affic_stats.txt
        NBRE_ENREGS_TOTAL = 1
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 6
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 1
        INDEX_LENGTH = 414
        BLOC_LENGTH_MAX = 429
        /**********************************************************/
php/courses_actuelles/cache_statistiques_new_courses.txt
        NBRE_ENREGS_TOTAL = 10
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 939
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 10
        INDEX_LENGTH = 4140
        BLOC_LENGTH_MAX = 1362
        /**********************************************************/
php/courses_actuelles/cache_pronostics_new_courses.txt
        NBRE_ENREGS_TOTAL = 33
        NBRE_ENREGS_BLOC = 20
        SIZEOF_AVG_SQL_CACHE = 523
        BLOC_LENGTH_INDEX = 1630
        NBRE_LIGNE_INDEX = 2
        INDEX_LENGTH = 3260
        BLOC_LENGTH_MAX = 10883
        /**********************************************************/
php/courses_actuelles/cache_new_courses.txt
        NBRE_ENREGS_TOTAL = 2
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 445
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 2
        INDEX_LENGTH = 828
        BLOC_LENGTH_MAX = 868
        /**********************************************************/
php/courses_actuelles/cache_tmp_enreg.txt
        NBRE_ENREGS_TOTAL = 2
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 445
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 2
        INDEX_LENGTH = 828
        BLOC_LENGTH_MAX = 868
        /**********************************************************/
php/courses_nouvelles/cache_pronostics_new_courses.txt
        NBRE_ENREGS_TOTAL = 24
        NBRE_ENREGS_BLOC = 20
        SIZEOF_AVG_SQL_CACHE = 128
        BLOC_LENGTH_INDEX = 1630
        NBRE_LIGNE_INDEX = 2
        INDEX_LENGTH = 3260
        BLOC_LENGTH_MAX = 2983
        /**********************************************************/
php/courses_nouvelles/cache_tmp_enreg.txt
        NBRE_ENREGS_TOTAL = 2
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 445
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 2
        INDEX_LENGTH = 828
        BLOC_LENGTH_MAX = 868
        /**********************************************************/
php/courses_nouvelles/cache_new_courses.txt
        NBRE_ENREGS_TOTAL = 2
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 445
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 2
        INDEX_LENGTH = 828
        BLOC_LENGTH_MAX = 868
        /**********************************************************/
php/courses_nouvelles/cache_statistiques_new_courses.txt
        NBRE_ENREGS_TOTAL = 4
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 272
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 4
        INDEX_LENGTH = 1656
        BLOC_LENGTH_MAX = 695
        /**********************************************************/
php/courses_anciennes/cache_old_historique.txt
        NBRE_ENREGS_TOTAL = 1
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 6
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 1
        INDEX_LENGTH = 414
        BLOC_LENGTH_MAX = 429
        /**********************************************************/
php/courses_anciennes/cache_statistiques_old_courses.txt
        NBRE_ENREGS_TOTAL = 1
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 6
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 1
        INDEX_LENGTH = 414
        BLOC_LENGTH_MAX = 429
        /**********************************************************/
php/courses_anciennes/cache_old_courses.txt
        NBRE_ENREGS_TOTAL = 5
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 90
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 5
        INDEX_LENGTH = 2070
        BLOC_LENGTH_MAX = 513
        /**********************************************************/
php/courses_anciennes/cache_tmp_enreg.txt
        NBRE_ENREGS_TOTAL = 1
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 6
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 1
        INDEX_LENGTH = 414
        BLOC_LENGTH_MAX = 429
        /**********************************************************/
php/courses_anciennes/cache_action_old_courses.txt
        NBRE_ENREGS_TOTAL = 1311
        NBRE_ENREGS_BLOC = 40
        SIZEOF_AVG_SQL_CACHE = 256
        BLOC_LENGTH_INDEX = 2910
        NBRE_LIGNE_INDEX = 33
        INDEX_LENGTH = 96030
        BLOC_LENGTH_MAX = 10663
        /**********************************************************/
php/courses_anciennes/cache_pronostics_new_old_courses.txt
        NBRE_ENREGS_TOTAL = 14
        NBRE_ENREGS_BLOC = 1
        SIZEOF_AVG_SQL_CACHE = 9062
        BLOC_LENGTH_INDEX = 414
        NBRE_LIGNE_INDEX = 14
        INDEX_LENGTH = 5796
        BLOC_LENGTH_MAX = 9485
        /**********************************************************/
 
Dernière édition:
WRInaute accro
Bonjour

Besoin d'une info php sur la fonction :

shmop_open ( int $key , string $flags , int $mode , int $size )

Si $flags = "a" ( lecture seule ), deux questions :

- Si le shm n'existe pas la fonction rend false ?

- Le $mode (peut/doit)-il être à 0 comme le dit le PHP Manual ?

Ajouté :

La valeur $size ( taille allocatée du shm ), peut-elle être augmentée par un shmop_open( int $key, "w", $mode, $size) ?

Merci beaucoup.

Amicalement.
 
Dernière édition:
WRInaute accro
Bonjour

J'ai pratiquement mis au point une version alpha sans régulation automatique des tailles des allocations des blocs et index.

Je bute sur le problème de la taille trop élevée des caches des requêtes MySQL.

Ces caches sont sérialisées.

Sous PHP, y a-t-il des fonctions de compression / décompression pour chaînes de caractères ?

Merci.

Respectueusement.
 
WRInaute accro
Bonjour Spout ;)

Qu'est-ce qui est mieux :

gzdeflate() ou gzcompress()

et

gzinflate() ou gzcompress()

Merci beaucoup. ;)

Amicalement.
 
WRInaute accro
Bonjour spout

Comment faire une écriture en append dans un SHM déjà partiellement rempli ?

Ceci, sans avoir à garder trace des tailles des remplissages précédents ?

Le flag "w" de shmop_open() semble convenir, mais comment faire un append ?

Merci beaucoup.

Amicalement.
 
WRInaute accro
Bonjour spout

J'ai une petite librairie de shared memory avec shmop_open() etc... et j'aimerais synchroniser les processus avec des sémaphores.

Y a-t-il des inconvénients à utiliser sem_get() et shmop_open() en même temps avec la même key ?

Sinon, j'essaierai de générer les clés pour sem_get() de manière bijective.

Merci beaucoup spout. ;)

Amicalement.
 
WRInaute accro
Bonjour

A partir d'une classe lecture/écriture shmop sur le PHP Manual, j'ai fait ceci ci-dessous :

Celà présente l'intérêt d'allocater automatiquement la mémoire quand la taille des blocs augmente.

Et puis la fonction append().

Comment abstractiser plus l'objet $this->shmId ( ou $this->shmReadId pour les lectures ) ?

De manière à ce qu'il n'y ait plus besoin de séparer shmId et shmReadId ?

Merci beaucoup de votre aide.

Amicalement.


PHP:
<?php
########################
# shmop.class.php
########################
class SHMOP
{
        const MAXINT = 65536 * 65536 - 1;
    private $shmId        = null;
    private $shmReadId    = null;
    public $shmKEY        = null;
    public $shmKey        = null;
    private $shmMode    = null;
    private $shmFlags    = null;
    private $shmHeaderSize    = null;
    private $shmHeaderOffset    = null;
    private $shmBlockSize        = null;
    private $shmMaxBlockSize    = null;
    private $shmLimitBlockSize    = null;
    /**
    * C'est un singleton
    * par clés $this->shmKey.
    **/
    protected static $instance; // Instance de la classe.
    protected function __clone() { } // Méthode de clonage en privé.
    public static function getInstance($key)
    {
        /**   
        * Si on n'a pas 
        * encore instancié 
        * notre classe
        * pour cette $this->shmKey.
        **/
        if (!isset(self::$instance[$key])) 
        {
            self::$instance[$key] = new  self($key); // On s'instancie nous-mêmes. :)
        }
        return self::$instance[$key];
    }
    protected function __construct(int $key)
    {
        $this->shmKey = $key;
        $this->shmMode = 0;
        $this->shmFlags = "a";
        $size = 2048;
        $this->shmHeaderSize = strlen($size);
        $PHP_MAX = (string)self::MAXINT;
        $this->shmHeaderOffset = strlen($PHP_MAX) + 1;
        $this->shmMaxBlockSize = $size;
        $this->shmBlockSize = $size + $this->shmHeaderOffset + 1;
        /**
        * Surplus
        * pour dépassements
        * peu fréquents.
        **/
        $this->shmLimitBlockSize = 4096 * (1 + ceil(1.5 * $this->shmBlockSize / 4096.0));
        return $this;
    }
    public function update_size(int $size)
    {
        if((empty($this->shmKey))||
            (empty($this->shmId)))
        {
            return false;
        }
        @shmop_close($this->shmId);
        /**
        * Le SHM
        * doit exister.
        **/
        $shm = @shmop_open($this->shmKey, "a", 0, 0);
        if($shm === false)
        {
            return false;
        }
        // Get Header
        $enreg = @shmop_read($shm, 1, $this->shmHeaderOffset);
        $pos = strpos($enreg, "\0");
        if($pos !== false)
        {
            $dataSize = (int)substr($enreg, 0, $pos);
        }
        else
        {
            throw new Exception("Erreur lecture avant update taille enreg.");
            return false;
        }
        $len = shmop_size($shm) - $this->shmHeaderOffset;
        /**
        * Précédent
        * $enreg
        * avant update.
        **/
        unset($enreg);
//        $enreg = @shmop_read($shm, $this->shmHeaderOffset, $dataSize);
        $enreg = @shmop_read($shm, $this->shmHeaderOffset, $len);
        unset($pos);
        $pos = strpos($enreg, "\0");
        if($pos !== false)
        {
            $preced_enreg = (int)substr($enreg, 0, $pos);
        }
        else
        {
            throw new Exception("Erreur lecture avant update taille enreg.");
            return false;
        }
        $preced_enreg .= "\0";
        @shmop_delete($shm);
        $this->ALLOCATE($size);
        $shm = @shmop_open($this->shmKey, "n", $this->shmMode, $this->shmLimitBlockSize);
        if($shm === false)
        {
            throw new Exception("Erreur création update SHM.");
            return false;
        }
        // pack very slow use kludge
        $dataSize = strlen($preced_enreg);
        $dataSize .= "\0";
        // Write Header
        @shmop_write($shm, $dataSize, 1);
        $enreg .= "\0";
        if(@shmop_write($shm, $preced_enreg, $this->shmHeaderOffset) === false)
        {
            throw new Exception("Erreur écriture update SHM.");
            return false;
        }
        $this->shmId = $shm;
        unset($shm);
        return true;
    }
    function EXIST()
    {
        /**
        * Tester
        *
        * $this->shmId
        * !== false
        * et* !== null
        **/
        /**
        * SHM existe.
        **/
        $shm = @shmop_open($this->shmKey, "a", 0, 0);
        if($shm !== false)
        {
            $this->shmReadId = $shm;
            return $this;
        }
        return false;
    }
    function ALLOCATE(int $size)
    {
        if(($this->shmHeaderSize <= strlen($size))||
        ($this->shmMaxBlockSize <= $size)||
        ($this->shmBlockSize <= ($size + $this->shmHeaderOffset + 1))||
        ($this->shmLimitBlockSize <= (4096 * (1 + ceil(1.5 * $this->shmBlockSize / 4096.0)))))
        {
            $this->shmHeaderSize = strlen($size);
            $this->shmMaxBlockSize = $size;
            $this->shmBlockSize = $size + $this->shmHeaderOffset + 1;
            /**
            * Surplus
            * pour dépassements
            * peu fréquents.
            **/
            $this->shmLimitBlockSize = 4096 * (1 + ceil(1.5 * $this->shmBlockSize / 4096.0));
        }
        return true;
    }
    function OPEN(string $flags, int $mode, int $size)
    {
        if(in_array($flags, array("a", "w"), true))
        {
            $shm = @shmop_open($this->shmKey, $flags, 0, 0);
            if($shm === false)
            {
                return false;
            }
            switch ($flags) {
            case "a" :
                $this->shmReadId = $shm;
                break;
            case"w" :
                $this->shmId = $shm;
                break;
            default :
                break;
            }
            /**
            * Il faudrait
            * abstractiser
            * plus le maniement
            * des objets.
            **/
            return $this;
        }
        switch ($flags) {
        /**
        * Pour créer
        * un nouveau bloc
        * même s'il existe.
        **/
        case "n" :
            $this->shmMode = $mode;
            $this->shmFlags = $flags;
            /**
            * Le SHM
            * ne doit
            * pas exister.
            **/
            $shm = @shmop_open($this->shmKey, "a", 0, 0);
            if($shm !== false)
            {
                @shmop_delete($shm);
            }
            unset($shm);
            $this->ALLOCATE($size);
            /**
            * Delete 
            * instantané ?
            **/
            $shm = @shmop_open($this->shmKey, $this->shmFlags, $this->shmMode, $this->shmLimitBlockSize);
            if($shm === false)
            {
                unset($shm);
                throw new Exception("Erreur création SHM. en mode : " . $this->shmFlags);
                return false;
            }
            $this->shmId = $shm;
            unset($shm);
            /**
            * SHM créé
            **/
            // release spinlock
            shmop_write($this->shmId, "\0", 0);
            return $this;
            break;
        /**
        * Pour créer
        * un bloc
        * s'il n'existe pas,
        * ou l'ouvrir
        * en lecture/écriture
        * s'il existe.
        **/
        case "c" :
            /**
            * SHM existe,
            * ouvert
            * en lecture/écriture.
            **/
            $shm = @shmop_open($this->shmKey, "a", 0, 0);
            if($shm !== false)
            {
                @shmop_close($shm);
                unset($shm);
                $shm = @shmop_open($this->shmKey, "w", 0, 0);
                if($shm === false)
                {
                    throw new Exception("Erreur ouverture/création SHM. en mode : " . $flags);
                    return false;
                }
       
                $this->shmId = $shm;
                /**
                * Il faudrait
                * abstractiser
                * plus le maniement
                * des objets.
                **/
                return $this;
            }
            /**
            * SHM n'existe pas,
            * il est créé.
            **/
            else
            {
                unset($shm);
                $this->shmMode = $mode;
                $this->shmFlags = $flags;
                $this->ALLOCATE($size);
                /**
                * Faut-il
                * un $this->shmFlags = "n" ?
                **/
                $shm = @shmop_open($this->shmKey, $this->shmFlags, $this->shmMode, $this->shmLimitBlockSize);
                if($shm === false)
                {
                    throw new Exception("Erreur création SHM. en mode : " . $this->shmFlags);
                    return false;
                }
                $this->shmId = $shm;
                unset($shm);
                // release spinlock
                shmop_write($this->shmId, "\0", 0);
                return $this;
            }
            break;
        default :
            break;
        }
        return false;
    }
    function __destruct()
    {
        self::$instance[$this->shmKey] = null;
        @shmop_close($this->shmId);
        return true;
    }
    public function read()
    {
        // Check SpinLock
        if(@shmop_read($this->shmReadId, 0, 1) !== "\0")
        {
            return false;
        }
        //
        // Get Header
        $enreg = shmop_read($this->shmReadId, 1, $this->shmHeaderOffset);
        $pos = strpos($enreg, "\0");
        if($pos !== false)
        {
            $dataSize = (int)substr($enreg, 0, $pos);
        }
        else
        {
            throw new Exception("Erreur lecture taille enreg.");
            return false;
        }
        $len = shmop_size($this->shmReadId) - $this->shmHeaderOffset;
        $data = @shmop_read($this->shmReadId, $this->shmHeaderOffset, $len);
        $pos = strpos($data, "\0");
        if($pos !== false)
        {
            $data = (int)substr($data, 0, $pos);
        }
        else
        {
            throw new Exception("Erreur lecture avant update taille enreg.");
            return false;
        }
        return $data;
    }
    /**
    * Nombre d'octets
    * allocatés
    * pour la $data.
    **/
    public function ALLOCATED_SIZE()
    {
        $size = $this->shmLimitBlockSize - $this->shmHeaderOffset -1;
        return $size;
    }
    public function append(string $data)
    {
        // Check SpinLock
        if(@shmop_read($this->shmId, 0, 1) !== "\0")
        {
            return false;
        }
        // Write spinlock
        @shmop_write($this->shmId, "\1", 0);
        $dataSize = strlen($data);
        if($dataSize < 1)
        {
            // release spinlock
            @shmop_write($this->shmId, "\0", 0);
            throw new Exception('dataSize < 1');
        }
        //
        // Get Header
        $enreg = shmop_read($this->shmId, 1, $this->shmHeaderOffset);
        $pos = strpos($enreg, "\0");
        if($pos !== false)
        {
            $dataSize = (int)substr($enreg, 0, $pos);
        }
        else
        {
            throw new Exception("Erreur lecture taille enreg.");
            return false;
        }
        $len = shmop_size($this->shmId) - $this->shmHeaderOffset;
        /**
        * Précédent
        * $enreg
        * avant update.
        **/
        unset($enreg);
//        $enreg = @shmop_read($this->shmId, $this->shmHeaderOffset, $dataSize);
        $enreg = @shmop_read($this->shmId, $this->shmHeaderOffset, $len);
        unset($pos);
        $pos = strpos($enreg, "\0");
        if($pos !== false)
        {
            $preced_enreg = (int)substr($enreg, 0, $pos);
        }
        else
        {
            throw new Exception("Erreur lecture avant update taille enreg.");
            return false;
        }
        /**
        * Append.
        **/
        $preced_enreg .= $data;
        $preced_enreg .= "\0";
        $dataSize = strlen($preced_enreg);
        /**
        * Adaptation
        * de la taille
        * du SHM.
        **/
        if($this->ALLOCATED_SIZE() < $dataSize)
        {
            if($this->update_size($dataSize) !== true)
            {
                // release spinlock
                @shmop_write($this->shmId, "\0", 0);
                return false;
            }
        }
           
        // pack very slow use kludge
        $dataSize .= "\0";
        /**
        * $this->shmId
        * a probablement changé.
        **/
        // Write Header
        @shmop_write($this->shmId, $dataSize, 1);
        // Write Data
        @shmop_write($this->shmId, $preced_enreg, $this->shmHeaderOffset);
        // release spinlock
        @shmop_write($this->shmId, "\0", 0);
        return $this;
    }
    public function write(string $data)
    {
        // Check SpinLock
        if(@shmop_read($this->shmId, 0, 1) !== "\0")
        {
            return false;
        }
        // Write spinlock
        @shmop_write($this->shmId, "\1", 0);
        $data .= "\0";
        $dataSize = strlen($data);
        if($dataSize < 1)
        {
            // release spinlock
            @shmop_write($this->shmId, "\0", 0);
            throw new Exception('dataSize < 1');
        }
        /**
        * Adaptation
        * de la taille
        * du SHM.
        **/
        if($this->ALLOCATED_SIZE() < $dataSize)
        {
            if($this->update_size($dataSize) !== true)
            {
                // release spinlock
                @shmop_write($this->shmId, "\0", 0);
                return false;
            }
        }
           
        // pack very slow use kludge
        $dataSize .= "\0";
        /**
        * $this->shmId
        * a probablement changé.
        **/
        // Write Header
        @shmop_write($this->shmId, $dataSize, 1);
        // Write Data
        @shmop_write($this->shmId, $data, $this->shmHeaderOffset);
        // release spinlock
        @shmop_write($this->shmId, "\0", 0);
        return $this;
    }
    public function eof()
    {
        return (@shmop_read($this->shmId, 0, 1) === "\2") ? true : false;
    }
    public function sendeof()
    {
        // Check SpinLock
        if(@shmop_read($this->shmId, 0, 1) !== "\0")
        {
            return false;
        }
        @shmop_write($this->shmId, "\2", 0);
        return true;
    }
    public function canWrite()
    {
        // Check SpinLock
        return (@shmop_read($this->shmId, 0, 1) === "\0") ? true : false;
    }
    public function close($flags)
    {
        switch ($flags) {
        case "a" :
            return @shmop_close($this->shmReadId);
       
            break;
        case "c" :
        case "w" :
        case "n" :
            return @shmop_close($this->shmId);
       
            break;
        default :
            break;
        }
        return false;
    }
    public function delete($flags)
    {
        switch ($flags) {
        case "a" :
            $del = @shmop_delete($this->shmId);
            break;
        case "c" :
        case "w" :
        case "n" :
            $del = @shmop_delete($this->shmId);
            break;
        default :
            break;
        }
        if($del === false)
        {
            return false;
        }
        return $this;
    }
    public function SHMOP_WRITE(string $data)
    {
        while(true)
        {
            if($this->write($data) !== false)
            {
                break;
            }
        }
        return true;
    }
    public function SHMOP_READ()
    {
        /**
        * Mettre
        * un délai.
        **/
        while(true)
        {
            if(($data = $this->read()) !== false)
            {
                return $data;
            }
        }
    }
    public function SHMOP_DELETE($flags)
    {
        return $this->delete($flags);
    }
    public function SHMOP_CLOSE($flags)
    {
        return $this->close($flags);
    }
    public function RELEASE_LOCK()
    {
        // release spinlock
        // for writing.
        @shmop_write($this->shmId, "\0", 0);
        return true;
    }
    public function SET_LOCK()
    {
        // Write spinlock
        // for reading.
        @shmop_write($this->shmId, "\1", 0);
        return true;
    }
}
?>
 
WRInaute accro
Je vous demande pardon ;)

J'ai la réponse à la question.

Pas besoin de séparer $this->shmReadId de $this->shmId , c'est l'ident du shm.

Celà parce que deux open en lecture ou en écriture sur le même shm
sont séquentiels avec les close.

Dans ma classe SHMOP, je met le $this->hmId à null dans close().

Pour l'instant, je n'arrive pas à lire des requêtes SQL enregistrées dans des shm.

Elles ne sont pas reconnues par leur sql_cash

Je vais tracer.

Amicalement.
 
WRInaute accro
Excusez-moi

J'ai une question à poser.

Est-ce que la fonction serialize() peut produire en sortie des octets "\0" ( null ) ?

J'ai une très bonne version même pas alpha de ma librairie de cache MySQL avec des shared memory ( fonctions shmop_ ), mais c'est un problème théorique et pratique, enregistrement/lecture des données.

Merci beaucoup.

Amicalement.
 
WRInaute accro
Rebonjour

Comment faites-vous pour allocater de manière dynamique les tailles des shmop_open() ?

Est-ce que c'est possible de réécrire sur le même shm ( même clé ) en faisant un shmop_remove() puis shmop_open() ?

C'est- à-dire : Un shmop_remove() a-t-il un effet immédiat ?

Merci beaucoup de votre aide.

Respectueusement.
 
WRInaute accro
Bonjour

J'ai fait une classe sémaphore normale et une classe singleton/key d'enregistrement/lecture en shared memory ( fonctions shmop_*() )

Cette approche est-elle correcte en POO PHP ?

C'est pour ma librairie de cache MySQL qui est déjà valide ( précédente version fichiers plats en partition tmpfs ).

Merci beaucoup de vos avis et suggestions.

Amicalement.


PHP:
<?php
#########################
#     SEM.php        #
#########################
class SEM
{
    private $semKey        = null;        // Clé de SEM.
    private $semId        = null;        // Id de SEM.
    private $semIsLocked    = null;        // IsLocked de SEM.
    protected function __construct(int $key)
    {
        $this->semKey = crc32($key);
        return $this;
    }
    protected function LOCK()
    {
        while(true)
        {
            if(($this->semId = sem_get ($this->semKey, 1 , 0666, 1)) !== false)
            {
                break;
            }
        }
        if(sem_acquire($this->semId, false) === false)
        {
            return false;
        }
        $this->semIsLocked = true;
        return true;
    }
    protected function UNLOCK()
    {
        if(is_resource($this->semId))
        {
            sem_release($this->semId);
        }
        $this->semIsLocked = false;
        return true;
    }
    protected function IS_LOCKED()
    {
        return $this->semIsLocked;
    }
}
?>

<?php

require(__DIR__ . '/SEM.php');
#########################
#     SHMOP.php    #
#########################
class SHMOP extends SEM
{
    private $shmId        = null;        // Id de SHM.
    public $shmKey        = null;        // Clé de SHM.
    /**
    * C'est un singleton
    * par clés $this->shmKey.
    **/
    protected static $instance = array(); // Instance de la classe.
    protected function __clone() { } // Méthode de clonage en privé.
    protected static function getInstance($key)
    {
        /**   
        * Si on n'a pas 
        * encore instancié 
        * notre classe
        * pour cette $this->shmKey.
        **/
        if (!isset(self::$instance[$key])) 
        {
            self::$instance[$key] = new  self($key); // On s'instancie nous-mêmes. :)
        }
        return self::$instance[$key];
    }
    protected function __construct(int $key)
    {
        $this->shmKey = $key;
        parent::__construct($this->shmKey);
        return $this;
    }
    /**
    * Format type
    * string conpressée
    * après linearisation
    * en amont.
    **/
    private function SHMOP_DEFLATE($value)
    {
        /**
        * VALUE => SERIALIZE => COMPRESS => BASE64_ENCODE => STR
        **/
        $str = base64_encode(gzcompress(serialize($value)));
        /**
        * On ajoute un "\0".
        **/
        return $this->str_to_nts($str); 
    }
    /**
    * Format type
    * string déconpressée
    * destiné à
    * être délinéarisé.
    **/
    private function SHMOP_INFLATE($value)
    {
        /**
        * On enlève le "\0".
        **/
        $str = $this->str_from_mem($value);
        /*
        * STR => BASE64_DECODE => UNCOMPRESS => UNSERIALIZE.
        */
        return unserialize(gzuncompress(base64_decode($str)));
    }
    private function str_from_mem(&$value) {
        $i = strpos($value, "\0");
        if ($i === false) {
            return $value;
        }
        $result =  substr($value, 0, $i);
        return $result;
    }
    private function str_to_nts($value) {
        return "$value\0";
    }
    function EXIST()
    {
        /**
        * SHM existe.
        **/
        $shm = @shmop_open($this->shmKey, "a", 0, 0);
        if($shm !== false)
        {
            shmop_close($shm);
            return true;
        }
        return false;
    }
    public function perso_remove()
    {
        $this->LOCK();
        $shm = @shmop_open($this->shmKey, "a", 0, 0);
        if($shm === false)
        {
            return false;
        }
        shmop_delete($shm);
        shmop_close($shm);
        $this->UNLOCK();
        return $this;
    }
    public function perso_read()
    {
        $this->LOCK();
        $shm = @shmop_open($this->shmKey, "a", 0, 0);
        if($shm === false)
        {
            $this->UNLOCK();
            return false;
        }
        $length = shmop_size ($shm);
        $value = shmop_read ($shm, 0, $length);
        shmop_close($shm);
        $this->UNLOCK();
        $data = $this->SHMOP_INFLATE($value);
        return $data;
    }
    public function perso_write(string $value)
    {
        $this->LOCK();
        $data = $this->SHMOP_DEFLATE($value);
        $value_length = strlen ($data);
        if(($shm = @shmop_open($this->shmKey, "a", 0, 0)) !== false)
        {
            shmop_delete($shm);
            shmop_close($shm);
               
            $shm = false;
        }
        $shm = @shmop_open($this->shmKey, "n", 0644, $value_length);
        if ($shm === false)
        {
            $this->UNLOCK();
            return false;
        }
        // Write Data
        shmop_write($shm, $data, 0);
        // Libération du segment de mémoire
        shmop_close($shm);
        $this->UNLOCK();
        return $this;
    }
    public function REMOVE()
    {
        while(true)
        {
            if($this->perso_remove() !== false)
            {
                break;
            }
        }
        return $this;
    }
    public function READ()
    {
        while(true)
        {
            if(($data = $this->perso_read()) !== false)
            {
                break;
            }
        }
        return $data;
    }
    public function WRITE(string $value)
    {
        while(true)
        {
            if($this->perso_write($value) !== false)
            {
                break;
            }
        }
        return $this;
    }
}
?>
 
WRInaute accro
Bonjour

Voici le type d'indexation vaguement séquentiel indexé que j'ai choisi pour l'allocation de mes shared memories :

CACHE_HASH = hash('sha256', $SQL);
KEY_BLOC = clé SMHOP du bloc
SQL_CACHE = le résultat de la requête $SQL, après sérialisation,
$timestamp = time().

TOKEN_CACHE = séparateur de champ,
SEPA = séparateur de champ,
TOKEN_EOL = séparateur de ligne.

Mon problème :

Jusqu'à présent, il y avait un index par script php utilisant la librairie de cache MySQL.

Je ne m'étais pas aperçu, que les SQL_CACHE d'autres scripts n'étaient pas accessibles.

Mais, comment indexer en séquentiel indexé, un seul index englobant tous les index, à moins de rajouter un niveau d'indirection dans les recherches , ( il y en a déjà deux ) ?

Et si oui, comment ?

Pour chercher le SQL_CACHE d'un CASH_HASH, on le cherche le KEY_BLOC dans l'index, puis on lit le bloc.

Merci beaucoup beaucoup de votre aide.


Code:
INDEX
*****
// KEY_BLOC_1 | SEPA | CACHE_HASH_1_1 | SEPA | CACHE_HASH_1_2 | SEPA | CACHE_HASH_1_3 | SEPA | ... | TOKEN_EOL
BLOC
****
// CACHE_HASH | TOKEN_CACHE | $timestamp | TOKEN_CACHE  | SQL_CACHE | TOKEN_CACHE | ...  | TOKEN_EOL

[code]
 
WRInaute accro
Bonjour

Il me semble avoir une autre solution pour l'indexation de mes blocs.

Avec un hashing search :

PHP:
/**
 * Fonction de hashing :
 */
function hash(string $key)
{
   $M = // un nombre premier
   $len = strlen($key);
   for($h = 0, $i =0; $i < $len; $i++)
        $h = (64 * $h + ord(substr($key, $i, 1) - 32) % $M;
   return $h;
}
 
INDEX :
******
  $CLE_HASH = hash($CACHE_HASH);

// CLE_HASH | SEPA | CACHE_HASH1 | SEPA | KEY_BLOC1 | SEPA | CACHE_HASH2 | SEPA | KEY_BLOC2 | etc..

KEY_BLOC :
********
// CACHE_HASH1 | TOKEN_CACHE | $timestamp1 | TOKEN_CACHE  | SQL_CACHE1 | TOKEN_CACHE | CACHE_HASH2 | TOKEN_CACHE | $timestamp2 | TOKEN_CACHE |SQL_CACHE2 | [...] | TOKEN_EOL

Ainsi, je pourrais mettre plus de CACHE_HASHn par ligne, et puis la lecture de l'index se ferait en accès direct.

Qu'en pensez-vous ?

Y a-t-il déjà des librairies de pseudo fichiers en shared memory, avec lecture/écriture rapide ?

Merci.
 
WRInaute accro
Rebonjour

Je crois avoir trouvé la solution au problème.

Avec des accès quasi directs.

La fonction de hash ci-dessous :

PHP:
/**
 * Fonction de hashing :
 */
function hash(string $key)
{
   $M = 101; // un nombre premier
   $len = strlen($key);
   for($h = 0, $i =0; $i < $len; $i++)
        $h = (64 * $h + ord(substr($key, $i, 1) - 47) % $M;
   return $h;
}

// Format des BLOC :
*********************
  CLE_HASH = hash( CACHE_HASH ) à arranger pour être une clé du shm_open() de ce bloc.

CLE_HASH | SEPA | CACHE_HASH_1| SEPA | SQL_CACHE_1 | SEPA | CACHE_HASH_2 | SEPA | SQL_CACHE_2 | [...]

Vous comprenez, je calcule en fonction de CASH_HASH avec hash() la clé hashée CLE_HASH du bloc devant contenir CASH_HASH et SQL_CACHE, et puis vogue la galère : Pour retrouver SQL_CACHE, je lit le bloc CLE_HASH, et le SQL_CACHE est indexé dedans.

Le livre : "Algorihms in C" de Robert Sedgewick dit que pour la fonction hash(), $M nombre premier juste au dessus de nbre_total_enregs/10 peut convenir.

48 est le code ascii de 0, donc j'enlève 47 au code ascii.

Pour obtenir une clé valide du bloc correct, je me propose de multiplier le résultat de hash() par une constante pour élargir les valeurs des clés.

Direct => array interprétable.

Correct ?

Merci beaucoup de votre aide.

Amicalement.
 
WRInaute accro
Intéressant ton système de cache. Si je m'ennuyais je n'hésiterais pas une seconde à l'implémenter.

Pour l'instant mon système maison est beaucoup plus rudimentaire :

Code:
$CACHEACTIF = "ON";      // à mettre dans un fichier séquentiel de paramétrage


IF ($CACHEACTIF != "ON") {
$listecache = array();
} else {
$listecache = array(220, 96, 103, 124, 88, 365, 72, 1, 86, 7, 34, 102, 76, 428, 87, 2, 3, 17, 65, 77, 146, 153, 170, 172, 173, 174, 176, 177, 199, 462, 19, 121, 206, 214, 256, 267, 268, 316, 320, 326, 330, 338, 339, 345, 362, 98, 363, 364, 367, 371, 374, 379, 405, 410, 413, 414, 415, 420, 421, 92, 433, 437, 448, 453, 458, 461, 175, 464, 478, 479, 480, 481, 482, 487, 488, 489, 490, 517, 518, 520, 521, 522, 534, 553, 559, 566, 582, 583, 586, 594, 601, 620, 631, 696, 730, 810, 651);
}
if ( (($numart > 48) AND ($numart < 57) AND ($numart != 50))
     or (in_array ($numart, $listecache))
     )
    {
    include ($URI);                       // on affiche la page HTML sans passer par la génération php 
}  else {
                      // traitement normal
.....
 
WRInaute accro
Voilà

Suite à une visite sur Wikipedia Semaphore, voici la classe faite par mes soins, implémentant l'algorithme lecteur/rédacteur.

Maintenant, ma classe de cache MySQL semble fonctionner sans blocage.

Je vais mettre au point l'ensemble, puis le mettre sur le site.

Super Wikipedia !

Bien à vous.

Amicalement.



PHP:
<?php
class Semaphore
{
    protected $KeyM_Lect = null;
    protected $KeyM_Red = null;
    protected $Key_Red = null;
    protected $M_Lect = null;    // Sémaphore mutex en lecture.
    protected $M_Red = null;    // Sémaphore mutex en écriture.
    protected $Red = null;    // Sémaphore bloquant les écritures.
    protected $Lect = null;    // Variable protégée par $Red.
    protected $is_locked_M_Lect = null;
    protected $is_locked_M_Red = null;
    protected $is_locked_Red = null;
    protected function __construct(int $key)
    {
        /**
        * Il faut que
        * les clés paramètres
        * possibles
        * soient séparées
        * par plus que 20000.
        **/
        $this->KeyM_Lect = $key;
        $this->KeyM_Red= $key + 10000;
        $this->Key_Red= $key + 20000;
        $this->Lect = 0;
        if (!($this->M_Lect = sem_get($this->KeyM_Lect, 1, 0666))) {
            throw new RuntimeException("Cannot get $key semaphore identifier");
        }
        if (!($this->M_Red = sem_get($this->KeyM_Red, 1, 0666))) {
            throw new RuntimeException("Cannot get $key semaphore identifier");
        }
        if (!($this->Red = sem_get($this->Key_Red, 1, 0666))) {
            throw new RuntimeException("Cannot get $key semaphore identifier");
        }
        return $this;
    }
    public function __destruct()
    {
        if((is_resource($this->M_Lect))&&(!$this->is_locked_M_Lect))
            sem_remove($this->M_Lect);
        if((is_resource($this->Red))&&(!$this->is_locked_Red))
            sem_remove($this->Red);
        if((is_resource($this->M_Red))&&(!$this->is_locked_M_Red))
            sem_remove($this->M_Red);
        return true;
    }
    protected function BEGIN_READ()
    {
        if(sem_acquire($this->M_Lect) === false)
            return false;
        $this->is_locked_M_Lect = true;
        $this->Lect++;
        if($this->Lect == 1)
        {
            if(sem_acquire($this->Red) === false)
                return false;
            $this->is_locked_Red = true;
        }
        if($this->is_locked_M_Lect)
            sem_release($this->M_Lect);
        return true;
    }
    protected function END_READ()
    {
        if(sem_acquire($this->M_Lect) === false)
            return false;
        $this->is_locked_M_Lect = true;
        $this->Lect--;
        if($this->Lect == 0)
        {
            if($this->is_locked_Red)
                sem_release($this->Red);
        }
        if($this->is_locked_M_Lect)
            sem_release($this->M_Lect);
        return true;
    }
    protected function BEGIN_WRITE()
    {
        if(sem_acquire($this->M_Red) === false)
            return false;
        $this->is_locked_M_Red = true;
        if(sem_acquire($this->Red) === false)
            return false;
        $this->is_locked_Red = true;
        return true;
    }
    protected function END_WRITE()
    {
        if($this->is_locked_Red)
            sem_release($this->Red);
        if($this->is_locked_M_Red)
            sem_release($this->M_Red);
        return true;
    }
}
?>
 
WRInaute accro
Voili, voilou

Je dispose des clés des blocs et de leur contenus, de la forme :

Code:
BLOC de clé : CLE_HASH :
**********************
// CACHE_HASH_1 | SEPA | FREQ | SEPA | $timestamp | SEPA  | SQL_CACHE_1 | SEPA | CACHE_HASH_2 | SEPA | FREQ | SEPA | $timestamp | SEPA | SQL_CACHE_2 | SEPA |

FREQ est le nombre de cas ou le cache a été lu pour ce CACHE_HASH_i/SQL_CACHE_i.

Ce nombre est incrémenté à chaque fois que la requête MySQL est lue dans le cache plutôt que dans la BDD.

D'autre part, chaque bloc de clé CLE_HASH, a une taille en octets facilement lisible avec : $SHM->SIZE().

Pour ne pas exagérer en ressources RAM, je dois effacer des blocs trop grands, les enregs trop anciens en gardant de préférence les FREQ élevés, donc plus fréquemment lus.

Last but not least, je dois éventuellement garder les SQL_CACHEi les plus longs, car gourmands en délai lecture BDD.

Comment quantifier toute ces contraintes, quel algorithme formaliser pour repérer
les champs à effacer des blocs ?

Merci beaucoup pour votre aide.

Respectueusement.
 
WRInaute accro
Rebonjour

Voilà, j'ai quatre variables statistiques représentatives de l'ordre souhaitable d"effacement des enregs des blocs.

Les _MAX et _MIN s'entendent non pas par bloc, mais pour tous les blocs.


- BLOC_SIZE en octets,

- ( TIMESTAMP_i - TIMESTAMP_MIN ) / TIMESTAMP_MAX - TIMESTAMP_MIN ),

- ( FREQ_i- FREQ_MIN ) / ( FREQ_MAX - FREQ_MIN ),

- ( SQL_CACHE_SIZE_i - SQL_CACHE_SIZE_MIN ) / ( SQL_CACHE_SIZE_MAX - SQL_CACHE_MIN )

Ma question est : Comment calculer une fonction d'ordre pondérant ces 4 variables, pour fixer l'enreg à effacer ( l'enreg correspondant à l'indice -i ) ?

Merci beaucoup de vos suggestions.

Respect.
 
WRInaute accro
Rebond.

Pour donner suite, l'ordre d'effacement serait :

1) Ordre croissant : SQL_CACHE_SIZE_i,

2) Ordre croissant : TIMESTAMP_i

3) Ordre croissant : FREQ_i

Je n'ai plus qu'à fixer les facteurs de ma combinaison linéaire.

Le BLOC_SIZE n'a pas d'importance.

A+.
 
WRInaute accro
Bonjour

Voilà j'ai mis mon cache MySQL en ligne.

J'ai également désactivé le cache html, pour tester le cache MySQL.

J'ai prévu un cache maximum de 1 Go, ce maximum n'est jamais atteint car dès qu'il est à moitié rempli, des champs de blocs sont libérés automatiquement, ce qui divise par deux environ l'espace RAM occupé. ( Donc 1 Go / 2 / 2 = 256 Mo en théorie ).

Je visualiserai les variables en cours demain matin.

Merci de tester au : https://www.pronostics-courses.fr

Voilà.

Bien amicalement.
 
WRInaute accro
Bonjour

J'ai actuellement quatre programmes :

1) Accès à ma bdd style orm Eloquent version 2,
2) 1 classe de cache MySQL avec mémoires partagées,
3) 1 classe d'accès écriture/lecture à la mémoire partagée,
4) 1 classe de synchronisation des accès, implémentant l'algorithme lecteur/rédacteur, et l'algorithme exclusion mutuelle.

Le problème, est que le cache MySQL allocate des blocs de mémoires partagée, dont le nombre paramètre peut être entre 101 blocs pour 128 Ko max de RAM occupée, à 601 blocs pour 7 Mo de RAM max occupée.

Pour chaque blocs de mémoire partagée, il y a 3 sémaphores assurant l'algorithme lecteur/rédacteur et 2 sémaphores pour l'exclusion mutuelle.

Quand la RAM globale allocatée dépasse la moitié du max de RAM occupée, une fonction libère une fraction de cette RAM, en utilisant l'exclusion mutuelle pour éviter 2 lancements simultanés de cette fonction.

Le blème, est qu'l y a trop de sémaphores, et leur nombre semble empêcher leur propre instanciation.

Vous, comment assurez-vous la synchronisation de vos accès aux mémoires partagées ?

Ceci, dans le cas où il y a un certain nombre de blocs allocatés ?

Merci beaucoup de vos réponses.

Respectueusement.
 
WRInaute accro
Bonjour

J'ai fait une classe SHMOP d'accès à de la mémoire partagée en lecture/écriture, avec synchronisation incorporée par sémaphore virtuel consistant en le caractère en début de la shmop :

"0" non locké, accès libre pour lecture et écriture,
"1" locké, accès refusé pour lecture et écriture,
"3" eof.

Le "1" n'est positionné que au début d'une écriture, et mis à "0" après l'écriture.

C'est une classe singleton pour chaque clés de chaque shmop.

Merci de me donner vos avis par rapport à cette implémentation.

Amicalement.


PHP:
<?php
########################
# shmop.class.php
########################
class SHMOP
{
    const MAXINT = 65536 * 65536 - 1;
    /********************************/
    /*    VARIABLES MUTEX        */
    /********************************/
    /**
    * @access private
    * @var int
    */
    private $writers = 0;
    /********************************/
    /*    VARIABLES SHMOP        */
    /********************************/
    private $shmKEY        = null;
    private $shmId        = null;
    private $shmMode    = null;
    private $shmFlags    = null;
    private $shmHeaderOffset    = null;
    private $shmBlockSize        = null;
    private $shmMaxBlockSize    = null;
    private $shmLimitBlockSize    = null;
    /**
    * C'est un singleton
    * par clés $this->shmKey.
    **/
    protected static $instance; // Instance de la classe.
    protected function __clone() { } // Méthode de clonage en privé.
    public static function getInstance(int $key)
    {
        /**   
        * Si on n'a pas 
        * encore instancié 
        * notre classe
        * pour cette $this->shmKey.
        **/
        if (!isset(self::$instance[$key])) 
        {
            self::$instance[$key] = new  self($key); // On s'instancie nous-mêmes. :)
        }
        return self::$instance[$key];
    }
    protected function __construct(int $key)
    {
        $this->shmKey = $key;
        $this->shmMode = 0;
        $this->shmFlags = "a";
        $size = 2048;
        $CHAR_MAX = "A";
        $this->shmHeaderOffset = strlen($CHAR_MAX) + 1;
        $this->shmMaxBlockSize = $size;
        $this->shmBlockSize = $size + $this->shmHeaderOffset + 1;
        /**
        * Surplus
        * pour dépassements
        * peu fréquents.
        **/
        $this->shmLimitBlockSize = 4096 * (1 + ceil(1.5 * $this->shmBlockSize / 4096.0));
        return $this;
    }
    function __destruct()
    {
        @shmop_close($this->shmId);
        self::$instance[$this->shmKey] = null;
        return true;
    }
    /**
    * Format type
    * string conpressée
    * après linearisation.
    **/
    private function SHMOP_DEFLATE(string $value)
    {
        /**
        * On ajoute un "\0".
        **/
        $data = $this->str_to_nts($value); 
        /**
        * VALUE => SERIALIZE => COMPRESS => BASE64_ENCODE => STR
        **/
        return base64_encode(gzcompress(serialize($data)));
    }
    /**
    * Format type
    * string déconpressée
    * et délinéarisée.
    **/
    private function SHMOP_INFLATE($value)
    {
        /**
        * On enlève le "\0".
        **/
        $data = $this->str_from_mem($value);
        /*
        * STR => BASE64_DECODE => UNCOMPRESS => UNSERIALIZE.
        */
        return unserialize(gzuncompress(base64_decode($data)));
    }
    private function str_from_mem(string &$value) {
        $i = strpos($value, "\0");
        if ($i === false) {
            $result = $value;
        }
        else {
            $result =  substr($value, 0, $i);
        }
        return $result;
    }
    private function str_to_nts(string $value) {
        return "$value\0";
    }
    private function wrapper_shmop_open(int $key, string $flags, int $perm = 0666, int $size = 0)
    {
        /**
        * USER root,
        * specific threatment
        * for opening
        * the SHM as nginx.
        **/
        if(posix_getuid() == 0)
        {
            switch($flags) {
            case "n" :
            case "c" :
                /**
                * Creation
                * comme user
                * nginx.
                **/
                exec("sudo -u nginx php -r 'shmop_open(" . $key . ", " . $flags . ", " . $perm . ", " . $size . ");'"); //Create Shared Memory segment as USER nginx
                break;
            default :
                break;
            }
        }
        return @shmop_open($this->shmKey, $flags, $perm, $size);
    }
    function OPEN(string $flags, int $mode, int $size)
    {
        $this->shmMode = $mode;
        $this->shmFlags = $flags;
        if(in_array($this->shmFlags, array("a", "w"), true))
        {
            $shm = @$this->wrapper_shmop_open($this->shmKey, $this->shmFlags, $this->shmMode, 0);
            if($shm === false)
            {
                return false;
            }
            $this->shmId = $shm;
            /**
            * Il faudrait
            * abstractiser
            * plus le maniement
            * des objets.
            **/
            return $this;
        }
        switch ($this->shmFlags) {
            /**
            * Pour créer
            * un nouveau bloc
            * même s'il existe.
            **/
        case "n" :
            /**
            * Le SHM
            * ne doit
            * pas exister.
            **/
            $shm = @$this->wrapper_shmop_open($this->shmKey, "a", $this->shmMode, 0);
            if($shm !== false)
            {
                @shmop_delete($shm);
                shmop_close($shm);
            }
            unset($shm);
            $this->ALLOCATE($size);
            /**
            * Delete 
            * instantané ?
            **/
            $shm = @$this->wrapper_shmop_open($this->shmKey, $this->shmFlags, $this->shmMode, $this->shmLimitBlockSize);
            if($shm === false)
            {
                unset($shm);
                throw new RuntimeException("Erreur création SHM. en mode : " . $this->shmFlags);
                return false;
            }
            $this->shmId = $shm;
            /**
            * SHM créé
            **/
            // release spinlock
            @shmop_write($this->shmId, "0", 0);
            shmop_write($this->shmId, $this->SHM_DEFLATE(""), 1);
            break;
            /**
            * Pour créer
            * un bloc
            * s'il n'existe pas,
            * ou l'ouvrir
            * en lecture/écriture
            * s'il existe.
            **/
        case "c" :
            /**
            * SHM existe,
            * ouvert
            * en lecture/création/écriture.
            **/
            $shm = @$this->wrapper_shmop_open($this->shmKey, "c", $this->shmMode, $this->shmLimitBlockSize);
            if($shm === false)
            {
                throw new RuntimeException("Erreur création/écriture SHM.");
                return false;
            }
            $drapeau_exist = false;
            /**
            * Limite inférieure
            * à déterminer.
            **/
            if(shmop_size($shm) > 0)
            {
                $drapeau_exist = true;
                $this->shmId = $shm;
                $data = shmop_read($shm, 0, shmop_size($shm));
                $writers = (int)substr($data, 0, 1);
                $enreg = substr($data, 1);
            }
            else
            {
                $writers = 0;
                $enreg  = $this->SHMOP_DEFLATE("");
            }
            if($this->ALLOCATE($size))
            {
                shmop_delete($shm);
                shmop_close($shm);
                /**
                * Delete 
                * instantané ?
                **/
                $shm = @$this->wrapper_shmop_open($this->shmKey, "n", $this->shmMode, $this->shmLimitBlockSize);
                if($shm === false)
                {
                    unset($shm);
                    throw new RuntimeException("Erreur création SHM.");
                    return false;
                }
                $this->shmId = $shm;
                /**
                * SHM créé
                **/
                $value = $writers . $enreg;
                shmop_write($this->shmId, $value, 0);
            }
            else
            {
                $this->shmId = $shm;
                if($drapeau_exist === false)
                {
                    /**
                    * SHM initialisé
                    **/
                    $value = $writers . $enreg;
                    shmop_write($this->shmId, $value, 0);
                }
            }
            break;
        default :
            break;
        }
        return $this;
    }
    function EXIST()
    {
        /**
        * SHM existe.
        **/
        if($this->OPEN("a", 0666, 0) !== false)
        {
            shmop_close($this->shmId);
            return true;
        }
        return false;
    }
    function ALLOCATE(int $size)
    {
        $BlockSize = $size + $this->shmHeaderOffset + 1;
        if(($this->shmMaxBlockSize <= $size)||
            ($this->shmBlockSize <= $BlockSize)||
            ($this->shmLimitBlockSize <= (4096 * (1 + ceil(1.5 * $BlockSize / 4096.0)))))
        {
            $this->shmMaxBlockSize = $size;
            $this->shmBlockSize = $size + $this->shmHeaderOffset + 1;
            /**
            * Surplus
            * pour dépassements
            * peu fréquents.
            **/
            $this->shmLimitBlockSize = 4096 * (1 + ceil(1.5 * $this->shmBlockSize / 4096.0));
            return true;
        }
        return false;
    }
    private function tmp_read(bool $block = false)
    {
        if($this->OPEN("w", 0666, 0) === false)
        {
            return false;
        }
        // Check SpinLock
        if(@shmop_read($this->shmId, 0, 1) !== "0")
        {
            return false;
        }
        if(($enreg = @shmop_read($this->shmId, 1, @shmop_size($this->shmId) - 1)) === false)
        {
            throw new RuntimeException("Erreur lecture SHM.");
            return false;
        }
        if($block === true)
        {
            // Write spinlock
            // for update.
            @shmop_write($this->shmId, "2", 0);
        }
        shmop_close($this->shmId);
        return $this->SHMOP_INFLATE($enreg);
    }
    private function tmp_write(string $data, bool $block = false)
    {
        $size = strlen($this->SHMOP_DEFLATE($data)) + 256;
        if($this->OPEN("c", 0666, $size) === false)
        {
            return false;
        }
        if($block === false)
        {
            // Check SpinLock
            if(@shmop_read($this->shmId, 0, 1) !== "0")
            {
                return false;
            }
        }
        else
        {
            // Check SpinLock
            if(@shmop_read($this->shmId, 0, 1) !== "2")
            {
                return false;
            }
        }
        // Write spinlock
        @shmop_write($this->shmId, "1", 0);
        if(($enreg = @shmop_read($this->shmId, 1, @shmop_size($this->shmId) - 1)) === false)
        {
            throw new RuntimeException("Erreur écriture SHM.");
            return false;
        }
        if(strlen($data) < 1)
        {
            @shmop_write($this->shmId, "0", 1);
            throw new RuntimeException('dataSize < 1');
            return false;
        }
        // Write Data
        @shmop_write($this->shmId, $this->SHMOP_DEFLATE($data), 1);
        // release spinlock
        @shmop_write($this->shmId, "0", 0);
        shmop_close($this->shmId);
        return true;
    }
    protected function READ(bool $block = false)
    {
        /**
        * Mettre
        * un délai.
        **/
        while(true)
        {
            if(($data = $this->tmp_read($block)) !== false)
            {
                return $data;
            }
        }
    }
    protected function WRITE(string $data, bool $block = false)
    {
        /**
        * Mettre
        * un délai.
        **/
        while(true)
        {
            if($this->tmp_write($data, $block) !== false)
            {
                break;
            }
        }
        return $this;
    }
    protected function APPEND(string $data)
    {
        $enreg = $this->READ(true);
        $str = $this->SHMOP_DEFLATE($enreg) . $data;
        return $this->WRITE($str , true);
    }
    protected function CLOSE()
    {
        return @shmop_close($this->shmId);
    }
    protected function DELETE()
    {
        return @shmop_delete($this->shmId);
    }
    protected function EOF()
    {
        if($this->OPEN("a", 0666, 0) === false)
        {
            return false;
        }
        $res =  (@shmop_read($this->shmId, 0, 1) === "3") ? true : false;
        shmop_close($this->shmId);
        return $res;
    }
    protected function SEND_EOF()
    {
        if($this->OPEN("w", 0666, 0) === false)
        {
            return false;
        }
        // Check SpinLock
        if(@shmop_read($this->shmId, 0, 1) !== "0")
        {
            shmop_close($this->shmId);
            return false;
        }
        @shmop_write($this->shmId, "3", 0);
        shmop_close($this->shmId);
        return true;
    }
    protected function IS_LOCKED()
    {
        if($this->OPEN("a", 0666, 0) === false)
        {
            return false;
        }
        // Check SpinLock
        $res =  (@shmop_read($this->shmId, 0, 1) === "1") ? true : false;
        shmop_close($this->shmId);
        return $res;
    }
    protected function RELEASE_LOCK()
    {
        if($this->OPEN("w", 0666, 0) === false)
        {
            return false;
        }
        // release spinlock
        // for writing.
        @shmop_write($this->shmId, "0", 0);
        shmop_close($this->shmId);
        return true;
    }
    protected function SET_LOCK()
    {
        if($this->OPEN("w", 0666, 0) === false)
        {
            return false;
        }
        // Write spinlock
        @shmop_write($this->shmId, "1", 0);
        shmop_close($this->shmId);
        return true;
    }
    protected function SIZE()
    {
        $str = $this->READ();
        if($str === false)
        {
            return false;
        }
        return strlen($this->SHMOP_DEFLATE($str));
    }
}
?>
 
WRInaute accro
Bonjour

J'ai un problème.

Je peux faire un shmop_delete($shmId) correct ( il rend 1 ), mais pas le shmop_close($shmid) après 10ms ( rend rien ).

Comment se fait-il que le $shmId ne soit plus valide après le shmop_delete() ?

Par ailleurs, je n'arrive pas à ouvrir le même SHM en mode "n" ou "c", après l'avoir détruit avec ces deux fonctions.

Sinon tout baigne, je teste pour l'instant 4 requêtes MySQL qui semblent être correctement cachées.

Merci beaucoup beaucoup de votre aide.
 
WRInaute accro
Pardon

shmop_close() est de type void, donc normal qu'il ne rende rien.

Mais pourquoi ( sous Linux Fedora 30 ) :

PHP:
  shmop_delete($shmId); // Correct, rend 1
  shmop_close($shmId);  // void

   usleep(10000);

  $shm = open($same_key, "n", 0666, $new_size);

  if(empty($shm))
  {
      echo "Erreur open SHM en mode création.\n\n";

     return false;
  }

  $shmId = $shm;

Le message d'erreur est toujours affiché.

Pourquoi ?

Merci beaucoup.
 
WRInaute accro
Bonjour

Ma question est plus générale.

Mettons des ressources ( shmop ) par clés $key et une classe singleton par clé.

Pour l'accès à la ressource de clé $key , j'ai besoin d 'un verrou.

Est-ce qu'une variable array par clé static mise à zéro une fois dans le constructeur pourrait faire office de verrou ?

C'est-à-dire : Atomicité suffisante pour les accès concurrents ?

Si oui, comment çà se fait que je n'ai pas vu d'implémentation sur le net ?

C'est beaucoup plus rapide d'incrémenter/décrémenter une variable qu'un bout de shmop ?

Merci beaucoup de vos réponses.

Amicalement.
 
WRInaute accro
Je vous demande pardon

Ma stupide précédente question est absurde, les variables static ne sont pas partagées entre processus.

Je dois augmenter la taille d'un SHM.

Comment faire celà ?

Le paramètre "n" de shmop_open($key, "n", 0777, $size) a ce commentaire dans le PHP Manual :

  • "n" crée un nouveau segment de mémoire partagée (utilise IPC_CREATE|IPC_EXCL). Utilisez cette option lorsque vous voulez créer un nouveau segment de mémoire partagée sauf s'il en existe déjà un corrompu avec la même option. Ceci est très pratique pour des raisons de sécurité, pour éviter des trous de sécurité qui exploiteraient la course aux ressources.

Le problème est : Est-on obligé de ne strictement jamais augmenter la taille
d'un SHM à l'ouverture en écriture ?


Comment faire si s'est le cas ?

Le processus qui l'a créé est-il le seul à pouvoir le deleter ?

Merci beaucoup pour votre aide.

Respectueusement.
 
WRInaute accro
Bonjour

Avec le même algorithme lecteur/rédacteur, je peux faire en sorte que les ouvertures de blocs ne soient jamais simultanées.

La variable "Lect" de nombre de rédacteurs est partagée car mise au début de chaque bloc.

Dans ce cas ( ouvertures non simultanées ) , j'arrive bien ( semble-t-il ), à deleter et recréer les blocs en en augmentant la taille si besoin.

Le problème est dans l'évaluation et le choix de la taille, qui ne peut être fait que par bloc.

Mais celà m'occasionne souvent des updates de tailles.

D'un autre côté, comment rendre atomistique les cycles READ() ->WRITE() ?

Voici le soft :

Merci beaucoup.



Code:
<?php

########################
class SHMOP
{
    /********************************/
    /*    VARIABLES MUTEX        */
    /********************************/
    /*    3 SEMAPHORES        */
    /********************************/
    /*         CLES        */
    /********************************/
    private $shmLect_1    = null;
    private $shmRed_1    = null;
    private $shmRed        = null;
    /********************************/
    /*        SEM_ID        */
    /********************************/
    private $semLect_1    = array();
    private $semRed_1    = array();
    private $semRed        = array();
  
    /********************************/
    /*    VARIABLE NBRE LECTEURS    */
    /********************************/
    private $shmLect    = array();
    /********************************/
    /*    VARIABLES SHMOP        */
    /********************************/
    private $shmKEY        = null;
    private $shmId        = null;
    private $shmMode    = null;
    private $shmFlags    = null;
    private $shmOffsetEnreg        = array();
    private $shmBlockSize        = array();
    private $shmLimitBlockSize    = array();
    /**
    * C'est un singleton
    * par clés $this->shmKey.
    **/
    protected static $instance    = array(); // Instance de la classe.
    protected function __clone() { } // Méthode de clonage en privé.
    public static function getInstance(int $key)
    {
        /**  
        * Si on n'a pas
        * encore instancié
        * notre classe
        * pour cette $this->shmKey.
        **/
        if (!isset(self::$instance[$key]))
        {
            self::$instance[$key] = new  self($key); // On s'instancie nous-mêmes. :)
        }
        return self::$instance[$key];
    }
    protected function __construct(int $key)
    {
        $this->shmKey = $key;
        $this->shmMode = 0;
        $this->shmFlags = "a";
        /**
        mutex Lect_1 = 1     => protège variable Lect
        mutex Red_1 = 1        => bloque les rédactions
        sémaphore Red = 1     => bloque lectures si Rédaction en cours.
        variable Lect        = nombre de Lecteurs
        **/
        $this->shmLect[$this->shmKey] = $this->shmKey;
        $this->shmLect_1[$this->shmKey] = $this->shmKey + 1000;
        $this->shmRed_1[$this->shmKey] = $this->shmKey + 2000;
        $this->shmRed[$this->shmKey] = $this->shmKey + 3000;
        $size = 1024;
        $this->shmOffsetEnreg[$this->shmKey] = strlen($size);
        $this->shmBlockSize[$this->shmKey] = $this->shmOffsetEnreg[$this->shmKey] + $size + 1;
        /**
        * Surplus
        * pour dépassements[$this->shmKey]
        * peu fréquents.
        **/
        /**
        * Valeur courante.
        **/
        $this->shmLimitBlockSize[$this->shmKey] = 2048 * ceil($this->shmBlockSize[$this->shmKey] / 2048.0);
//        error_reporting(true);
        return $this;
    }
    function __destruct()
    {
        /**
        sem_remove($this->semLect_1[$this->shmKey]);
        sem_remove($this->semRed_1[$this->shmKey]);
        sem_remove($this->semRed[$this->shmKey]);
        **/
        self::$instance[$this->shmKey] = null;
        return true;
    }
    private function Init_Mutex()
    {
        /************************/
        /* INSTANCIATION MUTEX    */
        /************************/
        if(($this->semLect_1[$this->shmKey] = sem_get($this->shmLect_1[$this->shmKey])) === false)
            return false;
        if(($this->semRed_1[$this->shmKey] = sem_get($this->shmRed_1[$this->shmKey])) === false)
            return false;
        if(($this->semRed[$this->shmKey] = sem_get($this->shmRed[$this->shmKey])) === false)
            return false;
        /************************/
        /* INIIALISATION LECT    */
        /************************/
        if(!$this->wrapper_shmop_write($this->shmId, $this->SHMOP_DEFLATE("0"), 0))
            return false;
        return true;
    }
    private function BEGIN_READ()
    {
        /**
        P(M_Lect)
            Lect++
        si Lect==1 alors
            P(Red)
        FIN SI
        V(M_Lect)
        **/
        /************************/
        /*   Commencer_Lire    */
        /************************/
        if((!isset($this->semLect_1[$this->shmKey]))
            &&(!isset($this->semRed_1[$this->shmKey]))
            &&(!isset($this->semRed[$this->shmKey])))
        {
            $this->Init_Mutex();
        }
        sem_acquire($this->semLect_1[$this->shmKey]);
        if($this->wrapper_shmop_write($this->shmId, $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId, 0, $this->shmOffsetEnreg[$this->shmKey]))) + 1), 0) === false)
        {
            sem_release($this->semLect_1[$this->shmKey]);
            return false;
        }
        if((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId, 0, $this->shmOffsetEnreg[$this->shmKey])) == 1)
            sem_acquire($this->semRed[$this->shmKey]);
        sem_release($this->semLect_1[$this->shmKey]);
        return true;
    }
    private function END_READ()
    {
        /**
        P(M_Lect)
        Lect--
        SI Lect==0 ALORS
        V(Red)
        FIN SI
        V(M_Lect)
        **/
        if((!isset($this->semLect_1[$this->shmKey]))
            &&(!isset($this->semRed_1[$this->shmKey]))
            &&(!isset($this->semRed[$this->shmKey])))
        {
            $this->Init_Mutex();
        }
        /************************/
        /*    Finir_Lire    */
        /************************/
        sem_acquire($this->semLect_1[$this->shmKey]);
        if($this->wrapper_shmop_write($this->shmId, $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId, 0, $this->shmOffsetEnreg[$this->shmKey]))) - 1), 0) === false)
        {
            sem_release($this->semLect_1[$this->shmKey]);
            return false;
        }
        if((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId, 0, $this->shmOffsetEnreg[$this->shmKey])) == 0)
            sem_release($this->semRed[$this->shmKey]);
        sem_release($this->semLect_1[$this->shmKey]);
        return true;
    }
    private function BEGIN_WRITE()
    {
        /**
        P(M_Red)
        P(Red)
        **/
        /************************/
        /*   Commencer_Ecrire    */
        /************************/
      
        if((!isset($this->semLect_1[$this->shmKey]))
            &&(!isset($this->semRed_1[$this->shmKey]))
            &&(!isset($this->semRed[$this->shmKey])))
        {
            $this->Init_Mutex();
        }
        sem_acquire($this->semRed_1[$this->shmKey]);
        sem_acquire($this->semRed[$this->shmKey]);
        return true;
    }
    protected function END_WRITE()
    {
        /**
        V(Red)
        V(M_Red)
        **/
        if((!isset($this->semLect_1[$this->shmKey]))
            &&(!isset($this->semRed_1[$this->shmKey]))
            &&(!isset($this->semRed[$this->shmKey])))
        {
            $this->Init_Mutex();
        }
        /************************/
        /*   Finir_Ecrire    */
        /************************/
        sem_release($this->semRed[$this->shmKey]);
        sem_release($this->semRed_1[$this->shmKey]);
        return true;
    }
        protected function millisecond()
        {
                return floor(microtime(true)/0.001 + 0.5);
        }
    /**
    * Pour les
    * ID de SHMOP.
    **/
        private function SHM_ID($str)
        {
        return '"' . $str . '"';
        }
    /**
    * Format type
    * string conpressée
    * après linearisation.
    **/
    private function SHMOP_DEFLATE(string $value)
    {
        /**
        * On ajoute un '\0'.
        **/
        return $this->str_to_nts($value);
        /**
        * VALUE => COMPRESS => BASE64_ENCODE => STR
        **/
        $str = base64_encode($value);
        $str =  base64_encode(gzcompress($value));
    }
    /**
    * Format type
    * string déconpressée
    * et délinéarisée.
    **/
    private function SHMOP_INFLATE($value)
    {
        /**
        * On enlève le '\0'.
        **/
        $data =  $this->str_from_mem($value);
        return $data;
        /*
        * STR => BASE64_DECODE => UNCOMPRESS.
        */
        return base64_decode($data);
        return gzuncompress(base64_decode($data));
    }
    private function str_from_mem(string &$value) {
        $i = strpos($value, chr(0));
        if ($i !== false) {
            return substr($value, 0, $i);
        }
        return $value;
    }
    private function str_to_nts(string $value) {
        return $value.chr(0);
    }
    private function wrapper_shmop_open(int $key, string $flags, int $perm = 0777, int $size = 0)
    {
        /**
        * USER root,
        * specific threatment
        * for opening
        * the SHM as nginx.
        **/
        if(posix_geteuid() == 0)
        {
            switch($flags) {
            case "n" :
                /**
                * Creation
                * comme user
                * nginx.
                **/
                exec("sudo -u nginx php -r 'shmop_open(" . $key . ", \"" . $flags . "\", " . $perm . ", " . $size . ");'"); //Create Shared Memory segment as USER nginx
                /**
                ob_start();
                passthru("/usr/bin/sudo -u nginx -g nginx /usr/bin/php -r '@shmop_open(" . $key . ", \"" . $flags . "\", " . $perm . ", " . $size . ");'", $result); //Create Shared Memory segment as USER nginx
                $output = ob_get_contents();
                ob_end_clean();
                **/
                $flags = "w";
                return shmop_open($key, $flags, $perm, $size);
                break;
            case "c" :
                /**
                * Creation
                * comme user
                * nginx.
                **/
                exec("sudo -u nginx php -r 'shmop_open(" . $key . ", \"" . $flags . "\", " . $perm . ", " . $size . ");'"); //Create Shared Memory segment as USER nginx
                /**
                ob_start();
                passthru("/usr/bin/sudo -u nginx -g nginx /usr/bin/php -r '@shmop_open(" . $key . ", \"" . $flags . "\", " . $perm . ", " . $size . ");'", $result); //Create Shared Memory segment as USER nginx
                $output = ob_get_contents();
                ob_end_clean();
                **/
                $flags = "w";
                break;
            default :
                break;
            }
        }
        return @shmop_open($key, $flags, $perm, $size);
    }
    private function wrapper_shmop_delete($shmId)
    {
        /**
        * USER root,
        * maybe
        * specific threatment
        * for deleting
        * the SHM as nginx.
        **/
        /**
        if(posix_geteuid() == 0)
        {
            echo "DELETE<br />\n\n";
            **/
            /**
            * Delete
            * comme user
            * nginx.
            **/
//            exec("sudo -u nginx php -r 'shmop_delete(" . $this->SHM_ID($shmId) . ");'"); //Create Shared Memory segment as USER nginx
//            exec("sudo -u nginx php -r '@shmop_delete(\"" . $shmId . "\");'", $output, $result); //Create Shared Memory segment as USER nginx
            /**
            ob_start();
            passthru("/usr/bin/sudo -u nginx -g nginx /usr/bin/php -r '@shmop_delete(" . $this->SHM_ID($shmId) . ");'", $result); //Create Shared Memory segment as USER nginx
            ob_end_clean();
            **/
            /**
            if(empty($result))
                $result = false;
                **/
/**
                echo "\t\t\tRESULTAT DELETE = ";
                if(is_array($output))
                {
                    print_r($output);
                }
                else
                {
                    echo $output;
                }
                echo "<br /><br />\n";
            echo "\t\t\tRESULT DELETE = " . $result . "<br /><br />\n";
                return $result;
        }
        **/
        $result = shmop_delete($shmId);
//        echo "RESULTAT DELETE = " . $result . "<br />\n\n";
        return $result;
    }
    private function wrapper_shmop_size($shmId)
    {
        /**
        * USER root,
        * maybe
        * specific threatment
        * for closing
        * the SHM as nginx.
        **/
        /**
        if(posix_geteuid() == 0)
        {
            echo "SHMOP_SIZE<br />\n\n";
            **/
            /**
            * Delete
            * comme user
            * nginx.
            **/
//            exec("sudo -u nginx -g nginx php -r '@shmop_size(" . $this->SHM_ID($shmId) . ");'", $output, $result); //Create Shared Memory segment as USER nginx
//            exec("sudo -u nginx -g nginx php -r '@shmop_size(\"" . $shmId . "\");'", $output, $result); //Create Shared Memory segment as USER nginx
        //            ob_start();
        /**
            passthru("/usr/bin/sudo -u nginx -g nginx /usr/bin/php -r '@shmop_size(" . $this->SHM_ID($shmId) . ");'", $result); //Create Shared Memory segment as USER nginx
            $output = ob_get_contents();
//            ob_end_clean();
            return $output;
            return $result;
        }
        **/
        return shmop_size($shmId);
    }
    private function wrapper_shmop_close($shmId)
    {
        /**
        * USER root,
        * maybe
        * specific threatment
        * for closing
        * the SHM as nginx.
        **/
        /**
        if(posix_geteuid() == 0)
        {
            echo "CLOSE<br />\n\n";
            **/
            /**
            * Delete
            * comme user
            * nginx.
            **/
        /**
            exec("sudo -u nginx php -r '@shmop_close(" . $this->SHM_ID($shmId) . ");'"); //Create Shared Memory segment as USER nginx
//            exec("sudo -u nginx -g nginx php -r '@shmop_close(\"" . $shmId . "\");'", $output, $result); //Create Shared Memory segment as USER nginx
            ob_start();
            passthru("/usr/bin/sudo -u nginx -g nginx /usr/bin/php -r '@shmop_close(" . $this->SHM_ID($shmId) . ");'", $result); //Create Shared Memory segment as USER nginx
            ob_end_clean();
            return;
        }
    **/
        return shmop_close($shmId);
    }
    private function wrapper_shmop_read($shmId, $offset, $tmp_count)
    {
        /**
        * USER root,
        * maybe
        * specific threatment
        * for reading
        * the SHM as nginx.
        **/
        /**
        if(posix_geteuid() == 0)
        {
        **/
            /**
            * Delete
            * comme user
            * nginx.
            **/
//            return exec("sudo -u nginx -g nginx php -r '@shmop_read(" . $this->SHM_ID($shmId) . ", " . $offset . ", " . $tmp_count . ");'", $output, $result); //Create Shared Memory segment as USER nginx
/**
            ob_start();
            passthru("/usr/bin/sudo -u nginx -g nginx /usr/bin/php -r '@shmop_read(" . $this->SHM_ID($shmId) . ", " . $offset . ", " . $tmp_count . ");'", $result); //Create Shared Memory segment as USER nginx
            $output = ob_get_contents();
            ob_end_clean();
            return $output;
        }
        **/
        return shmop_read($shmId, $offset, $tmp_count);
    }
    private function wrapper_shmop_write($shmId, $value, $offset)
    {
        /**
        * USER root,
        * maybe
        * specific threatment
        * for writing
        * the SHM as nginx.
        **/
        /**
        if(posix_geteuid() == 0)
        {
            if(strlen($value) < 3)
            {
                $value = $this->SHM_ID($value);
            }
            echo "WRITE<br />\n\n";
            **/
            /**
            * Delete
            * comme user
            * nginx.
            **/
            //    exec("sudo -u nginx -g nginx php -r '@shmop_write(" . $this->SHM_ID($shmId) . ", \"" . $value . "\", " . $offset . ");'", $output, $result); //Create Shared Memory segment as USER nginx
/**
      
            ob_start();
            passthru("/usr/bin/sudo -u nginx -g nginx /usr/bin/php -r '@shmop_write(" . $this->SHM_ID($shmId) . ", " . $value . ", " . $offset . ");'", $result); //Create Shared Memory segment as USER nginx
            ob_end_clean();
            return $result;
        }
        **/
        return shmop_write($shmId, $value, $offset);
    }
    private function OPEN(string $flags, int $mode, int $size)
    {
        $this->shmMode = $mode;
        $this->shmFlags = $flags;
        $this->shmId = false;
        if(in_array($this->shmFlags, array("a", "w")))
        {
            if($size == 0)
            {
                $shm = $this->wrapper_shmop_open($this->shmKey, $this->shmFlags, 0777, 0);
            }
            else
            {
                $shm = $this->wrapper_shmop_open($this->shmKey, $this->shmFlags, 0777, $this->shmLimitBlockSize[$this->shmKey]);
            }
            if($shm === false)
            {
                return false;
            }
            $this->shmId = $shm;
            return true;
        }
        switch ($this->shmFlags) {
        case "n" :
            /**
            * On update
            * si besoin
            * les paramètres
            * d'allocation
            * mémoire.
            **/
            $this->ALLOCATE($size);
            $shm = $this->wrapper_shmop_open($this->shmKey, $this->shmFlags, 0777, $this->shmLimitBlockSize[$this->shmKey]);
            /**
            * Le SHM
            * ne doit
            * pas exister.
            **/
            if($shm === false)
            {
                echo "\t\t" . 'Erreur création : Le SHM existe déjà.' . "<br />\n\n";
                return false;
            }
          
            $this->shmId = $shm;
            return true;
            break;
            /**
            * Pour créer
            * un bloc
            * s'il n'existe pas,
            * ou l'ouvrir
            * en lecture/écriture
            * s'il existe.
            **/
        case "c" :
            /**
            * On vérifie
            * si le SHM
            * existe.
            **/
            $shm = $this->wrapper_shmop_open($this->shmKey, "w", 0777, $this->shmLimitBlockSize[$this->shmKey]);
            /**
            * Le SHM existe.
            *
            * On ne peut
            * l'effacer
            * puis le recréer
            * que si le sémaaphore
            * est libre.
            **/
            if($shm !== false)
            {
                /**
                * Pour le BEGIN_WRITE().
                **/
                $this->shmId = $shm;
                $this->BEGIN_WRITE();
                /**
                * On update
                * si besoin
                * les paramètres
                * d'allocation
                * mémoire.
                **/
                if($this->ALLOCATE($size))
                {
                    if($this->wrapper_shmop_delete($shm) == false)
                    {
                        $this->END_WRITE();
                        $this->shmId = false;
                        return false;
                    }
                    $this->wrapper_shmop_close($shm);
                    $this->shmId = false;
                    if(($shm = $this->wrapper_shmop_open($this->shmKey, "n", 0777, $this->shmLimitBlockSize[$this->shmKey])) === false)
                    {
                        echo "\t\t" . 'Erreur création : Le SHM existait déjà.' . "<br />\n\n";
                        return false;
                    }
                    $this->shmId = $shm;
                    $this->END_WRITE();
                }
                else
                {
                    $this->END_WRITE();
                }
            }
            /**
            * Le SHM n'existe pas,
            * on peut
            * mettre à jour
            * sa dimension.
            **/
            else
            {
                /**
                * On update
                * si besoin
                * les paramètres
                * d'allocation
                * mémoire.
                **/
                $this->ALLOCATE($size);
                if(($shm = $this->wrapper_shmop_open($this->shmKey, "n", 0777, $this->shmLimitBlockSize[$this->shmKey])) === false)
                {
                    echo "\t\t" . 'Erreur création : Le SHM existe déjà.' . "<br />\n\n";
                    return false;
                }
                $this->shmId = $shm;
            }
          
            return true;
            break;
        default :
                        throw new RuntimeException("Paramètre SHM faux = " . $this->shmFlags);
                        return false;
                        break;
                }
        return true;
    }
    private function ALLOCATE(int $size)
    {
        $BlockSize = $this->shmOffsetEnreg[$this->shmKey] + $size + 1;
        if(($this->shmBlockSize[$this->shmKey] < $BlockSize)||
            ($this->shmLimitBlockSize[$this->shmKey] < (2048 * ceil($BlockSize[$this->shmKey] / 2048.0))))
        {
            $this->shmBlockSize[$this->shmKey] = $this->shmOffsetEnreg[$this->shmKey] + $size + 1;
            /**
            * Surplus
            * pour dépassements[$this->shmKey]
            * peu fréquents.
            **/
            $this->shmLimitBlockSize[$this->shmKey] = 2048 * ceil($this->shmBlockSize[$this->shmKey] / 2048.0);
            return true;
        }
        return false;
    }
    protected function EXIST()
    {
        /**
        * SHM existe.
        **/
        if($this->OPEN("a", 0777, 0) !== false)
        {
            $this->wrapper_shmop_close($this->shmId);
            return true;
        }
        return false;
    }
    protected function READ(bool $block = false)
    {
        if($this->OPEN("w", 0, 0) === false)
        {
            echo "\t\t" . 'OPEN("w", 0, ' . 0 . ') = false' . "<br />\n\n";
            return false;
        }
        if($block)
        {
            $this->BEGIN_WRITE();
        }
        else
        {
            $this->BEGIN_READ();
        }
        $len = $this->wrapper_shmop_size($this->shmId) - $this->shmOffsetEnreg[$this->shmKey];
        $enreg = $this->wrapper_shmop_read($this->shmId, $this->shmOffsetEnreg[$this->shmKey], $len);
        if(strlen($enreg) != $len)
        {
            echo "\t\t\t" . 'TAILLE ENREG LU = ' . strlen($enreg) . ' <> TAILLE SHMOP = ' . $len . "<br /><br />\n";
            if(!$block)
            {
                $this->END_READ();
            }
            else
            {
                $this->END_WRITE();
            }
            $this->wrapper_shmop_close($this->shmId);
            return false;
        }
        if(!$block)
        {
            $this->END_READ($this->shmId);
            $this->wrapper_shmop_close($this->shmId);
        }
//        $this->wrapper_shmop_close($this->shmId);
      
//        echo "\t\t" . 'DATA READ = ' . $enreg . "<br /><br />\n";
        return $this->SHMOP_INFLATE($enreg);
    }
    protected function WRITE(string $data, bool $block = false)
    {
        $str = $this->SHMOP_DEFLATE($data);
        $size = strlen($str) + 1024;
//        echo "\t\t" . 'DATA WRITE = ' . $str . "<br /><br />\n";
//        echo "\t\t" . 'SIZE = ' . $size . "<br /><br />\n";
        /**
        if($size < $this->shmLimitBlockSize[$this->shmKey])
        {
            $size = $this->shmLimitBlockSize[$this->shmKey];
        }
        **/
        if($this->OPEN("c", 0777, $size) === false)
        {
            echo "\t\t" . 'OPEN("c", 0777, ' . $size . ') = false' . "<br />\n\n";
            return false;
        }
        /**
        * Si true,
        * sémaphore déjà posé
        * en écriture
        * par le READ().
        **/
        if(!$block)
        {
            $this->BEGIN_WRITE();
        }
        if(strlen($str) < 1)
        {
            $this->END_WRITE();
            $this->wrapper_shmop_close($this->shmId);
            echo "\t\t\tDATASIZE < 1.<br /><br />\n";
            return false;
        }
        // Write Data
        $this->wrapper_shmop_write($this->shmId, $str, $this->shmOffsetEnreg[$this->shmKey]);
        $this->END_WRITE();
        $this->wrapper_shmop_close($this->shmId);
        return true;
    }
    protected function APPEND(string $data)
    {
        if($this->OPEN("w", 0777, 0) === false)
        {
            return false;
        }
        $enreg = $this->READ(true);
        if($enreg === false)
        {
            $this->END_WRITE();
            return false;
        }
        $str = $this->SHMOP_DEFLATE($enreg) . $data;
        $res = $this->WRITE($str , true);
        $this->wrapper_shmop_close($this->shmId);
        return $res;
    }
    protected function RELEASE_LOCK()
    {
        if($this->OPEN("w", 0777, 0) === false)
        {
            return false;
        }
        $this->END_WRITE();
        $this->wrapper_shmop_close($this->shmId);
        return true;
    }
    protected function SIZE()
    {
        if($this->OPEN("a", 0777, 0) === false)
        {
            return false;
        }
        $res = $this->wrapper_shmop_size($this->shmId);
        $this->wrapper_shmop_close($this->shmId);
        return $res;
    }
}
?>
 
WRInaute accro
Bonjour Spout

Voici l'algorithme Lecteur/Rédacteur sur lequel je m'arrache les cheveux.

L'algo est à gauche, à droite c'est une traduction visible.

P() et V() sont les acquire et release des mutex.

Il me semble que le else terminal des fonctions : "Commencer_Lire" et "Finir_Ecrire" devrait bloquer dans certain cas, car le mutex semWait de début de fonction n'est jamais désactivé.

Je n'arrive pas à "faire tourner l'algorithme à la main".

$okw_semNbWait et $okr_semNbWait sont théoriquement les nombres des rédacteurs et lecteurs, du moins les nombres d'occurences des FIFO.

L'algorithme provient de l'url :
www.montefiore.ulg.ac.be/~pw/cours/psfiles/struct-cours8.pdf


Merci beaucoup de votre aide.

Amicalement et respectueusement.



Code:
    /*********************************************************************/
        /************************/
        /*   Commencer_Lire    */
        /************************/
        /*                    *
        * P(semWait)                           *    Pose Mutex        <--
        * if (($shm_writing == true)||        *    IF ((Rédacteur == true)      |
        * ($okw_semNbWait > 0))          *    OU (FIFO Rédacteur > 0))  |
        * { V(semWait)                           *     => Enlève Mutex        <--
        *   P($okr_semWait)                 *    ET  Pose SEM Lecteur
        * }                    *
        * $shm_readers++;            *    Nbre Lecteurs++;
        * if($okr_semNbWait > 0)        *    (FIFO Lecteur > 0)
        *   V($okr_semWait)            *    => Enlève SEM Lecteur
        * else V(semWait)            *    ELSE Enlève Mutex
        **/                    *
    /*********************************************************************/
        /************************/
        /*    Finir_Lire    */
        /************************/
        /**                    *
        * P(semWait)                *    Pose Mutex
        * $shm_readers--;            *    Nbre Lecteurs--;
        * if (($shm_readers == 0)&&        *    IF ((Nbre Lecteurs == 0)
        * ($okw_semNbWait > 0))        *    ET ( FIFO Rédacteurs > 0))
        *   V($okw_semWait)            *    Enlève SEM Rédacteur
        * else                    *    SINON
        * V(semWait)                *    Enlève Mutex
        **/                    *
    /*********************************************************************/
        /************************/
        /*   Commencer_Ecrire    */
        /************************/
     
        /**                    *
        * P(semWait)                *    Pose Mutex
        * if (($shm_readers != 0)||        *    IF ((Nbre Lecteurs != 0)
        * ($shm_writing))            *    OU (Rédacteur == true))
        * { V(semWait)                *    => Enlève Mutex
        *   P($okw_semWait)            *    ET  Pose SEM Rédacteur
        * }                    *
        * $shm_writing = true            *    Rédacteur = true
        * V(semWait)                *    Enlève Mutex
        **/                    *
    /*********************************************************************/
        /************************/
        /*   Finir_Ecrire    */
        /************************/
        /**                    *
        * P(semWait)                *    Pose Mutex
        * $shm_writing = false;        *    Rédacteur = false
        * if($okr_semNbWait > 0)        *    if (FIFO Lecteur > 0)
        *   V($okr_semWait)            *    => Enlève SEM Lecteur
        * else                    *    SINON
        * if($okw_semNbWait > 0))        *    IF (FIFO Rédacteur > 0)
        *   V($okw_semWait)            *    Enlève SEM Rédacteur
        * else V(semWait)            *    SINON Enlève Mutex
        **/                    *
 
WRInaute accro
Bonjour

Dans Wikipedia il y a l'indication d'utilisation de moniteurs informatiques pour la synchronisation de processus.

Voici ci-dessous le code de Wikipedia mis en PHP.

Pourriez-vous m'indiquer des urls sur le sujet de la théorie et des applications des moniteurs ?

Merci beaucoup.



PHP:
<?php
 class EchangeMessage {
    private $l = array();
    function __construct()
    {
    }
    public function enfiler($o) {
        $l[count($l)] = $o;
        if(count($l) == 1)
        {
            try {
                sem_release($id);
            } catch (Exception $e) {};
        }
    }
    public function defiler() {
        if(count($l)==0)
        {
            try {
                sem_acquire($id);
            } catch (Exception $e){}
        }
        $o = $l[0];
        array_shift($l);
        return $o;
    }
}
?>
 
WRInaute accro
Bonjour Monsieur

Voici ci-dessous new_SHMOP.php mon implémentation du deuxième ( pas mon dernier message ) algorithme "Lecteur/Rédacteur" avec l'interface SHMOP.

J'ai testé à l'instant le cache MySQL avec 4 requêtes faciles.

Premier coup çà bloque à la fin du script.

Deuxième coup çà marche, les requêtes ont l'air d'être cachées.

Le blocage avant est probablement du à la complexité de mysq_cache.php , le script contenant le code du cache.

Sur le plan théorique, j'ai fait "tourner l'algorithme à la main" ( dans ma tête ), et normalement il ne devrait pas y avoir de blocages.

Cependant merci pour vos avis.

Amicalement.


PHP:
<?php
class SHMOP
{
    /********************************/
    /*    VARIABLES MUTEX        */
    /********************************/
    /*    3 SEMAPHORES        */
    /********************************/
    /*         CLES        */
    /********************************/
    private $shmWaitKey    = null;        // mutex principal.
    private $okr_shmWaitKey    = null;
    private $okw_shmWaitKey    = null;
    /********************************/
    /*        SEM_ID        */
    /********************************/
    private $semWait    = array();
    private $okr_semWait    = array();
    private $okw_semWait    = array();
    /********************************/
    /*  SHARED VAR ( PSEUDO FIFO )    */
    /********************************/
    private $okr_semNbWait    = array();
    private $okw_semNbWait    = array();
   
    /********************************/
    /*   NBRE LECTEURS/REDACTEURS    */
    /********************************/
    /*      ( SHARED VAR )    */
    /********************************/
    private $shm_readers    = array();
    private $shm_writing    = array();
    /********************************/
    /*       RECORD OFFSET    */
    /********************************/
    private $shmOffsetEnreg        = array();
    private $shmOkrOffset        = null;
    private $shmOkwOffset        = null;
    private $shm_readersOffset    = null;
    private $shm_writingOffset    = null;
    /********************************/
    /*      RECORD LENGTH        */
    /********************************/
    private $shmOkrLength        = null;
    private $shmOkwLength        = null;
    private $shm_readersLength    = null;
    private $shm_writingLength    = null;
    /********************************/
    /*    VARIABLES SHMOP        */
    /********************************/
    private $shmId            = array();
    private $shmMode        = array();
    private $shmFlags        = array();
    private $shmBlockSize        = array();
    private $shmLimitBlockSize    = array();
    /**
    * C'est un singleton
    * par clés $this->shmKey.
    **/
    protected static $instance    = array(); // Instance de la classe.
    protected function __clone() { } // Méthode de clonage en privé.
    public static function getInstance(int $key)
    {
        /**   
        * Si on n'a pas 
        * encore instancié 
        * notre classe
        * pour cette $this->shmKey.
        **/
        if (!isset(self::$instance[$key])) 
        {
            self::$instance[$key] = new  self($key); // On s'instancie nous-mêmes. :)
        }
        return self::$instance[$key];
    }
    protected function __construct(int $key)
    {
        $this->shmKey = $key;
        $this->shmMode[$this->shmKey] = 0;
        $this->shmFlags[$this->shmKey] = "a";
        $this->shmWaitKey[$this->shmKey]    = $this->shmKey + 1000;
        $this->okr_shmWaitKey[$this->shmKey]    = $this->shmKey + 2000;
        $this->okw_shmWaitKey[$this->shmKey]    = $this->shmKey + 3000;
        $size = 1024;
        // Offset
        $this->shmOkrOffset        = 0;    // Offset FIFO Lecteurs.
        $this->shmOkwOffset        = 64;    // Offset FIFO Rédacteurs.
        $this->shm_readersOffset    = 128;    // Offset Nbre Lecteurs.
        $this->shm_writingOffset    = 192;    // Offset Nbre Rédacteurs.
       
        $this->shmOffsetEnreg        = 256;    // Offset Enregistrement.
        // Length
        $this->shmOkrLength        = $this->shmOkwOffset - $this->shmOkrOffset;        // FIFO Lecteurs
        $this->shmOkwLength        = $this->shm_readersOffset - $this->shmOkwOffset;    // FIFO Rédacteurs
           
        $this->shm_readersLength    = $this->shm_writingOffset - $this->shm_readersOffset;    // Nbre Lecteurs
        $this->shm_writingLength    = $this->shmOffsetEnreg - $this->shm_writingOffset;    // Nbre Rédacteurs
       
        $this->shmBlockSize[$this->shmKey] = $this->shmOffsetEnreg[$this->shmKey] + $size + 1;
        /**
        * Longueur totale shared memory.
        **/
        $this->shmLimitBlockSize[$this->shmKey] = 2048 * ceil($this->shmBlockSize[$this->shmKey] / 2048.0);
        error_reporting(true);
        return $this;
    }
    function __destruct()
    {
        /**
        sem_remove($this->okr_semWait[$this->shmKey]);
        sem_remove($this->semWait[$this->shmKey]);
        sem_remove($this->okw_semWait[$this->shmKey]);
        **/
        self::$instance[$this->shmKey] = null;
        return true;
    }
    private function INIT_MUTEX()
    {
        /************************/
        /* INSTANCIATION MUTEX    */
        /************************/
        if(($this->semWait[$this->shmKey] = sem_get($this->shmWaitKey[$this->shmKey])) === false)        // ID Mutex
            return false;
        if(($this->okr_semWait[$this->shmKey] = sem_get($this->okr_shmWaitKey[$this->shmKey])) === false)    // ID SEM Lecteur
            return false;
        if(($this->okw_semWait[$this->shmKey] = sem_get($this->okw_shmWaitKey[$this->shmKey])) === false)    // ID SEM Rédacteur
            return false;
        /************************/
        /*  INIIALISATION VAR    */
        /************************/
   
        /**
        * Init à zéro
        * de $this->shm_readers.
        **/
        if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE("0"), $this->shm_readersOffset) === false)    // $readers = 0.
            return false;
        /**
        * Init à false/zéro
        * de $this->shm_writing.
        **/
        if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE("0"), $this->shm_writingOffset) === false)    // $writing = false.
            return false;
        /**
        * Init à zéro
        * de $this->okr_semNbWait.
        **/
        if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE("0"), $this->shmOkrOffset) === false)    // FIFO Lecteur vide;
            return false;
        /**
        * Init à zéro
        * de $this->okw_semNbWait.
        **/
        if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE("0"), $this->shmOkwOffset) === false)    // FIFO Rédacteur vide.
            return false;
        return true;
    }
    private function RELEASE_MUTEX()
    {
        if(is_resource($this->okr_semWait[$this->shmKey]))
        {
            sem_release($this->okr_semWait[$this->shmKey]);
            sem_remove($this->okr_semWait[$this->shmKey]);
        }
        if(is_resource($this->okw_semWait[$this->shmKey]))
        {
            sem_release($this->okw_semWait[$this->shmKey]);
            sem_remove($this->okw_semWait[$this->shmKey]);
        }
        if(is_resource($this->semWait[$this->shmKey]))
        {
            sem_release($this->semWait[$this->shmKey]);
            sem_remove($this->semWait[$this->shmKey]);
        }
        return true;
    }
    private function BEGIN_READ()
    {
        /**
        P(M_Lect)
            Lect++
        si Lect==1 alors
            P(_okw_Mutex)
        FIN SI
        V(M_Lect)
        **/
        /**
        * P(semWait)
        * if (($shm_writing == true)||
        * ($okw_semNbWait > 0))
        * { V(semWait)
        *   P($okr_semWait)
        * }
        * $shm_readers++;
        * if($okr_semNbWait > 0)
        *   V($okr_semWait)
        * else V(semWait)
        **/
        /************************/
        /*   Commencer_Lire    */
        /************************/
        if((!is_resource($this->semWait[$this->shmKey]))
            &&(!is_resource($this->okr_semWait[$this->shmKey]))
            &&(!is_resource($this->okw_semWait[$this->shmKey])))
            $this->INIT_MUTEX();
        // SET THE MUTEX.
        sem_acquire($this->semWait[$this->shmKey]);
        // IF((WRITING == true)||(FIFO Rédacteur > 0))
        if(($this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_writingOffset, $this->shm_writingLength)) == "1")||((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shmOkwOffset, $this->shmOkwLength)) > 0))
        {
            // RELEASE THE MUTEX.
            sem_release($this->semWait[$this->shmKey]);
            // add FIFO Lecteurs
            if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shmOkrOffset, $this->shmOkrLength)) + 1)), $this->shmOkrOffset) === false)
            {
                $this->RELEASE_MUTEX();
                return false;
            }
            // RELEASE THE Lecteurs SEM.
            sem_acquire($this->okr_semWait[$this->shmKey]);
        }
        // INCREMENT READERS.
        if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_readersOffset, $this->shm_readersLength)) + 1)), $this->shm_readersOffset) === false)
        {
            $this->RELEASE_MUTEX();
            return false;
        }
        // IF(FIFO Lecteurs > 0)
        if((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shmOkrOffset, $this->shmOkrLength)) > 0)
        {
            // DECREMENT FIFO Lecteurs.
            if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shmOkrOffset, $this->shm_readersLength)) - 1)), $this->shmOkrOffset) === false)
            {
                $this->RELEASE_MUTEX();
                return false;
            }
            // RELEASE THE Lecteurs SEM.
            sem_release($this->okr_semWait[$this->shmKey]);
        }
        else
            // RELEASE THE MUTEX.
            sem_release($this->semWait[$this->shmKey]);
        return true;
    }
    private function END_READ()
    {
        /**
        P(M_Lect)
        Lect--
        SI Lect==0 ALORS
        V(_okw_Mutex)
        FIN SI
        V(M_Lect)
        **/
        /**
        * P(semWait)
        * $shm_readers--;
        * if (($shm_readers == 0)&&
        * ($okw_semNbWait > 0))
        *   V($okw_semWait)
        * else
        * V(semWait)
        **/
        /************************/
        /*    Finir_Lire    */
        /************************/
        // SET THE MUTEX.
        sem_acquire($this->semWait[$this->shmKey]);
        // DECREMENT READERS.
        if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_readersOffset, $this->shm_readersLength)) - 1)), $this->shm_readersOffset) === false)
        {
            $this->RELEASE_MUTEX();
            return false;
        }
        // IF((READERS == 0)&&(FIFO Rédacteur > 0))
        if(((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_readersOffset, $this->shm_readersLength)) == 0)&&((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shmOkwOffset, $this->shmOkwLength)) > 0))
        {
            // DECREMENT FIFO Rédacteurs.
            if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_OkwOffset, $this->shm_OkwLength)) - 1)), $this->shm_OkwOffset) === false)
            {
                $this->RELEASE_MUTEX();
                return false;
            }
            // RELEASE THE Rédacteurs SEM.
            sem_release($this->okw_semWait[$this->shmKey]);
        }
        else
            // RELEASE THE MUTEX.
            sem_release($this->semWait[$this->shmKey]);
        return true;
    }
    private function BEGIN_WRITE()
    {
        /**
        P(M__okw_Mutex)
        P(_okw_Mutex)
        **/
        /**
        * P(semWait)
        * if (($shm_readers != 0)||
        * ($shm_writing))
        * { V(semWait)
        *   P($okw_semWait)
        * }
        * $shm_writing = true
        * V(semWait)
        **/
        /************************/
        /*   Commencer_Ecrire    */
        /************************/
        if((!is_resource($this->semWait[$this->shmKey]))
            &&(!is_resource($this->okr_semWait[$this->shmKey]))
            &&(!is_resource($this->okw_semWait[$this->shmKey])))
            $this->INIT_MUTEX();
        // SET THE MUTEX.
        sem_acquire($this->semWait[$this->shmKey]);
        // IF((READERS != 0)||(WRITING == true))
        if(((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_readersOffset, $this->shm_readersLength)) != 0)||((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_writingOffset, $this->shm_writingLength)) == 1))
        {
            // RELEASE THE MUTEX.
            sem_release($this->semWait[$this->shmKey]);
            // INCREMENT FIFO Rédacteurs.
            if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_OkwOffset, $this->shm_OkwLength)) + 1)), $this->shm_OkwOffset) === false)
            {
                $this->RELEASE_MUTEX();
                return false;
            }
            // SET THE Rédacteurs SEM.
            sem_acquire($this->okw_semWait[$this->shmKey]);
        }
        // WRITING = true.
        if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE("1"),$this->shm_writingOffset) === false)
        {
            $this->RELEASE_MUTEX();
            return false;
        }
        // RELEASE THE MUTEX.
        sem_release($this->semWait[$this->shmKey]);
        return true;
    }
    protected function END_WRITE()
    {
        /**
        V(_okw_Mutex)
        V(M__okw_Mutex)
        **/
        /**
        * P(semWait)
        * $shm_writing = false;
        * if($okr_semNbWait > 0))
        *   V($okr_semWait)
        * else
        * if($okw_semNbWait > 0))
        *   V($okw_semWait)
        * else V(semWait)
        **/
        /************************/
        /*   Finir_Ecrire    */
        /************************/
        // SET THE MUTEX.
        sem_acquire($this->semWait[$this->shmKey]);
        // WRITING = false.
        if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE("0"),$this->shm_writingOffset) === false)
        {
            $this->RELEASE_MUTEX();
            return false;
        }
        // IF(FIFO Lecteur > 0)
        if((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shmOkrOffset, $this->shmOkrLength)) > 0)
        {
            // DECREMENT FIFO Lecteurs.
            if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_OkwOffset, $this->shm_OkwLength)) + 1)), $this->shm_OkwOffset) === false)
            {
                $this->RELEASE_MUTEX();
                return false;
            }
            sem_release($this->okr_semWait[$this->shmKey]);
        }
        // IF(FIFO Rédacteur > 0)
        elseif((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shmOkwOffset, $this->shmOkwLength)) > 0)
        {
            // DECREMENT FIFO Rédacteurs.
            if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $this->SHMOP_DEFLATE((string)((int)$this->SHMOP_INFLATE($this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shm_OkwOffset, $this->shm_OkwLength)) + 1)), $this->shm_OkwOffset) === false)
            {
                $this->RELEASE_MUTEX();
                return false;
            }
            sem_release($this->okw_semWait[$this->shmKey]);
        }
        else
        {
            // RELEASE THE MUTEX.
            sem_release($this->semWait[$this->shmKey]);
        }
        return true;
    }
        protected function millisecond()
        {
                return floor(microtime(true)/0.001 + 0.5);
        }
    /**
    * Pour les
    * ID de SHMOP.
    **/
        private function SHM_ID($str)
        {
        return '"' . $str . '"';
        }
    /**
    * Format type
    * string conpressée
    * après linearisation.
    **/
    private function SHMOP_DEFLATE(string $value)
    {
        /**
        * On ajoute un '\0'.
        **/
        return $this->str_to_nts($value);
        /**
        * VALUE => COMPRESS => BASE64_ENCODE => STR
        **/
        $str = base64_encode($value);
        $str =  base64_encode(gzcompress($value));
    }
    /**
    * Format type
    * string déconpressée
    * et délinéarisée.
    **/
    private function SHMOP_INFLATE($value)
    {
        /**
        * On enlève le '\0'.
        **/
        $data =  $this->str_from_mem($value);
        return $data;
        /*
        * STR => BASE64_DECODE => UNCOMPRESS.
        */
        return base64_decode($data);
        return gzuncompress(base64_decode($data));
    }
    private function str_from_mem(string &$value) {
        $i = strpos($value, chr(0));
        if ($i !== false) {
            return substr($value, 0, $i);
        }
        return $value;
    }
    private function str_to_nts(string $value) {
        return $value.chr(0);
    }
    private function wrapper_shmop_open(int $key, string $flags, int $perm = 0777, int $size = 0)
    {
        /**
        * USER root,
        * specific threatment
        * for opening
        * the SHM as nginx.
        **/
        if(posix_geteuid() == 0)
        {
            switch($flags) {
            case "n" :
            case "c" :
                /**
                * Creation
                * comme user
                * nginx.
                **/
                exec("sudo -u nginx php -r 'shmop_open(" . $key . ", \"" . $flags . "\", " . $perm . ", " . $size . ");'"); //Create Shared Memory segment as USER nginx
                $flags = "w";
                break;
            default :
                break;
            }
        }
        return @shmop_open($key, $flags, $perm, $size);
    }
    private function wrapper_shmop_delete($shmId)
    {
        $result = shmop_delete($shmId);
        echo "RESULTAT DELETE = " . $result . "<br />\n\n";
        return $result;
    }
    private function wrapper_shmop_size($shmId)
    {
        return shmop_size($shmId);
    }
    private function wrapper_shmop_close($shmId)
    {
        return shmop_close($shmId);
    }
    private function wrapper_shmop_read($shmId, $offset, $tmp_count)
    {
        return shmop_read($shmId, $offset, $tmp_count);
    }
    private function wrapper_shmop_write($shmId, $value, $offset)
    {
        return shmop_write($shmId, $value, $offset);
    }
    private function OPEN(string $flags, int $mode, int $size)
    {
        $this->shmMode[$this->shmKey] = $mode;
        $this->shmFlags[$this->shmKey] = $flags;
        $this->shmId[$this->shmKey] = false;
        if(in_array($this->shmFlags[$this->shmKey], array("a", "w")))
        {
            if($size == 0)
            {
                $shm = $this->wrapper_shmop_open($this->shmKey, $this->shmFlags[$this->shmKey], 0777, 0);
            }
            else
            {
                $shm = $this->wrapper_shmop_open($this->shmKey, $this->shmFlags[$this->shmKey], 0777, $this->shmLimitBlockSize[$this->shmKey]);
            }
            if($shm === false)
            {
                return false;
            }
            $this->shmId[$this->shmKey] = $shm;
            return true;
        }
        switch ($this->shmFlags[$this->shmKey]) {
        case "n" :
            /**
            * On update
            * si besoin
            * les paramètres
            * d'allocation
            * mémoire.
            **/
            $this->ALLOCATE($size);
            $shm = $this->wrapper_shmop_open($this->shmKey, $this->shmFlags[$this->shmKey], 0777, $this->shmLimitBlockSize[$this->shmKey]);
            /**
            * Le SHM
            * ne doit
            * pas exister.
            **/
            if($shm === false)
            {
                echo "\t\t" . 'Erreur création : Le SHM existe déjà.' . "<br />\n\n";
                return false;
            }
           
            $this->shmId[$this->shmKey] = $shm;
            return true;
            break;
            /**
            * Pour créer
            * un bloc
            * s'il n'existe pas,
            * ou l'ouvrir
            * en lecture/écriture
            * s'il existe.
            **/
        case "c" :
            /**
            * On vérifie
            * si le SHM
            * existe.
            **/
            $shm = $this->wrapper_shmop_open($this->shmKey, "w", 0777, $this->shmLimitBlockSize[$this->shmKey]);
            /**
            * Le SHM existe.
            *
            * On ne peut
            * l'effacer
            * puis le recréer
            * que si le sémaaphore
            * est libre.
            **/
            if($shm !== false)
            {
                /**
                * Pour le BEGIN_WRITE().
                **/
                $this->shmId[$this->shmKey] = $shm;
                $this->BEGIN_WRITE();
                /**
                * On update
                * si besoin
                * les paramètres
                * d'allocation
                * mémoire.
                **/
                if($this->ALLOCATE($size))
                {
                    if($this->wrapper_shmop_delete($shm) == false)
                    {
                        $this->END_WRITE();
                        $this->shmId[$this->shmKey] = false;
                        return false;
                    }
                    $this->wrapper_shmop_close($shm);
                    $this->shmId[$this->shmKey] = false;
                    if(($shm = $this->wrapper_shmop_open($this->shmKey, "n", 0777, $this->shmLimitBlockSize[$this->shmKey])) === false)
                    {
                        echo "\t\t" . 'Erreur création : Le SHM existait déjà.' . "<br />\n\n";
                        return false;
                    }
                    $this->shmId[$this->shmKey] = $shm;
                    $this->END_WRITE();
                }
                else
                {
                    $this->END_WRITE();
                }
            }
            /**
            * Le SHM n'existe pas,
            * on peut
            * mettre à jour
            * sa dimension.
            **/
            else
            {
                /**
                * On update
                * si besoin
                * les paramètres
                * d'allocation
                * mémoire.
                **/
                $this->ALLOCATE($size);
                if(($shm = $this->wrapper_shmop_open($this->shmKey, "n", 0777, $this->shmLimitBlockSize[$this->shmKey])) === false)
                {
                    echo "\t\t" . 'Erreur création : Le SHM existe déjà.' . "<br />\n\n";
                    return false;
                }
                $this->shmId[$this->shmKey] = $shm;
            }
           
            return true;
            break;
        default :
                        throw new RuntimeException("Paramètre SHM faux = " . $this->shmFlags[$this->shmKey]);
                        return false;
                        break;
                }
        return true;
    }
    private function ALLOCATE(int $size)
    {
        $BlockSize = $this->shmOffsetEnreg[$this->shmKey] + $size + 1;
        if(($this->shmBlockSize[$this->shmKey] < $BlockSize)||
            ($this->shmLimitBlockSize[$this->shmKey] < (2048 * ceil($BlockSize[$this->shmKey] / 2048.0))))
        {
            $this->shmBlockSize[$this->shmKey] = $this->shmOffsetEnreg[$this->shmKey] + $size + 1;
            /**
            * Surplus
            * pour dépassements[$this->shmKey]
            * peu fréquents.
            **/
            $this->shmLimitBlockSize[$this->shmKey] = 2048 * ceil($this->shmBlockSize[$this->shmKey] / 2048.0);
            return true;
        }
        return false;
    }
    protected function EXIST()
    {
        /**
        * SHM existe.
        **/
        if($this->OPEN("a", 0777, 0) !== false)
        {
            $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
            return true;
        }
        return false;
    }
    protected function READ(bool $block = false)
    {
        if($this->OPEN("w", 0, 0) === false)
        {
            echo "\t\t" . 'OPEN("w", 0, ' . 0 . ') = false' . "<br />\n\n";
            return false;
        }
        /**
        if($block)
        {
            $this->BEGIN_WRITE();
        }
        else
        {
            $this->BEGIN_READ();
        }
        **/
        $this->BEGIN_READ();
        $len = $this->wrapper_shmop_size($this->shmId[$this->shmKey]) - $this->shmOffsetEnreg[$this->shmKey];
        $enreg = $this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shmOffsetEnreg[$this->shmKey], $len);
        if(strlen($enreg) != $len)
        {
            echo "\t\t\t" . 'TAILLE ENREG LU = ' . strlen($enreg) . ' <> TAILLE SHMOP = ' . $len . "<br /><br />\n";
            /**
            if(!$block)
            {
                $this->END_READ();
            }
            else
            {
                $this->END_WRITE();
            }
            **/
            $this->END_READ();
            $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
            return false;
        }
        /**
        if(!$block)
        {
        **/
            $this->END_READ($this->shmId[$this->shmKey]);
//        }
        $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
        echo "\t\t" . 'DATA READ = ' . $enreg . "<br /><br />\n";
        return $this->SHMOP_INFLATE($enreg);
    }
    protected function WRITE(string $data, bool $block = false)
    {
        $str = $this->SHMOP_DEFLATE($data);
        $size = strlen($str) + 1024;
        echo "\t\t" . 'DATA WRITE = ' . $str . "<br /><br />\n";
        echo "\t\t" . 'SIZE = ' . $size . "<br /><br />\n";
        /**
        if($size < $this->shmLimitBlockSize[$this->shmKey])
        {
            $size = $this->shmLimitBlockSize[$this->shmKey];
        }
        **/
        if($this->OPEN("c", 0777, $size) === false)
        {
            echo "\t\t" . 'OPEN("c", 0777, ' . $size . ') = false' . "<br />\n\n";
            return false;
        }
        /**
        if($block)
        {
            $this->END_READ();
        }
        **/
        /**
        * Si true,
        * sémaphore déjà posé
        * en écriture
        * par le READ().
        **/
        /**
        if(!$block)
        {
        **/
            $this->BEGIN_WRITE();
//        }
        if(strlen($str) < 1)
        {
            $this->END_WRITE();
            $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
            echo "\t\t\tDATASIZE < 1.<br /><br />\n";
            return false;
        }
        // Write Data
        $res = $this->wrapper_shmop_write($this->shmId[$this->shmKey], $str, $this->shmOffsetEnreg[$this->shmKey]);
        $this->END_WRITE();
        $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
        return $res;
    }
    /**
    protected function APPEND(string $data)
    {
        if($this->OPEN("w", 0777, 0) === false)
        {
            return false;
        }
        $enreg = $this->READ(true);
        if($enreg === false)
        {
            $this->END_WRITE();
            return false;
        }
        $str = $this->SHMOP_DEFLATE($enreg) . $data;
        $res = $this->WRITE($str , true);
        $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
        return $res;
    }
    protected function RELEASE_LOCK()
    {
        if($this->OPEN("w", 0777, 0) === false)
        {
            return false;
        }
        $this->END_WRITE();
        $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
        return true;
    }
    **/
    protected function SIZE()
    {
        if($this->OPEN("a", 0777, 0) === false)
        {
            return false;
        }
        $res = $this->wrapper_shmop_size($this->shmId[$this->shmKey]);
        $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
        return $res;
    }
}
?>
 
WRInaute accro
Rebond

J'ai besoin d'une information au sujet des sémaphores.

Qu'est-ce que c'est un sémaphore FIFO ?

First-In First-Out n'est-il pas dans le concept d'un sémaphore quel que soit $max_acquire ?


Comment implémenter un sémaphore FIFO en PHP ?

Un sémaphore ouvert avec : sem_get($key, $max_acquire, $perm = 0666, $auto_release = 1) est-il un sémaphore FIFO si $max_acquire > 1 ?

"Si $auto_release == 1 le sémaphore sera libéré à leur fermeture" ( sem_close ).

Celà veut-il-dire qu'il y a sem_remove( ) dans ce cas ?

Merci beaucoup.
 
WRInaute accro
Voilà voilà

Je touche au but.

Cà marche, je n'ai plus qu'à mémoriser $size ( taille paramètre de chaque bloc ) et $BlockSize ( idem ) , à chaque mise à jour de la taille des blocs.

Je compte faire celà au début de chaque blocs.

Les requêtes MySQL sont correctement mises en cache.

Merci beaucoup.

Amicalement.
 
WRInaute accro
Bonjour

Voilà c'est fait.

La mémoire shmop est régulée automatiquement.

Quand le niveau de RAM occupé par les shmop_size() dépasse la moitié de 7 Mo, des enregs des blocs sont effacés, l'index est mis à jour et la RAM occupée baisse.

Il y a 157 blocs au maximum, et les enregs sont répartis à peu près également sur les blocs par une clé de hashage en fonction de la clé de la requête MySQL à cacher.

Cependant j'ai laissé le cache HTML ( merci à Noren ;) ), car le top m'indique souvent 100+% pour le processus mysqld.

Merci de tester : https://www.pronostics-courses.fr

Amicalement.
 
WRInaute accro
Bonjour @ortolojf et bravo pour ton acharnement. Car dans ce cas, c'est une qualité. Tu t'es embarqué dans un domaine très complexe et pas forcément bien documenté.
Merci d'avoir mis à disposition tes résultats pour la communauté.
Je vais être hors sujet sur ce coup mais... tu sembles avoir de sérieuses compétences en dev mais ne penses-tu pas qu'il est grand temps de mettre à profit ces compétences pour faire un vrai design pour ton site ? Parce que sincèrement, AMHA, c'est vraiment pas attractif et convivial.
Ne dénigre pas l'apparence au détriment des performances techniques.

Tu sais sans doute qu'un internaute porte d'abord attention aux images sur un site plutôt que du texte. C'est valable pour tout le monde. La grande majorité des internautes ne prennent pas le temps de lire.
Je pense que tu pourras le confirmer par la suite avec tes stats, ton taux de rebond devrait diminuer.

On ne fait jamais un site pour soi mais pour les autres. Ce n'est pas si simple de se mettre à la place des utilisateurs. Il faut avoir suffisamment de recul pour changer de casquettes et ne plus penser comme le webmaster mais comme son utilisateur.

Voilà... c'était mon observation du jour.
Encore bravo pour ton travail. ;)
 
Dernière édition:
WRInaute accro
@passion : Ça fait des années qu'on lui dit. Il réinvente la roue tout le temps mais pas la bonne. S'il mettait son énergie à ce que tu dis il aurait THE site de référence dans les pronos.

Il n'est pire sourd que celui qui ne veut pas entendre

ob_ea0302_autruche.jpg
 
WRInaute accro
Oui @spout lol
J'ai pu souvent lire que @ortolojf avait du mal à entendre autre chose que ce que pourquoi il travaille. Mais bon, je suis d'une nature altruiste héhéhéhé donc bah, j'aurai fait ma BA ;)
Mais bon, je me doute de sa réponse ;)
 
WRInaute accro
Il y a autre chose...

Je m'apprête d'une part à corriger des erreurs dans le moteur de stats avant les courses, qui fait que des chevaux sont à zéro ( jamais couru ) avant, alors que c'est correct après les courses.

D'autre part et conjointement, à poursuivre avec l'aide des tests déjà fait de RM Tech, et l'outil de Chrome, les améliorations SEO de mon site.

Après celà, je ferai peut-être appel à un graphiste, mais j'ai peur de perdre la main sur mon site, et de recevoir des mauvais conseils.

Addendum : Je vais rapidement programmer une fonction de correction des erreurs éventuelles dans les blocs, qui sont susceptibles de survenir à l'occasion d'arrêts intempestifs des scripts php

Si l'index est endommagé aussi, je tâcherai de faire quelque chose de propre.

Merci beaucoup pour votre aide.

P.S Je peux si vous voulez, vous communiquer le code de ma librairie de synchronisation, et celle de mon cache, sinon mon orm maison qui l'utilise, sachant qu'avec d'autres interfaces MySQL il y aurait un gros travail d'adaptation du cache à faire.
 
Dernière édition:
WRInaute accro
Bonjour

MariaDB souffre d'un défaut, c'est qu'il ne supporte pas les JOIN sur la même table.

Par exemple :

Code:
  SELECT CHEVAUX2.NUMCH, CHEVAUX2.NOMCH FROM CHEVAUX AS CHEVAUX1 LEFT JOIN CHEVAUX AS CHEVAUX2 ON CHEVAUX2.NOMCH LIKE CONCAT(CHEVAUX1.NOMCH, ':(%)') WHERE CHEVAUX1.NOMCH IN ('SIOUX', 'PLEUTRE' );

Cà passe pas :

Erreur : SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: ''


A part MariaDB / MySQL, qu'est-ce qu'il y aurait comme SGDBR qui supporte les JOIN sur deux tables identiques ?

Merci beaucoup.

Amicalement.
 
WRInaute accro
Bonjour Spout

Cà marche :

Code:
SELECT CHEVAUX1.NUMCH, CHEVAUX1.NOMCH, CHEVAUX2.NUMCH, CHEVAUX2.NOMCH FROM CHEVAUX AS CHEVAUX1 LEFT JOIN CHEVAUX AS CHEVAUX2 ON CHEVAUX2.NOMCH LIKE CONCAT(CHEVAUX1.NOMCH, ':(%)') WHERE CHEVAUX1.NOMCH IN ('FOUDRE:DU:GOSIER', 'FAMOUS:STAR', 'FLAYA:DU:SAPTEL', 'FAYETTE', 'FONTAINEAUXPERLES', 'FLORE:BUISSONAY', 'FOLIE:DE:HOUELLE', 'FELINA', 'FRAISE:BLANCHE', 'FREEDOM:DU:BOULAY', 'FUTAIE:DzERPION', 'FUSEE:DU:MOUCHEL', 'FILLE:A:PAPA', 'FUSEE', 'FIBULE:DU:VIVIER', 'DELMONICA');

Me donne tous les chevaux avec et sans nationalité.

CHEVAUX2.NOMCH = NULL quand pas de nationalité.

J'ai déjà mis l'add-on des alias à mon orm.

Amicalement.
 
WRInaute accro
Bonjour

Je ne résiste pas au plaisir de vous communiquer le code de ma librairie d'accès partagé en lecture/écriture utilisant l'algorithme lecteur/rédacteur.

Suis fatigué ce soir, à demain plus d'infos.

Bien amicalement.

PHP:
<?php

class SHMOP
{
    const SUDO = '/usr/bin/sudo';
    const PHP  = '/usr/bin/php';
    /********************************/
    /*    VARIABLES MUTEX        */
    /********************************/
    /*    3 SEMAPHORES        */
    /********************************/
    /*         CLES        */
    /********************************/
    private $semWaitKey        = array();        // Clé mutex principal.
    private $semWaitKeyRead        = array();        // Sémaphore Lecture.
    private $semWaitKeyWrite    = array();        // Sémaphore Ecriture.
    /********************************/
    /*        SEM_ID        */
    /********************************/
    private $semWait    = array();
    private $semWaitRead    = array();
    private $semWaitWrite    = array();
    /********************************/
    /*  SHARED VAR ( PSEUDO FIFO )    */
    /********************************/
    private $shmReadVar        = array();    // Clé Variable Nbre Lecteurs.
    private $shmMemVar        = null;        // Qté RAM  Variable Nbre Lecteurs.
    private $shmReadKey        = array();    // Clé Variable Nbre Lecteurs.
    private $shmRead        = array();    // Variable Nbre Lecteurs.
    /********************************/
    /*      RECORD LENGTH        */
    /********************************/
    private $shmReadersLength    = null;
    /********************************/
    /*    VARIABLES SHM        */
    /********************************/
    private $shmId            = array();
    private $shmMode        = array();
    private $shmFlags        = array();
    private $shmEnregOffset        = null;
    private $shmSize        = null;
    private $shmBlockSize        = array();
    private $shmLimitBlockSize    = array();
    /**
    * C'est un singleton
    * par clés $this->shmKey.
    **/
    protected static $instance    = array(); // Instance de la classe.
    protected function __clone() { } // Méthode de clonage en privé.
    public static function getInstance(int $key)
    {
        /**   
        * Si on n'a pas 
        * encore instancié 
        * notre classe
        * pour cette $this->shmKey.
        **/
        if (!isset(self::$instance[$key])) 
        {
            self::$instance[$key] = new  self($key); // On s'instancie nous-mêmes. :)
        }
        return self::$instance[$key];
    }
    protected function __construct(int $key)
    {
        /**
        * Paramètres
        * du SHM
        * contenant
        * les data.
        **/
        $this->shmKey = $key;
        $this->shmMode[$this->shmKey] = 0;
        $this->shmFlags[$this->shmKey] = "a";
        $this->shmId[$this->shmKey] = false;
        $this->shmEnregOffset = 128;        // Offset du SHM;
        /**
        * Corriger
        * pour des clés
        * constantes.
        *
        * 3 sémaphores
        * seulement
        * pour toutes
        * les ressources
        * de synchronisation
        * SHM.
        **/
        $this->semWaitKey[$this->shmKey] = $this->shmKey + 1000;
        $this->semWaitKeyRead[$this->shmKey] = $this->shmKey + 2000;
        $this->semWaitKeyWrite[$this->shmKey] = $this->shmKey + 3000;
        /**
        * 1 variable partagée
        * Nbre Lecteurs
        * par SHM.
        **/
        $this->shmReadKey[$this->shmKey] = $this->shmKey + 4000;    // Clé du SHM Lect.
        $this->shmReadVar[$this->shmKey] = $this->shmKey + 5000;    // Clé de la variable Lect.
        $this->semWait[$this->shmKey]        = 0;
        $this->semWaitRead[$this->shmKey]    = 0;
        $this->semWaitWrite[$this->shmKey]    = 0;
        $this->shmRead[$this->shmKey]        = 0;
        $this->shmMemVar            = 256;        // Qté RAM  Variable Nbre Lecteurs.
        $this->shmSize = 1024;
        $this->INIT_MUTEX();
        $this->shmBlockSize[$this->shmKey] = $this->shmSize + 1;
        /**
        * Longueur totale shared memory.
        **/
        $this->shmLimitBlockSize[$this->shmKey] = 2048 * ceil($this->shmBlockSize[$this->shmKey] / 2048.0);
        $this->INIT_SIZE();
        $this->shmBlockSize[$this->shmKey] = $this->shmSize + 1;
        /**
        * Longueur totale shared memory.
        **/
        $this->shmLimitBlockSize[$this->shmKey] = 2048 * ceil($this->shmBlockSize[$this->shmKey] / 2048.0);
        error_reporting(true);
        return $this;
    }
    function __destruct()
    {
        $this->RELEASE_MUTEX();
        self::$instance[$this->shmKey] = null;
        return true;
    }
    private function INIT_SIZE()
    {
        $this->BEGIN_WRITE();
        /**
        * On vérifie
        * si le SHM
        * existe.
        **/
        $shm_alloc = $this->wrapper_shmop_open($this->shmKey, "a", 0666, $this->shmLimitBlockSize[$this->shmKey]);
        /**
        * Le SHM existe.
        **/
        if($shm_alloc !== false)
        {
            /**
            * Enreg
            * des tailles
            * brutes et
            * réelles.
            **/
            if(($size = $this->SHM_INFLATE($this->wrapper_shmop_read($shm_alloc, 0, $this->shmEnregOffset))) === false)
            {
                echo "\t\t" . 'Erreur lecture taille SHM.' . "<br />\n\n";
                return false;
            }
            $this->shmSize = (int)$size;
            $this->wrapper_shmop_close($shm_alloc);
        }
        $this->END_WRITE();
        return true;
    }
    private function INIT_MUTEX()
    {
        /**
        * USER root,
        * specific threatment
        * for opening
        * the SHM as nginx.
        **/
        if(posix_geteuid() != 0)
        {
            /************************/
            /* INSTANCIATION MUTEX    */
            /************************/
            if(!is_resource($this->semWait[$this->shmKey]))
            {
                if(($this->semWait[$this->shmKey] = sem_get($this->semWaitKey[$this->shmKey], 1, 0666, 1)) === false)        // ID Mutex
                    return false;
            }
            if(!is_resource($this->semWaitRead[$this->shmKey]))
            {
                if(($this->semWaitRead[$this->shmKey] = sem_get($this->semWaitKeyRead[$this->shmKey], 1, 0666, 1)) === false)    // ID SEM Lecteur
                    return false;
            }
            if(!is_resource($this->semWaitWrite[$this->shmKey]))
            {
                if(($this->semWaitWrite[$this->shmKey] = sem_get($this->semWaitKeyWrite[$this->shmKey], 1, 0666, 1)) === false)    // ID SEM Rédacteur
                    return false;
            }
            if(!is_resource($this->shmRead[$this->shmKey]))
            {
                if(($this->shmRead[$this->shmKey] = shm_attach($this->shmReadKey[$this->shmKey], $this->shmMemVar, 0666)) === false)    // ID Nbre Lecteurs
                    return false;
            }
        }
        else
        {
            /************************
            * INSTANCIATION MUTEX    *
            ************************/
            if(!is_resource($this->semWait[$this->shmKey]))
            {
                unset($cmd);
                $cmd = self::SUDO . " -u nginx " . self::PHP . " -r 'unset(\$id1); \$id1 = sem_get(" . $this->semWaitKey[$this->shmKey] . ", " . 1 . ", " . 0666 . ", " . 1 . "); /* echo \$id1; */'";    //Create ID Mutex as USER nginx
                exec($cmd);
                if(($this->semWait[$this->shmKey] = sem_get($this->semWaitKey[$this->shmKey], 1, 0666, 1)) === false)    //Create ID Mutex as USER nginx
                {
                    return false;
                }
            }
            if(!is_resource($this->semWaitRead[$this->shmKey]))
            {
                unset($cmd);
                $cmd = self::SUDO . " -u nginx " . self::PHP . " -r 'unset(\$id2); \$id2 = sem_get(" . $this->semWaitKeyRead[$this->shmKey] . ", " . 1 . ", " . 0666 . ", " . 1 . "); /* echo \$id2; */'";    //Create ID Mutex as USER nginx
                exec($cmd);
                if(($this->semWaitRead[$this->shmKey] = sem_get($this->semWaitKeyRead[$this->shmKey], 1, 0666, 1)) === false)    //Create ID Mutex as USER nginx
                {
                    return false;
                }
            }
            if(!is_resource($this->semWaitWrite[$this->shmKey]))
            {
                unset($cmd);
                $cmd = self::SUDO . " -u nginx " . self::PHP . " -r 'unset(\$id3); \$id3 = sem_get(" . $this->semWaitKeyWrite[$this->shmKey] . ", " . 1 . ", " . 0666 . ", " . 1 . "); /* echo \$id3; */ '";    //Create ID Mutex as USER nginx
                exec($cmd);
                if(($this->semWaitWrite[$this->shmKey] = sem_get($this->semWaitKeyWrite[$this->shmKey], 1, 0666, 1)) === false)    //Create ID Mutex as USER nginx
                {
                    return false;
                }
            }
            if(!is_resource($this->shmRead[$this->shmKey]))
            {
                unset($cmd);
                $cmd = self::SUDO . " -u nginx " . self::PHP . " -r 'unset(\$id4); \$id4 = shm_attach(" . $this->shmReadKey[$this->shmKey] . ", " . $this->shmMemVar . ", " . 0666 . "); /* echo \$id4; */'";    //Create ID Mutex as USER nginx
                exec($cmd);
                if(($this->shmRead[$this->shmKey] = shm_attach($this->shmReadKey[$this->shmKey], $this->shmMemVar, 0666)) === false)    //Create ID Mutex as USER nginx
                {
                    return false;
                }
            }
        }
        /************************/
        /*  INIIALISATION VAR    */
        /************************/
        /**
        * Init à zéro
        * de $this->shmRead
        * ( 1 variable Lect Par SHM ).
        **/
        if((!shm_has_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey]))
            &&((shm_put_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey], "0")) === false))    // Lect = 0.
        {
            echo "\t\tERREUR AFFECTATION VAR RATEE.<br />\n\n";
            return false;
        }
        return true;
    }
    private function RELEASE_MUTEX()
    {
        if(is_resource($this->semWaitRead[$this->shmKey]))
        {
            sem_release($this->semWaitRead[$this->shmKey]);
            sem_remove($this->semWaitRead[$this->shmKey]);
        }
        if(is_resource($this->semWaitWrite[$this->shmKey]))
        {
            sem_release($this->semWaitWrite[$this->shmKey]);
            sem_remove($this->semWaitWrite[$this->shmKey]);
        }
        if(is_resource($this->semWait))
        {
            sem_release($this->semWait[$this->shmKey]);
            sem_remove($this->semWait[$this->shmKey]);
        }
        if(is_resource($this->shmRead[$this->shmKey]))
        {
            shm_detach($this->shmRead[$this->shmKey]);
        }
        return true;
    }
    private function BEGIN_READ()
    {
        /**
        * Version CNAM
        **************
        * P(semWait)
        * P(semWaitRead
        * Lect = Lect + 1
        * IF(Lect == 1) P(semWaitWrite
        * V(semWaitRead
        * V(semWait)
        * lectures.
        **/
        /************************/
        /*   Commencer_Lire    */
        /************************/
        if((!is_resource($this->semWait[$this->shmKey]))
            &&(!is_resource($this->semWaitRead[$this->shmKey]))
            &&(!is_resource($this->semWaitWrite[$this->shmKey]))
            &&(!is_resource($this->shmRead[$this->shmKey])))
            $this->INIT_MUTEX();
        // SET THE FIFO.
        sem_acquire($this->semWait[$this->shmKey]);
        // SET THE SEM_READ.
        sem_acquire($this->semWaitRead[$this->shmKey]);
        //        echo "\t\tLect avant Incrementation = " . (int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey])  . "<br />\n\n";
        // INCREMENT var Lecteurs.
        if(shm_put_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey], (string)((int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey]) + 1)) === false)
        {
            echo "\t\tERREUR INCREMENTATION VAR.<br />\n\n";
            $this->RELEASE_MUTEX();
            return false;
        }
        //        echo "\t\tLect après Incrementation = " . (int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey])  . "<br />\n\n";
        if((int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey]) == 1)
            // SET THE SEM_WRITE.
            sem_acquire($this->semWaitWrite[$this->shmKey]);
        //        echo "\t\tLect après Incrementation et blocage = " . (int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey])  . "<br />\n\n";
        // RELEASE THE SEM_READ.
        sem_release($this->semWaitRead[$this->shmKey]);
        // RELEASE THE FIFO.
        sem_release($this->semWait[$this->shmKey]);
        return true;
    }
    private function END_READ()
    {
        /**
        * Version CNAM
        * ************
        * P(semWaitRead
        * Lect = Lect - 1
        * IF(Lect == 0) V(semWaitWrite
        * V(semWaitRead
        **/
        /************************/
        /*    Finir_Lire    */
        /************************/
        // SET THE SEM_READ.
        sem_acquire($this->semWaitRead[$this->shmKey]);
        //        echo "\t\tLect avant Décrémentation = " . (int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey])  . "<br />\n\n";
        // DECREMENT var Lecteurs.
        if(shm_put_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey], (string)((int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey]) - 1)) === false)
        {
            echo "\t\tERREUR DECREMENTATION VAR.<br />\n\n";
            $this->RELEASE_MUTEX();
            return false;
        }
        //        echo "\t\tLect après Décrémentation = " . (int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey])  . "<br />\n\n";
        if((int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey]) == 0)
            // RELEASE THE SEM_WRITE.
            sem_release($this->semWaitWrite[$this->shmKey]);
        //        echo "\t\tLect après Décrémentation et blocage = " . (int)shm_get_var($this->shmRead[$this->shmKey], $this->shmReadVar[$this->shmKey])  . "<br />\n\n";
        // RELEASE THE SEM_READ.
        sem_release($this->semWaitRead[$this->shmKey]);
        return true;
    }
    private function BEGIN_WRITE()
    {
        /**
        * Version CNAM
        **************
        * P(semWait)
        * P(semWaitWrite
        * V(semWait)
        * écritures.
        **/
        /************************/
        /*   Commencer_Ecrire    */
        /************************/
        if((!is_resource($this->semWait[$this->shmKey]))
            &&(!is_resource($this->semWaitRead[$this->shmKey]))
            &&(!is_resource($this->semWaitWrite[$this->shmKey]))
            &&(!is_resource($this->shmRead[$this->shmKey])))
            $this->INIT_MUTEX();
        // SET THE FIFO.
        sem_acquire($this->semWait[$this->shmKey]);
        // SET THE SEM_WRITE.
        sem_acquire($this->semWaitWrite[$this->shmKey]);
        // RELEASE THE FIFO.
        sem_release($this->semWait[$this->shmKey]);
        return true;
    }
    protected function END_WRITE()
    {
        /**
        * Version CNAM
        **************
        * V(semWaitWrite
        **/
        /************************/
        /*   Finir_Ecrire    */
        /************************/
        // RELEASE THE FIFO.
        sem_release($this->semWaitWrite[$this->shmKey]);
        return true;
    }
    protected function millisecond()
    {
        return floor(microtime(true)/0.001 + 0.5);
    }
    /**
    * Pour les
    * ID de SHM.
    **/
    private function SHM_ID($str)
    {
        return '"' . $str . '"';
    }
    /**
    * Format type
    * string conpressée
    * après linearisation.
    **/
    private function SHM_DEFLATE(string $value)
    {
        /**
        * On ajoute un '\0'.
        **/
        return $this->str_to_nts($value);
        /**
        * VALUE => COMPRESS => BASE64_ENCODE => STR
        **/
        $str = base64_encode($value);
        $str =  base64_encode(gzcompress($value));
    }
    /**
    * Format type
    * string déconpressée
    * et délinéarisée.
    **/
    private function SHM_INFLATE($value)
    {
        if($value === false)
        {
            return false;
        }
        /**
        * On enlève le '\0'.
        **/
        $data =  $this->str_from_mem($value);
        return $data;
        /*
        * STR => BASE64_DECODE => UNCOMPRESS.
        */
        return base64_decode($data);
        return gzuncompress(base64_decode($data));
    }
    private function str_from_mem(string &$value) {
        $i = strpos($value, chr(0));
        if ($i !== false) {
            return substr($value, 0, $i);
        }
        return $value;
    }
    private function str_to_nts(string $value) {
        return $value.chr(0);
    }
    private function wrapper_shmop_open(int $key, string $flags, int $perm = 0666, int $size = 0)
    {
        /**
        * USER root,
        * specific threatment
        * for opening
        * the SHM as nginx.
        **/
        if(posix_geteuid() == 0)
        {
            switch($flags) {
            case "n" :
            case "c" :
                /**
                * Creation
                * comme user
                * nginx.
                **/
                exec(self::SUDO . " -u nginx " . self::PHP . " -r '@shmop_open(" . $key . ", \"" . $flags . "\", " . $perm . ", " . $size . ");'"); //Create Shared Memory segment as USER nginx
                $flags = "w";
                break;
            default :
                break;
            }
        }
        return @shmop_open($key, $flags, $perm, $size);
    }
    private function wrapper_shmop_delete($shmId)
    {
        $result = shmop_delete($shmId);
        //        echo "RESULTAT DELETE = " . $result . "<br />\n\n";
        return $result;
    }
    private function wrapper_shmop_size($shmId)
    {
        return shmop_size($shmId);
    }
    private function wrapper_shmop_close($shmId)
    {
        return shmop_close($shmId);
    }
    private function wrapper_shmop_read($shmId, $offset, $tmp_count)
    {
        return shmop_read($shmId, $offset, $tmp_count);
    }
    private function wrapper_shmop_write($shmId, $value, $offset)
    {
        return shmop_write($shmId, $value, $offset);
    }
    private function OPEN(string $flags, int $mode, int $size)
    {
        $this->shmMode[$this->shmKey] = $mode;
        $this->shmFlags[$this->shmKey] = $flags;
        $this->shmId[$this->shmKey] = false;
        if($this->shmFlags[$this->shmKey] == "a")
        {
            if($size == 0)
            {
                $shm = $this->wrapper_shmop_open($this->shmKey, $this->shmFlags[$this->shmKey], 0666, 0);
            }
            else
            {
                $shm = $this->wrapper_shmop_open($this->shmKey, $this->shmFlags[$this->shmKey], 0666, $this->shmLimitBlockSize[$this->shmKey]);
            }
            if($shm === false)
            {
                return false;
            }
            $this->shmId[$this->shmKey] = $shm;
            return true;
        }
        switch ($this->shmFlags[$this->shmKey]) {
        case "n" :
            /**
            * On update
            * si besoin
            * les paramètres
            * d'allocation
            * mémoire.
            **/
            $this->ALLOCATE($size);
            $shm = $this->wrapper_shmop_open($this->shmKey, $this->shmFlags[$this->shmKey], 0666, $this->shmLimitBlockSize[$this->shmKey]);
            /**
            * Le SHM
            * ne doit
            * pas exister.
            **/
            if($shm === false)
            {
                echo "\t\t" . 'Erreur création : Le SHM existe déjà.' . "<br />\n\n";
                return false;
            }
            $this->shmId[$this->shmKey] = $shm;
            /**
            * Enregistrement
            * de la taille
            * demandée.
            **/
            $str_size = $this->SHM_DEFLATE($size);
            if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $str_size, 0) === false)
            {
                echo "\t\t" . 'Erreur initialisation taille SHM.' . "<br />\n\n";
                return false;
            }
            return true;
            break;
            /**
            * Pour créer
            * un bloc
            * s'il n'existe pas,
            * ou l'ouvrir
            * en lecture/écriture
            * s'il existe.
            **/
        case "c" :
        case "w" :
            /**
            * On vérifie
            * si le SHM
            * existe.
            **/
            $shm = $this->wrapper_shmop_open($this->shmKey, "w", 0666, $this->shmLimitBlockSize[$this->shmKey]);
            /**
            * Le SHM existe.
            *
            * On ne peut
            * l'effacer
            * puis le recréer
            * que si le sémaaphore
            * est libre.
            **/
            if($shm !== false)
            {
                if(($enreg = $this->SHM_INFLATE($this->wrapper_shmop_read($shm, $this->shmEnregOffset, $this->wrapper_shmop_size($shm) - $this->shmEnregOffset))) === false)
                {
                    echo "\t\t" . 'Erreur lecture SHM.' . "<br />\n\n";
                    return false;
                }
                /**
                * On update
                * si besoin
                * les paramètres
                * d'allocation
                * mémoire.
                **/
                if($this->ALLOCATE($size))
                {
                    if($this->wrapper_shmop_delete($shm) == false)
                    {
                        $this->shmId[$this->shmKey] = false;
                        return false;
                    }
                    $this->wrapper_shmop_close($shm);
                    $this->shmId[$this->shmKey] = false;
                    if(($shm = $this->wrapper_shmop_open($this->shmKey, "n", 0666, $this->shmLimitBlockSize[$this->shmKey])) === false)
                    {
                        echo "\t\t" . 'Erreur création : Le SHM existait déjà.' . "<br />\n\n";
                        return false;
                    }
                    $this->shmId[$this->shmKey] = $shm;
                    /**
                    * Enregistrement
                    * de la taille
                    * demandée.
                    **/
                    $str_size = $this->SHM_DEFLATE($size);
                    if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $str_size, 0) === false)
                    {
                        echo "\t\t" . 'Erreur update taille SHM.' . "<br />\n\n";
                        return false;
                    }
                    /**
                    * Recopie
                    * de l'enregistrement
                    * précédent.
                    **/
                    $str = $this->SHM_DEFLATE($enreg);
                    if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $str, $this->shmEnregOffset) === false)
                    {
                        echo "\t\t" . 'Erreur update et recopie SHM.' . "<br />\n\n";
                        return false;
                    }
                }
                else
                {
                    /**
                    * On ne change pas
                    * la taille
                    * du SHM..
                    **/
                    $this->shmId[$this->shmKey] = $shm;
                }
            }
            /**
            * Le SHM n'existe pas,
            * on peut
            * mettre à jour
            * sa dimension.
            **/
            else
            {
                /**
                * On update
                * si besoin
                * les paramètres
                * d'allocation
                * mémoire.
                **/
                $this->ALLOCATE($size);
                if(($shm = $this->wrapper_shmop_open($this->shmKey, "n", 0666, $this->shmLimitBlockSize[$this->shmKey])) === false)
                {
                    echo "\t\t" . 'Erreur création : Le SHM existe déjà.' . "<br />\n\n";
                    return false;
                }
                $this->shmId[$this->shmKey] = $shm;
                /**
                * Enreg
                * des tailles
                * brutes et
                * réelles.
                **/
                $str_size = $this->SHM_DEFLATE($size);
                if($this->wrapper_shmop_write($this->shmId[$this->shmKey], $str_size, 0) === false)
                {
                    echo "\t\t" . 'Erreur initialisation taille SHM.' . "<br />\n\n";
                    return false;
                }
            }
            return true;
            break;
        default :
            throw new RuntimeException("Paramètre SHM faux = " . $this->shmFlags[$this->shmKey]);
            return false;
            break;
        }
        return true;
    }
    private function ALLOCATE(int $size)
    {
        $BlockSize = $size + 1;
        if(($this->shmBlockSize[$this->shmKey] < $BlockSize)||
            ($this->shmLimitBlockSize[$this->shmKey] < (2048 * ceil($BlockSize[$this->shmKey] / 2048.0))))
        {
            $this->shmBlockSize[$this->shmKey] = $size + 1;
            /**
            * Surplus
            * pour dépassements[$this->shmKey]
            * peu fréquents.
            **/
            $this->shmLimitBlockSize[$this->shmKey] = 2048 * ceil($this->shmBlockSize[$this->shmKey] / 2048.0);
            return true;
        }
        return false;
    }
    protected function SHM_EXIST()
    {
        /**
        * SHM existe.
        **/
        if($this->OPEN("a", 0666, 0) !== false)
        {
            $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
            return true;
        }
        return false;
    }
    protected function SHM_DELETE()
    {
        $this->BEGIN_WRITE();
        if($this->OPEN("w", 0666, 128) === false)
        {
            echo "\t\t" . 'ERREUR OPEN("w", 0666, ' . 128 . ') = false' . "<br />\n\n";
            $this->END_WRITE();
            return false;
        }
        $this->wrapper_shmop_delete($this->shmId[$this->shmKey]);
        $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
        $this->END_WRITE();
    }
    protected function SHM_READ(bool $block = false)
    {
        if($block)
            /**
            * Blocage en écriture
            * en prévision
            * d'un appel
            * à $this->WRITE($data, true),
            * qui appellera
            * le END_WRITE();
            **/
            $this->BEGIN_WRITE();
        else
            /**
            * Blocage en lecture
            * END_READ() est lancé
            * en fin de
            * fonction.
            **/
            $this->BEGIN_READ();
        if($this->OPEN("a", 0666, 0) === false)
        {
            echo "\t\t" . 'ERREUR OPEN("a", 0666, ' . 0 . ') = false' . "<br />\n\n";
            if($block)
                $this->END_WRITE();
            else
                $this->END_READ();
            return false;
        }
        $len = $this->wrapper_shmop_size($this->shmId[$this->shmKey]) - $this->shmEnregOffset;
        $enreg = $this->wrapper_shmop_read($this->shmId[$this->shmKey], $this->shmEnregOffset, $len);
        if(strlen($enreg) != $len)
        {
            echo "\t\t\t" . 'ERREUR TAILLE ENREG LU = ' . strlen($enreg) . ' <> TAILLE LUE = ' . $len . "<br />\n";
            $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
            if($block)
                $this->END_WRITE();
            else
                $this->END_READ();
            return false;
        }
        $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
        if(!$block)
            $this->END_READ();
        return $this->SHM_INFLATE($enreg);
    }
    protected function SHM_WRITE(string $data, bool $block = false)
    {
        if(!$block)
            $this->BEGIN_WRITE();
        $str = $this->SHM_DEFLATE($data);
        $size = strlen($str) + 1024;
        /**
        if($size < $this->shmLimitBlockSize[$this->shmKey])
        {
            $size = $this->shmLimitBlockSize[$this->shmKey];
        }
        **/
        if($this->OPEN("c", 0666, $size) === false)
        {
            echo "\t\t" . 'ERREUR OPEN("c", 0666, ' . $size . ') = false' . "<br />\n\n";
            $this->END_WRITE();
            return false;
        }
        // Write Data
        $res = $this->wrapper_shmop_write($this->shmId[$this->shmKey], $str, $this->shmEnregOffset);
        $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
        $this->END_WRITE();
        return $res;
    }
    protected function SHM_APPEND(string $data)
    {
        $enreg = $this->READ(true);
        if($enreg === false)
        {
            return false;
        }
        $str = $this->SHM_DEFLATE($enreg) . $data;
        $res = $this->WRITE($str, true);
        return $res;
    }
    protected function SHM_SIZE()
    {
        if($this->OPEN("a", 0666, 0) === false)
        {
            return false;
        }
        $res = $this->wrapper_shmop_size($this->shmId[$this->shmKey]);
        $this->wrapper_shmop_close($this->shmId[$this->shmKey]);
        return $res;
    }
}
?>
 
Discussions similaires
Haut