On Fri, Sep 9, 2016 at 6:23 PM, Simon Riggs <si...@2ndquadrant.com> wrote: > On 8 September 2016 at 10:26, Masahiko Sawada <sawada.m...@gmail.com> wrote: > >> "k (n1, n2, n3)" == "first k (n1, n2, n3)" doesn't break backward >> compatibility but most users would think "k(n1, n2, n3)" as quorum >> after introduced quorum. >> I wish we can change the s_s_names syntax of 9.6 to "first k(n1, n2, >> n3)" style before 9.6 releasing if we got consensus. > > Let's see the proposed patch, so we can evaluate the proposal. >
Attached 2 patches. 000 patch changes syntax of s_s_names from 'k(n1, n2, n3)' to 'First k (n1, n2,n3)' for PG9.6. 001 patch adds the quorum commit using syntax 'Any k (n1, n2,n3)' for PG10. Since we already released 9.6RC1, I understand that it's quite hard to change syntax of 9.6. But considering that we support the quorum commit, this could be one of the solutions in order to avoid breaking backward compatibility and to provide useful user interface. So I attached these patches. Regards, -- Masahiko Sawada NIPPON TELEGRAPH AND TELEPHONE CORPORATION NTT Open Source Software Center
commit bd18dda9be5ab0341eca81de3c48ec6f7466dded Author: Masahiko Sawada <sawada.m...@gmail.com> Date: Fri Sep 16 15:32:24 2016 -0700 Change syntax diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index cd66abc..f0f510c 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -3037,7 +3037,7 @@ include_dir 'conf.d' This parameter specifies a list of standby servers using either of the following syntaxes: <synopsis> -<replaceable class="parameter">num_sync</replaceable> ( <replaceable class="parameter">standby_name</replaceable> [, ...] ) +FIRST <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="parameter">standby_name</replaceable> [, ...] ) <replaceable class="parameter">standby_name</replaceable> [, ...] </synopsis> where <replaceable class="parameter">num_sync</replaceable> is @@ -3048,7 +3048,9 @@ include_dir 'conf.d' <literal>3 (s1, s2, s3, s4)</> makes transaction commits wait until their WAL records are received by three higher-priority standbys chosen from standby servers <literal>s1</>, <literal>s2</>, - <literal>s3</> and <literal>s4</>. + <literal>s3</> and <literal>s4</>. <literal>FIRST</> is + case-insensitive but the standby having name <literal>FIRST</> + must be double-quoted. </para> <para> The second syntax was used before <productname>PostgreSQL</> diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index 06f49db..84ccb6e 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -1150,7 +1150,7 @@ primary_slot_name = 'node_a_slot' An example of <varname>synchronous_standby_names</> for multiple synchronous standbys is: <programlisting> -synchronous_standby_names = '2 (s1, s2, s3)' +synchronous_standby_names = 'FIRST 2 (s1, s2, s3)' </programlisting> In this example, if four standby servers <literal>s1</>, <literal>s2</>, <literal>s3</> and <literal>s4</> are running, the two standbys diff --git a/src/backend/replication/Makefile b/src/backend/replication/Makefile index c99717e..da8bcf0 100644 --- a/src/backend/replication/Makefile +++ b/src/backend/replication/Makefile @@ -26,7 +26,7 @@ repl_gram.o: repl_scanner.c # syncrep_scanner is complied as part of syncrep_gram syncrep_gram.o: syncrep_scanner.c -syncrep_scanner.c: FLEXFLAGS = -CF -p +syncrep_scanner.c: FLEXFLAGS = -CF -p -i syncrep_scanner.c: FLEX_NO_BACKUP=yes # repl_gram.c, repl_scanner.c, syncrep_gram.c and syncrep_scanner.c diff --git a/src/backend/replication/syncrep_gram.y b/src/backend/replication/syncrep_gram.y index 35c2776..b6d2f6c 100644 --- a/src/backend/replication/syncrep_gram.y +++ b/src/backend/replication/syncrep_gram.y @@ -46,7 +46,7 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync, SyncRepConfigData *config; } -%token <str> NAME NUM JUNK +%token <str> NAME NUM JUNK FIRST %type <config> result standby_config %type <list> standby_list @@ -61,7 +61,7 @@ result: standby_config: standby_list { $$ = create_syncrep_config("1", $1); } - | NUM '(' standby_list ')' { $$ = create_syncrep_config($1, $3); } + | FIRST NUM '(' standby_list ')' { $$ = create_syncrep_config($1, $4); } ; standby_list: @@ -70,7 +70,7 @@ standby_list: ; standby_name: - NAME { $$ = $1; } + NAME { $$ = $1;} | NUM { $$ = $1; } ; %% diff --git a/src/backend/replication/syncrep_scanner.l b/src/backend/replication/syncrep_scanner.l index d20662e..9dbdfbc 100644 --- a/src/backend/replication/syncrep_scanner.l +++ b/src/backend/replication/syncrep_scanner.l @@ -64,6 +64,11 @@ xdinside [^"]+ %% {space}+ { /* ignore */ } +first { + yylval.str = pstrdup(yytext); + return FIRST; + } + {xdstart} { initStringInfo(&xdbuf); BEGIN(xd);
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index f0f510c..0ad06ad 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -3021,44 +3021,68 @@ include_dir 'conf.d' There will be one or more active synchronous standbys; transactions waiting for commit will be allowed to proceed after these standby servers confirm receipt of their data. - The synchronous standbys will be those whose names appear - earlier in this list, and - that are both currently connected and streaming data in real-time - (as shown by a state of <literal>streaming</literal> in the - <link linkend="monitoring-stats-views-table"> - <literal>pg_stat_replication</></link> view). - Other standby servers appearing later in this list represent potential - synchronous standbys. If any of the current synchronous - standbys disconnects for whatever reason, - it will be replaced immediately with the next-highest-priority standby. Specifying more than one standby name can allow very high availability. </para> <para> This parameter specifies a list of standby servers using either of the following syntaxes: <synopsis> -FIRST <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="parameter">standby_name</replaceable> [, ...] ) +[ FIRST | ANY ] <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="parameter">standby_name</replaceable> [, ...] ) <replaceable class="parameter">standby_name</replaceable> [, ...] </synopsis> + + where <replaceable class="parameter">num_sync</replaceable> is the number of synchronous standbys that transactions need to wait for replies from, and <replaceable class="parameter">standby_name</replaceable> - is the name of a standby server. For example, a setting of - <literal>3 (s1, s2, s3, s4)</> makes transaction commits wait - until their WAL records are received by three higher-priority standbys - chosen from standby servers <literal>s1</>, <literal>s2</>, - <literal>s3</> and <literal>s4</>. <literal>FIRST</> is - case-insensitive but the standby having name <literal>FIRST</> - must be double-quoted. + is the name of a standby server. + <literal>FIRST</> and <literal>ANY</> specify the method of + that how master server controls the standby servers. + </para> + + <para> + <literal>FIRST</> means to control the standby servers with + different priorities. The synchronous standbys will be those + whose name appear earlier in this list, and that are both + currently connected and streaming data in real-time(as shown + by a state of <literal>streaming</> in the + <link linkend="monitoring-stats-views-table"> + <literal>pg_stat_replication</></link> view). Other standby + servers appearing later in this list represent potential + synchronous standbys. If any of the current synchronous + standbys disconnects for whatever reason, it will be replaced + immediately with the next-highest-priority standby. + For example, a setting of <literal>FIRST 3 (s1, s2, s3, s4)</> + makes transaction commits wait until their WAL records are received + by three higher-priority standbys chosen from standby servers + <literal>s1</>, <literal>s2</>, <literal>s3</> and <literal>s4</>. + </para> + + <para> + <literal>ANY</> means to control all of standby servers with + same priority. The master sever will wait for receipt from + at least <replaceable class="parameter">num_sync</replaceable> + standbys, which is quorum commit in the literature. The all of + listed standbys are considered as candidate of quorum commit. + For example, a setting of <literal> ANY 3 (s1, s2, s3, s4)</> makes + transaction commits wait until receiving receipts from at least + any three standbys of four listed servers <literal>s1</>, + <literal>s2</>, <literal>s3</>, <literal>s4</>. + </para> + + <para> + <literal>FIRST</> and <literal>ANY</> are case-insensitive word + and the standby name having these words are must be double-quoted. </para> + <para> The second syntax was used before <productname>PostgreSQL</> version 9.6 and is still supported. It's the same as the first syntax - with <replaceable class="parameter">num_sync</replaceable> equal to 1. - For example, <literal>1 (s1, s2)</> and - <literal>s1, s2</> have the same meaning: either <literal>s1</> - or <literal>s2</> is chosen as a synchronous standby. + with <literal>FIRST</> and <replaceable class="parameter">num_sync</replaceable> + equal to 1. For example, <literal>1 (s1, s2)</> and <literal>s1, s2</> + have the same meaning: either <literal>s1</> or <literal>s2</> is + chosen as a synchronous standby. </para> <para> The name of a standby server for this purpose is the diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index 84ccb6e..8a9e65d 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -1134,7 +1134,7 @@ primary_slot_name = 'node_a_slot' <para> Synchronous replication supports one or more synchronous standby servers; - transactions will wait until all the standby servers which are considered + transactions will wait until the multiple standby servers which are considered as synchronous confirm receipt of their data. The number of synchronous standbys that transactions must wait for replies from is specified in <varname>synchronous_standby_names</>. This parameter also specifies @@ -1161,6 +1161,18 @@ synchronous_standby_names = 'FIRST 2 (s1, s2, s3)' <literal>s2</> fails. <literal>s4</> is an asynchronous standby since its name is not in the list. </para> + <para> + Another example of <varname>synchronous_standby_names</> for multiple + synchronous standby is: +<programlisting> + synchronous_standby_names = 'ANY 2 (s1, s2, s3)' +</programlisting> + In this example, if four standby servers <literal>s1</>, <literal>s2</>, + <literal>s3</> and <literal>s4</> are running, the all of listed standbys + will be considered as candidate of quorum commit. The master server will + wait for at least 2 replies from any of three standbys. <literal>s4</> is + an asynchronous standby since its name is not in the list. + </para> </sect3> <sect3 id="synchronous-replication-performance"> diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 0776428..ad2c8e6 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -1220,7 +1220,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i <row> <entry><structfield>sync_state</></entry> <entry><type>text</></entry> - <entry>Synchronous state of this standby server</entry> + <entry>Synchronous state of this standby server. <literal>quorum</> + when standby is considered as a candidate of quorum commit.</entry> </row> </tbody> </tgroup> diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index b442d06..bc67fce 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -76,9 +76,9 @@ char *SyncRepStandbyNames; #define SyncStandbysDefined() \ (SyncRepStandbyNames != NULL && SyncRepStandbyNames[0] != '\0') -static bool announce_next_takeover = true; +SyncRepConfigData *SyncRepConfig = NULL; -static SyncRepConfigData *SyncRepConfig = NULL; +static bool announce_next_takeover = true; static int SyncRepWaitMode = SYNC_REP_NO_WAIT; static void SyncRepQueueInsert(int mode); @@ -89,7 +89,12 @@ static bool SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, XLogRecPtr *applyPtr, bool *am_sync); +static bool SyncRepGetNNewestSyncRecPtr(XLogRecPtr *writePtr, + XLogRecPtr *flushPtr, + XLogRecPtr *applyPtr, + int pos, bool *am_sync); static int SyncRepGetStandbyPriority(void); +static int cmp_lsn(const void *a, const void *b); #ifdef USE_ASSERT_CHECKING static bool SyncRepQueueIsOrderedByLSN(int mode); @@ -384,7 +389,7 @@ SyncRepReleaseWaiters(void) XLogRecPtr writePtr; XLogRecPtr flushPtr; XLogRecPtr applyPtr; - bool got_oldest; + bool got_recptr; bool am_sync; int numwrite = 0; int numflush = 0; @@ -411,11 +416,16 @@ SyncRepReleaseWaiters(void) LWLockAcquire(SyncRepLock, LW_EXCLUSIVE); /* - * Check whether we are a sync standby or not, and calculate the oldest - * positions among all sync standbys. + * Check whether we are a sync standby or not, and calculate the synced + * positions among all sync standbys using method. */ - got_oldest = SyncRepGetOldestSyncRecPtr(&writePtr, &flushPtr, - &applyPtr, &am_sync); + if (SyncRepConfig->sync_method == SYNC_REP_PRIORITY) + got_recptr = SyncRepGetOldestSyncRecPtr(&writePtr, &flushPtr, + &applyPtr, &am_sync); + else /* SYNC_REP_QUORUM */ + got_recptr = SyncRepGetNNewestSyncRecPtr(&writePtr, &flushPtr, + &applyPtr, SyncRepConfig->num_sync, + &am_sync); /* * If we are managing a sync standby, though we weren't prior to this, @@ -433,7 +443,7 @@ SyncRepReleaseWaiters(void) * If the number of sync standbys is less than requested or we aren't * managing a sync standby then just leave. */ - if (!got_oldest || !am_sync) + if (!got_recptr || !am_sync) { LWLockRelease(SyncRepLock); announce_next_takeover = !am_sync; @@ -469,6 +479,88 @@ SyncRepReleaseWaiters(void) } /* + * Calculate the 'pos' newest Write, Flush and Apply positions among sync standbys. + * + * Return false if the number of sync standbys is less than + * synchronous_standby_names specifies. Otherwise return true and + * store the 'pos' newest positions into *writePtr, *flushPtr, *applyPtr. + * + * On return, *am_sync is set to true if this walsender is connecting to + * sync standby. Otherwise it's set to false. + */ +static bool +SyncRepGetNNewestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, + XLogRecPtr *applyPtr, int pos, bool *am_sync) +{ + XLogRecPtr *write_array; + XLogRecPtr *flush_array; + XLogRecPtr *apply_array; + List *sync_standbys; + ListCell *cell; + int len; + int i = 0; + + *writePtr = InvalidXLogRecPtr; + *flushPtr = InvalidXLogRecPtr; + *applyPtr = InvalidXLogRecPtr; + *am_sync = false; + + /* Get standbys that are considered as synchronous at this moment */ + sync_standbys = SyncRepGetSyncStandbys(am_sync); + + /* + * Quick exit if we are not managing a sync standby or there are not + * enough synchronous standbys. + */ + if (!(*am_sync) || + SyncRepConfig == NULL || + list_length(sync_standbys) < SyncRepConfig->num_sync) + { + list_free(sync_standbys); + return false; + } + + len = list_length(sync_standbys); + write_array = (XLogRecPtr *) palloc(sizeof(XLogRecPtr) * len); + flush_array = (XLogRecPtr *) palloc(sizeof(XLogRecPtr) * len); + apply_array = (XLogRecPtr *) palloc(sizeof(XLogRecPtr) * len); + + /* + * Scan through all sync standbys and calculate 'pos' Newest + * Write, Flush and Apply positions. + */ + foreach (cell, sync_standbys) + { + WalSnd *walsnd = &WalSndCtl->walsnds[lfirst_int(cell)]; + + SpinLockAcquire(&walsnd->mutex); + write_array[i] = walsnd->write; + flush_array[i]= walsnd->flush; + apply_array[i] = walsnd->flush; + SpinLockRelease(&walsnd->mutex); + + i++; + } + + /* Sort each array in descending order to get 'pos' newest element */ + qsort(write_array, len, sizeof(XLogRecPtr), cmp_lsn); + qsort(flush_array, len, sizeof(XLogRecPtr), cmp_lsn); + qsort(apply_array, len, sizeof(XLogRecPtr), cmp_lsn); + + /* Get 'pos' newest Write, Flush, Apply positions */ + *writePtr = write_array[pos - 1]; + *flushPtr = flush_array[pos - 1]; + *applyPtr = apply_array[pos - 1]; + + pfree(write_array); + pfree(flush_array); + pfree(apply_array); + list_free(sync_standbys); + + return true; +} + +/* * Calculate the oldest Write, Flush and Apply positions among sync standbys. * * Return false if the number of sync standbys is less than @@ -506,12 +598,12 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, } /* - * Scan through all sync standbys and calculate the oldest Write, Flush - * and Apply positions. + * Scan through all sync standbys and calculate the oldest + * Write, Flush and Apply positions. */ - foreach(cell, sync_standbys) + foreach (cell, sync_standbys) { - WalSnd *walsnd = &WalSndCtl->walsnds[lfirst_int(cell)]; + WalSnd *walsnd = &WalSndCtl->walsnds[lfirst_int(cell)]; XLogRecPtr write; XLogRecPtr flush; XLogRecPtr apply; @@ -535,17 +627,88 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr, XLogRecPtr *flushPtr, } /* - * Return the list of sync standbys, or NIL if no sync standby is connected. + * Return the list of sync standbys using according to synchronous method, + * or NIL if no sync standby is connected. The caller must hold SyncRepLock. * - * If there are multiple standbys with the same priority, - * the first one found is selected preferentially. - * The caller must hold SyncRepLock. + * On return, *am_sync is set to true if this walsender is connecting to + * sync standby. Otherwise it's set to false. + */ +List * +SyncRepGetSyncStandbys(bool *am_sync) +{ + /* Set default result */ + if (am_sync != NULL) + *am_sync = false; + + /* Quick exit if sync replication is not requested */ + if (SyncRepConfig == NULL) + return NIL; + + if (SyncRepConfig->sync_method == SYNC_REP_PRIORITY) + return SyncRepGetSyncStandbysPriority(am_sync); + else /* SYNC_REP_QUORUM */ + return SyncRepGetSyncStandbysQuorum(am_sync); +} + +/* + * Return the list of sync standbys using quorum method, or + * NIL if no sync standby is connected. In quorum method, all standby + * priorities are same, that is 1. So this function returns the list of + * standbys except for the standbys which are not active, or connected + * as async. + * + * On return, *am_sync is set to true if this walsender is connecting to + * sync standby. Otherwise it's set to false. + */ +List * +SyncRepGetSyncStandbysQuorum(bool *am_sync) +{ + List *result = NIL; + int i; + + for (i = 0; i < max_wal_senders; i++) + { + volatile WalSnd *walsnd = &WalSndCtl->walsnds[i]; + + /* Must be active */ + if (walsnd->pid == 0) + continue; + + /* Must be streaming */ + if (walsnd->state != WALSNDSTATE_STREAMING) + continue; + + /* Must be synchronous */ + if (walsnd->sync_standby_priority == 0) + continue; + + /* Must have a valid flush position */ + if (XLogRecPtrIsInvalid(walsnd->flush)) + continue; + + /* + * Consider this standby as candidate of sync and append + * it to the result. + */ + result = lappend_int(result, i); + if (am_sync != NULL && walsnd == MyWalSnd) + *am_sync = true; + } + + return result; +} + +/* + * Return the list of sync standbys using priority method, or + * NIL if no sync standby is connected. In priority method, + * if there are multiple standbys with the same priority, + * the first one found is selected perferentially. * * On return, *am_sync is set to true if this walsender is connecting to * sync standby. Otherwise it's set to false. */ List * -SyncRepGetSyncStandbys(bool *am_sync) +SyncRepGetSyncStandbysPriority(bool *am_sync) { List *result = NIL; List *pending = NIL; @@ -558,14 +721,6 @@ 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; - lowest_priority = SyncRepConfig->nmembers; next_highest_priority = lowest_priority + 1; @@ -747,6 +902,10 @@ SyncRepGetStandbyPriority(void) standby_name += strlen(standby_name) + 1; } + /* In quroum method, all sync standby priorities are always 1 */ + if (found && SyncRepConfig->sync_method == SYNC_REP_QUORUM) + priority = 1; + return (found ? priority : 0); } @@ -890,6 +1049,23 @@ SyncRepQueueIsOrderedByLSN(int mode) #endif /* + * Compare lsn in order to sort array in descending order. + */ +static int +cmp_lsn(const void *a, const void *b) +{ + XLogRecPtr lsn1 = *((const XLogRecPtr *) a); + XLogRecPtr lsn2 = *((const XLogRecPtr *) b); + + if (lsn1 > lsn2) + return -1; + else if (lsn1 == lsn2) + return 0; + else + return 1; +} + +/* * =========================================================== * Synchronous Replication functions executed by any process * =========================================================== diff --git a/src/backend/replication/syncrep_gram.y b/src/backend/replication/syncrep_gram.y index b6d2f6c..e1335d1 100644 --- a/src/backend/replication/syncrep_gram.y +++ b/src/backend/replication/syncrep_gram.y @@ -21,7 +21,7 @@ SyncRepConfigData *syncrep_parse_result; char *syncrep_parse_error_msg; static SyncRepConfigData *create_syncrep_config(const char *num_sync, - List *members); + List *members, int sync_method); /* * Bison doesn't allocate anything that needs to live across parser calls, @@ -46,7 +46,7 @@ static SyncRepConfigData *create_syncrep_config(const char *num_sync, SyncRepConfigData *config; } -%token <str> NAME NUM JUNK FIRST +%token <str> NAME NUM JUNK ANY FIRST %type <config> result standby_config %type <list> standby_list @@ -60,8 +60,9 @@ result: ; standby_config: - standby_list { $$ = create_syncrep_config("1", $1); } - | FIRST NUM '(' standby_list ')' { $$ = create_syncrep_config($1, $4); } + standby_list { $$ = create_syncrep_config("1", $1, SYNC_REP_PRIORITY); } + | ANY NUM '(' standby_list ')' { $$ = create_syncrep_config($2, $4, SYNC_REP_QUORUM); } + | FIRST NUM '(' standby_list ')' { $$ = create_syncrep_config($2, $4, SYNC_REP_PRIORITY); } ; standby_list: @@ -77,7 +78,7 @@ standby_name: static SyncRepConfigData * -create_syncrep_config(const char *num_sync, List *members) +create_syncrep_config(const char *num_sync, List *members, int sync_method) { SyncRepConfigData *config; int size; @@ -98,6 +99,7 @@ create_syncrep_config(const char *num_sync, List *members) config->config_size = size; config->num_sync = atoi(num_sync); + config->sync_method = sync_method; config->nmembers = list_length(members); ptr = config->member_names; foreach(lc, members) diff --git a/src/backend/replication/syncrep_scanner.l b/src/backend/replication/syncrep_scanner.l index 9dbdfbc..319abdc 100644 --- a/src/backend/replication/syncrep_scanner.l +++ b/src/backend/replication/syncrep_scanner.l @@ -69,6 +69,10 @@ first { return FIRST; } +any { + yylval.str = pstrdup(yytext); + return ANY; + } {xdstart} { initStringInfo(&xdbuf); BEGIN(xd); diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index c7743da..00467a4 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -2862,7 +2862,8 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS) if (priority == 0) values[7] = CStringGetTextDatum("async"); else if (list_member_int(sync_standbys, i)) - values[7] = CStringGetTextDatum("sync"); + values[7] = SyncRepConfig->sync_method == SYNC_REP_PRIORITY ? + CStringGetTextDatum("sync") : CStringGetTextDatum("quorum"); else values[7] = CStringGetTextDatum("potential"); } diff --git a/src/include/access/brin_xlog.h b/src/include/access/brin_xlog.h index f614805..18793f3 100644 --- a/src/include/access/brin_xlog.h +++ b/src/include/access/brin_xlog.h @@ -124,7 +124,6 @@ typedef struct xl_brin_revmap_extend #define SizeOfBrinRevmapExtend (offsetof(xl_brin_revmap_extend, targetBlk) + \ sizeof(BlockNumber)) - extern void brin_redo(XLogReaderState *record); extern void brin_desc(StringInfo buf, XLogReaderState *record); extern const char *brin_identify(uint8 info); diff --git a/src/include/replication/syncrep.h b/src/include/replication/syncrep.h index e4e0e27..4ec1e47 100644 --- a/src/include/replication/syncrep.h +++ b/src/include/replication/syncrep.h @@ -32,6 +32,10 @@ #define SYNC_REP_WAITING 1 #define SYNC_REP_WAIT_COMPLETE 2 +/* sync_method of SyncRepConfigData */ +#define SYNC_REP_PRIORITY 0 +#define SYNC_REP_QUORUM 1 + /* * Struct for the configuration of synchronous replication. * @@ -45,10 +49,13 @@ typedef struct SyncRepConfigData int num_sync; /* number of sync standbys that we need to * wait for */ int nmembers; /* number of members in the following list */ + int sync_method; /* synchronous method */ /* member_names contains nmembers consecutive nul-terminated C strings */ char member_names[FLEXIBLE_ARRAY_MEMBER]; } SyncRepConfigData; +extern SyncRepConfigData *SyncRepConfig; + /* communication variables for parsing synchronous_standby_names GUC */ extern SyncRepConfigData *syncrep_parse_result; extern char *syncrep_parse_error_msg; @@ -68,6 +75,8 @@ extern void SyncRepReleaseWaiters(void); /* called by wal sender and user backend */ extern List *SyncRepGetSyncStandbys(bool *am_sync); +extern List *SyncRepGetSyncStandbysPriority(bool *am_sync); +extern List *SyncRepGetSyncStandbysQuorum(bool *am_sync); /* called by checkpointer */ extern void SyncRepUpdateSyncStandbysDefined(void);
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers