Léa-Linux & amis :   LinuxFR   GCU-Squad   GNU
Atomicité de la commande mv sous bash...
Envoyé par: frc0

Bonjour,

Dans un script bash, je renomme un (gros) fichier 'data.dat' avec la commande 'mv',
typiquement cela donne:

mv data.dat data_XXX.dat
ou 'XXX' est un identifiant unique utile pour mon application.

Ainsi, le nom 'data.dat' est a priori libéré dans le système de fichiers
et devrait pouvoir être réutilisé ultérieurement de manière générique,
notamment car ce segment de code tourne en boucle 24h/24 (c'est une acquisition de données).

Seulement voilà, il arrive (très très rarement) que le test de l'existence
du fichier 'data.dat' APRES l'exécution de la commande 'mv'
retourne que le fichier existe toujours!

mv data.dat data_XXX.dat
if [ -f data.dat ]; then
  echo "Erreur: le fichier existe toujours!!!"
fi

Pourtant quelques secondes plus tard (plus loin dans le script)
il apparaît que le 'mv' a bel et bien fonctionné correctement.

Après recherche infructeuse d'un éventuel bug dans mon script (qui est en fait
assez complexe car c'est un automate logiciel qui met en oeuvre
de nombreuses ressources/programmes de manière asynchrone),
j'en suis arrivé à formuler la question suivante:

La commande 'mv' est-elle atomique?.. c-à-d, peut-on compter
sur le fait que le boulot est effectivement achevé quand on passe
à la ligne de code suivante ?

et en corrolaire:

... si non est-ce que
le seul moyen de garantir la connaissance de l'état absolu
du filesystem est d'invoquer 'sync' apres 'mv'?

Un grand merci à celles et ceux qui éclaireront ma lanterne
sur ce point.

Pour info:
- j'utilise Linux ubuntu 6.06 (noyau 2.6)
- le disque est en SATA et dispose de suffisamment de capacité
- chaque fichier concerné fait environ 100 Mo,
- le FS est en ext3
- le renommage opère sur une même partition physique.
- le pb arrive entre 1 fois sur 100 et 1 fois sur 1000,
c'est aléatoire et je n'ai pas assez d'historique --
Je n'ai pas pu reproduire le pb dans un script minimal
sur une autre machine.
- il peut arriver qu'au moment du 'mv', la machine soit occupée par
un autre script tournant en parallèle pour compresser un gros fichier
situé sur le même disque.

frc0
--






Poste le Saturday 18 August 2007 02:01:41
Répondre     Citer    
Re: Atomicité de la commande mv sous bash...
Envoyé par: francoisp

c'est tout à fait normal puisque comme tout vrai système une commande peut etre mise en attente et exécutée plus tard lorsque la machine à un problème de ressources par exemple si le disque dur est occupé à autre chose avant d'enregistrer le nouveau nom de fichier.

la solution à ça est tout simplement d'attendre que l'enregistrement soit fini avant de traiter la suite

until [ -f dataXXX.dat ] ; do 
 sleep 1
done




Poste le Saturday 18 August 2007 10:08:15
Répondre     Citer    
Re: Atomicité de la commande mv sous bash...
Envoyé par: frc0

Bonjour,

Merci pour cette réponse, qui amène d'autre questionnements...

Dans les manpages de 'mv' (et aussi 'cp') il n'est fait référence à aucun
code de retour de ces commandes, or sous Linux Debian/Ubuntu,
on peut vérifier que la valeur de '$?' après un 'mv' ou un 'cp' sous 'bash'
est 0 ou 1 selon que la commande rencontre le succès ou pas.
Mais dans ce cas, qu'est-ce que signifie le succès d'un 'mv'? J'aurai 2 propositions:

a) la commande a été effectuée/achevée telle que l'utilisateur l'a demandée.

b) la commande ne rencontre pas d'obstacle à son exécution (pas de problème
de droits, taille de fichiers, validité des chemins...), exécution qui est
éventuellement postérieure (si un délai est nécessaire pour accéder aux ressources du disque),
mais on ne peut pas garantir qu'elle soit (physiquement) achevée à l'issue de son invocation.

D'après la réponse reçue précédemment, je penche évidemment pour la seconde solution.
Mais dans ce cas, tant que le travail n'est pas physiquement achevé, il peut encore survenir
des problèmes (à mon humble avis), à moins que le kernel possède des mécanismes qui garantissent
que "tout se passera bien" -- éventuellement plus tard -- au niveau du disque.
De tels mécanismes (une sorte de cache du filesystem physique) devrait donc permettre de
connaître l'état absolu du système de fichiers au niveau du kernel
et le test de l'existence d'un fichier après un 'mv' serait "resynchronisé" de fait
et je ne devrais pas rencontrer de problème!
Alors, qu'est ce qui ne va pas dans mon raisonnement?

Quoiqu'il en soit, il me semble dangereux d'utiliser le code de retour 0 ou 1 à 'mv'
dans un automate car il ne garantirait pas l'achèvement de la commande
en tout cas pas de manière synchrone.

Finalement, lorsqu'on utilise des scripts, on manipule souvent le système
de fichiers comme si tout était fait de manière synchrone. C'est donc une approche
pragmatique et approximativement correcte tant que l'on ne se trouve pas
dans des conditions critiques (accès concurrent aux ressources matérielles ).
C'est la première fois en 10 ans de bash que je suis confronté à ce problème.
Du coup, je pense que je vais devoir réexaminer d'autres scripts pour détecter
l'apparition de ce type de problème.

Cela signifie également que de manière générale, il est assez difficile
d'écrire du code robuste et qu'on en apprend tous les jours!

Merci encore pour votre réponse et pour tout commentaire supplémentaire
à mes interrogations.

frc0
--






Poste le Sunday 19 August 2007 09:24:32
Répondre     Citer    
Re: Atomicité de la commande mv sous bash...
Envoyé par: francoisp

ecrire un code robuste implique un langage compilé et pas interprete

la solution est la synchronisation des disques raid hardware 0+1, pour interdire tout risque de pb de code ou de ressources disques.


Poste le Sunday 19 August 2007 11:32:59
Répondre     Citer    
Re: Atomicité de la commande mv sous bash...
Envoyé par: Raph__

Salut,

A priori mv ne rend pas la main tant qu'il n'a pas fait son boulot. A moins qu'il ait échoué pour x raisons : problème de droit, problème de fs, plus d'espace disque,...
Donc si tes commandes sont séquentiels (cmd1 puis cmd2 puis ...), que les paramètres donnés à mv sont corrects et que ton fs est accessible, alors la condition if devrait toujours retourner 0. A moins que...

Tu dis qu'il s'agit d'un système d'acquisition de données... Comment le fichier data.dat est créé ?
On peut très bien imaginer que le fichier data.dat soit créé juste après que le mv soit réalisé et juste avant que la condition soit évaluée...

On peut aussi imaginer le scénario suivant:
Tonscript:
Traitement du fichier data.dat ...J'écris|Je lis => data.dat...
Renommage du fichier data.dat alors qu'il est en cours de traitement !
Le fichier data.dat est aussitôt créé après le renommage. La condition est positive, ton script dit que le rennomage à échoué.

J'imagine que tu as pris en compte ces quelques possibilités. Mais pour t'aider il nous faudrait plus d'infos sur la création du fichier data.dat.
Un bout de code de ton script ça serait bien aussi.

A Ciao.



Poste le Tuesday 21 August 2007 20:55:12
Répondre     Citer    
Re: Atomicité de la commande mv sous bash...
Envoyé par: frc0

Bonsoir,

Désolé, mais il est (à mon humble avis) inutile
de montrer le code impliqué car il s'agit de plusieurs programmes
parallèle (C/C++/scripts) asynchrones, multithreads et utilisant les FIFO pour
échanger des infos. Ca m'est donc quasiment impossible d'isoler le contexte
de l'erreur.
Cela dit, le shell script que j'utilise pour encapsuler/orchestrer tout ça fonctionne
en peu comme une machine d'état et en principe, il doit garantir l'automatisation
en régime synchrone des opérations de gestions des fichiers de données.

A priori donc -- je l'ai encore vérifié --
mon script-automate garantit que le programme d'acquisition (producer en C/C++) qui
génère le fichier 'data.dat' ne tourne plus lorsque
le temps est venu pour un autre composant (consumer) de traiter ce fichier (par exemple avec ce fameux
appel à 'mv'). Cependant, je ne peux garantir actuellement que, même si ce programme producer
est achevé, les buffers I/O correspondant au fichier 'data.dat' sont flushés au moment du 'mv'
par le script consumer (pas d'appel à fsync à la fin du producer).

Pour rebondir sur le commentaire de Raph_, je ne sais donc pas quel
serait le résultat dans le cas suivant:
1 - un programme écrit des data dans un fichier A
2 - ce programme s'achève (proprement mais sans fsync sur A)
3 - et hop! un autre programme qui tourne en parallèle renomme le fichier A en B
4 - et bang! dans le dos de tous, le système flushe
le cache I/O (une sorte de sync) du fichier précédemment connu
sous le nom A
Est-ce que l'opération 4 régénère un fichier A avec comme contenu
la "traine" du buffer I/O?
Un tel comportement pourrait éventuellement expliquer mon pb.

Enfin, ce qui me chiffone, c'est que les avis des francoisp et Raph_ divergent
profondemment sur le fonctionnement de 'mv'!

Merci encore de vous interesser à ce pb.

frc0
--

Poste le Wednesday 22 August 2007 00:49:35
Répondre     Citer    
Re: Atomicité de la commande mv sous bash...
Envoyé par: Raph__

Salut frc0,

Je me suis mal exprimé, désolé.
Francoisp est en partie dans le vrai lorsqu'il -- dit / sous entend -- que mv n'est pas atomique.
mv fait appel à plusieurs fonctions, certaines sont atomiques, d'autres non. La fonction rename l'est, par contre write ne l'est pas.
rename : [www.opengroup.org]

L'ajout d'une condition qui vérifie le ctime de data.dat devrait te permettre de voir d'où vient le problème.

ctime=`stat -c %Z data.dat`;
sleep 1;
mv data.dat data.XXX.dat;
if [ -f data.dat ] ;
________then if [ "$ctime" -ne `stat -c %Z data.dat` ]
________________then echo "La fonction rename n'est pas atomique sur ext3";
________else echo "Un process vient de recréer data.dat";
________fi;
fi;

Tiens nous au courant.

A Ciao.

Poste le Wednesday 22 August 2007 21:11:16
Répondre     Citer    
Re: Atomicité de la commande mv sous bash...
Envoyé par: Sve@r

Ici, les lock et/ou flock peuvent être d'une aide précieuse...

L'homme qui murmurait à l'oreille des pingouins
[fr.lang.free.fr]

Poste le Sunday 26 August 2007 20:56:05
Répondre     Citer    
Re: Atomicité de la commande mv sous bash...
Envoyé par: frc0

Bonsoir (ou bonjour plutôt),

Des nouvelles sur "l'atomicité de mv sous bash"...
J'ai dû attendre 15 jours avant que mon "bug" reapparaisse...
d'où le long silence. Entre temps, j'ai de nouveau regardé
attentivement mon code et suivi plusieurs pistes amorcées par les
remarques de Raph_ et Sve@r réunis: avais-je à mon insu un autre programme
producer qui charcutait mon fichier de données et pouvait eventuellement
intervenir de telle sorte que je crois (et mon automate egalement)
que "mv n'etait pas atomique"...

j'ai ecrit un mini usecase reproduisant la logique concurrentielle
de mes differents programmes et je l'ai fait tourner à fond
(avec des cycles 1000 fois plus rapides que mon programme et des tres gros fichiers
pour 'mv')... rien, nada, pas une erreur pendant des plombes. impossible
de mettre en default mv.

J'ai donc repris mon baton de pelerin pour arpenter le long chemin
des scenarii concurrentiels possibles dans mon code.
En principe, j'utilisais des mecanismes de lock (quoique rudimentaires
et par essence pas atomiques! tiens, tiens!)
pour empecher des programmes concurrents de faire n'importe quoi
... et puis, j'ai identifié des situations ou ma "machine d'etat"
ne savait justement plus *absolument* dans quel etat elle se trouvait...
et là j'ai pensé que cela commençait à faire un peu trop de degrés de liberté
pour espèrer qu'il ne se passe pas de temps en temps des choses bizarres!
j'ai aussi constaté qu'il existait des portions critiques
du code pour lesquelles je n'avais aucun logs dispo. j'etais donc
en aveuglepour deboguer ces parties là!
bref j'ai mis des appels
a syslog un peu partout dans les differents progs et j'ai attendu... attendu...

en parallele, j'ai cherché une librairie de lock (liblockfile
sous debian, parfait avec l'API en C et le programme dotlockfile sous bash)
et j'ai preparé une nouvelle version du soft
en attendant que l'autre se plante... ce qui est arrivé!

Aujourd'hui, je ne suis pas encore sur d'avoir tout compris,
[j'ai malheureusement des contraintes qui me forcent
à passer plus de temps à reecrire un code amélioré pour demain qu'à analyser
à fond les echecs d'hier; c'est assez casse-gueule comme situation, mais je dois
faire avec! et puis la vie de personne ne dépend de ce programme!]
Je pense toutefois que le fait d'utiliser
des locks atomiques va considerablement ameliorer la situation, au point
que s'il existe encore un pb, il arrivera peut-etre une fois par siecle!!!
cela dit, je ne suis pas encore satisfait car toute la lumiere n'est pas faite!
je vais donc patienter (dans l'angoisse!) pour voir comment réagit
le nouvel algorithme. J'ai l'intuition qu'il reste un cas specifique
qui laisse des possibilités de plantage, mais j'attends de voir...

Conclusions:
- je pense que le fait d'avoir accusé 'mv' d'anatomicité n'etait
vraiment pas sympa de ma part pour ce petit compagnon fidèle depuis tant d'années.
Je m'en excuse également auprès de ceux que cela aurait pu froisser!
- les symptomes constatés n'etaient tres certainement qu'un effet de bord
d'un defaut structurel et/ou logique de mon code
- j'ai découvert cette chouette liblockfile1 (et liblockfile-dev) pour
manipuler atomiquement des fichiers de lock et je vous la conseille.

merci pour vos remarques qui m'ont aidé à mieux reflechir
à mon triste sort.

a+

frc0
--




Poste le Thursday 20 September 2007 01:16:33
Répondre     Citer    

Veuillez vous authentifier auparavant pour commenter.

 

Ce forum !
Atomicité de la commande mv sous bash...
Pour poser vos questions sur les scripts shell, le Perl, le C, etc... Attention : nous ne sommes pas des spécialistes du dev, ce forum est juste pour de petites aides ponctuelles concernant le développement et les outils de développement.

Sauf mention contraire, les documentations publiées sont sous licence Creative-Commons