En général, que pouvons-nous tenir pour acquis lorsque nous ajoutons à un fichier sous UNIX à partir de plusieurs processus? Est-il possible de perdre des données (un processus écrasant les modifications de l'autre)? Est-il possible que les données soient altérées? (Par exemple, chaque processus ajoute une ligne par annexe à un fichier journal, est-il possible que deux lignes soient modifiées?) Si l'ajout n'est pas atomique dans le sens ci-dessus, alors quelle est la meilleure façon d'assurer l'exclusion mutuelle?
Une écriture dont la taille est inférieure à "PIPE_BUF" est censée être atomique. Cela devrait être d'au moins 512 octets, bien qu'il puisse facilement être plus grand (Linux semble l'avoir défini sur 4096).
Cela suppose que vous parlez de tous les composants entièrement compatibles POSIX. Par exemple, ce n'est pas vrai sur NFS.
Mais en supposant que vous écrivez dans un fichier journal que vous avez ouvert en mode 'O_APPEND' et que vous gardiez vos lignes (y compris la nouvelle ligne) sous 'PIPE_BUF' octets longtemps, vous devriez pouvoir avoir plusieurs écrivains dans un fichier journal sans aucun problème de corruption. Toutes les interruptions arriveront avant ou après l'écriture, pas au milieu. Si vous voulez que l'intégrité des fichiers survive à un redémarrage, vous devrez également appeler fsync(2)
après chaque écriture, mais c'est terrible pour les performances.
Clarification : lisez les commentaires et réponse d'Oz Solomon . Je ne suis pas sûr que O_APPEND
Est censé avoir cette atomicité de taille PIPE_BUF
. Il est tout à fait possible que ce soit juste la façon dont Linux a implémenté write()
, ou cela peut être dû à la taille des blocs du système de fichiers sous-jacent.
Edit: Mise à jour d'août 2017 avec les derniers résultats Windows.
Je vais vous donner une réponse avec des liens vers le code de test et les résultats en tant qu'auteur proposé Boost.AFIO qui implémente un système de fichiers asynchrone et une bibliothèque C++ d'e/s de fichiers.
Premièrement, O_APPEND ou l'équivalent FILE_APPEND_DATA sous Windows signifie que les incréments de l'étendue maximale du fichier ("longueur" du fichier) sont atomiques sous les écrivains concurrents. Ceci est garanti par POSIX, et Linux, FreeBSD, OS X et Windows l'implémentent tous correctement. Samba l'implémente également correctement, NFS avant la v5 ne le fait pas car il n'a pas la capacité de format de fil à ajouter atomiquement. Donc, si vous ouvrez votre fichier avec ajout uniquement, les écritures simultanées ne se déchireront pas les unes par rapport aux autres sur n'importe quel système d'exploitation majeur sauf si NFS est impliqué.
Cependant concurrent lit à atomic ajoute peut voir les écritures déchirées en fonction du système d'exploitation, du système de classement et des indicateurs avec lesquels vous avez ouvert le fichier - l'incrément du fichier maximal l'étendue est atomique, mais la visibilité des écritures par rapport aux lectures peut être atomique ou non. Voici un bref résumé par drapeaux, OS et système de classement:
Microsoft Windows 10 avec NTFS: mise à jour atomicité = 1 octet jusqu'au 10.0.10240 inclus, à partir du 10.0.14393 au moins 1 Mo, probablement infini (*).
Linux 4.2.6 avec ext4: mise à jour atomicité = 1 octet
FreeBSD 10.2 avec ZFS: atomicité de mise à jour = au moins 1 Mo, probablement infini (*)
Microsoft Windows 10 avec NTFS: mise à jour atomicité = jusqu'à et y compris 10.0.10240 jusqu'à 4096 octets uniquement si la page est alignée, sinon 512 octets si FILE_FLAG_WRITE_THROUGH désactivé, sinon 64 octets. Notez que cette atomicité est probablement une caractéristique de PCIe DMA plutôt que conçue en. Depuis le 10.0.14393, au moins 1 Mo, probablement infini (*).
Linux 4.2.6 avec ext4: mise à jour atomicité = au moins 1 Mo, probablement infini (*). Notez que les anciens Linux avec ext4 ne dépassaient certainement pas 4096 octets, XFS avait certainement un verrouillage personnalisé, mais il semble que Linux récent ait finalement corrigé cela.
FreeBSD 10.2 avec ZFS: atomicité de mise à jour = au moins 1 Mo, probablement infini (*)
Vous pouvez voir les résultats des tests empiriques bruts sur https://github.com/ned14/afio/tree/master/programs/fs-probe . Notez que nous testons les décalages déchirés uniquement sur des multiples de 512 octets, donc je ne peux pas dire si une mise à jour partielle d'un secteur de 512 octets se déchirerait pendant le cycle de lecture-modification-écriture.
Ainsi, pour répondre à la question de l'OP, les écritures O_APPEND n'interféreront pas les unes avec les autres, mais les lectures simultanées aux écritures O_APPEND verront probablement des écritures déchirées sur Linux avec ext4 sauf si O_DIRECT est activé, sur quoi vos écritures O_APPEND devront être un multiple de taille de secteur.
(*) "Probablement infini" découle de ces clauses dans la spécification POSIX:
Toutes les fonctions suivantes doivent être atomiques les unes par rapport aux autres dans les effets spécifiés dans POSIX.1-2008 lorsqu'elles fonctionnent sur des fichiers normaux ou des liens symboliques ... [plusieurs fonctions] ... read () ... write ( ) ... Si deux threads appellent chacun une de ces fonctions, chaque appel doit voir tous les effets spécifiés de l'autre appel, ou aucun d'entre eux. [Source]
et
Les écritures peuvent être sérialisées par rapport à d'autres lectures et écritures. Si une lecture () des données du fichier peut être prouvée (par tout moyen) après une écriture () des données, elle doit refléter cette écriture (), même si les appels sont effectués par des processus différents. [Source]
mais inversement:
Ce volume de POSIX.1-2008 ne spécifie pas le comportement des écritures simultanées dans un fichier à partir de plusieurs processus. Les applications doivent utiliser une forme de contrôle de concurrence. [Source]
Vous pouvez en savoir plus sur leur signification dans cette réponse
J'ai écrit un script pour tester empiriquement la taille maximale de l'ajout atomique. Le script, écrit en bash, génère plusieurs processus de travail qui écrivent tous des signatures spécifiques au travailleur dans le même fichier. Il lit ensuite le fichier, à la recherche de signatures qui se chevauchent ou sont corrompues. Vous pouvez voir la source du script ici article de blog .
La taille réelle maximale de l'ajout atomique varie non seulement selon le système d'exploitation, mais selon le système de fichiers.
Sous Linux + ext3, la taille est 4096 et sous Windows + NTFS, la taille est 1024. Voir les commentaires ci-dessous pour plus de tailles.
Voici ce que dit la norme: http://www.opengroup.org/onlinepubs/009695399/functions/pwrite.html .
Si la
O_APPEND
L'indicateur des indicateurs d'état du fichier est défini, l'offset de fichier doit être défini à la fin du fichier avant chaque écriture et aucune opération de modification de fichier intermédiaire ne doit se produire entre le changement de l'offset de fichier et l'opération d'écriture.