การเปิดใช้งาน/ปิดใช้งานโหมด Wal2
- โหมด "Wal2" ของ SQLite มีความคล้ายกับโหมด "wal (Write-Ahead Logging)" อย่างมาก
- หากต้องการเปลี่ยนฐานข้อมูลเป็นโหมด wal2 ให้ใช้คำสั่ง
PRAGMA journal_mode = wal2;
- ไม่สามารถเปลี่ยนจากโหมด "wal" ไปเป็นโหมด "wal2" ได้โดยตรง และต้องเปลี่ยนเป็นโหมด rollback ก่อน
- หากต้องการเปลี่ยนฐานข้อมูลโหมด wal ให้เป็นโหมด wal2 ให้ใช้คำสั่ง
PRAGMA journal_mode = delete; จากนั้นจึงใช้ PRAGMA journal_mode = wal2;
- ฐานข้อมูลโหมด wal2 สามารถเข้าถึงได้เฉพาะจาก SQLite เวอร์ชันที่คอมไพล์จากบรাঞ্চนั้นเท่านั้น
- หากพยายามใช้ SQLite เวอร์ชันอื่น จะเกิดข้อผิดพลาด SQLITE_NOTADB
- หากต้องการเปลี่ยนฐานข้อมูลโหมด wal2 กลับเป็นโหมด rollback เพื่อให้ SQLite ทุกเวอร์ชันเข้าถึงได้ ให้ใช้คำสั่ง
PRAGMA journal_mode = delete;
ข้อดีของโหมด Wal2
- ในโหมด wal เดิม เมื่อ writer เขียนข้อมูลลงฐานข้อมูล จะไม่แก้ไขไฟล์ฐานข้อมูลโดยตรง แต่จะเพิ่มข้อมูลใหม่ลงในไฟล์ "-wal"
- การอ่านข้อมูลจะอ่านจากทั้งไฟล์ฐานข้อมูลต้นฉบับและไฟล์ "-wal"
- ในบางช่วงเวลา ข้อมูลจากไฟล์ "-wal" จะถูกคัดลอกกลับไปยังไฟล์ฐานข้อมูล ซึ่งเรียกว่า "checkpoint"
- checkpoint อาจทำแบบระบุชัดเจนผ่าน
PRAGMA wal_checkpoint หรือ sqlite3_wal_checkpoint_v2() หรือทำโดยอัตโนมัติด้วยการตั้งค่า PRAGMA wal_autocheckpoint (ค่าเริ่มต้น)
- checkpointer จะไม่บล็อก writer และ writer ก็จะไม่บล็อก checkpointer
- แต่หาก writer เขียนลงฐานข้อมูลระหว่าง checkpoint ข้อมูลใหม่จะถูกเพิ่มต่อที่ท้ายไฟล์ wal ทำให้ไฟล์ wal อาจโตขึ้นเรื่อยๆ
- ในโหมด wal2 จะไม่มีปัญหาไฟล์ wal โตไม่สิ้นสุด แม้ checkpointer จะไม่มีโอกาสทำงานจนเสร็จโดยไม่ถูกรบกวน
- ในโหมด wal2 จะใช้ไฟล์ wal สองไฟล์แทนหนึ่งไฟล์ ("-wal" และ "-wal2")
- เมื่อมีการเขียนข้อมูล writer จะเริ่มเพิ่มข้อมูลใหม่ลงในไฟล์ wal แรก
- เมื่อไฟล์ wal แรกมีขนาดใหญ่พอ writer จะเริ่มเพิ่มข้อมูลลงในไฟล์ wal ที่สอง
- หลังจากนั้นไฟล์ wal แรกจะสามารถทำ checkpoint ได้ และเมื่อไฟล์ wal ที่สองมีขนาดใหญ่พอและไฟล์แรกถูก checkpoint แล้ว ก็จะสลับกลับไปใช้ไฟล์แรกอีกครั้ง
การเขียนโปรแกรมประยุกต์
- จากมุมมองของผู้ใช้ ความแตกต่างหลักระหว่างโหมด wal และ wal2 เกี่ยวข้องกับ checkpoint
- ในโหมด wal สามารถพยายามทำ checkpoint ได้ทุกเมื่อ แต่ในโหมด wal2 จะทำ checkpoint ได้ก็ต่อเมื่อ writer สลับไปยังไฟล์ wal "อีกฝั่ง" แล้วเท่านั้น
- ในโหมด wal wal-hook (callback) จะถูกเรียกหลังจาก transaction commit โดยส่งจำนวนหน้าทั้งหมดในไฟล์ wal เป็นอาร์กิวเมนต์
- ในโหมด wal2 wal-hook จะถูกเรียกโดยใช้อาร์กิวเมนต์เป็นจำนวนหน้าที่ยังไม่ถูก checkpoint รวมของ wal ทั้งสองไฟล์ หรือเป็น 0 หากไฟล์ wal "อีกฝั่ง" ว่างอยู่หรือถูก checkpoint ไปแล้ว
- แนะนำให้ไคลเอนต์ใช้กลยุทธ์ checkpoint แบบเดียวกับโหมด wal สำหรับฐานข้อมูลโหมด wal2
- wal-hook จะถูกเรียกหลังจาก transaction ถูก commit ลงดิสก์และปลดล็อกฐานข้อมูลแล้ว แต่ยังเกิดขึ้นภายในการเรียก
sqlite3_step()
- ในระบบ BEGIN CONCURRENT แทนที่จะรัน checkpoint ภายใน wal-hook อาจใช้เธรดที่เลื่อนงานนี้ออกไปหลังจาก application mutex ถูกปล่อยแล้ว
ความเห็นของ GN⁺
- โหมด wal2 ของ SQLite มอบแนวทาง journaling แบบใหม่ที่ช่วยเพิ่ม concurrency และประสิทธิภาพของฐานข้อมูล
- การแก้ปัญหาไฟล์ wal โตไม่สิ้นสุดมีความสำคัญต่อการปรับปรุงเสถียรภาพและประสิทธิภาพของระบบ
- นักพัฒนาควรทบทวนกลยุทธ์ checkpoint ของฐานข้อมูลเมื่อเริ่มใช้โหมด wal2 และจำเป็นต้องออกแบบ logic checkpoint ที่เหมาะสมเพื่อให้ได้ concurrency ที่ดียิ่งขึ้น
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
Bedrock
มีการให้ลิงก์ไปยัง left-right primitive ซึ่งเป็นเทคนิคที่คล้ายกับโหมด WAL2
Microsoft SQL Server ใช้สถาปัตยกรรมที่คล้ายกัน แต่แทนที่จะใช้ไฟล์ log แยกต่างหาก จะจัดสรร Virtual Log Files (VLF) ภายในไฟล์ log ทางกายภาพ (บนดิสก์) โดย VLF จะถูกจัดสรรจาก ring buffer และอาจมีได้เป็นพันไฟล์
ดูออกเลยว่าฟีเจอร์นี้ยังไม่ออกตัวจริง
ผมกังวลมาตลอดว่า WAL มีไว้เพื่อช่วยรักษาความถูกต้องสมบูรณ์ของข้อมูลและช่วยกู้คืนจากการ crash แต่ตัวไฟล์เองกลับถูกเขียนแบบเป็นชุด ๆ (และ commit ลงดิสก์อย่างเชื่อถือได้) ไม่ใช่หลังจากทุกการเปลี่ยนแปลงในฐานข้อมูล เพื่อแลกกับประสิทธิภาพ แบบนี้มันไม่ทำลายจุดประสงค์ของมันหรือ? พูดในภาพรวม ไม่ได้จำกัดเฉพาะฐานข้อมูลนี้ และผมหาคำตอบเรื่องนี้ไม่เจอ
สงสัยว่าสิ่งนี้จะส่งผลอย่างไรกับระบบ SQLite แบบกระจายตัวรุ่นใหม่อย่าง Litestream
งั้นโดยพื้นฐานแล้วมันคือ double buffering สำหรับฐานข้อมูลใช่ไหม? ฟังดูเข้าใจได้
โหมด WAL2 ถูกรวมอยู่ในการ benchmark ของงานวิจัย HC-tree backend แล้ว