mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Update minimum recovery point on truncation.
If a file is truncated, we must update minRecoveryPoint. Once a file is truncated, there's no going back; it would not be safe to stop recovery at a point earlier than that anymore. Per report from Kyotaro HORIGUCHI. Backpatch to 8.4. Before that, minRecoveryPoint was not updated during recovery at all.
This commit is contained in:
		@@ -4544,25 +4544,46 @@ xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid, XLogRecPtr lsn)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure files supposed to be dropped are dropped */
 | 
						/* Make sure files supposed to be dropped are dropped */
 | 
				
			||||||
	for (i = 0; i < xlrec->nrels; i++)
 | 
						if (xlrec->nrels > 0)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		SMgrRelation srel = smgropen(xlrec->xnodes[i], InvalidBackendId);
 | 
							/*
 | 
				
			||||||
		ForkNumber	fork;
 | 
							 * First update minimum recovery point to cover this WAL record. Once
 | 
				
			||||||
 | 
							 * a relation is deleted, there's no going back. The buffer manager
 | 
				
			||||||
 | 
							 * enforces the WAL-first rule for normal updates to relation files,
 | 
				
			||||||
 | 
							 * so that the minimum recovery point is always updated before the
 | 
				
			||||||
 | 
							 * corresponding change in the data file is flushed to disk, but we
 | 
				
			||||||
 | 
							 * have to do the same here since we're bypassing the buffer manager.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * Doing this before deleting the files means that if a deletion fails
 | 
				
			||||||
 | 
							 * for some reason, you cannot start up the system even after restart,
 | 
				
			||||||
 | 
							 * until you fix the underlying situation so that the deletion will
 | 
				
			||||||
 | 
							 * succeed. Alternatively, we could update the minimum recovery point
 | 
				
			||||||
 | 
							 * after deletion, but that would leave a small window where the
 | 
				
			||||||
 | 
							 * WAL-first rule would be violated.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							XLogFlush(lsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (fork = 0; fork <= MAX_FORKNUM; fork++)
 | 
							for (i = 0; i < xlrec->nrels; i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			XLogDropRelation(xlrec->xnodes[i], fork);
 | 
								SMgrRelation srel = smgropen(xlrec->xnodes[i], InvalidBackendId);
 | 
				
			||||||
			smgrdounlink(srel, fork, true);
 | 
								ForkNumber	fork;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (fork = 0; fork <= MAX_FORKNUM; fork++)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									XLogDropRelation(xlrec->xnodes[i], fork);
 | 
				
			||||||
 | 
									smgrdounlink(srel, fork, true);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								smgrclose(srel);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		smgrclose(srel);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
 | 
						 * We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
 | 
				
			||||||
	 * in normal operation. For example, in DROP DATABASE, we delete all the
 | 
						 * in normal operation. For example, in CREATE DATABASE, we copy all files
 | 
				
			||||||
	 * files belonging to the database, and then commit the transaction. If we
 | 
						 * from the template database, and then commit the transaction. If we
 | 
				
			||||||
	 * crash after all the files have been deleted but before the commit, you
 | 
						 * crash after all the files have been copied but before the commit, you
 | 
				
			||||||
	 * have an entry in pg_database without any files. To minimize the window
 | 
						 * have files in the data directory without an entry in pg_database. To
 | 
				
			||||||
 | 
						 * minimize the window
 | 
				
			||||||
	 * for that, we use ForceSyncCommit() to rush the commit record to disk as
 | 
						 * for that, we use ForceSyncCommit() to rush the commit record to disk as
 | 
				
			||||||
	 * quick as possible. We have the same window during recovery, and forcing
 | 
						 * quick as possible. We have the same window during recovery, and forcing
 | 
				
			||||||
	 * an XLogFlush() (which updates minRecoveryPoint during recovery) helps
 | 
						 * an XLogFlush() (which updates minRecoveryPoint during recovery) helps
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -508,6 +508,24 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
 | 
				
			|||||||
		 */
 | 
							 */
 | 
				
			||||||
		smgrcreate(reln, MAIN_FORKNUM, true);
 | 
							smgrcreate(reln, MAIN_FORKNUM, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Before we perform the truncation, update minimum recovery point
 | 
				
			||||||
 | 
							 * to cover this WAL record. Once the relation is truncated, there's
 | 
				
			||||||
 | 
							 * no going back. The buffer manager enforces the WAL-first rule
 | 
				
			||||||
 | 
							 * for normal updates to relation files, so that the minimum recovery
 | 
				
			||||||
 | 
							 * point is always updated before the corresponding change in the
 | 
				
			||||||
 | 
							 * data file is flushed to disk. We have to do the same manually
 | 
				
			||||||
 | 
							 * here.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * Doing this before the truncation means that if the truncation fails
 | 
				
			||||||
 | 
							 * for some reason, you cannot start up the system even after restart,
 | 
				
			||||||
 | 
							 * until you fix the underlying situation so that the truncation will
 | 
				
			||||||
 | 
							 * succeed. Alternatively, we could update the minimum recovery point
 | 
				
			||||||
 | 
							 * after truncation, but that would leave a small window where the
 | 
				
			||||||
 | 
							 * WAL-first rule could be violated.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							XLogFlush(lsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
 | 
							smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Also tell xlogutils.c about it */
 | 
							/* Also tell xlogutils.c about it */
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user