mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Add WAL consistency checking facility.
When the new GUC wal_consistency_checking is set to a non-empty value, it triggers recording of additional full-page images, which are compared on the standby against the results of applying the WAL record (without regard to those full-page images). Allowable differences such as hints are masked out, and the resulting pages are compared; any difference results in a FATAL error on the standby. Kuntal Ghosh, based on earlier patches by Michael Paquier and Heikki Linnakangas. Extensively reviewed and revised by Michael Paquier and by me, with additional reviews and comments from Amit Kapila, Álvaro Herrera, Simon Riggs, and Peter Eisentraut.
This commit is contained in:
@ -28,9 +28,11 @@
|
||||
|
||||
#include "access/commit_ts.h"
|
||||
#include "access/gin.h"
|
||||
#include "access/rmgr.h"
|
||||
#include "access/transam.h"
|
||||
#include "access/twophase.h"
|
||||
#include "access/xact.h"
|
||||
#include "access/xlog_internal.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "commands/async.h"
|
||||
#include "commands/prepare.h"
|
||||
@ -147,6 +149,10 @@ static bool call_enum_check_hook(struct config_enum * conf, int *newval,
|
||||
static bool check_log_destination(char **newval, void **extra, GucSource source);
|
||||
static void assign_log_destination(const char *newval, void *extra);
|
||||
|
||||
static bool check_wal_consistency_checking(char **newval, void **extra,
|
||||
GucSource source);
|
||||
static void assign_wal_consistency_checking(const char *newval, void *extra);
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
static int syslog_facility = LOG_LOCAL0;
|
||||
#else
|
||||
@ -3572,6 +3578,17 @@ static struct config_string ConfigureNamesString[] =
|
||||
check_cluster_name, NULL, NULL
|
||||
},
|
||||
|
||||
{
|
||||
{"wal_consistency_checking", PGC_SUSET, DEVELOPER_OPTIONS,
|
||||
gettext_noop("Sets the WAL resource managers for which WAL consistency checks are done."),
|
||||
gettext_noop("Full-page images will be logged for all data blocks and cross-checked against the results of WAL replay."),
|
||||
GUC_LIST_INPUT | GUC_NOT_IN_SAMPLE
|
||||
},
|
||||
&wal_consistency_checking_string,
|
||||
"",
|
||||
check_wal_consistency_checking, assign_wal_consistency_checking, NULL
|
||||
},
|
||||
|
||||
/* End-of-list marker */
|
||||
{
|
||||
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL
|
||||
@ -9888,6 +9905,86 @@ call_enum_check_hook(struct config_enum * conf, int *newval, void **extra,
|
||||
* check_hook, assign_hook and show_hook subroutines
|
||||
*/
|
||||
|
||||
static bool
|
||||
check_wal_consistency_checking(char **newval, void **extra, GucSource source)
|
||||
{
|
||||
char *rawstring;
|
||||
List *elemlist;
|
||||
ListCell *l;
|
||||
bool newwalconsistency[RM_MAX_ID + 1];
|
||||
|
||||
/* Initialize the array */
|
||||
MemSet(newwalconsistency, 0, (RM_MAX_ID + 1) * sizeof(bool));
|
||||
|
||||
/* Need a modifiable copy of string */
|
||||
rawstring = pstrdup(*newval);
|
||||
|
||||
/* Parse string into list of identifiers */
|
||||
if (!SplitIdentifierString(rawstring, ',', &elemlist))
|
||||
{
|
||||
/* syntax error in list */
|
||||
GUC_check_errdetail("List syntax is invalid.");
|
||||
pfree(rawstring);
|
||||
list_free(elemlist);
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach(l, elemlist)
|
||||
{
|
||||
char *tok = (char *) lfirst(l);
|
||||
bool found = false;
|
||||
RmgrId rmid;
|
||||
|
||||
/* Check for 'all'. */
|
||||
if (pg_strcasecmp(tok, "all") == 0)
|
||||
{
|
||||
for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
|
||||
if (RmgrTable[rmid].rm_mask != NULL)
|
||||
newwalconsistency[rmid] = true;
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Check if the token matches with any individual resource
|
||||
* manager.
|
||||
*/
|
||||
for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
|
||||
{
|
||||
if (pg_strcasecmp(tok, RmgrTable[rmid].rm_name) == 0 &&
|
||||
RmgrTable[rmid].rm_mask != NULL)
|
||||
{
|
||||
newwalconsistency[rmid] = true;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If a valid resource manager is found, check for the next one. */
|
||||
if (!found)
|
||||
{
|
||||
GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
|
||||
pfree(rawstring);
|
||||
list_free(elemlist);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pfree(rawstring);
|
||||
list_free(elemlist);
|
||||
|
||||
/* assign new value */
|
||||
*extra = guc_malloc(ERROR, (RM_MAX_ID + 1) * sizeof(bool));
|
||||
memcpy(*extra, newwalconsistency, (RM_MAX_ID + 1) * sizeof(bool));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
assign_wal_consistency_checking(const char *newval, void *extra)
|
||||
{
|
||||
wal_consistency_checking = (bool *) extra;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_log_destination(char **newval, void **extra, GucSource source)
|
||||
{
|
||||
|
Reference in New Issue
Block a user