I thought fsync()
does fflush()
internally, so using fsync()
on a stream is OK. But I am getting an unexpected result when executed under network I/O.
My code snippet:
FILE* fp = fopen(file, "wb"); /* multiple fputs() calls like: */ fputs(buf, fp); ... ... fputs(buf.c_str(), fp); /* get fd of the FILE pointer */ fd = fileno(fp); #ifndef WIN32 ret = fsync(fd); #else ret = _commit(fd); fclose(fp);
But it seems _commit()
is not flushing the data (I tried on Windows and the data was written on a Linux exported filesystem).
When I changed the code to be:
FILE* fp = fopen(file, "wb"); /* multiple fputs() calls like: */ fputs(buf, fp); ... ... fputs(buf.c_str(), fp); /* fflush the data */ fflush(fp); fclose(fp);
it flushes the data.
I am wondering if _commit()
does the same thing as fflush()
. Any inputs?
fflush() works on FILE* , it just flushes the internal buffers in the FILE* of your application out to the OS. fsync works on a lower level, it tells the OS to flush its buffers to the physical media.
Oh, and by the way: according to POSIX, The fsync() function is intended to force a physical write of data from the buffer cache, and to assure that after a system crash or other failure that all data up to the time of the fsync() call is recorded on the disk.
fsync() transfers ("flushes") all modified in-core data of (i.e., modified buffer cache pages for) the file referred to by the file descriptor fd to the disk device (or other permanent storage device) so that all changed information can be retrieved even if the system crashes or is rebooted.
fflush()
works on FILE*
, it just flushes the internal buffers in the FILE*
of your application out to the OS.
fsync
works on a lower level, it tells the OS to flush its buffers to the physical media.
OSs heavily cache data you write to a file. If the OS enforced every write to hit the drive, things would be very slow. fsync
(among other things) allows you to control when the data should hit the drive.
Furthermore, fsync/commit works on a file descriptor. It has no knowledge of a FILE*
and can't flush its buffers. FILE*
lives in your application, file descriptors live in the OS kernel, typically.
The standard C function fflush()
and the POSIX system call fsync()
are conceptually somewhat similar. fflush()
operates on C file streams (FILE
objects), and is therefore portable. fsync()
operate on POSIX file descriptors. Both cause buffered data to be sent to a destination.
On a POSIX system, each C file stream has an associated file descriptor, and all the operations on a C file stream will be implemented by delegating, when necessary, to POSIX system calls that operate on the file descriptor.
One might think that a call to fflush
on a POSIX system would cause a write
of any data in the buffer of the file stream, followed by a call of fsync()
for the file descriptor of that file stream. So on a POSIX system there would be no need to follow a call to fflush
with a call to fsync(fileno(fp))
. But is that the case: is there a call to fsync
from fflush
?
No, calling fflush
on a POSIX system does not imply that fsync
will be called.
The C standard for fflush
says (emphasis added) it
causes any unwritten data for [the] stream to be delivered to the host environment to be written to the file
Saying that the data is to be written, rather than that is is written implies that further buffering by the host environment is permitted. That buffering by the "host environment" could include, for a POSIX environment, the internal buffering that fsync
flushes. So a close reading of the C standard suggests that the standard does not require the POSIX implementation to call fsync
.
The POSIX standard description of fflush
does not declare, as an extension of the C semantics, that fsync
is called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With