You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-07-05 15:41:11 +03:00
Prevent invalid recovery when backup_label removed.
If backup_label is removed from a restored backup then PostgreSQL will instead use checkpoint information from pg_control to attempt (what is thinks is) crash recovery. This will nearly always result in a corrupt cluster because the checkpoint will not be from the beginning of the backup, and even if it is, the end point will not be specified, which could lead to recovery stopping too early. To prevent this, invalidate the checkpoint LSN in pg_control on restore. If backup_label is removed then recovery will still fail because PostgreSQL will not be able to find the invalid checkpoint. The LSN of the checkpoint is not logged but it will be visible in pg_controldata output as 0/DEAD. This value is invalid because PostgreSQL always skips the first WAL segment when initializing a cluster.
This commit is contained in:
@ -282,6 +282,34 @@ testRun(void)
|
||||
TEST_RESULT_UINT(info.systemId, 0xAAAA0AAAA, "check system id");
|
||||
TEST_RESULT_UINT(info.version, PG_VERSION_14, "check version");
|
||||
TEST_RESULT_UINT(info.catalogVersion, 202007201, "check catalog version");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("Invalidate checkpoint");
|
||||
|
||||
control = hrnPgControlToBuffer(0, 0, (PgControl){.version = PG_VERSION_13, .systemId = 0xAAAA0AAAA, .checkpoint = 777});
|
||||
|
||||
info = pgControlFromBuffer(control, NULL);
|
||||
TEST_RESULT_UINT(info.checkpoint, 777, "check checkpoint");
|
||||
|
||||
TEST_RESULT_VOID(pgControlCheckpointInvalidate(control, NULL), "invalidate checkpoint");
|
||||
info = pgControlFromBuffer(control, NULL);
|
||||
TEST_RESULT_UINT(info.checkpoint, 0xDEAD, "check invalid checkpoint");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("Invalidate checkpoint on force control version");
|
||||
|
||||
// Start with an invalid crc but write a valid one at a greater offset to test the forced scan
|
||||
control = hrnPgControlToBuffer(
|
||||
0, 0xFADEFADE, (PgControl){.version = PG_VERSION_94, .systemId = 0xAAAA0AAAA, .checkpoint = 777});
|
||||
crcOffset = pgInterfaceVersion(PG_VERSION_94)->controlCrcOffset() + sizeof(uint32_t) * 2;
|
||||
*((uint32_t *)(bufPtr(control) + crcOffset)) = crc32One(bufPtrConst(control), crcOffset);
|
||||
|
||||
info = pgControlFromBuffer(control, STRDEF(PG_VERSION_94_Z));
|
||||
TEST_RESULT_UINT(info.checkpoint, 777, "check checkpoint");
|
||||
|
||||
TEST_RESULT_VOID(pgControlCheckpointInvalidate(control, STRDEF(PG_VERSION_94_Z)), "invalidate checkpoint");
|
||||
info = pgControlFromBuffer(control, STRDEF(PG_VERSION_94_Z));
|
||||
TEST_RESULT_UINT(info.checkpoint, 0xDEAD, "check invalid checkpoint");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
|
Reference in New Issue
Block a user