การเขียนโปรแกรมเพื่อรับมือกับข้อผิดพลาดของ I / O ทำให้การเขียนที่หายไปบน Linux


138

TL; DR: ถ้าเคอร์เนล Linux สูญเสียการเขียน I / O ที่บัฟเฟอร์แล้วมีวิธีใดบ้างที่แอปพลิเคชันจะค้นหา?

ฉันรู้ว่าคุณต้องfsync()แฟ้ม (และไดเรกทอรีแม่ของมัน) เพื่อความทนทาน คำถามคือหากเคอร์เนลสูญเสียบัฟเฟอร์สกปรกที่รอการเขียนเนื่องจากข้อผิดพลาด I / O แอปพลิเคชันสามารถตรวจพบสิ่งนี้และกู้คืนหรือยกเลิก?

คิดว่าแอ็พพลิเคชันฐานข้อมูล ฯลฯ ที่ลำดับการเขียนและความทนทานในการเขียนมีความสำคัญ

เขียนหายไป? อย่างไร?

ลินุกซ์เคอร์เนลสามารถป้องกันชั้นภายใต้สถานการณ์บางแพ้บัฟเฟอร์การร้องขอ I / O ที่ได้รับการส่งเรียบร้อยแล้วโดยwrite(), pwrite()ฯลฯ ด้วยข้อผิดพลาดเช่น:

Buffer I/O error on device dm-0, logical block 12345
lost page write due to I/O error on dm-0

(ดูend_buffer_write_sync(...)และend_buffer_async_write(...)ในfs/buffer.c )

ในเมล็ดที่ใหม่กว่าข้อผิดพลาดจะมี "การหายไปของ async page write"แทนเช่น:

Buffer I/O error on dev dm-0, logical block 12345, lost async page write

เนื่องจากแอปพลิเคชันwrite()จะส่งคืนโดยไม่มีข้อผิดพลาดดูเหมือนจะไม่มีวิธีรายงานข้อผิดพลาดกลับไปที่แอปพลิเคชัน

กำลังตรวจจับพวกเขาหรือ

ฉันไม่คุ้นเคยกับที่มาของเคอร์เนล แต่ฉันคิดว่ามันตั้งAS_EIOอยู่บนบัฟเฟอร์ที่ล้มเหลวที่จะถูกตัดออกถ้ามันทำการเขียนแบบ async:

    set_bit(AS_EIO, &page->mapping->flags);
    set_buffer_write_io_error(bh);
    clear_buffer_uptodate(bh);
    SetPageError(page);

แต่มันก็ไม่ชัดเจนสำหรับฉันว่าแอปพลิเคชันสามารถค้นหาข้อมูลเกี่ยวกับเรื่องนี้ได้อย่างไรในภายหลังเมื่อมันfsync()เป็นไฟล์เพื่อยืนยันว่ามันอยู่ในดิสก์

ดูเหมือนว่าwait_on_page_writeback_range(...)ในmm/filemap.cยุทธโดยdo_sync_mapping_range(...)ในfs/sync.csys_sync_file_range(...)ซึ่งเป็นเลี้ยวเรียกได้ว่า มันจะส่งคืน-EIOหากไม่สามารถเขียนบัฟเฟอร์อย่างน้อยหนึ่งบัฟเฟอร์

หากตามที่ฉันคาดเดาสิ่งนี้จะแพร่กระจายไปสู่fsync()ผลลัพธ์ของมันหากแอปพลิเคชันตื่นตระหนกและพบว่าเกิดข้อผิดพลาด I / O จากfsync()และรู้วิธีการทำงานของมันอีกครั้งเมื่อรีสตาร์ทนั่นควรจะป้องกันอย่างเพียงพอหรือไม่

มีสันนิษฐานว่าวิธีการที่แอปรู้ว่าไม่มีซึ่งไบต์ชดเชยในสอดคล้องไฟล์ไปยังหน้าหายไปดังนั้นจึงสามารถเขียนพวกเขาถ้ามันรู้วิธี แต่ถ้าแอปซ้ำการทำงานทั้งหมดที่ค้างอยู่ตั้งแต่ช่วงที่ประสบความสำเร็จfsync()ของไฟล์และเขียนใหม่ว่า บัฟเฟอร์เคอร์เนลสกปรกใด ๆ ที่สอดคล้องกับการเขียนที่หายไปกับไฟล์ซึ่งควรล้างการตั้งค่าสถานะข้อผิดพลาด I / O ใด ๆ บนเพจที่สูญหายและอนุญาตให้ทำรายการถัดfsync()ไปจนเสร็จสมบูรณ์ใช่ไหม

มีสถานการณ์อื่นใดที่ไม่เป็นอันตรายซึ่งfsync()อาจกลับมาอีก-EIOเมื่อการประกันตัวออกไปและการทำซ้ำจะรุนแรงเกินไปหรือไม่?

ทำไม?

แน่นอนข้อผิดพลาดดังกล่าวไม่ควรเกิดขึ้น ในกรณีนี้ข้อผิดพลาดเกิดขึ้นจากการโต้ตอบที่โชคร้ายระหว่างdm-multipathค่าเริ่มต้นของไดรเวอร์และรหัสการรับรู้ที่ SAN ใช้เพื่อรายงานความล้มเหลวในการจัดสรรพื้นที่เก็บข้อมูลแบบ thin-provisioned แต่นี่ไม่ใช่เหตุการณ์เดียวที่พวกเขาสามารถเกิดขึ้นได้ฉันได้เห็นรายงานของมันจาก LVM แบบบางที่จัดเตรียมไว้เช่นที่ใช้โดย libvirt, Docker และอีกมากมาย แอปพลิเคชันที่สำคัญเช่นฐานข้อมูลควรพยายามจัดการกับข้อผิดพลาดดังกล่าวแทนที่จะดำเนินการอย่างสุ่มสี่สุ่มห้าราวกับว่าทั้งหมดนั้นดี

ถ้าเคอร์เนลคิดว่ามันโอเคที่จะสูญเสียการเขียนโดยไม่ต้องตายด้วยความตื่นตระหนกของเคอร์เนลแอปพลิเคชันต้องหาวิธีรับมือ

ผลกระทบในทางปฏิบัติคือฉันพบกรณีที่ปัญหา multipath กับ SAN ทำให้เกิดการเขียนที่หายไปซึ่งทำให้เกิดความเสียหายของฐานข้อมูลเนื่องจาก DBMS ไม่ทราบว่าการเขียนล้มเหลว ไม่สนุก.


1
ฉันกลัวว่านี่จะต้องมีฟิลด์เพิ่มเติมใน SystemFileTable เพื่อจัดเก็บ & จำเงื่อนไขข้อผิดพลาดเหล่านี้ และความเป็นไปได้ที่กระบวนการ userspace จะรับหรือตรวจสอบพวกเขาในการโทรครั้งต่อไป (fsync () และปิด () ส่งคืนข้อมูลประวัติศาสตร์ประเภทนี้หรือไม่)
joop

@joop ขอบคุณ ฉันเพิ่งโพสต์คำตอบกับสิ่งที่ฉันคิดว่าเกิดขึ้นใจมีสติตรวจสอบเพราะคุณดูเหมือนจะรู้เพิ่มเติมเกี่ยวกับสิ่งที่เกิดขึ้นกว่าคนที่ได้โพสต์ตัวแปรที่ชัดเจนของ "เขียน () ต้องการปิด () หรือ fsync ( ) เพื่อความทนทาน "โดยไม่ต้องอ่านคำถาม?
Craig Ringer

BTW: ฉันคิดว่าคุณควรเจาะลึกลงไปในแหล่งเคอร์เนล ระบบไฟล์ที่ถูกเจอร์นัลอาจมีปัญหาแบบเดียวกัน ไม่ต้องพูดถึงการจัดการพาร์ติชัน swap เนื่องจากสิ่งเหล่านี้อาศัยอยู่ในพื้นที่เคอร์เนลการจัดการเงื่อนไขเหล่านี้อาจจะเข้มงวดกว่านี้เล็กน้อย writev () ซึ่งสามารถมองเห็นได้จาก userspace ดูเหมือนว่าสถานที่ที่จะมอง [ที่เครก: ใช่เพราะฉันรู้จักชื่อของคุณและฉันรู้ว่าคุณไม่ใช่คนงี่เง่าที่สมบูรณ์ -]
joop

1
ฉันเห็นด้วยฉันไม่ยุติธรรมเลย อนึ่งคำตอบของคุณไม่ค่อยน่าพอใจฉันหมายถึงไม่มีวิธีแก้ปัญหาง่าย ๆ (น่าประหลาดใจ?)
Jean-Baptiste Yunès

1
@ Jean-BaptisteYunès True สำหรับ DBMS ที่ฉันทำงานด้วย "ขัดข้องและป้อนการทำซ้ำ" เป็นที่ยอมรับ สำหรับแอพส่วนใหญ่ที่ไม่ใช่ตัวเลือกและพวกเขาอาจต้องทนต่อประสิทธิภาพที่น่ากลัวของ I / O แบบซิงโครนัสหรือยอมรับพฤติกรรมที่กำหนดไว้อย่างไม่ดีและการทุจริตในข้อผิดพลาดของ I / O
Craig Ringer

คำตอบ:


91

fsync()ส่งคืน-EIOถ้าเคอร์เนลสูญเสียการเขียน

(หมายเหตุ: ส่วนแรกอ้างอิงถึงเมล็ดที่เก่ากว่า; อัปเดตด้านล่างเพื่อสะท้อนถึงเมล็ดที่ทันสมัย)

ดูเหมือนว่าการเขียนทับบัฟเฟอร์ async ในend_buffer_async_write(...)ความล้มเหลวตั้งค่า-EIOสถานะในหน้าบัฟเฟอร์สกปรกที่ล้มเหลวสำหรับไฟล์ :

set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);

ซึ่งมีการตรวจพบแล้วโดยwait_on_page_writeback_range(...)เรียกว่าโดยdo_sync_mapping_range(...)เรียกว่าโดยsys_sync_file_range(...)เรียกว่าโดยที่จะใช้โทรห้องสมุดsys_sync_file_range2(...) Cfsync()

แต่เพียงครั้งเดียว!

ความคิดเห็นนี้เมื่อ sys_sync_file_range

168  * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any
169  * I/O errors or ENOSPC conditions and will return those to the caller, after
170  * clearing the EIO and ENOSPC flags in the address_space.

แนะนำว่าเมื่อfsync()ส่งคืน-EIOหรือ (ไม่มีเอกสารใน manpage) -ENOSPCจะล้างสถานะข้อผิดพลาดดังนั้นลำดับต่อมาfsync()จะรายงานความสำเร็จแม้ว่าจะไม่เคยเขียนหน้าเว็บ

พอwait_on_page_writeback_range(...) ล้างข้อผิดพลาดบิตเมื่อมันทดสอบพวกเขา :

301         /* Check for outstanding write errors */
302         if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
303                 ret = -ENOSPC;
304         if (test_and_clear_bit(AS_EIO, &mapping->flags))
305                 ret = -EIO;

ดังนั้นหากแอปพลิเคชันคาดว่าจะสามารถลองได้อีกครั้งfsync()จนกว่าจะประสบความสำเร็จและเชื่อถือได้ว่าข้อมูลนั้นอยู่บนดิสก์มันผิดอย่างมาก

ฉันค่อนข้างแน่ใจว่านี่คือที่มาของความเสียหายของข้อมูลที่ฉันพบใน DBMS มันลองใหม่fsync()และคิดว่าทุกอย่างจะดีเมื่อสำเร็จ

ได้รับอนุญาตหรือไม่

POSIX / เอกสาร SUS บนfsync()ไม่ได้จริงๆระบุทั้งทางนี้:

หากฟังก์ชัน fsync () ล้มเหลวการดำเนินการ I / O ที่ยอดเยี่ยมจะไม่รับประกันว่าจะเสร็จสมบูรณ์

ลินุกซ์ของ man-page สำหรับfsync()เพียงแค่ไม่พูดอะไรเกี่ยวกับสิ่งที่เกิดขึ้นกับความล้มเหลว

ดังนั้นดูเหมือนว่าความหมายของfsync()ข้อผิดพลาดคือ "ไม่เกิดอะไรขึ้นกับการเขียนของคุณอาจจะใช้งานได้หรือไม่ดีกว่าลองอีกครั้งเพื่อให้แน่ใจ"

ใหม่กว่าเมล็ด

เมื่อวันที่ 4.9 end_buffer_async_writeชุดบนหน้าเว็บเพียงผ่าน-EIOmapping_set_error

    buffer_io_error(bh, ", lost async page write");
    mapping_set_error(page->mapping, -EIO);
    set_buffer_write_io_error(bh);
    clear_buffer_uptodate(bh);
    SetPageError(page);

ในด้านการซิงค์ฉันคิดว่ามันคล้ายกันแม้ว่าตอนนี้โครงสร้างจะค่อนข้างซับซ้อนที่จะติดตาม filemap_check_errorsในmm/filemap.cตอนนี้จะ:

    if (test_bit(AS_EIO, &mapping->flags) &&
        test_and_clear_bit(AS_EIO, &mapping->flags))
            ret = -EIO;

ซึ่งมีผลเหมือนกันมาก การตรวจสอบข้อผิดพลาดดูเหมือนจะผ่านfilemap_check_errorsการทดสอบและชัดเจน:

    if (test_bit(AS_EIO, &mapping->flags) &&
        test_and_clear_bit(AS_EIO, &mapping->flags))
            ret = -EIO;
    return ret;

ฉันกำลังใช้btrfsบนแล็ปท็อปของฉัน แต่เมื่อฉันสร้างext4ลูปแบ็คเพื่อทำการทดสอบ/mnt/tmpและตั้งค่าโพรบบน:

sudo dd if=/dev/zero of=/tmp/ext bs=1M count=100
sudo mke2fs -j -T ext4 /tmp/ext
sudo mount -o loop /tmp/ext /mnt/tmp

sudo perf probe filemap_check_errors

sudo perf record -g -e probe:end_buffer_async_write -e probe:filemap_check_errors dd if=/dev/zero of=/mnt/tmp/test bs=4k count=1 conv=fsync

ฉันพบ call stack ต่อไปนี้ในperf report -T:

        ---__GI___libc_fsync
           entry_SYSCALL_64_fastpath
           sys_fsync
           do_fsync
           vfs_fsync_range
           ext4_sync_file
           filemap_write_and_wait_range
           filemap_check_errors

การอ่านผ่านแสดงให้เห็นว่าใช่เมล็ดในปัจจุบันมีพฤติกรรมเหมือนกัน

ดูเหมือนว่าหมายความว่าหากfsync()((หรือสมมุติwrite()หรือclose()) ส่งคืน-EIOไฟล์จะอยู่ในสถานะที่ไม่ได้กำหนดบางอย่างระหว่างเมื่อคุณประสบความสำเร็จในการfsync()d หรือclose()d และล่าสุดเป็นwrite()สิบสถานะล่าสุด

ทดสอบ

ฉันใช้กรณีทดสอบเพื่อสาธิตพฤติกรรมนี้

ผลกระทบ

DBMS สามารถรับมือกับสิ่งนี้ได้โดยการเข้าสู่การกู้คืนความผิดพลาด แอปพลิเคชันผู้ใช้ทั่วไปบนโลกควรจะรับมือกับสิ่งนี้อย่างไร fsync()หน้าคนให้เตือนว่ามันหมายความว่า "fsync ถ้าคุณรู้สึกเหมือนมัน" และผมคาดว่าไม่มากปพลิเคชันจะไม่ดีรับมือกับปัญหานี้

รายงานบั๊ก

อ่านเพิ่มเติม

lwn.net สัมผัสเกี่ยวกับเรื่องนี้ในบทความ "จัดการข้อผิดพลาดที่ดีขึ้นบล็อกชั้น"

postgresql.org ด้ายรายชื่อผู้รับจดหมาย


3
lxr.free-electrons.com/source/fs/buffer.c?v=2.6.26#L598เป็นการแข่งขันที่เป็นไปได้เนื่องจากรอ {{& I / O ที่กำหนดเวลาไว้} ไม่ใช่สำหรับ {ยังไม่ได้กำหนด I / O} เห็นได้ชัดว่านี่คือการหลีกเลี่ยงการไปกลับอุปกรณ์พิเศษ (ฉันถือว่าผู้ใช้เขียน () ไม่กลับจนกว่าจะมีการกำหนด I / O สำหรับ mmap () ซึ่งแตกต่างกัน)
joop

3
เป็นไปได้ไหมว่าการเรียกกระบวนการ fsync สำหรับไฟล์อื่น ๆ ในดิสก์เดียวกันทำให้เกิดข้อผิดพลาด?
Random832

3
@ Random832 มีความเกี่ยวข้องมากสำหรับการประมวลผลฐานข้อมูลหลายอย่างเช่น PostgreSQL คำถามที่ดีมาก ดูเหมือนว่าจะเป็นไปได้ แต่ฉันไม่รู้รหัสเคอร์เนลที่ดีพอที่จะเข้าใจ procs ของคุณควรร่วมมือกันถ้าทั้งคู่มีไฟล์เดียวกันเปิดอยู่
Craig Ringer

1
@DavidFoerster: syscalls ส่งคืนความล้มเหลวโดยใช้รหัส errno ที่เป็นลบ errnoเป็นโครงสร้างของไลบรารี C userspace ทั้งหมด เป็นเรื่องปกติที่จะเพิกเฉยความแตกต่างของค่าส่งคืนระหว่าง syscalls และไลบรารี C เช่นนี้ (อย่างที่ Craig Ringer ทำเหนือ) เนื่องจากค่าส่งคืนข้อผิดพลาดระบุได้อย่างน่าเชื่อถือว่าหนึ่ง (syscall หรือฟังก์ชัน C ไลบรารี) จะถูกอ้างถึง: " -1with errno==EIO"หมายถึงฟังก์ชันไลบรารี C ในขณะที่" -EIO"หมายถึง syscall สุดท้ายหน้า man Linux ออนไลน์เป็นข้อมูลอ้างอิงล่าสุดสำหรับหน้า man Linux
สัตว์ที่กำหนด

2
@CraigRinger: เพื่อตอบคำถามสุดท้ายของคุณ: "โดยใช้ I / O ระดับต่ำและfsync()/ fdatasync()เมื่อขนาดของธุรกรรมเป็นไฟล์ที่สมบูรณ์โดยใช้mmap()/ msync()เมื่อขนาดของธุรกรรมเป็นระเบียนที่จัดเรียงหน้าและโดยใช้ระดับต่ำ I / O fdatasync()และหลายงานพร้อมกันอธิบายไฟล์ (หนึ่งบ่งและด้ายต่อรายการ) เพื่อไฟล์เดียวกันมิฉะนั้น" ล็อกคำอธิบายไฟล์ที่เปิดเฉพาะสำหรับ Linux ( fcntl(), F_OFD_) มีประโยชน์มากสำหรับไฟล์ล่าสุด
สัตว์ที่กำหนด

22

เนื่องจากการเขียนของแอปพลิเคชัน () จะกลับมาโดยไม่มีข้อผิดพลาดดูเหมือนจะไม่มีวิธีรายงานข้อผิดพลาดกลับไปที่แอปพลิเคชัน

ผมไม่เห็นด้วย. writeสามารถส่งคืนได้โดยไม่มีข้อผิดพลาดถ้าการเขียนนั้นอยู่ในคิว แต่ข้อผิดพลาดจะถูกรายงานในการดำเนินการครั้งต่อไปที่จะต้องมีการเขียนจริงบนดิสก์นั่นหมายถึงfsyncการเขียนครั้งต่อไป อย่างน้อยในไฟล์สุดท้ายปิด

นี่คือเหตุผลว่าทำไมจึงเป็นสิ่งจำเป็นสำหรับแอปพลิเคชันในการทดสอบค่าส่งคืนของการปิดเพื่อตรวจหาข้อผิดพลาดในการเขียนที่เป็นไปได้

หากคุณจำเป็นต้องทำการประมวลผลข้อผิดพลาดที่ฉลาดจริงๆคุณต้องสมมติว่าทุกอย่างที่เขียนตั้งแต่การประสบความสำเร็จครั้งล่าสุดfsync อาจล้มเหลวและทุกสิ่งที่ล้มเหลว


4
ใช่ฉันคิดว่าเล็บมัน นี้แน่นอนขอแนะนำว่าโปรแกรมประยุกต์ที่ควรอีกครั้งทำทุกอย่างตั้งแต่สุดท้ายได้รับการยืนยันที่ประสบความสำเร็จfsync()หรือclose()ของไฟล์ถ้ามันได้รับ-EIOจากwrite(), หรือfsync() close()ก็สนุกดี
Craig Ringer

1

write(2) ให้บริการน้อยกว่าที่คุณคาดหวัง หน้าคนเปิดกว้างเกี่ยวกับความหมายของการwrite()โทรที่ประสบความสำเร็จ:

การส่งคืนที่สำเร็จจากwrite()ไม่รับประกันว่าข้อมูลได้ถูกส่งไปยังดิสก์แล้ว ในความเป็นจริงในการใช้งานบั๊กกี้บางอย่างมันไม่ได้รับประกันว่าพื้นที่จะถูกจองไว้สำหรับข้อมูลเรียบร้อยแล้ว วิธีเดียวที่จะแน่ใจได้คือการโทรfsync(2) หลังจากที่คุณเขียนข้อมูลทั้งหมดเสร็จแล้ว

เราสามารถสรุปได้ว่าการประสบความสำเร็จwrite()นั้นหมายถึงว่าข้อมูลได้มาถึงสิ่งอำนวยความสะดวกการบัฟเฟอร์ของเคอร์เนล หากการเก็บบัฟเฟอร์ล้มเหลวการเข้าถึงไฟล์ descriptor ในภายหลังจะส่งคืนรหัสข้อผิดพลาด close()ในฐานะที่เป็นทางเลือกสุดท้ายที่อาจจะ man page ของการcloseเรียกระบบ (2) มีประโยคต่อไปนี้:

อาจเป็นไปได้ว่ามีการรายงานข้อผิดพลาดในการwriteดำเนินการ (2) ก่อนหน้าในขั้นสุดท้ายclose()

หากแอปพลิเคชันของคุณต้องคงข้อมูลที่ถูกลบทิ้งไว้มันจะต้องใช้งานfsync/ fsyncdataเป็นประจำ:

fsync()ถ่ายโอน ("flushes") ข้อมูล in-core ที่แก้ไขทั้งหมดของ (เช่นเพจแคชบัฟเฟอร์ที่แก้ไขแล้ว) ไฟล์ที่อ้างถึงโดย file descriptor fd ไปยังอุปกรณ์ดิสก์ (หรืออุปกรณ์เก็บข้อมูลถาวรอื่น ๆ ) เพื่อให้สามารถดึงข้อมูลที่เปลี่ยนแปลงทั้งหมดได้ แม้หลังจากระบบล้มเหลวหรือถูกรีบูต ซึ่งรวมถึงการเขียนหรือล้างแคชดิสก์หากมีอยู่ การโทรจะบล็อกจนกว่าอุปกรณ์จะรายงานว่าการถ่ายโอนเสร็จสิ้น


4
ใช่ฉันรู้ว่าfsync()จำเป็น แต่ในกรณีเฉพาะที่เคอร์เนลสูญเสียหน้าเนื่องจากข้อผิดพลาด I / Oจะfsync()ล้มเหลว? ภายใต้สถานการณ์ใดที่จะสามารถประสบความสำเร็จในภายหลัง
Craig Ringer

ฉันก็ไม่ทราบว่าที่มาของเคอร์เนล สมมติว่าfsync()ผลตอบแทน-EIOจากปัญหา I / O (จะเป็นอย่างอื่นดี?) ดังนั้นฐานข้อมูลจึงทราบว่าการเขียนก่อนหน้านี้ล้มเหลวและสามารถเข้าสู่โหมดการกู้คืนได้ นี่ไม่ใช่สิ่งที่คุณต้องการ? แรงจูงใจของคำถามสุดท้ายของคุณคืออะไร? คุณต้องการที่จะรู้ว่าการเขียนที่ล้มเหลวหรือกู้คืนไฟล์ descriptor เพื่อใช้งานต่อไปหรือไม่?
fzgregor

ในอุดมคติแล้ว DBMS จะไม่ต้องการเข้าสู่การกู้คืนความผิดพลาด (เริ่มจากผู้ใช้ทั้งหมดและไม่สามารถเข้าถึงได้ชั่วคราวหรืออย่างน้อยอ่านอย่างเดียว) หากสามารถหลีกเลี่ยงได้ แต่แม้ว่าเคอร์เนลสามารถบอกเราว่า "bytes 4096 ถึง 8191 ของ fd X" มันยากที่จะคิดออกว่าจะเขียนอะไรอีกครั้งโดยไม่ต้องทำการกู้คืนความเสียหาย ดังนั้นผมคิดว่าคำถามหลักคือว่ามีสถานการณ์บริสุทธิ์ใด ๆ ที่fsync()อาจจะกลับมา-EIOที่มันเป็นความปลอดภัยที่จะลองใหม่อีกครั้งและถ้ามันเป็นไปได้ที่จะบอกความแตกต่าง
Craig Ringer

การกู้คืนความผิดพลาดที่แน่นอนเป็นทางเลือกสุดท้าย แต่อย่างที่คุณพูดไปแล้วปัญหาเหล่านี้คาดว่าจะหายากมาก -EIOดังนั้นผมไม่เห็นปัญหาเกี่ยวกับการที่จะเข้าสู่การกู้คืนที่ใด ๆ หากแต่ละไฟล์ descriptor ถูกใช้โดยทีละหนึ่งเธรดเท่านั้นเธรดนี้สามารถย้อนกลับไปที่fsync()การwrite()โทรครั้งสุดท้ายและทำการโทรซ้ำ แต่ถึงกระนั้นหากสิ่งเหล่านั้นwrite()เขียนเพียงส่วนหนึ่งของส่วนส่วนที่ไม่ได้แก้ไขอาจยังเสียหาย
fzgregor

1
คุณพูดถูกว่าการกู้คืนความผิดพลาดนั้นสมเหตุสมผล ในฐานะที่เป็นภาคส่วนที่เสียหายบางส่วนที่ DBMS (PostgreSQL) เก็บภาพของทั้งหน้าเป็นครั้งแรกที่มันสัมผัสได้หลังจากที่ด่านใดก็ตามด้วยเหตุผลเพียงว่าดังนั้นจึงควรจะปรับ :)
เครก Ringer

0

ใช้การตั้งค่าสถานะ O_SYNC เมื่อคุณเปิดไฟล์ ช่วยให้มั่นใจว่าข้อมูลถูกเขียนลงดิสก์

หากสิ่งนี้ไม่เป็นที่พอใจคุณก็จะไม่มีอะไรเกิดขึ้น


17
O_SYNCเป็นฝันร้ายสำหรับการแสดง หมายความว่าแอปพลิเคชันไม่สามารถทำสิ่งอื่นได้ในขณะที่ดิสก์ I / O เกิดขึ้นเว้นแต่ว่ามันจะวางไข่นอกเธรด I / O คุณอาจพูดได้ว่าอินเตอร์เฟส I / O ที่บัฟเฟอร์ไม่ปลอดภัยและทุกคนควรใช้ AIO การเขียนที่หายไปอย่างเงียบ ๆ ไม่สามารถยอมรับได้ในบัฟเฟอร์ I / O?
Craig Ringer

3
( O_DATASYNCในเรื่องนั้นดีกว่าเล็กน้อยเท่านั้น)
Craig Ringer

@CraigRinger คุณควรใช้ AIO หากคุณต้องการและต้องการประสิทธิภาพใด ๆ หรือเพียงแค่ใช้ DBMS; มันจัดการทุกอย่างให้คุณ
Demi

10
@Demi แอปพลิเคชันที่นี่คือ dbms (postgresql) ฉันแน่ใจว่าคุณสามารถจินตนาการได้ว่าการเขียนแอปพลิเคชันทั้งหมดเพื่อใช้ AIO แทน I / O ที่ถูกบัฟเฟอร์ไม่เป็นประโยชน์ และไม่จำเป็นต้องมี
Craig Ringer

-5

ตรวจสอบค่าส่งคืนของการปิด การปิดสามารถล้มเหลวในขณะที่การเขียนบัฟเฟอร์ดูเหมือนจะสำเร็จ


8
เราต้องการที่จะรับopen()และclose()ส่งไฟล์ทุกสองสามวินาที นั่นเป็นเหตุผลที่เรามีfsync()...
เครก Ringer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.