fsync() yang berhasil pada regular file tidak, dengan sendirinya, menjamin bahwa directory entry yang memberi nama pada file tersebut sudah mencapai persistent storage. Linux mendokumentasikan boundary ini secara eksplisit: sinkronisasi file mencakup data file dan metadata terkait, sedangkan persistence directory entry yang memuatnya membutuhkan fsync() pada file descriptor untuk direktori tersebut.
Perbedaan ini penting ketika software membuat file baru atau mengganti pathname yang sudah ada secara atomik. Konten file dan metadata pathname adalah dua bagian filesystem state yang terpisah, dan crash dapat menguji durability boundary di antara keduanya.
File state dan directory state adalah hal terpisah
Regular file direpresentasikan oleh inode beserta data block dan metadata spesifik filesystem. Sebuah direktori berisi mapping dari nama ke filesystem object.
Menulis byte mengubah file state. Membuat, menghapus, atau me-rename pathname mengubah directory state. Operasi-operasi tersebut saling berkaitan, tetapi bukan persistence unit yang sama pada system-call interface.
fsync(file_fd) meminta sinkronisasi file yang dirujuk oleh file_fd. Linux juga melakukan flush metadata yang terkait dengan file tersebut. Call ini tidak selalu memaksa directory block yang berisi nama file ke stable storage.
Untuk file yang baru dibuat, ini berarti durable content tidak otomatis berarti durable name.
Atomic rename dan crash durability adalah properti berbeda
rename() menyediakan atomic namespace transition ketika filesystem dan path constraint mengizinkan operasi tersebut. Process lain tidak melihat state ketika destination pathname yang ada sekadar menghilang di antara removal dan replacement.
Atomicity ini menjelaskan visibility selama sistem berjalan. Ia tidak menyatakan bahwa namespace transition sudah dipaksa ke persistent media sebelum rename() kembali.
Urutan replacement yang umum menulis temporary file, melakukan sinkronisasi pada file tersebut, lalu me-rename-nya ke destination. Sinkronisasi file melindungi new file content dari pending writeback. Rename mengubah directory entry secara atomik. Sinkronisasi containing directory menangani persistence namespace change tersebut.
Jaminan-jaminan ini berbeda:
write temporary file
|
v
fsync temporary file
|
v
rename temporary -> target
|
v
fsync containing directorySinkronisasi pertama berkaitan dengan data dan file metadata milik replacement object. Sinkronisasi terakhir berkaitan dengan directory mutation yang membuat replacement dapat dijangkau melalui target name.
Write yang berhasil lebih lemah daripada fsync yang berhasil
Buffered write dapat selesai setelah data disalin ke kernel-managed cache tanpa menunggu storage device menyimpannya secara persisten. Dirty page dapat tetap menunggu writeback berikutnya.
fsync() menutup sebagian gap tersebut dengan meminta modified file data dan metadata relevan ditransfer melalui filesystem dan storage stack sesuai synchronization semantics platform.
Perbedaannya juga terlihat pada error handling. Linux dapat melaporkan delayed writeback error melalui pemanggilan fsync() berikutnya. Menganggap write() yang berhasil sebagai durability acknowledgment melewatkan error boundary ini.
Storage hardware, device cache, filesystem behavior, dan mount configuration tetap memengaruhi persistence model akhir. fsync() adalah primitive yang tersedia bagi aplikasi untuk meminta sinkronisasi ini; ia tidak dapat memperbaiki hardware yang secara salah melaporkan persistence telah selesai.
fdatasync memiliki kontrak metadata yang lebih sempit
fdatasync() mirip dengan fsync(), tetapi dapat mengabaikan metadata yang tidak diperlukan untuk retrieval data berikutnya. Perubahan file size, misalnya, relevan karena stored size menentukan byte mana yang nanti dapat dibaca. Sebagian timestamp update tidak perlu diperlakukan sama.
Kontrak yang lebih sempit ini dapat mengurangi metadata traffic untuk workload yang hanya membutuhkan durable file content.
Namun, ia tidak menyatukan file state dan directory state menjadi satu operasi. Directory entry yang dibuat atau diubah di sekitar file tetap merupakan namespace metadata milik direktori.
Replacement lintas direktori memperluas boundary
Rename dapat melibatkan dua parent directory. Source name dihapus dari satu direktori dan destination name dibuat atau diganti pada direktori lain.
Operasi tersebut memodifikasi kedua namespace container. Software dengan crash-consistency requirement yang ketat harus memperhitungkan setiap direktori yang persistent state-nya penting bagi hasil yang dimaksud.
Cross-filesystem move adalah kasus berbeda. System call rename() mengembalikan EXDEV ketika source dan destination berada pada mounted filesystem berbeda dan operasi tidak dapat direpresentasikan sebagai rename. User-space tool kemudian dapat mengimplementasikan urutan copy-and-delete, yang memiliki atomicity dan durability property berbeda.
Karena itu, operasi yang tampak sebagai “move” tidak berarti satu mekanisme persistence universal.
Journaling dapat memperkuat perilaku tanpa mengubah kontrak API
Journaled filesystem sering mengelompokkan metadata update terkait ke dalam transaction. Filesystem tertentu dapat memberikan behavior yang lebih kuat daripada minimum application-visible contract dalam konfigurasi tertentu.
Mengandalkan incidental transaction coupling membuat durability bergantung pada detail implementasi filesystem, mount option, kernel behavior, dan storage topology. Kode yang ingin menyatakan persistence requirement secara langsung seharusnya memakai synchronization operation yang sesuai dengan state yang diubah.
Hal ini juga membuat boundary terlihat saat review: file synchronization melindungi file object, sedangkan directory synchronization melindungi namespace mutation.
Sinkronisasi direktori melengkapi permintaan persistence namespace
Direktori dapat dibuka dan file descriptor-nya diberikan ke fsync() di Linux. Setelah membuat, menghapus, atau me-rename entry, call tersebut meminta sinkronisasi perubahan direktori.
Urutan ini bukan sekadar defensive pattern di sekitar rename(). Ia mencerminkan filesystem object yang dimodifikasi. File data milik file. Mapping dari komponen pathname ke file tersebut milik direktori.
Crash consistency bergantung pada keduanya ketika aplikasi membutuhkan durable content di bawah durable name. Atomic namespace operation dapat mencegah observer melihat intermediate replacement state, sementara explicit synchronization menetapkan persistence boundary terpisah untuk object dan namanya.