diff options
Diffstat (limited to 'src/backend/replication/syncrep.c')
-rw-r--r-- | src/backend/replication/syncrep.c | 168 |
1 files changed, 72 insertions, 96 deletions
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index 3c9142eddca..acdbf1e230c 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -78,7 +78,7 @@ char *SyncRepStandbyNames; static bool announce_next_takeover = true; -SyncRepConfigData *SyncRepConfig; +static SyncRepConfigData *SyncRepConfig = NULL; static int SyncRepWaitMode = SYNC_REP_NO_WAIT; static void SyncRepQueueInsert(int mode); @@ -361,11 +361,6 @@ SyncRepInitConfig(void) { int priority; - /* Update the config data of synchronous replication */ - SyncRepFreeConfig(SyncRepConfig); - SyncRepConfig = NULL; - SyncRepUpdateConfig(); - /* * Determine if we are a potential sync standby and remember the result * for handling replies from standby. @@ -509,7 +504,9 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, * Quick exit if we are not managing a sync standby or there are not * enough synchronous standbys. */ - if (!(*am_sync) || list_length(sync_standbys) < SyncRepConfig->num_sync) + if (!(*am_sync) || + SyncRepConfig == NULL || + list_length(sync_standbys) < SyncRepConfig->num_sync) { list_free(sync_standbys); return false; @@ -568,14 +565,15 @@ SyncRepGetSyncStandbys(bool *am_sync) volatile WalSnd *walsnd; /* Use volatile pointer to prevent * code rearrangement */ + /* Set default result */ + if (am_sync != NULL) + *am_sync = false; + /* Quick exit if sync replication is not requested */ if (SyncRepConfig == NULL) return NIL; - if (am_sync != NULL) - *am_sync = false; - - lowest_priority = list_length(SyncRepConfig->members); + lowest_priority = SyncRepConfig->nmembers; next_highest_priority = lowest_priority + 1; /* @@ -730,9 +728,8 @@ SyncRepGetSyncStandbys(bool *am_sync) static int SyncRepGetStandbyPriority(void) { - List *members; - ListCell *l; - int priority = 0; + const char *standby_name; + int priority; bool found = false; /* @@ -742,22 +739,19 @@ SyncRepGetStandbyPriority(void) if (am_cascading_walsender) return 0; - if (!SyncStandbysDefined()) + if (!SyncStandbysDefined() || SyncRepConfig == NULL) return 0; - members = SyncRepConfig->members; - foreach(l, members) + standby_name = SyncRepConfig->member_names; + for (priority = 1; priority <= SyncRepConfig->nmembers; priority++) { - char *standby_name = (char *) lfirst(l); - - priority++; - if (pg_strcasecmp(standby_name, application_name) == 0 || - pg_strcasecmp(standby_name, "*") == 0) + strcmp(standby_name, "*") == 0) { found = true; break; } + standby_name += strlen(standby_name) + 1; } return (found ? priority : 0); @@ -867,50 +861,6 @@ SyncRepUpdateSyncStandbysDefined(void) } } -/* - * Parse synchronous_standby_names and update the config data - * of synchronous standbys. - */ -void -SyncRepUpdateConfig(void) -{ - int parse_rc; - - if (!SyncStandbysDefined()) - return; - - /* - * check_synchronous_standby_names() verifies the setting value of - * synchronous_standby_names before this function is called. So - * syncrep_yyparse() must not cause an error here. - */ - syncrep_scanner_init(SyncRepStandbyNames); - parse_rc = syncrep_yyparse(); - syncrep_scanner_finish(); - - if (parse_rc != 0) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg_internal("synchronous_standby_names parser returned %d", - parse_rc))); - - SyncRepConfig = syncrep_parse_result; - syncrep_parse_result = NULL; -} - -/* - * Free a previously-allocated config data of synchronous replication. - */ -void -SyncRepFreeConfig(SyncRepConfigData *config) -{ - if (!config) - return; - - list_free_deep(config->members); - pfree(config); -} - #ifdef USE_ASSERT_CHECKING static bool SyncRepQueueIsOrderedByLSN(int mode) @@ -955,79 +905,105 @@ SyncRepQueueIsOrderedByLSN(int mode) bool check_synchronous_standby_names(char **newval, void **extra, GucSource source) { - int parse_rc; - if (*newval != NULL && (*newval)[0] != '\0') { + int parse_rc; + SyncRepConfigData *pconf; + + /* Reset communication variables to ensure a fresh start */ + syncrep_parse_result = NULL; + syncrep_parse_error_msg = NULL; + + /* Parse the synchronous_standby_names string */ syncrep_scanner_init(*newval); parse_rc = syncrep_yyparse(); syncrep_scanner_finish(); - if (parse_rc != 0) + if (parse_rc != 0 || syncrep_parse_result == NULL) { GUC_check_errcode(ERRCODE_SYNTAX_ERROR); - GUC_check_errdetail("synchronous_standby_names parser returned %d", - parse_rc); + if (syncrep_parse_error_msg) + GUC_check_errdetail("%s", syncrep_parse_error_msg); + else + GUC_check_errdetail("synchronous_standby_names parser failed"); return false; } /* * Warn if num_sync exceeds the number of names of potential sync - * standbys. This setting doesn't make sense in most cases because - * it implies that enough number of sync standbys will not appear, - * which makes transaction commits wait for sync replication - * infinitely. + * standbys. This setting doesn't make sense in most cases because it + * implies that enough number of sync standbys will not appear, which + * makes transaction commits wait for sync replication infinitely. * * If there are more than one standbys having the same name and * priority, we can see enough sync standbys to complete transaction - * commits. However it's not recommended to run multiple standbys - * with the same priority because we cannot gain full control of - * the selection of sync standbys from them. + * commits. However it's not recommended to run multiple standbys with + * the same priority because we cannot gain full control of the + * selection of sync standbys from them. * * OTOH, that setting is OK if we understand the above problem - * regarding the selection of sync standbys and intentionally - * specify * to match all the standbys. + * regarding the selection of sync standbys and intentionally specify * + * to match all the standbys. */ - if (syncrep_parse_result->num_sync > - list_length(syncrep_parse_result->members)) + if (syncrep_parse_result->num_sync > syncrep_parse_result->nmembers) { - ListCell *l; - bool has_asterisk = false; + const char *standby_name; + int i; + bool has_asterisk = false; - foreach(l, syncrep_parse_result->members) + standby_name = syncrep_parse_result->member_names; + for (i = 1; i <= syncrep_parse_result->nmembers; i++) { - char *standby_name = (char *) lfirst(l); - - if (pg_strcasecmp(standby_name, "*") == 0) + if (strcmp(standby_name, "*") == 0) { has_asterisk = true; break; } + standby_name += strlen(standby_name) + 1; } /* - * Only the postmaster warns this inappropriate setting - * to avoid cluttering the log. + * Only the postmaster warns about this inappropriate setting to + * avoid cluttering the log. */ if (!has_asterisk && !IsUnderPostmaster) ereport(WARNING, - (errmsg("The configured number of synchronous standbys (%d) exceeds the number of names of potential synchronous ones (%d)", - syncrep_parse_result->num_sync, list_length(syncrep_parse_result->members)), + (errmsg("configured number of synchronous standbys (%d) exceeds the number of names of potential synchronous ones (%d)", + syncrep_parse_result->num_sync, + syncrep_parse_result->nmembers), errhint("Specify more names of potential synchronous standbys in synchronous_standby_names."))); } + /* GUC extra value must be malloc'd, not palloc'd */ + pconf = (SyncRepConfigData *) + malloc(syncrep_parse_result->config_size); + if (pconf == NULL) + return false; + memcpy(pconf, syncrep_parse_result, syncrep_parse_result->config_size); + + *extra = (void *) pconf; + /* - * syncrep_yyparse sets the global syncrep_parse_result as side effect. - * But this function is required to just check, so frees it - * after parsing the parameter. + * We need not explicitly clean up syncrep_parse_result. It, and any + * other cruft generated during parsing, will be freed when the + * current memory context is deleted. (This code is generally run in + * a short-lived context used for config file processing, so that will + * not be very long.) */ - SyncRepFreeConfig(syncrep_parse_result); } + else + *extra = NULL; return true; } void +assign_synchronous_standby_names(const char *newval, void *extra) +{ + SyncRepConfig = (SyncRepConfigData *) extra; +} + +void assign_synchronous_commit(int newval, void *extra) { switch (newval) |