2012-11-13 124 views
1

我目前正在實施ping/pong緩衝方案來安全地將文件寫入磁盤。我在Linux/CentOS機器上使用C++/Boost。現在我面臨的問題是強制將文件實際寫入磁盤。不管文件系統的所有緩存策略(ext3/ext4)/ SO自定義規則/ RAID控制器/硬盤控制器,是否可以這樣做?強制將文件寫入磁盤

最好是使用普通的fread()/ fwrite(),C++ ostream或boost文件系統嗎?

我聽說,只是沖洗出來的文件(fflush())並不能保證實際寫入

謝謝!

回答

5

fflush(用於FILE *),std :: flush(用於IOStream)強制程序發送到操作系統。

POSIX有

  • 同步(2)要求安排寫其緩衝區,但可以寫入完成之前返回(Linux正在等待數據是在返回前發送到硬件)。 (2)這是保證等待數據發送到硬件,但需要一個文件描述符(你可以從FILE *獲得一個fileno(3),我知道沒有標準的方式從IOStream獲得一個)。

  • O_SYNC作爲打開標誌(2)。

在所有情況下,硬件可以有它自己的緩衝區(但如果上有控制,良好的實現將嘗試也刷新他們ISTR一些磁盤使用電容器,使他們能夠清除發生的任何事情)和網絡文件系統有他們自己的警告。

+0

而對於C++流,操作符是'std :: flush'而不是'fflush'。 –

+0

謝謝!所以我必須強制我的程序首先提交文件系統(fflush/flush),然後強制SO將其提交到磁盤控制器(sync)。你能告訴我一些概念驗證碼嗎? –

+0

@JoachimPileborg,這就是我打算用太簡潔(f)沖洗來表示的,我澄清了。 – AProgrammer

0

不是標準的C++。您必須使用某種系統特定的 IO,例如open,在Unix下爲O_SYNC標誌,然後爲write

請注意,這部分隱含於ostream(和 C,FILE*)被緩衝。如果您不確切地知道什麼時候寫入磁盤的東西是 ,那麼堅持寫入的事務完整性沒有多大意義。 (這不會是太難 設計streambuf只有當你做一個明確的紅暈,不過 寫。)

編輯:

舉個簡單的例子:

class SynchronizedStreambuf : public std::streambuf 
{ 
    int myFd; 
    std::vector<char> myBuffer; 

protected: 
    virtual int overflow(int ch); 
    virtual int sync(); 

public: 
    SynchronizedStreambuf(std::string const& filename); 
    ~SynchronizedStreambuf(); 
}; 

int SynchronizedStreambuf::overflow(int ch) 
{ 
    if (myFd == -1) { 
     return traits_type::eof(); 
    } else if (ch == traits_type::eof()) { 
     return sync() == -1 ? traits_type::eof() : 0; 
    } else { 
     myBuffer.push_back(ch); 
     size_t nextPos = myBuffer.size(); 
     myBuffer.resize(1000); 
     setp(&myBuffer[0] + nextPos, &myBuffer[0] + myBuffer.size()); 
     return ch; 
    } 
} 

int SynchronizedStreambuf::sync() 
{ 
    size_t toWrite = pptr() - &myBuffer[0]; 
    int result = (toWrite == 0 || write(myFd, &myBuffer[0], toWrite) == toWrite ? 0 : -1); 
    if (result == -1) { 
     close(myFd); 
     setp(NULL, NULL); 
     myFd = -1; 
    } else { 
     setp(&myBuffer[0], &myBuffer[0] + myBuffer.size()); 
    } 
    return result; 
} 

SynchronizedStreambuf::SynchronizedStreambuf(std::string const& filename) 
    : myFd(open(filename.c_str(), O_WRONLY | O_CREAT | O_SYNC, 0664)) 
{ 
} 

SynchronizedStreambuf::~SynchronizedStreambuf() 
{ 
    sync(); 
    close(myFd); 
} 

(這只是表面測試過的,但基本思路就是這樣。)

1

您可以使用fsync()/ fdatasync() ce(注1)將數據存入存儲器。 這些請求文件描述符,例如,打開()。 linux manpage有更多的linux特定的信息,特別是在fsync和fdatasync的區別。

如果您不直接使用文件描述符,許多抽象將包含駐留在您的過程中的內部緩衝區。

例如如果您使用FILE *,則必須首先將數據從應用程序中清除。

//... open and write data to a FILE *myfile 
fflush(myfile); 
fsync(fileno(myfile)); 
  • 注1:這些調用強制操作系統,以確保在任何操作系統的緩存上的所有數據被寫入到驅動器,並且驅動承認這一事實。許多硬盤驅動器都在操作系統中,可能會將數據填充到驅動器上的高速緩存中。
+0

fclose()呢?我們需要它嗎? –

+0

@G_G當你完成文件*,關閉文件,然後使用fclose() – nos

+0

對不起,我的意思是當直接使用文件描述符;我們是否需要明確的關閉(fd)呼叫? –