代码之家  ›  专栏  ›  技术社区  ›  f0b0s

fflush和'no disk space left'

  •  0
  • f0b0s  · 技术社区  · 15 年前

    我正在写一个程序,一种数据库。当我在看手册的时候 fclose(3) 我发现它叫 fflush(3) 冲洗 FILE* 缓冲区到磁盘(实际上是到操作系统缓冲区,但现在并不重要,我们可以随时调用 fsync(2) )

    因为我在写数据库,很明显我想防止数据丢失。如果没有磁盘空间, 弗卢什(3) 在里面 FHOCT(3) 失败,我们将丢失数据,因为

    使用 文件* 在发生错误后 fclose() 会导致未定义的行为

    所以我想明确使用 弗卢什(3) 之前 FHOCT(3) ,警告用户磁盘空间不足并重新调用 弗卢什(3) 过了一会儿。

    我读过 C 标准,认为这是个好主意。在实践中,失败后 fflush 第二个调用将始终返回0(无错误),但实际上不会执行任何操作。 fsync 没有帮助我(我以为数据可能保存在RAM中)。

    在这种情况下,如何防止数据丢失?也许有一些经验法则。

    这是我的测试代码:

    #include <stdio.h>
    int main()
    {
        FILE *a = fopen("/tmp/1", "wb")
        if ( !a )
            perror("fopen");
    
        if ( fwrite("test", 1, 4, a) != 4 )
            perror("fwrite");  // always OK, cause data is buffered
    
    
        while( fflush(a) )  // ...second call will always return 0!
        {
            perror("fflush");  // if there is no disk space, I will get this perror, but ...
        }
    
    
        if ( fclose(a) )  // always ok, because calls only close(2)
            perror("fclose"); 
    
        return 0;
    }
    
    4 回复  |  直到 9 年前
        1
  •  3
  •   Jonathan Leffler vy32    15 年前

    后续fflush()操作成功的原因是没有(新)数据可写入磁盘。第一个fflush()失败了;这是一个悲剧,但却是历史。随后的fflush()与此无关,因此它成功地做到了这一点。

    如果您要写入数据库,那么每次写入都必须小心,而不仅仅是在最后处理问题。根据您的数据有多重要,您可能需要通过各种旋转来处理问题——DBMS之所以复杂是有原因的,失败的写入就是其中之一。

    解决这个问题的一种方法是预先为数据分配空间。正如其他人所指出的,经典的Unix文件系统允许稀疏文件(存在空块且没有为其分配磁盘空间的文件),因此实际上您必须将一些数据写入需要分配的每个页面。然后,当您扩展空间时,您只需要担心“磁盘已满”的问题——并且您知道何时这样做,并且可以小心地处理该故障。

    在基于Unix的系统上,有多种系统调用可以帮助您同步磁盘上的数据,以及“打开”等选项。这些选项包括“o\u dsync”和相关值。但是,如果要扩展一个文件,它们仍然会导致“空间不足”的故障,即使使用了复杂的同步选项也是如此。当你遇到这种失败时,你必须等待空间变为可用(因为你要求用户告诉你空间何时可用),然后再尝试写。

        2
  •  1
  •   Duck    15 年前

    您可以预先分配一些合理的磁盘空间。编写、刷新和fsync一些二进制零(或其他),然后返回到原来的位置。必要时冲洗并重复。如有必要,请记住截断。

    有点疼,但应该管用。

        3
  •  1
  •   Aryabhatta    15 年前

    fflush只将C库内部缓冲区刷新到操作系统,因此fflush不能保证不会丢失数据。

    重复调用fflush(没有中间的fwrities)不会有帮助,因为您已经将数据刷新到操作系统一次了。第二个快速的呼叫会像现在一样成功 没有什么 冲洗到操作系统。如果由于硬盘已满而导致fflush失败,那么您已经丢失了一些数据。

    要将数据刷新到磁盘,请 需要 使用FSYNC。

    如果硬盘满了,你就走运了。防止数据丢失的唯一方法是保持进程的活动状态(以及内存中的数据:在用户空间/内核文件缓冲区中),直到在磁盘上找到一些空间进行fsync。如果停电了,你 丢失数据。

    简而言之,如果您的硬盘已满,就无法保证不会丢失数据。

        4
  •  0
  •   Steve Emmerson    15 年前

    在做任何事情之前,您可以将(3)保存到文件的末尾(假设您知道文件的长度)。这样就消除了磁盘空间不足导致故障的可能性。