diff options
Diffstat (limited to 'src/backend/access/transam/xlog.c')
-rw-r--r-- | src/backend/access/transam/xlog.c | 176 |
1 files changed, 175 insertions, 1 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 7a710e6490d..81d339d57d7 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -97,7 +97,8 @@ #include "storage/smgr.h" #include "storage/spin.h" #include "storage/sync.h" -#include "utils/guc.h" +#include "utils/guc_hooks.h" +#include "utils/guc_tables.h" #include "utils/memutils.h" #include "utils/ps_status.h" #include "utils/relmapper.h" @@ -105,6 +106,7 @@ #include "utils/snapmgr.h" #include "utils/timeout.h" #include "utils/timestamp.h" +#include "utils/varlena.h" extern uint32 bootstrap_data_checksum_version; @@ -161,6 +163,12 @@ static double CheckPointDistanceEstimate = 0; static double PrevCheckPointDistance = 0; /* + * Track whether there were any deferred checks for custom resource managers + * specified in wal_consistency_checking. + */ +static bool check_wal_consistency_checking_deferred = false; + +/* * GUC support */ const struct config_enum_entry sync_method_options[] = { @@ -4305,6 +4313,172 @@ check_wal_buffers(int *newval, void **extra, GucSource source) } /* + * GUC check_hook for wal_consistency_checking + */ +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); + int rmid; + + /* Check for 'all'. */ + if (pg_strcasecmp(tok, "all") == 0) + { + for (rmid = 0; rmid <= RM_MAX_ID; rmid++) + if (RmgrIdExists(rmid) && GetRmgr(rmid).rm_mask != NULL) + newwalconsistency[rmid] = true; + } + else + { + /* Check if the token matches any known resource manager. */ + bool found = false; + + for (rmid = 0; rmid <= RM_MAX_ID; rmid++) + { + if (RmgrIdExists(rmid) && GetRmgr(rmid).rm_mask != NULL && + pg_strcasecmp(tok, GetRmgr(rmid).rm_name) == 0) + { + newwalconsistency[rmid] = true; + found = true; + break; + } + } + if (!found) + { + /* + * During startup, it might be a not-yet-loaded custom + * resource manager. Defer checking until + * InitializeWalConsistencyChecking(). + */ + if (!process_shared_preload_libraries_done) + { + check_wal_consistency_checking_deferred = true; + } + else + { + 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; +} + +/* + * GUC assign_hook for wal_consistency_checking + */ +void +assign_wal_consistency_checking(const char *newval, void *extra) +{ + /* + * If some checks were deferred, it's possible that the checks will fail + * later during InitializeWalConsistencyChecking(). But in that case, the + * postmaster will exit anyway, so it's safe to proceed with the + * assignment. + * + * Any built-in resource managers specified are assigned immediately, + * which affects WAL created before shared_preload_libraries are + * processed. Any custom resource managers specified won't be assigned + * until after shared_preload_libraries are processed, but that's OK + * because WAL for a custom resource manager can't be written before the + * module is loaded anyway. + */ + wal_consistency_checking = extra; +} + +/* + * InitializeWalConsistencyChecking: run after loading custom resource managers + * + * If any unknown resource managers were specified in the + * wal_consistency_checking GUC, processing was deferred. Now that + * shared_preload_libraries have been loaded, process wal_consistency_checking + * again. + */ +void +InitializeWalConsistencyChecking(void) +{ + Assert(process_shared_preload_libraries_done); + + if (check_wal_consistency_checking_deferred) + { + struct config_generic *guc; + + guc = find_option("wal_consistency_checking", false, false, ERROR); + + check_wal_consistency_checking_deferred = false; + + set_config_option_ext("wal_consistency_checking", + wal_consistency_checking_string, + guc->scontext, guc->source, guc->srole, + GUC_ACTION_SET, true, ERROR, false); + + /* checking should not be deferred again */ + Assert(!check_wal_consistency_checking_deferred); + } +} + +/* + * GUC show_hook for archive_command + */ +const char * +show_archive_command(void) +{ + if (XLogArchivingActive()) + return XLogArchiveCommand; + else + return "(disabled)"; +} + +/* + * GUC show_hook for in_hot_standby + */ +const char * +show_in_hot_standby(void) +{ + /* + * We display the actual state based on shared memory, so that this GUC + * reports up-to-date state if examined intra-query. The underlying + * variable (in_hot_standby_guc) changes only when we transmit a new value + * to the client. + */ + return RecoveryInProgress() ? "on" : "off"; +} + + +/* * Read the control file, set respective GUCs. * * This is to be called during startup, including a crash recovery cycle, |