pg_backup_mirror_1.diff
text/x-patch
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/bin/pg_dump/Makefile | 0 | 0 |
| src/bin/pg_dump/parallel.c | 0 | 0 |
| src/bin/pg_dump/parallel.h | 0 | 0 |
| src/bin/pg_dump/pg_backup_archiver.c | 0 | 0 |
| src/bin/pg_dump/pg_backup_archiver.h | 0 | 0 |
| src/bin/pg_dump/pg_backup_directory.c | 0 | 0 |
| src/bin/pg_dump/pg_backup.h | 0 | 0 |
| src/bin/pg_dump/pg_backup_mirror.c | 0 | 0 |
| src/bin/pg_dump/pg_dump.c | 0 | 0 |
| src/bin/pg_dump/pg_restore.c | 0 | 0 |
diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
index 00501de..8e2e983 100644
*** a/src/bin/pg_dump/Makefile
--- b/src/bin/pg_dump/Makefile
*************** kwlookup.c: % : $(top_srcdir)/src/backen
*** 30,37 ****
all: pg_dump pg_restore pg_dumpall
! pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
! $(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
pg_restore: pg_restore.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
$(CC) $(CFLAGS) pg_restore.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
--- 30,37 ----
all: pg_dump pg_restore pg_dumpall
! pg_dump: pg_dump.o common.o pg_dump_sort.o pg_backup_mirror.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
! $(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o pg_backup_mirror.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
pg_restore: pg_restore.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
$(CC) $(CFLAGS) pg_restore.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
diff --git a/src/bin/pg_dump/parallel.c b/src/bin/pg_dump/parallel.c
index bcde24c..b4d0af4 100644
*** a/src/bin/pg_dump/parallel.c
--- b/src/bin/pg_dump/parallel.c
*************** WaitForCommands(ArchiveHandle *AH, int p
*** 921,927 ****
}
else if (messageStartsWith(command, "RESTORE "))
{
! Assert(AH->format == archDirectory || AH->format == archCustom);
Assert(AH->connection != NULL);
sscanf(command + strlen("RESTORE "), "%d%n", &dumpId, &nBytes);
--- 921,927 ----
}
else if (messageStartsWith(command, "RESTORE "))
{
! Assert(AH->format == archDirectory || AH->format == archCustom || AH->format == archMirror);
Assert(AH->connection != NULL);
sscanf(command + strlen("RESTORE "), "%d%n", &dumpId, &nBytes);
*************** ListenToWorkers(ArchiveHandle *AH, Paral
*** 1004,1010 ****
}
else if (messageStartsWith(msg, "ERROR "))
{
! Assert(AH->format == archDirectory || AH->format == archCustom);
pstate->parallelSlot[worker].workerStatus = WRKR_TERMINATED;
die_horribly(AH, modulename, "%s", msg + strlen("ERROR "));
}
--- 1004,1010 ----
}
else if (messageStartsWith(msg, "ERROR "))
{
! Assert(AH->format == archDirectory || AH->format == archCustom || AH->format == archMirror);
pstate->parallelSlot[worker].workerStatus = WRKR_TERMINATED;
die_horribly(AH, modulename, "%s", msg + strlen("ERROR "));
}
diff --git a/src/bin/pg_dump/parallel.h b/src/bin/pg_dump/parallel.h
index 4c86b9b..194dea4 100644
*** a/src/bin/pg_dump/parallel.h
--- b/src/bin/pg_dump/parallel.h
*************** typedef enum
*** 32,38 ****
typedef enum _action
{
ACT_DUMP,
! ACT_RESTORE,
} T_Action;
/* Arguments needed for a worker process */
--- 32,38 ----
typedef enum _action
{
ACT_DUMP,
! ACT_RESTORE
} T_Action;
/* Arguments needed for a worker process */
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index 767f865..3c90904 100644
*** a/src/bin/pg_dump/pg_backup.h
--- b/src/bin/pg_dump/pg_backup.h
*************** typedef enum _archiveFormat
*** 51,57 ****
archFiles = 2,
archTar = 3,
archNull = 4,
! archDirectory = 5
} ArchiveFormat;
typedef enum _archiveMode
--- 51,58 ----
archFiles = 2,
archTar = 3,
archNull = 4,
! archDirectory = 5,
! archMirror = 6
} ArchiveFormat;
typedef enum _archiveMode
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 0c81dfe..68e5307 100644
*** a/src/bin/pg_dump/pg_backup_archiver.c
--- b/src/bin/pg_dump/pg_backup_archiver.c
*************** CloseArchive(Archive *AHX)
*** 154,160 ****
int res = 0;
ArchiveHandle *AH = (ArchiveHandle *) AHX;
! (*AH->ClosePtr) (AH);
/* Close the output */
if (AH->gzOut)
--- 154,161 ----
int res = 0;
ArchiveHandle *AH = (ArchiveHandle *) AHX;
! if (AH->ClosePtr)
! (*AH->ClosePtr) (AH);
/* Close the output */
if (AH->gzOut)
*************** _allocAH(const char *FileSpec, const Arc
*** 2015,2020 ****
--- 2016,2025 ----
InitArchiveFmt_Tar(AH);
break;
+ case archMirror:
+ InitArchiveFmt_Mirror(AH);
+ break;
+
default:
die_horribly(AH, modulename, "unrecognized file format \"%d\"\n", fmt);
}
diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h
index 3b10384..929a32c 100644
*** a/src/bin/pg_dump/pg_backup_archiver.h
--- b/src/bin/pg_dump/pg_backup_archiver.h
*************** extern void EndRestoreBlob(ArchiveHandle
*** 398,406 ****
extern void EndRestoreBlobs(ArchiveHandle *AH);
extern void InitArchiveFmt_Custom(ArchiveHandle *AH);
extern void InitArchiveFmt_Files(ArchiveHandle *AH);
extern void InitArchiveFmt_Null(ArchiveHandle *AH);
- extern void InitArchiveFmt_Directory(ArchiveHandle *AH);
extern void InitArchiveFmt_Tar(ArchiveHandle *AH);
extern bool isValidTarHeader(char *header);
--- 398,407 ----
extern void EndRestoreBlobs(ArchiveHandle *AH);
extern void InitArchiveFmt_Custom(ArchiveHandle *AH);
+ extern void InitArchiveFmt_Directory(ArchiveHandle *AH);
extern void InitArchiveFmt_Files(ArchiveHandle *AH);
+ extern void InitArchiveFmt_Mirror(ArchiveHandle *AH);
extern void InitArchiveFmt_Null(ArchiveHandle *AH);
extern void InitArchiveFmt_Tar(ArchiveHandle *AH);
extern bool isValidTarHeader(char *header);
diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c
index 995cf31..5e1e8d9 100644
*** a/src/bin/pg_dump/pg_backup_directory.c
--- b/src/bin/pg_dump/pg_backup_directory.c
*************** static void _DeClone(ArchiveHandle *AH);
*** 89,96 ****
static char *_MasterStartParallelItem(ArchiveHandle *AH, TocEntry *te, T_Action act);
static int _MasterEndParallelItem(ArchiveHandle *AH, TocEntry *te, const char *str, T_Action act);
- static char *_WorkerJobRestoreDirectory(ArchiveHandle *AH, TocEntry *te);
- static char *_WorkerJobDumpDirectory(ArchiveHandle *AH, TocEntry *te);
static void createDirectory(const char *dir);
static char *prependDirectory(ArchiveHandle *AH, char *buf, const char *relativeFilename);
--- 89,94 ----
diff --git a/src/bin/pg_dump/pg_backup_mirror.c b/src/bin/pg_dump/pg_backup_mirror.c
index ...100cea1 .
*** a/src/bin/pg_dump/pg_backup_mirror.c
--- b/src/bin/pg_dump/pg_backup_mirror.c
***************
*** 0 ****
--- 1,453 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pg_backup_mirror.c
+ *
+ * Mirror a database from one host to another by doing a parallel
+ * pg_backup/restore.
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * Portions Copyright (c) 2000, Philip Warner
+ *
+ * Rights are granted to use this software in any way so long
+ * as this notice is not removed.
+ *
+ * The author is not responsible for loss or damages that may
+ * result from it's use.
+ *
+ * IDENTIFICATION
+ * src/bin/pg_dump/pg_backup_mirror.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ #include "compress_io.h"
+ #include "dumpmem.h"
+ #include "dumputils.h"
+ #include "parallel.h"
+
+ typedef struct
+ {
+ PGconn *dumpConn;
+ PGconn *restoreConn;
+ } lclContext;
+
+ typedef struct
+ {
+ int status;
+ } lclTocEntry;
+
+ static const char *modulename = gettext_noop("mirror archiver");
+
+ /* prototypes for private functions */
+ static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
+ static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
+ static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
+
+ static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
+ static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
+ static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
+ static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
+ static void _Clone(ArchiveHandle *AH);
+ static void _DeClone(ArchiveHandle *AH);
+
+ static void _ReopenArchive(ArchiveHandle *AH);
+
+ static char *_MasterStartParallelItem(ArchiveHandle *AH, TocEntry *te, T_Action act);
+ static int _MasterEndParallelItem(ArchiveHandle *AH, TocEntry *te, const char *str, T_Action act);
+ static char *_WorkerJobRestoreMirror(ArchiveHandle *AH, TocEntry *te);
+
+ /*
+ * Init routine required by ALL formats. This is a global routine
+ * and should be declared in pg_backup_archiver.h
+ *
+ * Its task is to create any extra archive context (using AH->formatData),
+ * and to initialize the supported function pointers.
+ *
+ * It should also prepare whatever its input source is for reading/writing,
+ * and in the case of a read mode connection, it should load the Header & TOC.
+ */
+ void
+ InitArchiveFmt_Mirror(ArchiveHandle *AH)
+ {
+ lclContext *ctx;
+
+ /* Assuming static functions, this can be copied for each format. */
+ AH->ArchiveEntryPtr = _ArchiveEntry;
+ AH->StartDataPtr = NULL;
+ AH->WriteDataPtr = _WriteData;
+ AH->EndDataPtr = NULL;
+ AH->WriteBytePtr = NULL;
+ AH->ReadBytePtr = NULL;
+ AH->WriteBufPtr = NULL;
+ AH->ReadBufPtr = NULL;
+ AH->ClosePtr = NULL;
+ AH->ReopenPtr = _ReopenArchive;
+ AH->PrintTocDataPtr = _PrintTocData;
+ AH->ReadExtraTocPtr = NULL;
+ AH->WriteExtraTocPtr = NULL;
+ AH->PrintExtraTocPtr = NULL;
+
+ AH->StartBlobsPtr = _StartBlobs;
+ AH->StartBlobPtr = _StartBlob;
+ AH->EndBlobPtr = _EndBlob;
+ AH->EndBlobsPtr = _EndBlobs;
+
+ AH->ClonePtr = _Clone;
+ AH->DeClonePtr = _DeClone;
+
+ AH->WorkerJobRestorePtr = _WorkerJobRestoreMirror;
+ AH->WorkerJobDumpPtr = NULL;
+
+ AH->MasterStartParallelItemPtr = _MasterStartParallelItem;
+ AH->MasterEndParallelItemPtr = _MasterEndParallelItem;
+
+ /* Set up our private context */
+ ctx = (lclContext *) pg_calloc(1, sizeof(lclContext));
+ AH->formatData = (void *) ctx;
+
+ /* Initialize LO buffering */
+ AH->lo_buf_size = LOBBUFSIZE;
+ AH->lo_buf = (void *) pg_malloc(LOBBUFSIZE);
+ }
+
+ /*
+ * Called by the Archiver when the dumper creates a new TOC entry.
+ */
+ static void
+ _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
+ {
+ lclTocEntry *tctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
+ te->formatData = (void *) tctx;
+ }
+
+ void
+ setActiveConnection(ArchiveHandle *AH, T_Action act, bool connOnly)
+ {
+ lclContext *ctx = (lclContext *) AH->formatData;
+
+ if (act == ACT_DUMP)
+ {
+ AH->connection = ctx->dumpConn;
+ if (connOnly)
+ return;
+ }
+ else
+ {
+ AH->connection = ctx->restoreConn;
+ if (connOnly)
+ return;
+
+ }
+ }
+
+ void
+ MirrorDecoupleDumpConn(ArchiveHandle *AH)
+ {
+ lclContext *ctx = (lclContext *) AH->formatData;
+
+ ctx->dumpConn = AH->connection;
+ AH->connection = NULL;
+ }
+
+ /*
+ * Called by the archiver when saving TABLE DATA (not schema). This routine
+ * should save whatever format-specific information is needed to read
+ * the archive back.
+ *
+ * It is called just prior to the dumper's 'DataDumper' routine being called.
+ *
+ * We create the data file for writing.
+ *
+ * static void _StartData(ArchiveHandle *AH, TocEntry *te) { }
+ */
+
+ /*
+ * Called by archiver when dumper calls WriteData. This routine is
+ * called for both BLOB and TABLE data; it is the responsibility of
+ * the format to manage each kind of data using StartBlob/StartData.
+ *
+ * It should only be called from within a DataDumper routine.
+ */
+ static size_t
+ _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
+ {
+ setActiveConnection(AH, ACT_RESTORE, true);
+ ahwrite(data, 1, dLen, AH);
+ setActiveConnection(AH, ACT_DUMP, true);
+
+ return dLen;
+ }
+
+ /*
+ * Called by the archiver when a dumper's 'DataDumper' routine has
+ * finished.
+ *
+ * static void _EndData(ArchiveHandle *AH, TocEntry *te) { }
+ */
+
+ /*
+ * Print data for a given TOC entry
+ */
+ static void
+ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
+ {
+ setActiveConnection(AH, ACT_DUMP, true);
+ WriteDataChunksForTocEntry(AH, te);
+ setActiveConnection(AH, ACT_RESTORE, true);
+ }
+
+ /*
+ * Write a byte of data to the archive.
+ * Called by the archiver to do integer & byte output to the archive.
+ * These routines are only used to read & write the headers & TOC.
+ *
+ * static int _WriteByte(ArchiveHandle *AH, const int i) { }
+ */
+
+ /*
+ * Read a byte of data from the archive.
+ * Called by the archiver to read bytes & integers from the archive.
+ * These routines are only used to read & write headers & TOC.
+ * EOF should be treated as a fatal error.
+ *
+ * static int _ReadByte(ArchiveHandle *AH) { }
+ */
+
+ /*
+ * Write a buffer of data to the archive.
+ *
+ * Called by the archiver to write a block of bytes to the TOC or a data file.
+ *
+ * static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len) { }
+ */
+
+ /*
+ * Read a block of bytes from the archive.
+ *
+ * Called by the archiver to read a block of bytes from the archive
+ *
+ * static size_t _ReadBuf(ArchiveHandle *AH, void *buf, size_t len) { }
+ */
+
+ /*
+ * Close the archive.
+ *
+ * When writing the archive, this is the routine that actually starts
+ * the process of saving it to files. No data should be written prior
+ * to this point, since the user could sort the TOC after creating it.
+ *
+ * If an archive is to be written, this routine must call:
+ * WriteHead to save the archive header
+ * WriteToc to save the TOC entries
+ * WriteDataChunks to save all DATA & BLOBs.
+ *
+ * static void _CloseArchive(ArchiveHandle *AH) { }
+ */
+
+ /*
+ * Reopen the archive's file handle.
+ */
+ static void _ReopenArchive(ArchiveHandle *AH) { }
+
+ /*
+ * BLOB support
+ */
+
+ /*
+ * Called by the archiver when starting to save all BLOB DATA (not schema).
+ * It is called just prior to the dumper's DataDumper routine.
+ *
+ * We open the large object TOC file here, so that we can append a line to
+ * it for each blob.
+ */
+ static void
+ _StartBlobs(ArchiveHandle *AH, TocEntry *te)
+ {
+ setActiveConnection(AH, ACT_RESTORE, true);
+ StartRestoreBlobs(AH);
+ setActiveConnection(AH, ACT_DUMP, true);
+ }
+
+ /*
+ * Called by the archiver when we're about to start dumping a blob.
+ *
+ * We create a file to write the blob to.
+ */
+ static void
+ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
+ {
+ setActiveConnection(AH, ACT_RESTORE, true);
+ StartRestoreBlob(AH, oid, AH->ropt->dropSchema);
+ setActiveConnection(AH, ACT_DUMP, true);
+ }
+
+ /*
+ * Called by the archiver when the dumper is finished writing a blob.
+ *
+ * We close the blob file and write an entry to the blob TOC file for it.
+ */
+ static void
+ _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
+ {
+ setActiveConnection(AH, ACT_RESTORE, true);
+ EndRestoreBlob(AH, oid);
+ setActiveConnection(AH, ACT_DUMP, true);
+ }
+
+ /*
+ * Called by the archiver when finishing saving all BLOB DATA.
+ *
+ * We close the blobs TOC file.
+ */
+ static void
+ _EndBlobs(ArchiveHandle *AH, TocEntry *te)
+ {
+ setActiveConnection(AH, ACT_RESTORE, true);
+ EndRestoreBlobs(AH);
+ setActiveConnection(AH, ACT_DUMP, true);
+ }
+
+ /*
+ * Clone format-specific fields during parallel restoration.
+ */
+ static void
+ _Clone(ArchiveHandle *AH)
+ {
+ char *dbname;
+ char *pghost;
+ char *pgport;
+ char *username;
+ const char *encname;
+
+ lclContext *ctx = (lclContext *) AH->formatData;
+
+ AH->formatData = (lclContext *) pg_malloc(sizeof(lclContext));
+ memcpy(AH->formatData, ctx, sizeof(lclContext));
+ ctx = (lclContext *) AH->formatData;
+
+ Assert(ctx->dumpConn != NULL);
+
+ ctx->restoreConn = AH->connection;
+ AH->connection = NULL;
+
+ /*
+ * Even though we are technically accessing the parent's database object
+ * here, these functions are fine to be called like that because all just
+ * return a pointer and do not actually send/receive any data to/from the
+ * database.
+ */
+ dbname = PQdb(ctx->dumpConn);
+ pghost = PQhost(ctx->dumpConn);
+ pgport = PQport(ctx->dumpConn);
+ username = PQuser(ctx->dumpConn);
+ /* XXX could we have different encodings ? */
+ encname = pg_encoding_to_char(AH->public.encoding);
+
+ if (AH->savedPassword)
+ AH->savedPassword = NULL;
+
+ /* XXX this does more than we most likely want */
+ ConnectDatabase((Archive *) AH, dbname, pghost, pgport, username, TRI_NO);
+
+ ctx->dumpConn = AH->connection;
+
+ /* Let the dumpConn be in AH->connection so that we run SetupConnection on
+ * it. */
+
+
+ /*
+ * Note: we do not make a local lo_buf because we expect at most one BLOBS
+ * entry per archive, so no parallelism is possible. Likewise,
+ * TOC-entry-local state isn't an issue because any one TOC entry is
+ * touched by just one worker child.
+ */
+
+ /*
+ * We also don't copy the ParallelState pointer (pstate), only the master
+ * process ever writes to it.
+ */
+ }
+
+ static void
+ _DeClone(ArchiveHandle *AH)
+ {
+ lclContext *ctx = (lclContext *) AH->formatData;
+ free(ctx);
+ }
+
+ /*
+ * This function is executed in the parent process. Depending on the desired
+ * action (dump or restore) it creates a string that is understood by the
+ * _WorkerJobDumpDirectory/_WorkerJobRestoreDirectory functions of the
+ * respective dump format.
+ */
+ static char *
+ _MasterStartParallelItem(ArchiveHandle *AH, TocEntry *te, T_Action act)
+ {
+ /*
+ * A static char is okay here, even on Windows because we call this
+ * function only from one process (the master).
+ */
+ static char buf[64];
+ snprintf(buf, sizeof(buf), "RESTORE %d", te->dumpId);
+ return buf;
+ }
+
+ /*
+ * This function is executed in the child of a parallel backup for the
+ * directory archive and dumps the actual data.
+ */
+ static char *
+ _WorkerJobRestoreMirror(ArchiveHandle *AH, TocEntry *te)
+ {
+ /* short fixed-size string + some ID so far, this needs to be malloc'ed
+ * instead of static because we work with threads on windows */
+ const int buflen = 64;
+ char *buf = (char*) pg_malloc(buflen);
+ ParallelArgs pargs;
+ int status;
+ lclTocEntry *tctx;
+
+ tctx = (lclTocEntry *) te->formatData;
+
+ /* Prepare the item */
+ pargs.AH = AH;
+ pargs.te = te;
+
+ /* Prepare AH */
+ setActiveConnection(AH, ACT_RESTORE, false);
+
+ status = parallel_restore(&pargs);
+
+ tctx->status = status;
+ snprintf(buf, buflen, "OK RESTORE %d %d %d", te->dumpId, status,
+ status == WORKER_IGNORED_ERRORS ? AH->public.n_errors : 0);
+
+ setActiveConnection(AH, ACT_RESTORE, false);
+
+ return buf;
+ }
+ /*
+ * This function is executed in the parent process. It analyzes the response of
+ * the _WorkerJobDumpDirectory/_WorkerJobRestoreDirectory functions of the
+ * respective dump format.
+ */
+ static int
+ _MasterEndParallelItem(ArchiveHandle *AH, TocEntry *te, const char *str, T_Action act)
+ {
+ DumpId dumpId;
+ int nBytes, n_errors;
+ int status = 0;
+
+ Assert(act == ACT_RESTORE);
+
+ sscanf(str, "%u %u %u%n", &dumpId, &status, &n_errors, &nBytes);
+
+ Assert(dumpId == te->dumpId);
+ Assert(nBytes == strlen(str));
+
+ AH->public.n_errors += n_errors;
+
+ return status;
+ }
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 5a15435..e8b60ff 100644
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
*************** static int no_security_labels = 0;
*** 143,148 ****
--- 143,149 ----
static int no_synchronized_snapshots = 0;
static int no_unlogged_table_data = 0;
static int serializable_deferrable = 0;
+ static int mirror_exit_on_error = false;
static void help(const char *progname);
*************** main(int argc, char **argv)
*** 266,271 ****
--- 267,276 ----
const char *pghost = NULL;
const char *pgport = NULL;
const char *username = NULL;
+ char *restore_dbname = NULL;
+ char *restore_pghost = NULL;
+ char *restore_pgport = NULL;
+ char *restore_username = NULL;
const char *dumpencoding = NULL;
bool oids = false;
TableInfo *tblinfo;
*************** main(int argc, char **argv)
*** 288,297 ****
--- 293,304 ----
RestoreOptions *ropt;
ArchiveFormat archiveFormat = archUnknown;
ArchiveMode archiveMode;
+ int exit_code;
static int disable_triggers = 0;
static int outputNoTablespaces = 0;
static int use_setsessauth = 0;
+ static int in_restore_options = false;
static struct option long_options[] = {
{"data-only", no_argument, NULL, 'a'},
*************** main(int argc, char **argv)
*** 345,350 ****
--- 352,365 ----
{"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
{"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
+ /*
+ * the following option switches to target db interpretation for the
+ * pg_backup_mirror options.
+ */
+ {"restore", no_argument, &in_restore_options, 1},
+ {"dbname", required_argument, NULL, 6},
+ {"mirror-exit-on-error", no_argument, &mirror_exit_on_error, 1},
+
{NULL, 0, NULL, 0}
};
*************** main(int argc, char **argv)
*** 414,420 ****
break;
case 'h': /* server host */
! pghost = optarg;
break;
case 'i':
--- 429,438 ----
break;
case 'h': /* server host */
! if (!in_restore_options)
! pghost = optarg;
! else
! restore_pghost = optarg;
break;
case 'i':
*************** main(int argc, char **argv)
*** 443,449 ****
break;
case 'p': /* server port */
! pgport = optarg;
break;
case 'R':
--- 461,470 ----
break;
case 'p': /* server port */
! if (!in_restore_options)
! pgport = optarg;
! else
! restore_pgport = optarg;
break;
case 'R':
*************** main(int argc, char **argv)
*** 468,474 ****
break;
case 'U':
! username = optarg;
break;
case 'v': /* verbose */
--- 489,498 ----
break;
case 'U':
! if (!in_restore_options)
! username = optarg;
! else
! restore_username = optarg;
break;
case 'v': /* verbose */
*************** main(int argc, char **argv)
*** 511,516 ****
--- 535,545 ----
set_section(optarg, &dumpSections);
break;
+ case 6:
+ /* XXX check that we're in --restore ? */
+ restore_dbname = optarg;
+ break;
+
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
*************** main(int argc, char **argv)
*** 602,608 ****
}
/* Parallel backup only in the directory archive format so far */
! if (archiveFormat != archDirectory && numWorkers > 1) {
write_msg(NULL, "parallel backup only supported by the directory format\n");
exit(1);
}
--- 631,637 ----
}
/* Parallel backup only in the directory archive format so far */
! if (archiveFormat != archDirectory && archiveFormat != archMirror && numWorkers > 1) {
write_msg(NULL, "parallel backup only supported by the directory format\n");
exit(1);
}
*************** main(int argc, char **argv)
*** 764,770 ****
sortDumpableObjectsByTypeOid(dobjs, numObjs);
/* If we do a parallel dump, we want the largest tables to go first */
! if (archiveFormat == archDirectory && numWorkers > 1)
sortDataAndIndexObjectsBySize(dobjs, numObjs);
sortDumpableObjects(dobjs, numObjs);
--- 793,799 ----
sortDumpableObjectsByTypeOid(dobjs, numObjs);
/* If we do a parallel dump, we want the largest tables to go first */
! if (numWorkers > 1 && (archiveFormat == archDirectory || archiveFormat == archMirror))
sortDataAndIndexObjectsBySize(dobjs, numObjs);
sortDumpableObjects(dobjs, numObjs);
*************** main(int argc, char **argv)
*** 789,795 ****
/*
* And finally we can do the actual output.
*/
! if (plainText)
{
ropt = NewRestoreOptions();
ropt->filename = (char *) filename;
--- 818,824 ----
/*
* And finally we can do the actual output.
*/
! if (plainText || archiveFormat == archMirror)
{
ropt = NewRestoreOptions();
ropt->filename = (char *) filename;
*************** main(int argc, char **argv)
*** 810,823 ****
ropt->suppressDumpWarnings = true; /* We've already shown them */
RestoreArchive(g_fout, ropt);
}
CloseArchive(g_fout);
PQfinish(g_conn);
! exit(0);
}
--- 839,874 ----
ropt->suppressDumpWarnings = true; /* We've already shown them */
+ if (archiveFormat == archMirror)
+ {
+ ropt->dbname = restore_dbname;
+ ropt->pghost = restore_pghost;
+ ropt->pgport = restore_pgport;
+ ropt->username = restore_username;
+ ropt->promptPassword = prompt_password;
+ ropt->useDB = 1;
+ ropt->exit_on_error = g_fout->exit_on_error = mirror_exit_on_error;
+
+ /* Disconnect the dump connection */
+ MirrorDecoupleDumpConn((ArchiveHandle *) g_fout);
+ }
+
RestoreArchive(g_fout, ropt);
}
+ /* done, print a summary of ignored errors */
+ if (g_fout->n_errors)
+ fprintf(stderr, _("WARNING: errors ignored on restore: %d\n"),
+ g_fout->n_errors);
+
+ /* AH may be freed in CloseArchive? */
+ exit_code = g_fout->n_errors ? 1 : 0;
+
CloseArchive(g_fout);
PQfinish(g_conn);
! exit(exit_code);
}
*************** parseArchiveFormat(const char *format, A
*** 1089,1094 ****
--- 1140,1149 ----
* documented.
*/
archiveFormat = archFiles;
+ else if (pg_strcasecmp(format, "m") == 0)
+ archiveFormat = archMirror;
+ else if (pg_strcasecmp(format, "mirror") == 0)
+ archiveFormat = archMirror;
else if (pg_strcasecmp(format, "p") == 0)
archiveFormat = archNull;
else if (pg_strcasecmp(format, "plain") == 0)
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
index 965e9f2..7db2c88 100644
*** a/src/bin/pg_dump/pg_restore.c
--- b/src/bin/pg_dump/pg_restore.c
*************** usage(const char *progname)
*** 498,500 ****
--- 498,504 ----
printf(_("\nIf no input file name is supplied, then standard input is used.\n\n"));
printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
}
+
+ /* dummy: while implemented as an archive format, it runs entirely in pg_dump */
+ void InitArchiveFmt_Mirror(ArchiveHandle *AH) {}
+