réécrire le fichier existant pour qu'il soit remplacé par une nouvelle version atomiquement, une fois entièrement écrit

18

Je me souviens vaguement d'avoir lu quelque part qu'il existait, dans certains Unices, un moyen d'ouvrir un fichier existant pour l'écriture, avec un indicateur qui demandait au noyau d'utiliser l'ancienne version (pour d'autres processus y accédant en lecture), jusqu'à ce que le "nouveau "la version a été entièrement écrite (fd fermé), à partir de ce moment le fichier est apparu comme la nouvelle version.

En d'autres termes, d'autres processus ont vu l'ancienne version ou la nouvelle, jamais une version incomplète.

Quelqu'un bien informé peut-il m'indiquer une référence?

eudoxos
la source
Cela ressemble à ce que Plan 9 pourrait faire, mais non.
Gilles 'SO- arrête d'être méchant'
2
Cela ressemble à Files-11 sur OpenVMS: "Chaque fois qu'un fichier est enregistré, plutôt que d'écraser la version existante, un nouveau fichier avec le même nom mais un numéro de version incrémenté est créé."
Mat
Pourquoi as-tu demandé? Avez-vous besoin de cette fonctionnalité ou était-ce simplement de la curiosité?
Nils
1
Je serais heureux d'avoir cette fonctionnalité, et je me souviens avoir lu quelque part qu'elle existait. Un mélange à la fois de besoin et de curiosité.
eudoxos
Tous les systèmes Unix le permettent d'une autre manière - créez un nouveau fichier dans le même répertoire, remplissez le contenu modifié et effectuez un renommage atomique. C'est beaucoup plus cher pour de petits changements mais cela fonctionne.
Netch

Réponses:

14

Ce que vous décrivez ressemble exactement à un changement de nom de base pour remplacer un fichier.

Lorsque vous renommez / déplacez un fichier au-dessus d'un autre, l'ancien fichier n'est pas lié. Cela signifie que le fichier existe toujours, mais il n'est plus dans l'arborescence du système de fichiers. Ainsi, les anciennes applications continueront à pouvoir accéder au fichier tant qu'elles le garderont ouvert. Une fois que toutes les applications ont fermé l'ancien fichier, il n'est en fait pas alloué sur le disque.

L' renameappel système est une opération atomique. Pour ce faire, vous devez créer un nouveau fichier sous un nom différent, puis appeler renamepour renommer le fichier temporaire comme celui que vous souhaitez remplacer. Puisque l'opération est atomique, il n'y a absolument aucune période où le fichier est manquant. Il passe instantanément de l'ancien fichier au nouveau fichier.
Notez cependant que le fichier temporaire et le fichier remplacé doivent résider sur le même point de montage.

Patrick
la source
Vous ne pouvez l'utiliser que si votre programme est spécifiquement écrit avec la fonctionnalité à l'esprit. Dans ce cas, cependant, c'était une fonctionnalité du système d'exploitation, d'où même les programmes réguliers recevaient automatiquement cette sémantique atomique.
eudoxos
1
@eudoxos votre commentaire n'a aucun sens. Vous dites que les programmes devraient être écrits spécifiquement pour faire la renamechose d'échange. Même si une telle «fonctionnalité du système d'exploitation» dont vous parlez existait, le programme devrait toujours être écrit pour en profiter également. Quelle est la différence?
Patrick
Il y a une différence si vous passez un indicateur (éventuellement non pris en charge) à l' openappel système ou si vous devez faire ce que vous décrivez à la main.
eudoxos
Gardez à l'esprit que pour conserver l'ancienne ou la nouvelle version entièrement écrite en cas de plantage, vous devez également synchroniser le nouveau fichier sur le disque avec fsync ou similaire
TextShell
@textshell sans la synchronisation, vous obtenez quand même l'atomicité .... mais pas la durabilité ... correct? Je ne comprends pas l'argument de goo.gl/qfQQfy dans ce cas. Dans mon cas, j'ai un système sous une charge extrême et je veux éviter les vidages du système de fichiers et je ne me soucie pas si le fichier survit à un crash.
wcochran
6

Comme Patrick l'écrit , la façon habituelle de le faire est d'écrire la nouvelle version dans un fichier séparé et, une fois terminé, de renommer la nouvelle version en l'ancien nom de fichier, en l'écrasant atomiquement. Cette deuxième opération est appelée écrasement par renommage .

Maintenant, quelques références:

Escargot mécanique
la source
man 3p renameme dit que renamec'est effectivement atomique, et je suppose que cela est destiné à tous les systèmes de fichiers Linux. Et quand je lis le premier article que vous avez lié, je pense toujours que les opérations de renommage de Btrfs sont atomiques.
hagello
1

Cela me rappelle Allocate On Flush . Lorsqu'un système de fichiers utilise cette fonctionnalité, au lieu d'écrire des données directement sur le disque, il soustrait la taille des données à écrire du compteur d'espace libre du disque et conserve les données en mémoire jusqu'à ce qu'un appel système de synchronisation soit effectué ou que le noyau décide pour vider les tampons sales.

Dans ce cas, si le fichier est modifié par un processus et est ouvert par un autre processus, ce dernier processus "verra" la version non modifiée ( ou "ancienne" si vous préférez ) du fichier.

Bien sûr, ce qui précède est théorique et dépend de divers facteurs, et je dirais un peu imprévisible - puisque vous ne savez pas exactement quand le noyau va vider les pages sales. Par exemple sous Linux ( comme vous pouvez également le lire dans la section 15.3 de Comprendre le noyau Linux ), les pages sales sont écrites sur le disque dans les conditions suivantes:

  • Le cache de pages est trop plein et plus de pages sont nécessaires, ou le nombre de pages sales devient trop important.

  • Trop de temps s'est écoulé depuis qu'une page est restée sale.

  • Un processus demande que toutes les modifications en attente d'un périphérique de bloc ou d'un fichier particulier soient vidées; il le fait en appelant un appel système sync (), fsync () ou fdatasync ().

Cette fonctionnalité est connue pour être implémentée dans les systèmes de fichiers HFS +, XFS, Reiser4, ZFS, Btrfs et ext4.

dkaragasidis
la source
2
Ce que vous décrivez est une technique de système de fichiers qui devrait être invisible depuis l'espace utilisateur (et ne fait donc pas ce que vous indiquez) sur les systèmes POSIX (fichiers) (voir écriture : "Si une lecture () des données de fichier peut être prouvée (par tous les moyens) pour se produire après une écriture () des données, il doit refléter cette écriture (), même si les appels sont effectués par des processus différents . "). Les autres processus ne verront pas les anciennes données (sur POSIX).
Mat
Merci pour la correction. Je suppose que ma compréhension de cette technique de système de fichiers était fausse.
dkaragasidis
Bon, cela ressemble à autre chose. Je me souviens vaguement maintenant que c'est dans une interview avec RMS qu'il a mentionné cette fonctionnalité, c'était peut-être un vieux système arcane qui n'a jamais vécu en dehors du milieu universitaire ... Merci quand même.
eudoxos