mirror of
https://github.com/postgres/postgres.git
synced 2025-06-29 10:41:53 +03:00
Allow on-line enabling and disabling of data checksums
This makes it possible to turn checksums on in a live cluster, without the previous need for dump/reload or logical replication (and to turn it off). Enabling checkusm starts a background process in the form of a launcher/worker combination that goes through the entire database and recalculates checksums on each and every page. Only when all pages have been checksummed are they fully enabled in the cluster. Any failure of the process will revert to checksums off and the process has to be started. This adds a new WAL record that indicates the state of checksums, so the process works across replicated clusters. Authors: Magnus Hagander and Daniel Gustafsson Review: Tomas Vondra, Michael Banck, Heikki Linnakangas, Andrey Borodin
This commit is contained in:
@ -856,6 +856,7 @@ static void SetLatestXTime(TimestampTz xtime);
|
||||
static void SetCurrentChunkStartTime(TimestampTz xtime);
|
||||
static void CheckRequiredParameterValues(void);
|
||||
static void XLogReportParameters(void);
|
||||
static void XlogChecksums(ChecksumType new_type);
|
||||
static void checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI,
|
||||
TimeLineID prevTLI);
|
||||
static void LocalSetXLogInsertAllowed(void);
|
||||
@ -1033,7 +1034,7 @@ XLogInsertRecord(XLogRecData *rdata,
|
||||
Assert(RedoRecPtr < Insert->RedoRecPtr);
|
||||
RedoRecPtr = Insert->RedoRecPtr;
|
||||
}
|
||||
doPageWrites = (Insert->fullPageWrites || Insert->forcePageWrites);
|
||||
doPageWrites = (Insert->fullPageWrites || Insert->forcePageWrites || DataChecksumsInProgress());
|
||||
|
||||
if (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr && doPageWrites)
|
||||
{
|
||||
@ -4673,10 +4674,6 @@ ReadControlFile(void)
|
||||
(SizeOfXLogLongPHD - SizeOfXLogShortPHD);
|
||||
|
||||
CalculateCheckpointSegments();
|
||||
|
||||
/* Make the initdb settings visible as GUC variables, too */
|
||||
SetConfigOption("data_checksums", DataChecksumsEnabled() ? "yes" : "no",
|
||||
PGC_INTERNAL, PGC_S_OVERRIDE);
|
||||
}
|
||||
|
||||
void
|
||||
@ -4748,12 +4745,90 @@ GetMockAuthenticationNonce(void)
|
||||
* Are checksums enabled for data pages?
|
||||
*/
|
||||
bool
|
||||
DataChecksumsEnabled(void)
|
||||
DataChecksumsNeedWrite(void)
|
||||
{
|
||||
Assert(ControlFile != NULL);
|
||||
return (ControlFile->data_checksum_version > 0);
|
||||
}
|
||||
|
||||
bool
|
||||
DataChecksumsNeedVerify(void)
|
||||
{
|
||||
Assert(ControlFile != NULL);
|
||||
|
||||
/*
|
||||
* Only verify checksums if they are fully enabled in the cluster. In
|
||||
* inprogress state they are only updated, not verified.
|
||||
*/
|
||||
return (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_VERSION);
|
||||
}
|
||||
|
||||
bool
|
||||
DataChecksumsInProgress(void)
|
||||
{
|
||||
Assert(ControlFile != NULL);
|
||||
return (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_INPROGRESS_VERSION);
|
||||
}
|
||||
|
||||
void
|
||||
SetDataChecksumsInProgress(void)
|
||||
{
|
||||
Assert(ControlFile != NULL);
|
||||
if (ControlFile->data_checksum_version > 0)
|
||||
return;
|
||||
|
||||
XlogChecksums(PG_DATA_CHECKSUM_INPROGRESS_VERSION);
|
||||
|
||||
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
|
||||
ControlFile->data_checksum_version = PG_DATA_CHECKSUM_INPROGRESS_VERSION;
|
||||
UpdateControlFile();
|
||||
LWLockRelease(ControlFileLock);
|
||||
}
|
||||
|
||||
void
|
||||
SetDataChecksumsOn(void)
|
||||
{
|
||||
Assert(ControlFile != NULL);
|
||||
|
||||
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
|
||||
|
||||
if (ControlFile->data_checksum_version != PG_DATA_CHECKSUM_INPROGRESS_VERSION)
|
||||
{
|
||||
LWLockRelease(ControlFileLock);
|
||||
elog(ERROR, "Checksums not in inprogress mode");
|
||||
}
|
||||
|
||||
ControlFile->data_checksum_version = PG_DATA_CHECKSUM_VERSION;
|
||||
UpdateControlFile();
|
||||
LWLockRelease(ControlFileLock);
|
||||
|
||||
XlogChecksums(PG_DATA_CHECKSUM_VERSION);
|
||||
}
|
||||
|
||||
void
|
||||
SetDataChecksumsOff(void)
|
||||
{
|
||||
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
|
||||
|
||||
ControlFile->data_checksum_version = 0;
|
||||
UpdateControlFile();
|
||||
LWLockRelease(ControlFileLock);
|
||||
|
||||
XlogChecksums(0);
|
||||
}
|
||||
|
||||
/* guc hook */
|
||||
const char *
|
||||
show_data_checksums(void)
|
||||
{
|
||||
if (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_VERSION)
|
||||
return "on";
|
||||
else if (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_INPROGRESS_VERSION)
|
||||
return "inprogress";
|
||||
else
|
||||
return "off";
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a fake LSN for unlogged relations.
|
||||
*
|
||||
@ -7788,6 +7863,16 @@ StartupXLOG(void)
|
||||
*/
|
||||
CompleteCommitTsInitialization();
|
||||
|
||||
/*
|
||||
* If we reach this point with checksums in inprogress state, we notify
|
||||
* the user that they need to manually restart the process to enable
|
||||
* checksums.
|
||||
*/
|
||||
if (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_INPROGRESS_VERSION)
|
||||
ereport(WARNING,
|
||||
(errmsg("checksum state is \"inprogress\" with no worker"),
|
||||
errhint("Either disable or enable checksums by calling the pg_disable_data_checksums() or pg_enable_data_checksums() functions.")));
|
||||
|
||||
/*
|
||||
* All done with end-of-recovery actions.
|
||||
*
|
||||
@ -9541,6 +9626,22 @@ XLogReportParameters(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Log the new state of checksums
|
||||
*/
|
||||
static void
|
||||
XlogChecksums(ChecksumType new_type)
|
||||
{
|
||||
xl_checksum_state xlrec;
|
||||
|
||||
xlrec.new_checksumtype = new_type;
|
||||
|
||||
XLogBeginInsert();
|
||||
XLogRegisterData((char *) &xlrec, sizeof(xl_checksum_state));
|
||||
|
||||
XLogInsert(RM_XLOG_ID, XLOG_CHECKSUMS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update full_page_writes in shared memory, and write an
|
||||
* XLOG_FPW_CHANGE record if necessary.
|
||||
@ -9969,6 +10070,17 @@ xlog_redo(XLogReaderState *record)
|
||||
/* Keep track of full_page_writes */
|
||||
lastFullPageWrites = fpw;
|
||||
}
|
||||
else if (info == XLOG_CHECKSUMS)
|
||||
{
|
||||
xl_checksum_state state;
|
||||
|
||||
memcpy(&state, XLogRecGetData(record), sizeof(xl_checksum_state));
|
||||
|
||||
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
|
||||
ControlFile->data_checksum_version = state.new_checksumtype;
|
||||
UpdateControlFile();
|
||||
LWLockRelease(ControlFileLock);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WAL_DEBUG
|
||||
|
Reference in New Issue
Block a user