pg_basebackup_rep_slot.v4.patch
application/octet-stream
Filename: pg_basebackup_rep_slot.v4.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v4
| File | + | − |
|---|---|---|
| src/bin/pg_basebackup/pg_basebackup.c | 136 | 84 |
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 669aa207a3..4cf875de45 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -173,6 +173,7 @@ static int bgpipe[2] = {-1, -1};
/* Handle to child process */
static pid_t bgchild = -1;
+static bool bgchild_exited = false;
static bool in_log_streamer = false;
/* End position for xlog streaming, empty string if unknown yet */
@@ -211,6 +212,7 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
static const char *get_tablespace_mapping(const char *dir);
static void tablespace_list_append(const char *arg);
+static void WaitForBGChild(const char *xlogend);
static void
@@ -967,6 +969,22 @@ ReceiveCopyData(PGconn *conn, WriteDataCallback callback,
int r;
char *copybuf;
+ if (bgchild > 0)
+ {
+ /* Check to see if our background process is still running fine. */
+ int status;
+ pid_t p;
+
+ p = waitpid(bgchild, &status, WNOHANG);
+
+ /* if our child process exited unexpectedly, we stop */
+ if (WIFEXITED(p))
+ {
+ bgchild_exited = true;
+ break;
+ }
+ }
+
r = PQgetCopyData(conn, ©buf, 0);
if (r == -1)
{
@@ -1167,6 +1185,11 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
ReceiveCopyData(conn, ReceiveTarCopyChunk, &state);
+ if (bgchild_exited)
+ {
+ return;
+ }
+
/*
* End of copy data. If requested, and this is the base tablespace, write
* configuration file into the tarfile. When done, close the file (but not
@@ -1531,6 +1554,11 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
if (state.file)
fclose(state.file);
+ if (bgchild_exited)
+ {
+ return;
+ }
+
progress_report(rownum, state.filename, true, false);
if (state.file != NULL)
@@ -1796,6 +1824,95 @@ ReceiveBackupManifestInMemoryChunk(size_t r, char *copybuf,
appendPQExpBuffer(buf, copybuf, r);
}
+static void
+WaitForBGChild(const char *xlogend)
+{
+ if (bgchild > 0)
+ {
+#ifndef WIN32
+ int status;
+ pid_t r;
+#else
+ DWORD status;
+
+ /*
+ * get a pointer sized version of bgchild to avoid warnings about
+ * casting to a different size on WIN64.
+ */
+ intptr_t bgchild_handle = bgchild;
+ uint32 hi,
+ lo;
+#endif
+
+ if (verbose)
+ pg_log_info("waiting for background process to finish streaming ...");
+
+#ifndef WIN32
+ if (write(bgpipe[1], xlogend, strlen(xlogend)) != strlen(xlogend))
+ {
+ pg_log_info("could not send command to background pipe: %m");
+ exit(1);
+ }
+
+ /* Just wait for the background process to exit */
+ r = waitpid(bgchild, &status, 0);
+ if (r == (pid_t) -1)
+ {
+ pg_log_error("could not wait for child process: %m");
+ exit(1);
+ }
+ if (r != bgchild)
+ {
+ pg_log_error("child %d died, expected %d", (int) r, (int) bgchild);
+ exit(1);
+ }
+ if (status != 0)
+ {
+ pg_log_error("%s", wait_result_to_str(status));
+ exit(1);
+ }
+ /* Exited normally, we're happy! */
+#else /* WIN32 */
+
+ /*
+ * On Windows, since we are in the same process, we can just store the
+ * value directly in the variable, and then set the flag that says
+ * it's there.
+ */
+ if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
+ {
+ pg_log_error("could not parse write-ahead log location \"%s\"",
+ xlogend);
+ exit(1);
+ }
+ xlogendptr = ((uint64) hi) << 32 | lo;
+ InterlockedIncrement(&has_xlogendptr);
+
+ /* First wait for the thread to exit */
+ if (WaitForSingleObjectEx((HANDLE) bgchild_handle, INFINITE, FALSE) !=
+ WAIT_OBJECT_0)
+ {
+ _dosmaperr(GetLastError());
+ pg_log_error("could not wait for child thread: %m");
+ exit(1);
+ }
+ if (GetExitCodeThread((HANDLE) bgchild_handle, &status) == 0)
+ {
+ _dosmaperr(GetLastError());
+ pg_log_error("could not get child thread exit status: %m");
+ exit(1);
+ }
+ if (status != 0)
+ {
+ pg_log_error("child thread exited with error %u",
+ (unsigned int) status);
+ exit(1);
+ }
+ /* Exited normally, we're happy */
+#endif
+ }
+}
+
static void
BaseBackup(void)
{
@@ -2020,8 +2137,26 @@ BaseBackup(void)
ReceiveTarFile(conn, res, i);
else
ReceiveAndUnpackTarFile(conn, res, i);
+
+ if (bgchild_exited)
+ break;
} /* Loop over all tablespaces */
+
+ /* if bgchild exited early, we need to stop now. */
+ if (bgchild_exited)
+ {
+ PQclear(res);
+ PQfinish(conn);
+ conn = NULL;
+
+ destroyPQExpBuffer(recoveryconfcontents);
+
+ /* wait for the child process to be finished entirely */
+ (void) WaitForBGChild(xlogend);
+ exit(1);
+ }
+
/*
* Now receive backup manifest, if appropriate.
*
@@ -2079,90 +2214,7 @@ BaseBackup(void)
exit(1);
}
- if (bgchild > 0)
- {
-#ifndef WIN32
- int status;
- pid_t r;
-#else
- DWORD status;
-
- /*
- * get a pointer sized version of bgchild to avoid warnings about
- * casting to a different size on WIN64.
- */
- intptr_t bgchild_handle = bgchild;
- uint32 hi,
- lo;
-#endif
-
- if (verbose)
- pg_log_info("waiting for background process to finish streaming ...");
-
-#ifndef WIN32
- if (write(bgpipe[1], xlogend, strlen(xlogend)) != strlen(xlogend))
- {
- pg_log_info("could not send command to background pipe: %m");
- exit(1);
- }
-
- /* Just wait for the background process to exit */
- r = waitpid(bgchild, &status, 0);
- if (r == (pid_t) -1)
- {
- pg_log_error("could not wait for child process: %m");
- exit(1);
- }
- if (r != bgchild)
- {
- pg_log_error("child %d died, expected %d", (int) r, (int) bgchild);
- exit(1);
- }
- if (status != 0)
- {
- pg_log_error("%s", wait_result_to_str(status));
- exit(1);
- }
- /* Exited normally, we're happy! */
-#else /* WIN32 */
-
- /*
- * On Windows, since we are in the same process, we can just store the
- * value directly in the variable, and then set the flag that says
- * it's there.
- */
- if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
- {
- pg_log_error("could not parse write-ahead log location \"%s\"",
- xlogend);
- exit(1);
- }
- xlogendptr = ((uint64) hi) << 32 | lo;
- InterlockedIncrement(&has_xlogendptr);
-
- /* First wait for the thread to exit */
- if (WaitForSingleObjectEx((HANDLE) bgchild_handle, INFINITE, FALSE) !=
- WAIT_OBJECT_0)
- {
- _dosmaperr(GetLastError());
- pg_log_error("could not wait for child thread: %m");
- exit(1);
- }
- if (GetExitCodeThread((HANDLE) bgchild_handle, &status) == 0)
- {
- _dosmaperr(GetLastError());
- pg_log_error("could not get child thread exit status: %m");
- exit(1);
- }
- if (status != 0)
- {
- pg_log_error("child thread exited with error %u",
- (unsigned int) status);
- exit(1);
- }
- /* Exited normally, we're happy */
-#endif
- }
+ (void) WaitForBGChild(xlogend);
/* Free the configuration file contents */
destroyPQExpBuffer(recoveryconfcontents);