XLogDumpPrivate *privateInfo);
static bool read_archive_file(XLogDumpPrivate *privateInfo);
static void setup_tmpwal_dir(const char *waldir);
-static void cleanup_tmpwal_dir_atexit(void);
static FILE *prepare_tmp_write(const char *fname, XLogDumpPrivate *privateInfo);
static void perform_tmp_write(const char *fname, StringInfo buf, FILE *file);
pg_log_debug("created directory \"%s\"", TmpWalSegDir);
}
-/*
- * Remove temporary directory at exit, if any.
- */
-static void
-cleanup_tmpwal_dir_atexit(void)
-{
- Assert(TmpWalSegDir != NULL);
-
- rmtree(TmpWalSegDir, true);
-
- TmpWalSegDir = NULL;
-}
-
/*
* Open a file in the temporary spill directory for writing an out-of-order
- * WAL segment, creating the directory and registering the cleanup callback
- * if not already done. Returns the open file handle.
+ * WAL segment, creating the directory if not already done.
+ * Returns the open file handle.
*/
static FILE *
prepare_tmp_write(const char *fname, XLogDumpPrivate *privateInfo)
char fpath[MAXPGPATH];
FILE *file;
- /*
- * Setup temporary directory to store WAL segments and set up an exit
- * callback to remove it upon completion if not already.
- */
+ /* Setup temporary directory to store WAL segments, if we didn't already */
if (unlikely(TmpWalSegDir == NULL))
- {
setup_tmpwal_dir(privateInfo->archive_dir);
- atexit(cleanup_tmpwal_dir_atexit);
- }
snprintf(fpath, MAXPGPATH, "%s/%s", TmpWalSegDir, fname);
static volatile sig_atomic_t time_to_stop = false;
+static XLogReaderState *xlogreader_state_cleanup = NULL;
+
static const RelFileLocator emptyRelFileLocator = {0, 0, 0};
typedef struct XLogDumpConfig
/*
* pg_waldump's XLogReaderRoutine->segment_close callback to support dumping
- * WAL files from tar archives. Segment tracking is handled by
- * TarWALDumpReadPage, so no action is needed here.
+ * WAL files from tar archives. Same as wal_segment_close.
*/
static void
TarWALDumpCloseSegment(XLogReaderState *state)
{
- /* No action needed */
+ close(state->seg.ws_file);
+ /* need to check errno? */
+ state->seg.ws_file = -1;
}
/*
total_len, "[100%]");
}
+/*
+ * Remove temporary directory at exit, if any.
+ */
+static void
+cleanup_tmpwal_dir_atexit(void)
+{
+ /*
+ * Before calling rmtree, we must close any open file we have in the temp
+ * directory; else rmdir fails on Windows.
+ */
+ if (xlogreader_state_cleanup != NULL &&
+ xlogreader_state_cleanup->seg.ws_file >= 0)
+ WALDumpCloseSegment(xlogreader_state_cleanup);
+
+ if (TmpWalSegDir != NULL)
+ {
+ rmtree(TmpWalSegDir, true);
+ TmpWalSegDir = NULL;
+ }
+}
+
static void
usage(void)
{
if (!xlogreader_state)
pg_fatal("out of memory while allocating a WAL reading processor");
+ /*
+ * Set up atexit cleanup of temporary directory. This must happen before
+ * archive_waldump.c could possibly create the temporary directory. Also
+ * arm the callback to cleanup the xlogreader state.
+ */
+ atexit(cleanup_tmpwal_dir_atexit);
+ xlogreader_state_cleanup = xlogreader_state;
+
/* first find a valid recptr to start from */
first_record = XLogFindNextRecord(xlogreader_state, private.startptr, &errormsg);
LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),
errormsg);
+ /*
+ * Disarm atexit cleanup of open WAL file; XLogReaderFree will close it,
+ * and we don't want the atexit callback trying to touch freed memory.
+ */
+ xlogreader_state_cleanup = NULL;
+
XLogReaderFree(xlogreader_state);
if (private.archive_name)