diff options
Diffstat (limited to 'src/port/copydir.c')
-rw-r--r-- | src/port/copydir.c | 84 |
1 files changed, 57 insertions, 27 deletions
diff --git a/src/port/copydir.c b/src/port/copydir.c index 0bf764ecffc..a52b1f71a1b 100644 --- a/src/port/copydir.c +++ b/src/port/copydir.c @@ -11,7 +11,7 @@ * as a service. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/port/copydir.c,v 1.25 2010/02/14 17:50:52 stark Exp $ + * $PostgreSQL: pgsql/src/port/copydir.c,v 1.26 2010/02/15 00:50:57 stark Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,7 @@ static void copy_file(char *fromfile, char *tofile); +static void fsync_fname(char *fname); /* @@ -91,27 +92,32 @@ copydir(char *fromdir, char *todir, bool recurse) copy_file(fromfile, tofile); } - FreeDir(xldir); - /* - * fsync the directory to make sure not just the data but also the - * new directory file entries have reached the disk. While needed - * by most filesystems, the window got bigger with newer ones like - * ext4. + * Be paranoid here and fsync all files to ensure we catch problems. */ - dirfd = BasicOpenFile(todir, - O_RDONLY | PG_BINARY, - S_IRUSR | S_IWUSR); - if(dirfd == -1) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not open directory for fsync \"%s\": %m", todir))); - - if(pg_fsync(dirfd) == -1) + if (xldir == NULL) ereport(ERROR, (errcode_for_file_access(), - errmsg("could not fsync directory \"%s\": %m", todir))); - close(dirfd); + errmsg("could not open directory \"%s\": %m", fromdir))); + + while ((xlde = ReadDir(xldir, fromdir)) != NULL) + { + if (strcmp(xlde->d_name, ".") == 0 || + strcmp(xlde->d_name, "..") == 0) + continue; + + snprintf(tofile, MAXPGPATH, "%s/%s", todir, xlde->d_name); + fsync_fname(tofile); + } + FreeDir(xldir); + + /* It's important to fsync the destination directory itself as + * individual file fsyncs don't guarantee that the directory entry + * for the file is synced. Recent versions of ext4 have made the + * window much wider but it's been true for ext3 and other + * filesyetems in the past + */ + fsync_fname(todir); } /* @@ -124,6 +130,7 @@ copy_file(char *fromfile, char *tofile) int srcfd; int dstfd; int nbytes; + off_t offset; /* Use palloc to ensure we get a maxaligned buffer */ #define COPY_BUF_SIZE (8 * BLCKSZ) @@ -149,7 +156,7 @@ copy_file(char *fromfile, char *tofile) /* * Do the data copying. */ - for (;;) + for (offset=0; ; offset+=nbytes) { nbytes = read(srcfd, buffer, COPY_BUF_SIZE); if (nbytes < 0) @@ -168,15 +175,14 @@ copy_file(char *fromfile, char *tofile) (errcode_for_file_access(), errmsg("could not write to file \"%s\": %m", tofile))); } - } - /* - * Be paranoid here to ensure we catch problems. - */ - if (pg_fsync(dstfd) != 0) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not fsync file \"%s\": %m", tofile))); + /* + * We fsync the files later but first flush them to avoid spamming + * the cache and hopefully get the kernel to start writing them + * out before the fsync comes. + */ + pg_flush_data(dstfd, offset, nbytes); + } if (close(dstfd)) ereport(ERROR, @@ -187,3 +193,27 @@ copy_file(char *fromfile, char *tofile) pfree(buffer); } + + + +/* + * fsync a file + */ +static void +fsync_fname(char *fname) +{ + int fd = BasicOpenFile(fname, + O_RDONLY | PG_BINARY, + S_IRUSR | S_IWUSR); + + if (fd < 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not open file \"%s\": %m", fname))); + + if (pg_fsync(fd) != 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not fsync file \"%s\": %m", fname))); + close(fd); +} |