diff options
author | Robert Haas | 2024-03-04 18:33:12 +0000 |
---|---|---|
committer | Robert Haas | 2024-03-04 18:33:28 +0000 |
commit | d75c4027b6f260f2045b162017567aeeb909b056 (patch) | |
tree | 35488e90b82274595b76e1484b2b582d7b779cba /src/backend | |
parent | cb6945dc8061d03e6ec670a6856228f12e94264c (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.c | 18 | ||||
-rw-r--r-- | src/backend/postmaster/walsummarizer.c | 75 |
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 |