คุณถามเกี่ยวกับ NFS โค้ดชนิดนี้มีแนวโน้มที่จะแตกภายใต้ NFS เนื่องจากการตรวจสอบnoclobber
เกี่ยวข้องกับการดำเนินการ NFS สองรายการแยกกัน (ตรวจสอบว่ามีไฟล์อยู่สร้างไฟล์ใหม่) และกระบวนการสองรายการจากไคลเอนต์ NFS แยกต่างหากสองแห่งอาจเข้าสู่สภาวะการแข่งขัน ทั้งการตรวจสอบที่B.part
ยังไม่มีอยู่จากนั้นทั้งคู่ก็ดำเนินการสร้างมันให้สำเร็จเพราะพวกเขาเขียนทับกัน)
ไม่มีจริง ๆ ที่จะทำการตรวจสอบทั่วไปว่าระบบไฟล์ที่คุณเขียนไปจะสนับสนุนบางอย่างเช่นnoclobber
อะตอมหรือไม่ คุณสามารถตรวจสอบประเภทของระบบไฟล์ไม่ว่าจะเป็น NFS แต่นั่นจะเป็นวิธีแก้ปัญหาและไม่จำเป็นต้องเป็นการรับประกัน ระบบไฟล์เช่น SMB / CIFS (Samba) มีแนวโน้มที่จะประสบปัญหาเดียวกัน ระบบไฟล์เปิดเผยผ่าน FUSE อาจหรืออาจทำงานไม่ถูกต้อง แต่ส่วนใหญ่ขึ้นอยู่กับการใช้งาน
วิธีการอาจจะดีกว่าที่จะหลีกเลี่ยงการปะทะในส่วนB.part
ขั้นตอนโดยใช้ชื่อไฟล์ที่ไม่ซ้ำกัน (ผ่านความร่วมมือกับตัวแทนอื่น ๆ ) noclobber
เพื่อให้คุณไม่จำเป็นต้องขึ้นอยู่กับ ตัวอย่างเช่นคุณอาจรวมชื่อไฟล์ชื่อโฮสต์ของคุณ PID และเวลาประทับ (+ อาจเป็นตัวเลขสุ่ม) เนื่องจากควรมีกระบวนการเดียวที่ทำงานภายใต้ PID เฉพาะในเวลาใดก็ตาม รับประกันเอกลักษณ์
ดังนั้นหนึ่งใน:
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.
หรือ:
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"
ดังนั้นหากคุณมีสภาพการแข่งขันระหว่างสองเอเจนต์พวกเขาทั้งสองจะดำเนินการต่อไป แต่การดำเนินการครั้งสุดท้ายจะเป็นแบบอะตอมดังนั้น B จะมีอยู่พร้อมสำเนา A ทั้งหมดหรือ B ไม่มีอยู่
คุณสามารถลดขนาดของการแข่งขันได้โดยตรวจสอบอีกครั้งหลังจากการคัดลอกและก่อนmv
หรือln
การดำเนินการ แต่ยังคงมีสภาพการแข่งขันขนาดเล็กอยู่ที่นั่น แต่ไม่ว่าสภาพการแข่งขันจะเป็นอย่างไรเนื้อหาของ B ควรสอดคล้องกันโดยสมมติว่าทั้งสองกระบวนการพยายามสร้างมันขึ้นมาจาก A (หรือคัดลอกจากไฟล์ที่ถูกต้องซึ่งเป็นต้นกำเนิด
โปรดทราบว่าในสถานการณ์แรกmv
เมื่อมีการแข่งขันกระบวนการสุดท้ายคือกระบวนการที่ชนะเนื่องจากการเปลี่ยนชื่อ (2)จะแทนที่ไฟล์ที่มีอยู่แบบอะตอม:
หากมีเส้นทางใหม่แล้วจะมีการแทนที่ด้วยอะตอมดังนั้นจึงไม่มีจุดที่กระบวนการอื่นที่พยายามเข้าถึงnewpathจะพบว่าหายไป [ ... ]
หากมีnewpathอยู่ แต่การดำเนินการล้มเหลวด้วยเหตุผลบางอย่างrename()
รับประกันให้ออกจากอินสแตนซ์ของnewpathไว้
ดังนั้นจึงเป็นไปได้มากที่กระบวนการที่ใช้ B ในเวลานั้นอาจเห็นรุ่นที่แตกต่างกัน (inodes ที่แตกต่างกัน) ในระหว่างกระบวนการนี้ หากนักเขียนทุกคนพยายามที่จะคัดลอกเนื้อหาเดียวกันและผู้อ่านกำลังใช้เนื้อหาของไฟล์เพียงอย่างเดียวนั่นอาจจะใช้ได้ถ้าพวกเขาได้รับ inode ที่แตกต่างกันสำหรับไฟล์ที่มีเนื้อหาเดียวกันพวกเขาจะมีความสุขเหมือนกัน
วิธีที่สองที่ใช้ฮาร์ดลิงค์นั้นดูดีกว่า แต่ฉันจำได้ว่าทำการทดลองกับฮาร์ดลิงก์ในลูปที่แน่นบน NFS จากไคลเอนต์ที่เกิดขึ้นพร้อมกันจำนวนมากและการนับความสำเร็จและดูเหมือนว่ายังมีสภาพการแข่งขันอยู่บ้าง ดำเนินการในเวลาเดียวกันโดยมีปลายทางเดียวกันดูเหมือนว่าทั้งสองจะประสบความสำเร็จ (เป็นไปได้ว่าพฤติกรรมนี้เกี่ยวข้องกับการใช้งานเซิร์ฟเวอร์ NFS โดยเฉพาะคือ YMMV) ในกรณีใด ๆ นั่นอาจเป็นสภาพการแข่งขันแบบเดียวกันซึ่งคุณอาจได้รับ inodes แยกกันสองไฟล์สำหรับไฟล์เดียวกันในกรณีที่มีของหนัก เกิดขึ้นพร้อมกันระหว่างผู้เขียนเพื่อเรียกสภาพการแข่งขันเหล่านี้ หากผู้เขียนของคุณมีความสอดคล้องกัน (ทั้งการคัดลอก A ถึง B) และผู้อ่านของคุณกำลังบริโภคเนื้อหาเพียงอย่างเดียวนั่นอาจเพียงพอ
ในที่สุดคุณพูดถึงการล็อค น่าเสียดายที่การล็อคขาดอย่างรุนแรงอย่างน้อยใน NFSv3 (ไม่แน่ใจเกี่ยวกับ NFSv4 แต่ฉันพนันได้ว่ามันไม่ดีเช่นกัน) หากคุณกำลังพิจารณาการล็อคคุณควรพิจารณาโปรโตคอลที่แตกต่างกันสำหรับการล็อคแบบกระจาย การคัดลอกไฟล์จริง แต่นั่นเป็นปัญหาที่ยุ่งยากซับซ้อนและมีแนวโน้มที่จะเกิดปัญหาเช่นการหยุดชะงักดังนั้นฉันจึงควรหลีกเลี่ยงการดีกว่า
สำหรับพื้นหลังเพิ่มเติมเกี่ยวกับหัวเรื่องของ atomicity บน NFS คุณอาจต้องการอ่านในรูปแบบกล่องจดหมาย Maildirซึ่งถูกสร้างขึ้นเพื่อหลีกเลี่ยงการล็อคและทำงานได้อย่างน่าเชื่อถือแม้ใน NFS ทำได้โดยการเก็บชื่อไฟล์ที่ไม่ซ้ำกันทุกที่ (ดังนั้นคุณจะไม่ได้ B สุดท้ายในตอนท้าย)
บางทีค่อนข้างน่าสนใจสำหรับกรณีของคุณรูปแบบ Maildir ++ จะขยาย Maildir เพื่อเพิ่มการสนับสนุนสำหรับโควต้ากล่องจดหมายและทำได้โดยการอัปเดตไฟล์ด้วยชื่อคงที่ในกล่องจดหมาย (โดยทั่วไปอาจมีความใกล้ชิดกับ B. ) ฉันคิดว่าพยายาม Maildir ++ เพื่อผนวกซึ่งไม่ปลอดภัยสำหรับ NFS แต่มีวิธีการคำนวณใหม่ซึ่งใช้กระบวนการที่คล้ายกับสิ่งนี้และใช้ได้ในฐานะการแทนที่อะตอมมิก
หวังว่าพอยน์เตอร์ทั้งหมดเหล่านี้จะเป็นประโยชน์!