rclsilver | Bonjour,
J'ai développé un module apache permettant de créer des hôtes virtuelles (apache2) via un annuaire LDAP. Ainsi, suivant le nom de domaine utilisé, et l'adresse IP (la machine en possède plusieurs), mon module retrouve bien à quel site ce couple DNS/IP correspond, et redirige vers le dossier adéquat.
Afin d'améliorer un peu ce module, j'ai souhaité ajouter des statistiques de visite en temps réel. Mon idée est donc qu'à chaque visite sur un des sites, une ligne est écrite dans un tube nommé, puis, dans un autre programme, d'avoir une boucle infini qui lit ce tube nommé, pour finalement insérer ces données dans une base de données.
En gros, tout ça fonctionne (enfin presque..). Mon problème, c'est dans mon programme (reader du tube). Voici le petit bout de code qui correspond à la lecture :
Code :
- pipe = open(env->named_pipe, O_RDONLY);
- if(pipe < 0)
- {
- log_append("Impossible d'ouvrir le tube nomme : %s [#%d %s]", env->named_pipe, errno, strerror(errno));
- }
- else
- {
- while(running)
- {
- len = read(pipe, buffer, BUFFER_SIZE);
- log_debug("Retour read() : %d", len);
- if(len > 0)
- {
- /* Je ne fais que traiter les données, absolument rien d'autre */
- }
- else if(len < 0)
- {
- log_append("ERROR Impossible de lire le flux : %s", strerror(errno));
- break;
- }
- }
- close(pipe);
- buckets_close_all();
- }
- remove_pid_file(env->pid_file);
- return 0;
|
Le problème avec ce code, c'est que le read() n'est pas bloquant, et que de ce fait, le programme va utilisé 100% du CPU [pour INFO, quand 100% du CPU est utilisé, read() retourne 0]. J'ai tenté de trouver des solutions avec un select(), mais, malgré avoir mis 0 pour le paramètre "timeout" du select(), le select() n'était pas non plus bloquant.
Dans mon module apache, voici le code pour écrire sur le tube nommé :
Code :
- FILE * f = fopen(conf->mh_stats_output_filename, "a" );
- if(!f)
- {
- f = stderr;
- perror("fopen" );
- fprintf(f, "Impossible d'ouvrir le tube !\n" );
- }
- fprintf
- (
- f,
- "%s|%s|%d|%ld|%s|%s|%s|%lld|%d\n",
- FORMAT_STR(stats_server_name),
- FORMAT_STR(r->uri),
- r->method_number,
- (long)r->clength,
- FORMAT_STR(r->connection->remote_ip),
- FORMAT_STR(apr_table_get(r->headers_in, "Referer" )),
- FORMAT_STR(apr_table_get(r->headers_in, "User-Agent" )),
- apr_time_sec(r->request_time),
- r->status
- );
- fflush(f);
- if(f != stderr)
- fclose(f);
|
Est-ce que le fait de fermer le flux en écriture à chaque fois peut poser un problème ? De plus voici la version d'apache que j'ai d'installée (je dis surtout ça pour le "mpm-prefork" :
server:~/apache2# dpkg -l | grep apache2
ii apache2-mpm-prefork 2.2.9-10+lenny3 Apache HTTP Server - traditional non-threaded model
ii apache2-prefork-dev 2.2.9-10+lenny3 Apache development headers - non-threaded MPM
ii apache2-utils 2.2.9-10+lenny3 utility programs for webservers
ii apache2.2-common 2.2.9-10+lenny3 Apache HTTP Server common files
ii libapache2-mod-php5 5.2.6.dfsg.1-1+lenny3 server-side, HTML-embedded scripting language (Apache 2 module
ii libapache2-mod-suphp 0.6.2-3 Apache2 module to run php scripts with the owner permissions
|
La version MPM Prefork, si je ne dis pas de bêtise, à chaque requête qui arrive, un "processus" (fork) isolé d'apache se lance, traite la requête et se termine. A priori, mon tube peut donc être ouvert à un instant t par un ou plusieurs instances d'apache, ou à un instant t2 par aucune instance (pas de requête reçue). Est-ce que ce comportement peut être problématique avec les tubes nommés, et est-ce que cela pourrait-être la cause de mon dysfonctionnement sur mon reader ?
J'ai choisi comme solution les tubes nommés, mais je suis ouvert à autre chose, si quelque chose est plus approprié pour répondre à mes attentes.
Je sais, cela fait beaucoup de questions, de code, ou de lecture tout simplement, mais au moins, tous les éléments sont là pour essayer de trouver la cause, et si possible la solution.
Merci beaucoup d'avance. |