การแทนที่ไฟล์โดยทั่วไป
ก่อนอื่นมีกลยุทธ์หลายวิธีในการแทนที่ไฟล์:
เปิดไฟล์ที่มีอยู่เพื่อเขียนตัดให้เหลือ 0 ความยาวและเขียนเนื้อหาใหม่ (ตัวแปรที่พบได้น้อยคือการเปิดไฟล์ที่มีอยู่เขียนทับเนื้อหาเก่าด้วยเนื้อหาใหม่ตัดทอนไฟล์ให้มีความยาวใหม่ถ้ามันสั้นกว่า) ในเงื่อนไขของเชลล์:
echo 'new content' >somefile
ลบไฟล์เก่าและสร้างไฟล์ใหม่ด้วยชื่อเดียวกัน ในเงื่อนไขของเชลล์:
rm somefile
echo 'new content' >somefile
เขียนไปยังไฟล์ใหม่ภายใต้ชื่อชั่วคราวจากนั้นย้ายไฟล์ใหม่ไปยังชื่อที่มีอยู่ การย้ายจะลบไฟล์เก่า ในเงื่อนไขของเชลล์:
echo 'new content' >somefile.new
mv somefile.new somefile
ฉันจะไม่แสดงความแตกต่างระหว่างกลยุทธ์ฉันจะพูดถึงสิ่งที่สำคัญที่นี่ ด้วย stategy 1 หากกระบวนการใดกำลังใช้ไฟล์อยู่กระบวนการจะเห็นเนื้อหาใหม่เมื่อกำลังมีการอัปเดต สิ่งนี้อาจทำให้เกิดความสับสนหากกระบวนการคาดว่าเนื้อหาไฟล์จะยังคงเหมือนเดิม โปรดทราบว่านี่เป็นเพียงเกี่ยวกับกระบวนการที่เปิดไฟล์ (เท่าที่เห็นในlsof
หรือในแอปพลิเคชันแบบโต้ตอบที่มีการเปิดเอกสาร (เช่นการเปิดไฟล์ในโปรแกรมแก้ไข) โดยปกติจะไม่เปิดไฟล์ไว้ การดำเนินการ“ เปิดเอกสาร” และพวกเขาแทนที่ไฟล์ (ใช้หนึ่งในกลยุทธ์ด้านบน) ในระหว่างการดำเนินการ“ บันทึกเอกสาร”/proc/PID/fd/
ด้วยกลยุทธ์ 2 และ 3 หากกระบวนการบางอย่างsomefile
เปิดไฟล์ไฟล์เก่าจะยังคงเปิดอยู่ในระหว่างการอัปเกรดเนื้อหา ด้วยกลยุทธ์ที่ 2 ขั้นตอนการลบไฟล์โดยข้อเท็จจริงแล้วจะลบรายการไฟล์ในไดเรกทอรีเท่านั้น ไฟล์จะถูกลบออกเมื่อไม่มีรายการไดเร็กทอรีที่นำไปสู่ (บนระบบไฟล์ Unix ทั่วไปอาจมีรายการไดเรกทอรีมากกว่าหนึ่งรายการสำหรับไฟล์เดียวกัน ) และไม่มีกระบวนการใดเปิดไว้ ต่อไปนี้เป็นวิธีในการสังเกตสิ่งนี้ - ไฟล์จะถูกลบออกเฉพาะเมื่อsleep
กระบวนการหยุดทำงาน ( rm
ลบเฉพาะรายการไดเรกทอรี)
echo 'old content' >somefile
sleep 9999999 <somefile &
df .
rm somefile
df .
cat /proc/$!/fd/0
kill $!
df .
ด้วยกลยุทธ์ 3 ขั้นตอนในการย้ายไฟล์ใหม่ไปยังชื่อที่มีอยู่จะลบรายการไดเรกทอรีที่นำไปสู่เนื้อหาเก่าและสร้างรายการไดเรกทอรีที่นำไปสู่เนื้อหาใหม่ สิ่งนี้ทำในการปฏิบัติการแบบอะตอมเดียวดังนั้นกลยุทธ์นี้มีข้อได้เปรียบที่สำคัญ: หากกระบวนการเปิดไฟล์ได้ตลอดเวลามันจะเห็นเนื้อหาเก่าหรือเนื้อหาใหม่ - ไม่มีความเสี่ยงในการผสมเนื้อหาหรือไฟล์ที่ไม่ได้ ที่มีอยู่เดิม.
แทนที่ executables
หากคุณลองกลยุทธ์ที่ 1 ด้วยการเรียกใช้งานได้บน Linux คุณจะได้รับข้อผิดพลาด
cp /bin/sleep .
./sleep 999999 &
echo oops >|sleep
bash: sleep: Text file busy
A“แฟ้มข้อความ” หมายความว่าไฟล์ที่มีรหัสปฏิบัติการด้วยเหตุผลทางประวัติศาสตร์ปิดบัง Linux เช่นเดียวกับรุ่นอื่น ๆ ของยูนิกซ์ปฏิเสธที่จะเขียนทับรหัสของโปรแกรมที่กำลังทำงานอยู่ unix บางตัวยอมให้สิ่งนี้นำไปสู่การล่มสลายยกเว้นว่ารหัสใหม่เป็นการดัดแปลงรหัสเก่าที่ดีมาก
บน Linux คุณสามารถเขียนทับรหัสของไลบรารีที่โหลดแบบไดนามิก มีแนวโน้มที่จะนำไปสู่ข้อผิดพลาดของโปรแกรมที่ใช้งานอยู่ (คุณอาจไม่สามารถสังเกตสิ่งนี้ได้sleep
เพราะมันจะโหลดรหัสห้องสมุดทั้งหมดที่จำเป็นเมื่อเริ่มใช้งานลองใช้โปรแกรมที่ซับซ้อนกว่าซึ่งทำสิ่งที่มีประโยชน์หลังจากนอนหลับเช่นperl -e 'sleep 9; print lc $ARGV[0]'
)
หากล่ามกำลังเรียกใช้สคริปต์ไฟล์สคริปต์จะเปิดขึ้นในลักษณะปกติโดยล่ามดังนั้นจึงไม่มีการป้องกันการเขียนทับสคริปต์ ล่ามบางคนอ่านและแยกสคริปต์ทั้งหมดก่อนที่จะเริ่มดำเนินการบรรทัดแรกส่วนคนอื่นอ่านสคริปต์ได้ตามต้องการ ดูจะเกิดอะไรขึ้นหากคุณแก้ไขสคริปต์ระหว่างการทำงาน และLinux จัดการกับเชลล์สคริปต์ได้อย่างไร? สำหรับรายละเอียดเพิ่มเติม
กลยุทธ์ที่ 2 และ 3 มีความปลอดภัยสำหรับไฟล์ที่เรียกใช้งานเช่นกัน: แม้ว่าการเรียกใช้ไฟล์ปฏิบัติการ (และไลบรารีที่โหลดแบบไดนามิก) จะไม่เปิดไฟล์ในกรณีที่มีตัวให้คำอธิบายไฟล์ แต่จะทำงานในลักษณะเดียวกัน ตราบใดที่บางโปรแกรมกำลังรันโค้ดไฟล์จะยังคงอยู่บนดิสก์แม้ไม่มีรายการไดเรกทอรี
การอัพเกรดแอปพลิเคชัน
ผู้จัดการแพ็คเกจส่วนใหญ่ใช้กลยุทธ์ 3 เพื่อแทนที่ไฟล์เนื่องจากข้อได้เปรียบที่สำคัญดังกล่าวข้างต้น - เมื่อใดก็ได้การเปิดไฟล์จะนำไปสู่เวอร์ชันที่ถูกต้อง
ในกรณีที่การอัปเกรดแอปพลิเคชันสามารถแตกได้ในขณะที่อัปเกรดหนึ่งไฟล์เป็นแบบปรมาณูการอัปเกรดแอปพลิเคชันโดยรวมนั้นไม่ใช่หากแอปพลิเคชันประกอบด้วยหลายไฟล์ (โปรแกรมไลบรารีข้อมูล ... ) พิจารณาลำดับเหตุการณ์ต่อไปนี้:
- อินสแตนซ์ของแอปพลิเคชันเริ่มต้นแล้ว
- แอปพลิเคชันได้รับการอัพเกรด
- แอปพลิเคชันอินสแตนซ์ที่ทำงานอยู่เปิดไฟล์ข้อมูลหนึ่งไฟล์
ในขั้นตอนที่ 3 อินสแตนซ์ที่ใช้งานอยู่ของแอปพลิเคชันเวอร์ชันเก่ากำลังเปิดไฟล์ข้อมูลจากเวอร์ชันใหม่ ทำงานได้หรือไม่ขึ้นอยู่กับแอปพลิเคชันซึ่งเป็นไฟล์และจำนวนไฟล์ที่ถูกแก้ไข
หลังจากอัปเกรดคุณจะทราบว่าโปรแกรมเดิมยังคงทำงานอยู่ หากคุณต้องการรันเวอร์ชันใหม่คุณจะต้องออกจากโปรแกรมเดิมและรันเวอร์ชันใหม่ ผู้จัดการแพคเกจมักจะฆ่าและรีสตาร์ท daemons ในการอัปเกรด แต่ปล่อยให้แอปพลิเคชันผู้ใช้ปลายทางเพียงอย่างเดียว
daemons สองสามตัวมีโพรซีเดอร์พิเศษเพื่อจัดการกับการอัพเกรดโดยไม่ต้องฆ่า daemon และรอให้อินสแตนซ์ใหม่เริ่มต้นใหม่ (ซึ่งทำให้บริการขัดข้อง) นี่เป็นสิ่งจำเป็นในกรณีของinitซึ่งไม่สามารถฆ่าได้ ระบบ init จัดเตรียมวิธีในการร้องขอให้การเรียกใช้อินสแตนซ์ที่ทำงานexecve
เพื่อแทนที่ตัวเองด้วยเวอร์ชันใหม่