Anda bertanya tentang NFS. Jenis kode ini kemungkinan akan pecah di bawah NFS, karena pemeriksaan untuk noclobber
melibatkan dua operasi NFS yang terpisah (memeriksa apakah ada file, membuat file baru) dan dua proses dari dua klien NFS yang terpisah dapat masuk ke kondisi balapan di mana keduanya berhasil ( keduanya memverifikasi yang B.part
belum ada, lalu keduanya melanjutkan untuk berhasil membuatnya, sebagai akibatnya mereka saling menimpa.)
Tidak ada benar-benar melakukan pemeriksaan generik untuk apakah sistem file yang Anda tulis akan mendukung sesuatu seperti noclobber
atom atau tidak. Anda dapat memeriksa tipe sistem file, apakah itu NFS, tetapi itu akan menjadi heuristik dan belum tentu menjadi jaminan. Sistem file seperti SMB / CIFS (Samba) kemungkinan akan mengalami masalah yang sama. Filesystem mengekspos melalui FUSE mungkin atau mungkin tidak berperilaku dengan benar, tetapi itu sebagian besar tergantung pada implementasinya.
Pendekatan yang mungkin lebih baik adalah menghindari tabrakan pada B.part
langkah tersebut, dengan menggunakan nama file unik (melalui kerja sama dengan agen lain) sehingga Anda tidak perlu bergantung noclobber
. Misalnya, Anda dapat memasukkan, sebagai bagian dari nama file, nama host Anda, PID dan stempel waktu (+ mungkin nomor acak). Karena harus ada satu proses yang berjalan di bawah PID tertentu pada host pada waktu tertentu, ini harus menjamin keunikan.
Jadi salah satu dari:
test -f B && continue # skip already existing
unique=$(hostname).$$.$(date +%s).$RANDOM
cp A B.part."$unique"
# Maybe check for existance of B again, remove
# the temporary file and bail out in that case.
mv B.part."$unique" B
# mv (rename) should always succeed, overwrite a
# previously copied B if one exists.
Atau:
test -f B && continue # skip already existing
unique=$(hostname).$$.$(date +%s).$RANDOM
cp A B.part."$unique"
if ln B.part."$unique" B ; then
echo "Success creating B"
else
echo "Failed creating B, already existed"
fi
# Both cases require cleanup.
rm B.part."$unique"
Jadi jika Anda memiliki kondisi balapan antara dua agen, mereka berdua akan melanjutkan dengan operasi, tetapi operasi terakhir akan menjadi atom, sehingga B ada dengan salinan penuh A, atau B tidak ada.
Anda dapat mengurangi ukuran balapan dengan memeriksa lagi setelah salinan dan sebelum mv
atau ln
operasi, tetapi masih ada kondisi balapan kecil di sana. Tetapi, terlepas dari kondisi balapan, isi B harus konsisten, dengan asumsi kedua proses mencoba membuatnya dari A (atau salinan dari file yang valid sebagai asal.)
Perhatikan bahwa dalam situasi pertama dengan mv
, ketika ada perlombaan, proses terakhir adalah yang menang, karena mengubah nama (2) secara atom akan menggantikan file yang ada:
Jika newpath sudah ada, maka akan atom diganti, sehingga tidak ada titik di mana proses lain mencoba untuk akses newpath akan menemukannya hilang. [...]
Jika newpath ada tapi operasi gagal karena beberapa alasan, rename()
jaminan untuk meninggalkan sebuah contoh dari newpath di tempat.
Jadi, sangat mungkin proses memakan B pada saat itu mungkin melihat versi yang berbeda (inode berbeda) selama proses ini. Jika penulis hanya mencoba menyalin konten yang sama, dan pembaca hanya mengkonsumsi konten file, itu mungkin baik-baik saja, jika mereka mendapatkan inode berbeda untuk file dengan konten yang sama, mereka akan senang sama saja.
Pendekatan kedua menggunakan hardlink terlihat lebih baik, tapi saya ingat membuat percobaan dengan hardlink dalam loop ketat pada NFS dari banyak klien bersamaan dan menghitung keberhasilan dan tampaknya masih ada beberapa kondisi lomba di sana, di mana tampaknya jika dua klien mengeluarkan hardlink Operasi pada saat yang sama, dengan tujuan yang sama, keduanya tampaknya berhasil. (Ada kemungkinan bahwa perilaku ini terkait dengan implementasi server NFS tertentu, YMMV.) Bagaimanapun, itu mungkin kondisi ras yang sama, di mana Anda mungkin mendapatkan dua inode terpisah untuk file yang sama dalam kasus di mana ada berat konkurensi antara penulis untuk memicu kondisi lomba ini. Jika penulis Anda konsisten (keduanya menyalin A ke B), dan pembaca Anda hanya mengkonsumsi konten, itu mungkin cukup.
Akhirnya, Anda menyebutkan penguncian. Sayangnya penguncian sangat kurang, setidaknya di NFSv3 (tidak yakin tentang NFSv4, tapi saya yakin itu juga tidak baik.) Jika Anda mempertimbangkan penguncian, Anda harus melihat ke protokol yang berbeda untuk penguncian yang didistribusikan, mungkin keluar dari band dengan salinan file yang sebenarnya, tapi itu mengganggu, kompleks dan rentan terhadap masalah seperti kebuntuan, jadi saya akan mengatakan lebih baik untuk dihindari.
Untuk latar belakang lebih lanjut tentang masalah atomisitas pada NFS, Anda mungkin ingin membaca pada format kotak surat Maildir , yang dibuat untuk menghindari kunci dan bekerja dengan andal bahkan pada NFS. Itu dilakukan dengan menjaga nama file unik di mana-mana (sehingga Anda bahkan tidak mendapatkan B akhir di akhir.)
Mungkin agak lebih menarik untuk kasus khusus Anda, format Maildir ++ memperluas Maildir untuk menambahkan dukungan untuk kuota kotak surat dan melakukannya dengan memperbarui secara atomis file dengan nama tetap di dalam kotak surat (sehingga mungkin lebih dekat ke B. Anda) Saya pikir Maildir ++ mencoba untuk menambahkan, yang tidak benar-benar aman di NFS, tetapi ada pendekatan perhitungan kembali yang menggunakan prosedur yang mirip dengan ini dan itu valid sebagai pengganti atom.
Semoga semua petunjuk ini bermanfaat!