[Fusioninventory-devel] [Perl] Acces concurrent à un fichier de log

Guillaume Rousse Guillaume.Rousse at inria.fr
Tue Oct 12 20:27:47 UTC 2010


Le 12/10/2010 18:27, Olivier Mengué a écrit :
> 
> 
> Le 11 octobre 2010 23:57, Guillaume Rousse <Guillaume.Rousse at inria.fr
> <mailto:Guillaume.Rousse at inria.fr>> a écrit :
> 
>     Bonjour.
> 
>     Voici mon problème épineux du jour. Dans le code de l'agent
>     fusioninventory, il y a un logger, qui supporte plusieurs backend, dont
>     un basé sur un fichier. Pour faire cours, voici le code actuel de la
>     branche de développement.
> 
>     http://github.com/guillomovitch/fusioninventory-agent/blob/212713a598fb54548ae82e004b45c8e9c8458237/lib/FusionInventory/LoggerBackend/File.pm
> 
>     C'est joli tout plein, mais voilà, l'agent est relativement parallélisé.
>     Et comme on ne se refuse rien, il utilise à la fois du multi-thread
>     (pour gérer son interface web, si nécessaire) et du multi-processus
>     (pour lancer ses taches, s'il tourne sous forme de démon). Et ce genre
>     de situations peut aboutir à deux problèmes:
>     - une corruption du fichier, pour le cas d'écriture simultanée
>     - un mauvais fonctionnement du mécanisme de surveillance automatique de
>     la taille du fichier, avec apparement un intervenant qui efface un
>     fichier, tandis qu'un autre garde le descripteur correspondant à
>     l'ancien... (http://forge.fusioninventory.org/issues/406)
> 
> 
> Le coup de l'écriture dans un fichier effacé (ou renommé) n'est pas un
> problème sous Unix : tant qu'un fichier est ouvert, son stockage sur le
> disque est conservé, même s'il n'est plus accessible par un nom.
> L'écriture continue donc à fonctionner.
Pas de la façon attendue cependant. Si je comprend bien le scénario
exact, ca doit correspondre à ca:

- deux processus A et B possèdent chacun leur propre descripteur de
fichier sur le même fichier 'foo'

- le processus A s'apprête à écrire dedans, s'apercoit que le fichier
est trop long, donc ferme son descripteur, efface le fichier 'foo', et
le réouvre immédiatement. A a donc un descripteur sur le fichier 'foo',
et B garde son descripteur, qui correspond alors à un fichier anonyme,
voué à disparaitre.

- le processus B s'apercoit que son descripteur correspond à un fichier
trop long, le ferme, efface alors le fichier 'foo', alors qu'il ne
s'agit plus en fait de celui qu'il utilise, puis le réouvre. A a alors
un descripteur sur un fichier non nommé, et B un descripteur sur le
fichier 'foo'

Bref, le dernier qui passe gagne, et l'autre loggue vers /dev/null...

> Mais bien sûr ça ne marche pas sous Windows. Ce serait trop facile.
Dans ce cas, l'effacement ne doit pas fonctionner (d'après mes lointains
souvenirs Windows). Ca doit être ca la situation bloquante reportée par
l'utilisateur.

[..]
>     Le patch est celui-ci:
> 
>     http://github.com/guillomovitch/fusioninventory-agent/commit/394822b9ac245920bfef82e3b32d7aa7ca38ed68
> 
> 
> Je doute que cela résolve vraiment ton problème. Tu vas juste crasher
> ton programme en cas de tentative d'accès concurrent.
D'après la doc, flock est censé être bloquant, et ne retourner un échec
que si vraiment il y a un problème.

>     Y a-t-il des meilleurs idées dans la salle ? Ah, j'oubliais une
>     contrainte, on doit aussi rester portable (il y a une version windows).
> 
> 
> La seule vraie solution est de ne pas avoir d'écriture simultanée.
> Pour cela il faut qu'un seul programme et une seule thread de ce
> programme ne puisse écrire dans ton log.
> 
> Dans un programme POE, le logger serait une POE::Session à laquelle les
> autres parties du programme enverraient les messages à écrire.
> Il existe POE::Component::Logger et j'envisage de travailler dessus très
> prochainement.
On a besoin de pouvoir exécuter des taches ponctuelles sous la forme de
processus distincts, pour cause de libération de mémoire. Mais
apparement, IKC permet de lancer des processus externes, tout en
continuant à communiquer avec le père. Donc, oui, POE parait la bonne
solution, mais c'est un peu invasif.

En attendant POE-qui-résoud-tous-les-problèmes, j'ai deux solutions
potentielles. L'une à base de truncate:

* aquérir un verrou exclusif
* si le fichier a depassé la taille maximum, utiliser truncate pour
ramener sa taille à 0 sans changer d'inode
* utiliser seek pour être sur d'être à la fin du fichier
* écrire dedans
* relacher le verrou

L'autre à base de 'je ne garde jamais de descripteur de fichier ouvert':

* aquérir un verrou exclusif
* si le fichier a depassé la taille maximum, l'effacer
* ouvrir le fichier
* écrire dedans
* fermer le fichier
* relacher le verrou

Est-ce que ca parait correct, à défaut d'être efficace, ou alors je suis
à coté de la plaque ?
-- 
BOFH excuse #261:

The Usenet news is out of date

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4251 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.alioth.debian.org/pipermail/fusioninventory-devel/attachments/20101012/32c7af65/attachment.bin>


More information about the Fusioninventory-devel mailing list