You need to swap 3 & 4 in your last listing - fsync(fd)
uses the file descriptor. and I don't see why that would be particularly costly - you want the data written to disk by the close() anyway. So the cost will be the same between what you want to happen and what will happen with fsync()
.
If the cost is too much, (and you have it) fdatasync(2)
avoid syncing the meta-data, so should be lighter cost.
EDIT:
So I wrote some extremely hacky test code:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
static void testBasic()
{
int fd;
const char* text = "This is some text";
fd = open("temp.tmp", O_WRONLY | O_CREAT);
write(fd,text,strlen(text));
close(fd);
rename("temp.tmp","temp");
}
static void testFsync()
{
int fd;
const char* text = "This is some text";
fd = open("temp1", O_WRONLY | O_CREAT);
write(fd,text,strlen(text));
fsync(fd);
close(fd);
rename("temp.tmp","temp");
}
static void testFdatasync()
{
int fd;
const char* text = "This is some text";
fd = open("temp1", O_WRONLY | O_CREAT);
write(fd,text,strlen(text));
fdatasync(fd);
close(fd);
rename("temp.tmp","temp");
}
#define ITERATIONS 10000
static void testLoop(int type)
{
struct timeval before;
struct timeval after;
long seconds;
long usec;
int i;
gettimeofday(&before,NULL);
if (type == 1)
{
for (i = 0; i < ITERATIONS; i++)
{
testBasic();
}
}
if (type == 2)
{
for (i = 0; i < ITERATIONS; i++)
{
testFsync();
}
}
if (type == 3)
{
for (i = 0; i < ITERATIONS; i++)
{
testFdatasync();
}
}
gettimeofday(&after,NULL);
seconds = (long)(after.tv_sec - before.tv_sec);
usec = (long)(after.tv_usec - before.tv_usec);
if (usec < 0)
{
seconds--;
usec += 1000000;
}
printf("%ld.%06ld\n",seconds,usec);
}
int main()
{
testLoop(1);
testLoop(2);
testLoop(3);
return 0;
}
On my laptop that produces:
0.595782
6.338329
6.116894
Which suggests doing the fsync()
is ~10 times more expensive. and fdatasync()
is slightly cheaper.
I guess the problem I see is that every application is going to think it's data is important enough to fsync(), so the performance advantages of merging writes over a minute will be eliminated.