Skip to content

Set wasShutdown=true during hot-standby replica startup only when primary is not alive #365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion src/backend/access/transam/xlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,18 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;


/*
* NEON: check if primary node is running.
* Correspondent GUC is received from control plane
*/
static bool
IsPrimaryAlive()
{
const char* val = GetConfigOption("neon.primary_is_running", true, false);
return val != NULL && strcmp(val, "on") == 0;
}

/*
* State of an exclusive backup, necessary to control concurrent activities
* across sessions when working on exclusive backups.
Expand Down Expand Up @@ -7031,7 +7043,25 @@ StartupXLOG(void)
EndRecPtr = ControlFile->checkPointCopy.redo;

memcpy(&checkPoint, &ControlFile->checkPointCopy, sizeof(CheckPoint));
wasShutdown = true;
// When primary Neon compute node is started, we pretend that it started after a clean shutdown and
// no recovery is needed. We don't need to do WAL replay, the page server does that on a page-by-page basis.
// When a read-only replica is started, PostgreSQL normally waits for a shutdown checkpoint or running-xacts
// record before enabling hot standby, to establish which transactions are still running in the primary,
// and might still commit later. But if we know that the primary is not running - because the control plane
// says so - we can skip that. That avoids having to wait indefinitely if the primary is not running. This is
// particularly important for Neon because we don't start recovery from a checkpoint record, so there's
// no guarantee on when we'll see the next checkpoint or running-xacts record, if ever. so if we know the primary is
// not currently running, also set wasShutdown to 'true'.
if (StandbyModeRequested &&
PrimaryConnInfo != NULL && *PrimaryConnInfo != '\0')
{
if (!IsPrimaryAlive())
wasShutdown = true;
else
wasShutdown = false;
}
else
wasShutdown = true;

/* Initialize expectedTLEs, like ReadRecord() does */
expectedTLEs = readTimeLineHistory(checkPoint.ThisTimeLineID);
Expand Down Expand Up @@ -7201,6 +7231,24 @@ StartupXLOG(void)
ereport(PANIC,
(errmsg("invalid next transaction ID")));

if (ZenithRecoveryRequested)
{
if (wasShutdown)
checkPoint.oldestActiveXid = InvalidTransactionId;
else if (!TransactionIdIsValid(checkPoint.oldestActiveXid))
{
/*
* It should not actually happen: PS oldestActiveXid
* from running xacts WAL records and include it in checkpoint
* sent in basebackup.
* FirstNormalTransactionId is conservative estimation of oldest active XACT, unless
* current XID is greater than 1^31. So it is also not 100% safe solution but better than assertion failure.
*/
elog(FATAL, "oldestActiveXid=%d", checkPoint.oldestActiveXid);
checkPoint.oldestActiveXid = FirstNormalTransactionId;
}
}

/* initialize shared memory variables from the checkpoint record */
ShmemVariableCache->nextXid = checkPoint.nextXid;
ShmemVariableCache->nextOid = checkPoint.nextOid;
Expand Down