Hi, dumping a database to /dev/null via pg_dump is (AFAIK) one recommended way to check for corruption. However, dumping to /dev/null is currently not supported in directory mode which makes it not possible to dump to /dev/null in parallel.
I had a look at this, and it appears it would suffice to just override the few spots in pg_backup_directory.c which assemble filenames in the target directory to revert to '/dev/null' (or 'NUL' on Windows). The attached proof-of-concept patch does that, and it seems to work; I'm getting some nice speedups on a 170 GB test database: $ time pg_dump -Fc -Z0 -f /dev/null TESTDB real 32m45.120s [...] $ time pg_dump -Fd -j8 -Z0 -f /dev/null TESTDB real 9m28.357s Thoughts? Michael -- Michael Banck Projektleiter / Senior Berater Tel.: +49 2166 9901-171 Fax: +49 2166 9901-100 Email: michael.ba...@credativ.de credativ GmbH, HRB Mönchengladbach 12080 USt-ID-Nummer: DE204566209 Trompeterallee 108, 41189 Mönchengladbach Geschäftsführung: Dr. Michael Meskes, Jörg Folz, Sascha Heuer
diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c index a96da15dc1..82aeb01f91 100644 --- a/src/bin/pg_dump/compress_io.c +++ b/src/bin/pg_dump/compress_io.c @@ -512,7 +512,10 @@ cfopen_write(const char *path, const char *mode, int compression) #ifdef HAVE_LIBZ char *fname; - fname = psprintf("%s.gz", path); + if (strcmp(path, NULL_DEVICE) != 0) + fname = psprintf("%s.gz", path); + else + fname = strdup(path); fp = cfopen(fname, mode, compression); free_keep_errno(fname); #else diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h index becfee6e81..ecdd9fc8d3 100644 --- a/src/bin/pg_dump/pg_backup_archiver.h +++ b/src/bin/pg_dump/pg_backup_archiver.h @@ -62,6 +62,13 @@ typedef struct _z_stream typedef z_stream *z_streamp; #endif +/* Null device */ +#ifdef WIN32 +#define NULL_DEVICE "NUL" +#else +#define NULL_DEVICE "/dev/null" +#endif + /* Data block types */ #define BLK_DATA 1 #define BLK_BLOBS 3 diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c index 4aabb40f59..cd418ac7ee 100644 --- a/src/bin/pg_dump/pg_backup_directory.c +++ b/src/bin/pg_dump/pg_backup_directory.c @@ -192,9 +192,14 @@ InitArchiveFmt_Directory(ArchiveHandle *AH) } } - if (!is_empty && mkdir(ctx->directory, 0700) < 0) - exit_horribly(modulename, "could not create directory \"%s\": %s\n", - ctx->directory, strerror(errno)); + /* + * Create the output directory, unless it exists already and is empty. + * If the output directory is the null device, we need not create it. + */ + if (!is_empty && strcmp(ctx->directory, NULL_DEVICE) != 0) + if (mkdir(ctx->directory, 0711) < 0) + exit_horribly(modulename, "could not create directory \"%s\": %s\n", + ctx->directory, strerror(errno)); } else { /* Read Mode */ @@ -602,8 +607,10 @@ _CloseArchive(ArchiveHandle *AH) /* * In directory mode, there is no need to sync all the entries * individually. Just recurse once through all the files generated. + * If the output directory is the null device, it does not need + * syncing. */ - if (AH->dosync) + if (AH->dosync && strcmp(ctx->directory, NULL_DEVICE) != 0) fsync_dir_recurse(ctx->directory, progname); } AH->FH = NULL; @@ -659,7 +666,10 @@ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid) lclContext *ctx = (lclContext *) AH->formatData; char fname[MAXPGPATH]; - snprintf(fname, MAXPGPATH, "%s/blob_%u.dat", ctx->directory, oid); + if (strcmp(ctx->directory, NULL_DEVICE) != 0) + snprintf(fname, MAXPGPATH, "%s/blob_%u.dat", ctx->directory, oid); + else + snprintf(fname, MAXPGPATH, NULL_DEVICE); ctx->dataFH = cfopen_write(fname, PG_BINARY_W, AH->compression); @@ -721,9 +731,18 @@ setFilePath(ArchiveHandle *AH, char *buf, const char *relativeFilename) if (strlen(dname) + 1 + strlen(relativeFilename) + 1 > MAXPGPATH) exit_horribly(modulename, "file name too long: \"%s\"\n", dname); - strcpy(buf, dname); - strcat(buf, "/"); - strcat(buf, relativeFilename); + /* + * If the output directory is the null device, we cannot set a file path + * and just set the buffer to the null device. + */ + if (strcmp(ctx->directory, NULL_DEVICE) == 0) + { + strcpy(buf, NULL_DEVICE); + } else { + strcpy(buf, dname); + strcat(buf, "/"); + strcat(buf, relativeFilename); + } } /*