summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorRobert Haas2024-03-04 18:33:12 +0000
committerRobert Haas2024-03-04 18:33:28 +0000
commitd75c4027b6f260f2045b162017567aeeb909b056 (patch)
tree35488e90b82274595b76e1484b2b582d7b779cba /src/backend
parentcb6945dc8061d03e6ec670a6856228f12e94264c (diff)
Fix incremental backup interaction with XLOG_DBASE_CREATE_FILE_COPY.
After XLOG_DBASE_CREATE_FILE_COPY, a correct incremental backup needs to copy in full everything with the database and tablespace OID mentioned in that record; but that record doesn't specifically mention the blocks, or even the relfilenumbers, of the affected relations. As a result, we were failing to copy data that we should have copied. To fix, enter the DB OID and tablespace OID into the block reference table with relfilenumber 0 and limit block 0; and treat that as a limit block of 0 for every relfilenumber whose DB OID and tablespace OID match. Also, add a test case. Patch by me, reviewed by Noah Misch. Discussion: http://postgr.es/m/CA+Tgmob0xa=ByvGLMdAgkUZyVQE=r4nyYZ_VEa40FCfEDFnTKA@mail.gmail.com
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/backup/basebackup_incremental.c18
-rw-r--r--src/backend/postmaster/walsummarizer.c75
2 files changed, 92 insertions, 1 deletions
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index 18c78adda26..a8f2e72e7b1 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -777,9 +777,25 @@ GetFileBackupMethod(IncrementalBackupInfo *ib, const char *path,
return BACK_UP_FILE_FULLY;
}
- /* Look up the block reference table entry. */
+ /*
+ * Look up the special block reference table entry for the database as
+ * a whole.
+ */
rlocator.spcOid = spcoid;
rlocator.dbOid = dboid;
+ rlocator.relNumber = 0;
+ if (BlockRefTableGetEntry(ib->brtab, &rlocator, MAIN_FORKNUM,
+ &limit_block) != NULL)
+ {
+ /*
+ * According to the WAL summary, this database OID/tablespace OID
+ * pairing has been created since the previous backup. So, everything
+ * in it must be backed up fully.
+ */
+ return BACK_UP_FILE_FULLY;
+ }
+
+ /* Look up the block reference table entry for this relfilenode. */
rlocator.relNumber = relfilenumber;
brtentry = BlockRefTableGetEntry(ib->brtab, &rlocator, forknum,
&limit_block);
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index 54fab16c378..5a8006ea4c7 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -29,6 +29,7 @@
#include "access/xlogutils.h"
#include "backup/walsummary.h"
#include "catalog/storage_xlog.h"
+#include "commands/dbcommands_xlog.h"
#include "common/blkreftable.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
@@ -146,6 +147,8 @@ static void HandleWalSummarizerInterrupts(void);
static XLogRecPtr SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn,
bool exact, XLogRecPtr switch_lsn,
XLogRecPtr maximum_lsn);
+static void SummarizeDbaseRecord(XLogReaderState *xlogreader,
+ BlockRefTable *brtab);
static void SummarizeSmgrRecord(XLogReaderState *xlogreader,
BlockRefTable *brtab);
static void SummarizeXactRecord(XLogReaderState *xlogreader,
@@ -961,6 +964,9 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
/* Special handling for particular types of WAL records. */
switch (XLogRecGetRmid(xlogreader))
{
+ case RM_DBASE_ID:
+ SummarizeDbaseRecord(xlogreader, brtab);
+ break;
case RM_SMGR_ID:
SummarizeSmgrRecord(xlogreader, brtab);
break;
@@ -1075,6 +1081,75 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
}
/*
+ * Special handling for WAL records with RM_DBASE_ID.
+ */
+static void
+SummarizeDbaseRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
+{
+ uint8 info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
+
+ /*
+ * We use relfilenode zero for a given database OID and tablespace OID
+ * to indicate that all relations with that pair of IDs have been
+ * recreated if they exist at all. Effectively, we're setting a limit
+ * block of 0 for all such relfilenodes.
+ *
+ * Technically, this special handling is only needed in the case of
+ * XLOG_DBASE_CREATE_FILE_COPY, because that can create a whole bunch
+ * of relation files in a directory without logging anything
+ * specific to each one. If we didn't mark the whole DB OID/TS OID
+ * combination in some way, then a tablespace that was dropped after
+ * the reference backup and recreated using the FILE_COPY method prior
+ * to the incremental backup would look just like one that was never
+ * touched at all, which would be catastrophic.
+ *
+ * But it seems best to adopt this treatment for all records that drop
+ * or create a DB OID/TS OID combination. That's similar to how we
+ * treat the limit block for individual relations, and it's an extra
+ * layer of safety here. We can never lose data by marking more stuff
+ * as needing to be backed up in full.
+ */
+ if (info == XLOG_DBASE_CREATE_FILE_COPY)
+ {
+ xl_dbase_create_file_copy_rec *xlrec;
+ RelFileLocator rlocator;
+
+ xlrec =
+ (xl_dbase_create_file_copy_rec *) XLogRecGetData(xlogreader);
+ rlocator.spcOid = xlrec->tablespace_id;
+ rlocator.dbOid = xlrec->db_id;
+ rlocator.relNumber = 0;
+ BlockRefTableSetLimitBlock(brtab, &rlocator, MAIN_FORKNUM, 0);
+ }
+ else if (info == XLOG_DBASE_CREATE_WAL_LOG)
+ {
+ xl_dbase_create_wal_log_rec *xlrec;
+ RelFileLocator rlocator;
+
+ xlrec = (xl_dbase_create_wal_log_rec *) XLogRecGetData(xlogreader);
+ rlocator.spcOid = xlrec->tablespace_id;
+ rlocator.dbOid = xlrec->db_id;
+ rlocator.relNumber = 0;
+ BlockRefTableSetLimitBlock(brtab, &rlocator, MAIN_FORKNUM, 0);
+ }
+ else if (info == XLOG_DBASE_DROP)
+ {
+ xl_dbase_drop_rec *xlrec;
+ RelFileLocator rlocator;
+ int i;
+
+ xlrec = (xl_dbase_drop_rec *) XLogRecGetData(xlogreader);
+ rlocator.dbOid = xlrec->db_id;
+ rlocator.relNumber = 0;
+ for (i = 0; i < xlrec->ntablespaces; ++i)
+ {
+ rlocator.spcOid = xlrec->tablespace_ids[i];
+ BlockRefTableSetLimitBlock(brtab, &rlocator, MAIN_FORKNUM, 0);
+ }
+ }
+}
+
+/*
* Special handling for WAL records with RM_SMGR_ID.
*/
static void