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: [email protected]
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);
+ }
}
/*