Apakah file menambahkan atom di UNIX?

106

Secara umum, apa yang dapat kita anggap remeh ketika kita menambahkan file di UNIX dari berbagai proses? Apakah mungkin kehilangan data (satu proses menimpa perubahan yang lain)? Apakah mungkin data rusak? (Misalnya, setiap proses menambahkan satu baris per penambahan ke file log, apakah mungkin dua baris terkoyak?) Jika penambahan tidak atom dalam pengertian di atas, lalu apa cara terbaik untuk memastikan pengecualian timbal balik?

Lajos Nagy
sumber

Jawaban:

65

Tulisan dengan ukuran di bawah 'PIPE_BUF' seharusnya bersifat atom. Itu setidaknya harus 512 byte, meskipun bisa dengan mudah lebih besar (linux tampaknya telah mengaturnya ke 4096).

Ini mengasumsikan bahwa Anda membicarakan semua komponen yang sepenuhnya sesuai dengan POSIX. Misalnya, ini tidak benar di NFS.

Tetapi dengan asumsi Anda menulis ke file log yang Anda buka dalam mode 'O_APPEND' dan mempertahankan baris Anda (termasuk baris baru) di bawah byte 'PIPE_BUF', Anda seharusnya dapat memiliki beberapa penulis ke file log tanpa masalah korupsi. Setiap interupsi akan tiba sebelum atau sesudah penulisan, bukan di tengah. Jika Anda ingin integritas file bertahan saat reboot, Anda juga harus meneleponfsync(2) setelah setiap penulisan, tetapi itu buruk untuk kinerja.

Klarifikasi : baca komentar dan jawaban Oz Solomon . Saya tidak yakin yang O_APPENDseharusnya memiliki PIPE_BUFatomicity sebesar itu. Sangat mungkin bahwa itu hanya bagaimana Linux diimplementasikan write(), atau mungkin karena ukuran blok sistem file yang mendasarinya.

freiheit
sumber
11
Pada sistem file yang waras, fsync(2)memberikan jaminan sebanyak yang diberikan sync(2), dan tidak memiliki banyak pengaruh besar pada kinerja.
singkat
4
Apa kamu yakin akan hal itu? Bisakah Anda memberikan beberapa tautan tentang perilaku itu? Saya menemukannya dikonfirmasi jika deskriptornya adalah pipa, tetapi saya tidak dapat menemukan bukti bahwa itu berfungsi untuk file apa pun . termasuk objek file normal dan non-NFS.
Alan Franzoni
6
Di mana tepatnya di ... / write.html? Untuk O_APPEND, saya tidak melihat PIPE_BUF disebutkan, dan saya melihat janji bahwa "tidak ada operasi modifikasi file yang mengganggu antara mengubah offset file dan operasi tulis" , tetapi saya tidak begitu yakin apakah ini berarti operasi tulis itu sendiri adalah tidak terputus ...
akavel
6
Seperti yang ditunjukkan jawaban ini , pernyataan tentang PIPE_BUFpada halaman itu hanya berlaku untuk pipa dan FIFO, bukan file biasa.
Greg Inozemtsev
3
Dengan datangnya sinyal, ini bisa menjadi lebih buruk: bugzilla.kernel.org/show_bug.cgi?id=55651 . Mengapa ini bahkan ditandai sebagai jawaban? PIPE_BUF tidak ada hubungannya dengan file.
menipis
35

Edit: Diperbarui Agustus 2017 dengan hasil Windows terbaru.

Saya akan memberi Anda jawaban dengan tautan untuk menguji kode dan hasil sebagai penulis Boost.AFIO yang diusulkan yang mengimplementasikan sistem file asinkron dan pustaka file i / o C ++.

Pertama, O_APPEND atau FILE_APPEND_DATA yang setara di Windows berarti bahwa kenaikan tingkat file maksimum ("panjang" file) bersifat atomic di bawah penulis bersamaan. Ini dijamin oleh POSIX, dan Linux, FreeBSD, OS X dan Windows semuanya menerapkannya dengan benar. Samba juga mengimplementasikannya dengan benar, NFS sebelum v5 tidak karena tidak memiliki kemampuan format kabel untuk ditambahkan secara atomik. Jadi jika Anda membuka file dengan append-only, penulisan bersamaan tidak akan robek satu sama lain di OS utama mana pun kecuali NFS terlibat.

Namun, pembacaan bersamaan ke atomic appends dapat melihat penulisan yang robek tergantung pada OS, sistem pengarsipan, dan flag apa yang Anda gunakan untuk membuka file - penambahan luas file maksimum bersifat atomic, tetapi visibilitas penulisan sehubungan dengan pembacaan mungkin atau mungkin tidak menjadi atom. Berikut ringkasan singkat berdasarkan bendera, OS, dan sistem pengarsipan:


Tidak ada O_DIRECT / FILE_FLAG_NO_BUFFERING:

Microsoft Windows 10 dengan NTFS: perbarui atomicity = 1 byte hingga dan termasuk 10.0.10240, dari 10.0.14393 setidaknya 1Mb, mungkin tak terbatas (*).

Linux 4.2.6 dengan ext4: memperbarui atomicity = 1 byte

FreeBSD 10.2 dengan ZFS: perbarui atomicity = setidaknya 1Mb, mungkin tak terbatas (*)

O_DIRECT / FILE_FLAG_NO_BUFFERING:

Microsoft Windows 10 dengan NTFS: perbarui atomicity = hingga dan termasuk 10.0.10240 hingga 4096 byte hanya jika halaman sejajar, sebaliknya 512 byte jika FILE_FLAG_WRITE_THROUGH nonaktif, 64 byte lainnya. Perhatikan bahwa atomicity ini mungkin merupakan fitur PCIe DMA daripada yang dirancang. Sejak 10.0.14393, setidaknya 1Mb, mungkin tak terbatas (*).

Linux 4.2.6 dengan ext4: memperbarui atomicity = setidaknya 1Mb, mungkin tak terbatas (*). Perhatikan bahwa Linux sebelumnya dengan ext4 pasti tidak melebihi 4096 byte, XFS tentu saja memiliki penguncian khusus tetapi sepertinya Linux baru-baru ini akhirnya memperbaikinya.

FreeBSD 10.2 dengan ZFS: perbarui atomicity = setidaknya 1Mb, mungkin tak terbatas (*)


Anda dapat melihat hasil uji empiris mentah di https://github.com/ned14/afio/tree/master/programs/fs-probe . Perhatikan bahwa kami menguji robekan offset hanya pada kelipatan 512 byte, jadi saya tidak dapat mengatakan jika pembaruan sebagian dari sektor 512 byte akan robek selama siklus baca-ubah-tulis.

Jadi, untuk menjawab pertanyaan OP, penulisan O_APPEND tidak akan mengganggu satu sama lain, tetapi penulisan O_APPEND yang bersamaan dengan O_APPEND mungkin akan melihat penulisan yang robek di Linux dengan ext4 kecuali O_DIRECT aktif, di mana penulisan O_APPEND Anda harus berupa beberapa sektor berukuran sektor.


(*) "Probably infinite" berasal dari klausa berikut di spek POSIX:

Semua fungsi berikut harus bersifat atomik satu sama lain dalam efek yang ditentukan dalam POSIX.1-2008 ketika mereka beroperasi pada file biasa atau tautan simbolik ... [banyak fungsi] ... read () ... write ( ) ... Jika dua utas masing-masing memanggil salah satu fungsi ini, setiap panggilan akan melihat semua efek yang ditentukan dari panggilan lainnya, atau tidak satupun dari mereka. [Sumber]

dan

Penulisan dapat dibuat bersambung sehubungan dengan membaca dan menulis lainnya. Jika read () data file dapat dibuktikan (dengan cara apa pun) terjadi setelah write () data, itu harus mencerminkan write () itu, bahkan jika panggilan dibuat oleh proses yang berbeda. [Sumber]

tapi sebaliknya:

Volume POSIX.1-2008 ini tidak menentukan perilaku penulisan bersamaan ke file dari beberapa proses. Aplikasi harus menggunakan beberapa bentuk kontrol konkurensi. [Sumber]

Anda dapat membaca lebih lanjut tentang artinya di jawaban ini

Niall Douglas
sumber
29

Saya menulis skrip untuk menguji secara empiris ukuran pelengkap atom maksimum. Skrip, yang ditulis dalam bash, memunculkan banyak proses pekerja yang semuanya menulis tanda tangan khusus pekerja ke file yang sama. Ia kemudian membaca file tersebut, mencari tanda tangan yang tumpang tindih atau rusak. Anda dapat melihat sumber skrip di posting blog ini .

Ukuran penambahan atomik maksimum sebenarnya bervariasi tidak hanya menurut OS, tetapi menurut sistem file.

Di Linux + ext3 ukurannya adalah 4096, dan di Windows + NTFS ukurannya 1024. Lihat komentar di bawah untuk mengetahui ukuran lainnya.

Oz Solomon
sumber
Sistem file apa yang Anda uji di Linux? Saya bertanya-tanya apakah mungkin itu didasarkan pada ukuran blok sistem file.
freiheit
@freiheit saya percaya pada saat saya mengujinya di ext3. Jika Anda menjalankannya di FS lain dan mendapatkan hasil yang berbeda, silakan kirim komentar.
Oz Solomon
3
@OzSolomon, saya menggunakan skrip Anda pada Debian 7.8, dan saya hanya bisa mendapatkan atomic write hingga dan termasuk 1008 byte (1024 - 16 byte overhead?) Pada partisi ext4 saya dan tmpfs mount. Apa pun di luar itu selalu menghasilkan korupsi.
Eric Pruitt
6
Pengujian Anda tampaknya berasumsi bahwa echo $line >> $OUTPUT_FILEakan menghasilkan satu panggilan ke writeberapa pun ukurannya $line.
Tomas
16

Inilah yang dikatakan standar: http://www.opengroup.org/onlinepubs/009695399/functions/pwrite.html .

Jika O_APPENDbendera bendera status file disetel, offset file harus disetel ke akhir file sebelum setiap penulisan dan tidak ada operasi modifikasi file yang akan terjadi antara mengubah offset file dan operasi tulis.

Bastien Léonard
sumber
20
"antara" - tapi bagaimana dengan intervensi selama penulisan, yang menurut pemahaman saya terjadi setelah "antara"? (Yaitu: <change_offset_action> ... "the_between_period" ... <write_action>) - haruskah saya mengerti bahwa tidak ada jaminan tentang itu?
akavel
@akavel setuju; tidak ada jaminan bahwa tulisan itu sendiri adalah atom. Tapi saya bingung: berdasarkan jaminan yang diberikan dalam kutipan Anda, tampaknya kami dapat menyimpulkan bahwa aplikasi multithread yang menambahkan file yang sama tidak akan mencampur bagian dari catatan tertulis yang berbeda. Namun, dari eksperimen yang dilaporkan oleh OzSolomon, kami melihat bahwa asumsi itu pun dilanggar. Mengapa?
maks
@max maaf, saya khawatir saya tidak mengerti pertanyaan Anda: pertama, percobaan OzSolomon adalah multi- proses , bukan aplikasi multi- thread (proses tunggal); kedua, saya tidak mengerti bagaimana Anda menarik kesimpulan bahwa "aplikasi multithread [...] tidak akan bercampur" - itulah yang saya tidak lihat dijamin oleh kutipan dari Bastien, seperti yang saya sebutkan dalam komentar saya. Bisakah Anda menjelaskan pertanyaan Anda?
akavel
2
Hmm saya tidak bisa merekonstruksi logika saya sendiri pada saat saya menulis komentar itu ... Ya, jika interpretasi Anda benar maka tentu saja catatan yang berbeda dapat tercampur. Tapi sekarang saya membaca ulang kutipan Bastien, saya pikir itu berarti tidak ada yang dapat menyela "selama penulisan" - jika tidak, seluruh paragraf dalam standar tidak akan berguna, secara harfiah tidak memberikan jaminan sama sekali (bahkan penulisan akan terjadi pada akhirnya, karena orang lain mungkin akan bergerak offset saat langkah "tulis" sedang dijalankan.
maks