0

I am writing file handling code using C++. Problem is after writing to file if power off occures immediately, file is not getting written.

As I found problem is due to delay in writing from system buffer to persistent file storage.

I over came this scenario with bash sync command. here is code snippet

cout << "Writting to file" << endl;
ofstream fout("demo.dat", ios::out);
fout << "hello world" <<flush;
fout.close();
system("sync");
cout << "file written" << endl << "Sleeping for 3 secs"<<endl;
this_thread::sleep_for(chrono::seconds(3)); //disconnect power here
... some more statements

Problem is system() is considered bad keeping performance in mind, as I have to write to files very frequently.

Please let me know if C++ provides any better way.

I tried with std::flush, pubsync() but it does not work.

I am doing C++ style file handling so can not use C style file handling.

rakesh.sahu
  • 465
  • 8
  • 18
  • 2
    What didn't work when using `std::flush` – Inian Feb 14 '19 at 06:09
  • 2
    Did you try `fsync`? - http://pubs.opengroup.org/onlinepubs/7908799/xsh/fsync.html – Inian Feb 14 '19 at 06:11
  • 1
    @Inian AFAIK `std::flush` only guarantees that the data is completely passed to the responsibility of the OS and that any further read of that file will provide the written data. But it does not guarantee that the OS wrote the data to the hardware. – t.niese Feb 14 '19 at 06:36
  • @Inian fsync is C api which takes file descriptor. I am using ostream for file IO. Wanted to know if there is anything in C++. – rakesh.sahu Feb 14 '19 at 06:45
  • @rakesh.sahu You would need to create some system/stdlib specific code. The answer to this questioin [How to do fsync on an ofstream?](https://stackoverflow.com/questions/676787) show how this could look like. But you need to do some more research, if there are more methods to do this, and then choose the one that suits best. – t.niese Feb 14 '19 at 07:27
  • 1
    Doing a `system` call is not necessarily bad and using it in a wrapper function as fallback can be a first step. But you are right `system("sync")` can be a performance problem, as it will sync all pending writes, and not one specific file. – t.niese Feb 14 '19 at 07:29

2 Answers2

1
#include <fstream>
#include <iostream>
#include <unistd.h>

using namespace std;

class sync_filebuf : public filebuf
{
public:
    sync_filebuf(ofstream &fout)
    {
        sync_filebuf *fbuf;
        fbuf = static_cast<sync_filebuf *>(fout.rdbuf());
        fsync(fbuf->_M_file.fd());
    }
};

int main()
{
    cout << "Writting to file" << endl;
    ofstream fout("demo.dat", ios::out);
    fout << "hello world" <<flush;
    fout.flush();
    sync_filebuf x(fout);
    fout.close();
    cout << "file written" << endl << "Sleeping for 3 secs"<<endl;
    return 0;
}
ccxxshow
  • 844
  • 6
  • 5
  • 1
    This works but some explanation might be good with what it is doing and how it relates to what the OP wanted. – Duck Dodgers Feb 14 '19 at 08:33
  • I believe this answer is incomplete. `fsync` is necessary but not sufficient, see https://man7.org/linux/man-pages/man2/fdatasync.2.html - `Calling fsync() does not necessarily ensure that the entry in the directory containing the file has also reached disk. For that an explicit fsync() on a file descriptor for the directory is also needed.` – J Trana Sep 28 '21 at 21:50
1

If your concern is performance then fsync will be faster than sync because the latter will transmit all the datas cached by the kernel and waiting to be written to the hard drive controller, not only the datas bound to your specific file.

You can even be faster by using the following system call :

/* _POSIX_SYNCHRONIZED_IO should be defined in <unistd.h> */
int fdatasync(int fd) 

It's like fsync but without transmitting control informations to the controller ( such as the inode modification time, ..).

Alternatively, you may find interesting to open your file with the following flag O_DSYNC : it is the equivalent of doing a fdatasync() after each write()

Remember that even with those system calls, there is no guarantee that datas are physically written to the hard drive in case of a power failure but only that they were transmitted to the hard drive controller.

Fryz
  • 2,119
  • 2
  • 25
  • 45