Re: trying again to get incremental backup
Robert Haas <robertmhaas@gmail.com>
On Thu, Nov 30, 2023 at 9:33 AM Robert Haas <robertmhaas@gmail.com> wrote: > 0005: Incremental backup itself. Changes: > - Remove UPLOAD_MANIFEST replication command and instead add > INCREMENTAL_WAL_RANGE replication command. Unfortunately, I think this change is going to need to be reverted. Jakub reported out a problem to me off-list, which I think boils down to this: take a full backup on the primary. create a database on the primary. now take an incremental backup on the standby using the full backup from the master as the prior backup. What happens at this point depends on how far replay has progressed on the standby. I think there are three scenarios: (1) If replay has not yet reached a checkpoint later than the one at which the full backup began, then taking the incremental backup will fail. This is correct, because it makes no sense to take an incremental backup that goes backwards in time, and it's pointless to take one that goes forwards but not far enough to reach the next checkpoint, as you won't save anything. (2) If replay has progressed far enough that the redo pointer is now beyond the CREATE DATABASE record, then everything is fine. (3) But if the redo pointer for the backup is a later checkpoint than the one from which the full backup started, but also before the CREATE DATABASE record, then the new database's files exist on disk, but are not mentioned in the WAL summary, which covers all LSNs from the start of the prior backup to the start of this one. Here, the start of the backup is basically the LSN from which replay will start, and since the database was created after that, those changes aren't in the WAL summary. This means that we think the file is unchanged since the prior backup, and so backup no blocks at all. But now we have an incremental file for a relation for which no full file is present in the prior backup, and we're in big trouble. If my analysis is correct, this bug should be new in v12. In v11 and prior, I think that we always included every file that didn't appear in the prior manifest in full. I didn't really quite know why I was doing that, which is why I was willing to rip it out and thus remove the need for the manifest, but now I think it was actually preventing exactly this problem. This issue, in general, is files that get created after the start of the backup. By that time, the WAL summary that drives the backup has already been built, so it doesn't know anything about the new files. That would be fine if we either (A) omitted those new files from the backup completely, since replay would recreate them or (B) backed them up in full, so that there was nothing relying on them being there in the earlier backup. But an incremental backup of such a file is no good. Then I started worrying about whether there were problems in cases where a file was dropped and recreated with the same name. I *think* it's OK. If file F is dropped and recreated after being copied into the full backup but before being copied into the incremental backup, then there are basically two cases. First, F might be dropped before the start LSN of the incremental backup; if so, we'll know from the WAL summary that the limit block is 0 and back up the whole thing. Second, F might be dropped after the start LSN of the incremental backup and before it's actually coped. In that case, we'll not know when backing up the file that it was dropped and recreated, so we'll back it up incrementally as if that hadn't happened. That's OK as long as reconstruction doesn't fail, because WAL replay will again drop and recreate F. And I think reconstruction won't fail: blocks that are in the incremental file will be taken from there, blocks in the prior backup file will be taken from there, and blocks in neither place will be zero-filled. The result is logically incoherent, but replay will nuke the file anyway, so whatever. It bugs me a bit that we don't obey the WAL-before-data rule with file creation, e.g. RelationCreateStorage does smgrcreate() and then log_smgrcreate(). So in theory we could see a file on disk for which nothing has been logged yet; it could even happen that the file gets created before the start LSN of the backup and the log record gets written afterward. It seems like it would be far more comfortable to swap the order there, so that if it's on disk, it's definitely in the WAL. But I haven't yet been able to think of a scenario in which the current ordering causes a real problem. If we backup a stray file in full (or, hypothetically, if we skipped it entirely) then nothing will happen that can't already happen today with full backup; any problems we end up having are, I think, not new problems. It's only when we back up a file incrementally that we need to be careful, and the analsysis is basically the same as before ... whatever we put into an incremental file will cause *something* to get reconstructed except when there's no prior file at all. Having the manifest for the prior backup lets us avoid the incremental-with-no-prior-file scenario. And as long as *something* gets reconstructed, I think WAL replay will fix up the rest. Considering all this, what I'm inclined to do is go and put UPLOAD_MANIFEST back, instead of INCREMENTAL_WAL_RANGE, and adjust accordingly. But first: does anybody see more problems here that I may have missed? -- Robert Haas EDB: http://www.enterprisedb.com
Commits
-
Minor fixes to pg_combinebackup and its documentation.
- 1713e3d6cd39 17.0 cited
-
Fix defects in PrepareForIncrementalBackup.
- dffde5bf16a5 17.0 landed
-
Add WALSummarizerLock to wait_event_names.txt
- 5c430f9dc559 17.0 landed
-
Initialize variable to placate compiler.
- da083b20f637 17.0 landed
-
Replace nonsense comment with a relevant one.
- ffc6ab9b56ae 17.0 landed
-
Fix numerous typos in incremental backup commits.
- 49f2194ed5c1 17.0 landed
-
Add support for incremental backup.
- dc212340058b 17.0 landed
-
Add a new WAL summarizer process.
- 174c480508ac 17.0 landed
-
Move src/bin/pg_verifybackup/parse_manifest.c into src/common.
- aafc07c7a191 17.0 landed
-
Fix brown paper bag bug in 5c47c6546c413d5eb51c1626070a807026e6139d.
- 47f01d727e3a 17.0 landed
-
Rename pg_verifybackup's JsonManifestParseContext callback functions.
- 278eb13c4823 17.0 landed
-
Rename JsonManifestParseContext callbacks.
- d463aa06a9a8 17.0 landed
-
Change how a base backup decides which files have checksums.
- 025584a168a4 17.0 landed
-
Change struct tablespaceinfo's oid member from 'char *' to 'Oid'
- 5b36e8f078a3 17.0 landed
-
Refactor parse_filename_for_nontemp_relation to parse more.
- 5c47c6546c41 17.0 landed
-
During online checkpoints, insert XLOG_CHECKPOINT_REDO at redo point.
- afd12774ae89 17.0 landed
-
In basebackup.c, refactor to create read_file_data_into_buffer.
- c2ba3fdea593 17.0 landed
-
In basebackup.c, refactor to create verify_page_checksum.
- 053183138a7a 17.0 landed
-
Report syncscan position at end of scan.
- e8d74ad625f7 17.0 cited
-
Exclude additional directories in pg_basebackup
- 6ad8ac602628 10.0 cited
-
Add new JSON processing functions and parser API.
- a570c98d7fa0 9.3.0 cited