From a5dc43396834fe278063b4de8e7113e7e4dca6f9 Mon Sep 17 00:00:00 2001 From: Yura Sokolov Date: Wed, 20 Oct 2021 21:18:04 +0300 Subject: [PATCH 01/14] sync regression_ee.diff PGPRO-5676 --- expected/regression_ee.diff | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/expected/regression_ee.diff b/expected/regression_ee.diff index f75fa64e6f..02a7581a1b 100644 --- a/expected/regression_ee.diff +++ b/expected/regression_ee.diff @@ -172,7 +172,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou \d concur_heap Table "public.concur_heap" Column | Type | Collation | Nullable | Default -@@ -2428,46 +2428,38 @@ +@@ -2447,46 +2447,38 @@ INSERT INTO concur_reindex_tab4 VALUES (1), (1), (2); -- This trick creates an invalid index. CREATE UNIQUE INDEX CONCURRENTLY concur_reindex_ind5 ON concur_reindex_tab4 (c1); @@ -570,7 +570,34 @@ diff ../../../src/test/regress/expected/rowsecurity.out ../tmp_check/regress_out diff ../../../src/test/regress/expected/atx.out ../tmp_check/regress_outdir/results/atx.out --- ../../../src/test/regress/expected/atx.out CENSORED +++ ../tmp_check/regress_outdir/results/atx.out CENSORED -@@ -1143,6 +1143,7 @@ +@@ -851,6 +851,7 @@ + declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); + insert into atx_tt1 values(2); + commit; ++ERROR: cannot PREPARE a transaction that has created a cursor WITH HOLD + commit; + begin; + begin autonomous; +@@ -866,6 +867,7 @@ + drop function count_tt1_s(); + drop table if exists atx_tt1; + close c2; ++ERROR: cursor "c2" does not exist + -- 13 + create table atx_13_t(i int); + begin; +@@ -985,9 +987,7 @@ + insert into atx_tt2 values(1); + declare c2 cursor with hold for select error_function(); + commit; +-NOTICE: other exception 22012, division by zero +-ERROR: control reached end of function without RETURN +-CONTEXT: PL/pgSQL function error_function() ++ERROR: cannot PREPARE a transaction that has created a cursor WITH HOLD + commit; + drop function if exists error_function(); + drop table if exists atx_tt2; +@@ -1074,6 +1074,7 @@ RESET client_min_messages; create database regression_atx_test_database; ALTER DATABASE "regression_atx_test_database" SET lc_messages TO 'C'; From 7ca0008cc25d7567121085e3f9b7a43eb6f3d068 Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Tue, 7 Dec 2021 09:20:26 +0000 Subject: [PATCH 02/14] fix transaction parsing In the commit 04e72dd9e67d8672268816335eacf57bb2239ab9 the code for reading sender_node_id and action type was removed. This commit fixes this issue. --- src/pglogical_apply.c | 5 +++-- src/pglogical_receiver.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pglogical_apply.c b/src/pglogical_apply.c index 850810bae2..566d5acb97 100644 --- a/src/pglogical_apply.c +++ b/src/pglogical_apply.c @@ -194,9 +194,10 @@ static void process_remote_begin(StringInfo s, MtmReceiverWorkerContext *rwctx) { /* there is no need to send this, but since we do, check its sanity */ -#ifdef USE_ASSERT_CHECKING int sender_node_id = pq_getmsgint(s, 4); -#endif + + (void) sender_node_id; /* keep the compiler quiet when asserts are disabled*/ + Assert(rwctx->sender_node_id == sender_node_id); rwctx->origin_xid = pq_getmsgint64(s); mtm_log(MtmApplyTrace, "processing begin of xid " XID_FMT, rwctx->origin_xid); diff --git a/src/pglogical_receiver.c b/src/pglogical_receiver.c index b75e7be445..95388fee27 100644 --- a/src/pglogical_receiver.c +++ b/src/pglogical_receiver.c @@ -318,12 +318,12 @@ MtmFilterTransaction(char *record, int size, Syncpoint *spvector, } else if (msgtype == 'M') { -#ifdef USE_ASSERT_CHECKING char action = pq_getmsgbyte(&s); -#endif int messageSize; char const *messageBody; + (void) action; /* keep the compiler quiet when asserts are disabled*/ + end_lsn = pq_getmsgint64(&s); messageSize = pq_getmsgint(&s, 4); messageBody = pq_getmsgbytes(&s, messageSize); From ef0c766728b5bb01f547870e411e9338b3282dc2 Mon Sep 17 00:00:00 2001 From: Alexey Masterov Date: Thu, 30 Dec 2021 21:48:20 +0700 Subject: [PATCH 03/14] [PGPRO-5554] Make add_node get port via mm_get_free_port from Cluster.pm in order to fix rare error Could not bind IPv4 address in TAP tests. tags: multimaster --- Cluster.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cluster.pm b/Cluster.pm index 78410ccdb2..ea7860f695 100644 --- a/Cluster.pm +++ b/Cluster.pm @@ -340,7 +340,8 @@ sub add_node() { my ($self) = @_; - my $new_node = get_new_node("node@{[$#{$self->{nodes}} + 2]}"); + my $new_node = get_new_node("node@{[$#{$self->{nodes}} + 2]}", + (port => mm_get_free_port())); push(@{$self->{nodes}}, $new_node); return $#{$self->{nodes}}; From dceff14aa025cfd68f145d6a52f107e651d8124e Mon Sep 17 00:00:00 2001 From: Andrei Krichinin Date: Tue, 30 Nov 2021 19:38:14 +0500 Subject: [PATCH 04/14] Multimaster init_cluster() with empty nodes list: replace assertion with error report. Tags: multimaster. --- src/multimaster.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/multimaster.c b/src/multimaster.c index 9f4d3c6479..e94facfd2c 100644 --- a/src/multimaster.c +++ b/src/multimaster.c @@ -933,7 +933,8 @@ mtm_init_cluster(PG_FUNCTION_ARGS) /* parse array with peer connstrings */ Assert(ARR_ELEMTYPE(peers_arr) == TEXTOID); - Assert(ARR_NDIM(peers_arr) == 1); + if (ARR_NDIM(peers_arr) != 1) + mtm_log(ERROR, "node list should not be empty"); deconstruct_array(peers_arr, TEXTOID, -1, false, 'i', &peers_datums, &peers_nulls, &n_peers); From 8345b3a933799398bc55409e1ca658d55eca19c5 Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Mon, 17 Jan 2022 15:29:30 +0700 Subject: [PATCH 05/14] update regression_ee.diff --- expected/regression_ee.diff | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expected/regression_ee.diff b/expected/regression_ee.diff index 02a7581a1b..9d9bfa229d 100644 --- a/expected/regression_ee.diff +++ b/expected/regression_ee.diff @@ -318,9 +318,9 @@ diff ../../../src/test/regress/expected/sanity_check.out ../tmp_check/regress_ou stud_emp|f student|f +syncpoints|t + tab_core_types|f tableam_parted_a_heap2|f tableam_parted_b_heap2|f - tableam_parted_c_heap2|f diff ../../../src/test/regress/expected/transactions.out ../tmp_check/regress_outdir/results/transactions.out --- ../../../src/test/regress/expected/transactions.out CENSORED +++ ../tmp_check/regress_outdir/results/transactions.out CENSORED From 524f9151d39f478adf5039190f851f655674f950 Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Wed, 9 Mar 2022 18:13:09 +0700 Subject: [PATCH 06/14] fix multimaster tests The perl2host() function was removed in the upstream commit, but 000_regress.pl is used it. This commit fixes this issue. --- expected/regression_ee.diff | 16 ++++++++-------- t/001_regress.pl | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/expected/regression_ee.diff b/expected/regression_ee.diff index 9d9bfa229d..ebc60ab969 100644 --- a/expected/regression_ee.diff +++ b/expected/regression_ee.diff @@ -29,7 +29,7 @@ diff ../../../src/test/regress/expected/create_table.out ../tmp_check/regress_ou diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_outdir/results/create_index.out --- ../../../src/test/regress/expected/create_index.out CENSORED +++ ../tmp_check/regress_outdir/results/create_index.out CENSORED -@@ -1367,31 +1367,33 @@ +@@ -1394,31 +1394,33 @@ CREATE TABLE concur_heap (f1 text, f2 text); -- empty table CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1); @@ -70,7 +70,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou COMMIT; -- test where predicate is able to do a transactional update during -- a concurrent build before switching pg_index state flags. -@@ -1403,7 +1405,9 @@ +@@ -1430,7 +1432,9 @@ END; $$; CREATE INDEX CONCURRENTLY concur_index8 ON concur_heap (f1) WHERE predicate_stable(); @@ -80,7 +80,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou DROP FUNCTION predicate_stable(); -- But you can do a regular index build in a transaction BEGIN; -@@ -1412,8 +1416,6 @@ +@@ -1439,8 +1443,6 @@ -- Failed builds are left invalid by VACUUM FULL, fixed by REINDEX VACUUM FULL concur_heap; REINDEX TABLE concur_heap; @@ -89,7 +89,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou DELETE FROM concur_heap WHERE f1 = 'b'; VACUUM FULL concur_heap; \d concur_heap -@@ -1423,12 +1425,6 @@ +@@ -1450,12 +1452,6 @@ f1 | text | | | f2 | text | | | Indexes: @@ -102,7 +102,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou "std_index" btree (f2) REINDEX TABLE concur_heap; -@@ -1439,12 +1435,6 @@ +@@ -1466,12 +1462,6 @@ f1 | text | | | f2 | text | | | Indexes: @@ -115,7 +115,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou "std_index" btree (f2) -- Temporary tables with concurrent builds and on-commit actions -@@ -1454,7 +1444,9 @@ +@@ -1481,7 +1471,9 @@ ON COMMIT PRESERVE ROWS; INSERT INTO concur_temp VALUES (1, 'foo'), (2, 'bar'); CREATE INDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); @@ -125,7 +125,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou DROP TABLE concur_temp; -- ON COMMIT DROP BEGIN; -@@ -1463,34 +1455,42 @@ +@@ -1490,34 +1482,42 @@ INSERT INTO concur_temp VALUES (1, 'foo'), (2, 'bar'); -- Fails when running in a transaction. CREATE INDEX CONCURRENTLY concur_temp_ind ON concur_temp(f1); @@ -172,7 +172,7 @@ diff ../../../src/test/regress/expected/create_index.out ../tmp_check/regress_ou \d concur_heap Table "public.concur_heap" Column | Type | Collation | Nullable | Default -@@ -2447,46 +2447,38 @@ +@@ -2474,46 +2474,38 @@ INSERT INTO concur_reindex_tab4 VALUES (1), (1), (2); -- This trick creates an invalid index. CREATE UNIQUE INDEX CONCURRENTLY concur_reindex_ind5 ON concur_reindex_tab4 (c1); diff --git a/t/001_regress.pl b/t/001_regress.pl index fc9397fb11..cbe1feaaa0 100644 --- a/t/001_regress.pl +++ b/t/001_regress.pl @@ -92,7 +92,7 @@ unlink('parallel_schedule'); TestLib::append_to_file('parallel_schedule', $schedule); -my $regress_shlib = TestLib::perl2host($ENV{REGRESS_SHLIB}); +my $regress_shlib = $ENV{REGRESS_SHLIB}; my $regress_libdir = dirname($regress_shlib); my $regress_outdir = "$ENV{TESTDIR}/tmp_check/regress_outdir"; mkdir($regress_outdir); From 02f0b9e58fe1b0d1eb2e591a51dbab694746c5c0 Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Thu, 17 Feb 2022 16:07:22 +0700 Subject: [PATCH 07/14] Disable timeouts for multimaster To avoid disconnection between multimaster components the following timeouts were disabled for the multimaster: - statement_timeout; - lock_timeout; - idle_in_transaction_session_timeout; - idle_session_timeout. --- Makefile | 2 +- src/bgwpool.c | 2 + src/ddl.c | 1 - src/dmq.c | 10 ++- src/include/mtm_utils.h | 24 +++++++ src/mtm_utils.c | 133 +++++++++++++++++++++++++++++++++++++++ src/multimaster.c | 12 ++-- src/pglogical_output.c | 3 + src/pglogical_receiver.c | 3 + src/resolver.c | 3 + src/state.c | 5 ++ 11 files changed, 189 insertions(+), 9 deletions(-) create mode 100644 src/include/mtm_utils.h create mode 100644 src/mtm_utils.c diff --git a/Makefile b/Makefile index 505f5d9f57..994e04ff8a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ OBJS = src/multimaster.o src/dmq.o src/commit.o src/bytebuf.o src/bgwpool.o \ src/pglogical_output.o src/pglogical_proto.o src/pglogical_receiver.o \ src/pglogical_apply.o src/pglogical_hooks.o src/pglogical_config.o \ src/pglogical_relid_map.o src/ddd.o src/bkb.o src/spill.o src/state.o \ -src/resolver.o src/ddl.o src/syncpoint.o src/global_tx.o +src/resolver.o src/ddl.o src/syncpoint.o src/global_tx.o src/mtm_utils.o MODULE_big = multimaster ifndef USE_PGXS # hmm, user didn't requested to use pgxs diff --git a/src/bgwpool.c b/src/bgwpool.c index 7288ba3781..efc1cd24e5 100644 --- a/src/bgwpool.c +++ b/src/bgwpool.c @@ -31,6 +31,7 @@ #include "multimaster.h" #include "state.h" #include "logger.h" +#include "mtm_utils.h" /* * Store the size of tx body, position of it in the tx list and transaction @@ -324,6 +325,7 @@ BgwPoolMainLoop(BgwPool *poolDesc) void BgwPoolDynamicWorkerMainLoop(Datum arg) { + MtmDisableTimeouts(); BgwPoolMainLoop((BgwPool *) DatumGetPointer(arg)); } diff --git a/src/ddl.c b/src/ddl.c index cf9d08e2a3..49ccc2d0c4 100644 --- a/src/ddl.c +++ b/src/ddl.c @@ -666,7 +666,6 @@ MtmProcessUtility(PlannedStmt *pstmt, const char *queryString, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc) { - /* * Quick exit if multimaster is not enabled. * XXX it's better to do MtmIsEnabled here, but this needs cache access diff --git a/src/dmq.c b/src/dmq.c index a02c02fd95..c655df3010 100644 --- a/src/dmq.c +++ b/src/dmq.c @@ -31,6 +31,7 @@ #include "dmq.h" #include "logger.h" #include "compat.h" +#include "mtm_utils.h" #include "access/transam.h" #include "libpq/libpq.h" @@ -527,6 +528,8 @@ dmq_sender_main(Datum main_arg) pqsignal(SIGTERM, die); BackgroundWorkerUnblockSignals(); + MtmDisableTimeouts(); + memcpy(&heartbeat_send_timeout, MyBgworkerEntry->bgw_extra, sizeof(int)); memcpy(&connect_timeout, MyBgworkerEntry->bgw_extra + sizeof(int), sizeof(int)); @@ -796,7 +799,7 @@ dmq_sender_main(Datum main_arg) int pos = event.pos; pqtime = dmq_now(); - status = PQconnectPoll(conns[conn_id].pgconn); + status = MtmPQconnectPoll(conns[conn_id].pgconn); mtm_log(DmqPqTiming, "[DMQ] [TIMING] pqp = %f ms", dmq_now() - pqtime); mtm_log(DmqStateIntermediate, @@ -1386,6 +1389,11 @@ dmq_receiver_loop(PG_FUNCTION_ARGS) double last_message_at = dmq_now(); void *extra = NULL; + /* + * We do not call MtmDisbaleTimeouts() here because of connection to this + * client is made by MtmPQconnectPoll() that sets all needed timeouts. + */ + sender_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); recv_timeout = PG_GETARG_INT32(1); diff --git a/src/include/mtm_utils.h b/src/include/mtm_utils.h new file mode 100644 index 0000000000..51eaf19c80 --- /dev/null +++ b/src/include/mtm_utils.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * mtm_utils.h + * Utility functions: + * - disable global timeouts settings; + * - libpq connect function wrappers. + * + * + * Copyright (c) 2022, Postgres Professional + * + *------------------------------------------------------------------------- + */ +#ifndef MTM_UTILS_H +#define MTM_UTILS_H + +#include "libpq/pqformat.h" +#include "libpq-fe.h" + +extern void MtmDisableTimeouts(void); + +extern PostgresPollingStatusType MtmPQconnectPoll(PGconn *conn); +extern PGconn* MtmPQconnectdb(const char *conninfo); + +#endif diff --git a/src/mtm_utils.c b/src/mtm_utils.c new file mode 100644 index 0000000000..57a4c62410 --- /dev/null +++ b/src/mtm_utils.c @@ -0,0 +1,133 @@ +/*---------------------------------------------------------------------------- + * + * mtm_utils.c + * Utility functions + * + * Copyright (c) 2022, Postgres Professional + * + *---------------------------------------------------------------------------- + */ + +#include "logger.h" +#include "mtm_utils.h" + +#include "utils/timeout.h" + +/* + * Disables timeouts on a client side: + * - statement_timeout; + * - lock_timeout; + * - idle_in_transaction_session_timeout; + * - idle_session_timeout. + * + * This timeouts, when set in the postgres config file, affect all process. + * The multimaster needs his sessions not to be interrupted, so we disable + * these timeouts. + * + * This function raises an error on PQExec failed. + */ +static void +disable_client_timeouts(PGconn *conn) +{ + PGresult *res; + + res = PQexec(conn, "SET statement_timeout = 0"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + char *msg = pchomp(PQerrorMessage(conn)); + mtm_log(ERROR, "failed to set statement_timeout: %s", msg); + } + + res = PQexec(conn, "SET lock_timeout = 0"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + char *msg = pchomp(PQerrorMessage(conn)); + mtm_log(ERROR, "failed to set lock_timeout: %s", msg); + } + + res = PQexec(conn, "SET idle_in_transaction_session_timeout = 0"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + char *msg = pchomp(PQerrorMessage(conn)); + mtm_log(ERROR, "failed to set idle_in_transaction_session_timeout: %s", msg); + } + + res = PQexec(conn, "SET idle_session_timeout = 0"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + char *msg = pchomp(PQerrorMessage(conn)); + mtm_log(ERROR, "failed to set idle_session_timeout: %s", msg); + } +} + +/* + * Disable timeouts for a current process + * - statement_timeout; + * - lock_timeout; + * - idle_in_transaction_session_timeout; + * - idle_session_timeout. + * + * We disable these timeout for the same reason as in the disable_client_timeout() + */ +extern void +MtmDisableTimeouts(void) +{ + if (get_timeout_active(STATEMENT_TIMEOUT)) + { + disable_timeout(STATEMENT_TIMEOUT, false); + } + + if (get_timeout_active(LOCK_TIMEOUT)) + { + disable_timeout(LOCK_TIMEOUT, false); + } + + if (get_timeout_active(IDLE_IN_TRANSACTION_SESSION_TIMEOUT)) + { + disable_timeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, false); + } + + if (get_timeout_active(IDLE_SESSION_TIMEOUT)) + { + disable_timeout(IDLE_SESSION_TIMEOUT, false); + } +} + +/* + * Wrapper on PQconnectPoll + * + * On connect disables timeouts on a client side + */ +PostgresPollingStatusType +MtmPQconnectPoll(PGconn *conn) +{ + PostgresPollingStatusType status; + + status = PQconnectPoll(conn); + if (status != PGRES_POLLING_OK) + return status; + + disable_client_timeouts(conn); + + return status; +} + +/* + * Wrapper on PQconnectdb + * + * On connect disables timeouts on a client side + */ +PGconn * +MtmPQconnectdb(const char *conninfo) +{ + PGconn *conn; + + conn = PQconnectdb(conninfo); + if (PQstatus(conn) != CONNECTION_OK) + return conn; + + disable_client_timeouts(conn); + + return conn; +} + diff --git a/src/multimaster.c b/src/multimaster.c index e94facfd2c..1ee7b60d6c 100644 --- a/src/multimaster.c +++ b/src/multimaster.c @@ -48,6 +48,7 @@ #include "commit.h" #include "messaging.h" #include "syncpoint.h" +#include "mtm_utils.h" #include "compat.h" @@ -333,7 +334,6 @@ MtmSleep(int64 usec) } } - /* * These were once used to setup mtm state in parallel workers, but as long as * they are read-only we don't really need it (historically it imported csn @@ -970,7 +970,7 @@ mtm_init_cluster(PG_FUNCTION_ARGS) int j; /* connect */ - peer_conns[i] = PQconnectdb(conninfo); + peer_conns[i] = MtmPQconnectdb(conninfo); if (PQstatus(peer_conns[i]) != CONNECTION_OK) { char *msg = pchomp(PQerrorMessage(peer_conns[i])); @@ -1300,7 +1300,7 @@ mtm_join_node(PG_FUNCTION_ARGS) if (new_node == NULL) mtm_log(ERROR, "new node %d not found", new_node_id); conninfo = new_node->conninfo; - conn = PQconnectdb(conninfo); + conn = MtmPQconnectdb(conninfo); if (PQstatus(conn) != CONNECTION_OK) { char *msg = pchomp(PQerrorMessage(conn)); @@ -1495,7 +1495,7 @@ mtm_ping(PG_FUNCTION_ARGS) if (!BIT_CHECK(curr_gen.members, peer->node_id - 1)) continue; - conn = PQconnectdb(peer->conninfo); + conn = MtmPQconnectdb(peer->conninfo); if (PQstatus(conn) != CONNECTION_OK) { char *msg = pchomp(PQerrorMessage(conn)); @@ -2554,7 +2554,7 @@ _mtm_get_snapshots(const MtmConfig *mcfg, PGconn **conns, char **snapnames, for (i = 0; i < mcfg->n_nodes; i++) { /* Establish connection to each node */ - conns[i] = PQconnectdb(mcfg->nodes[i].conninfo); + conns[i] = MtmPQconnectdb(mcfg->nodes[i].conninfo); if (conns[i] == NULL || PQstatus(conns[i]) == CONNECTION_BAD) { @@ -2680,7 +2680,7 @@ mtm_check_query(PG_FUNCTION_ARGS) int pos = index[i]; /* Establish connection to each online node */ - conn = PQconnectdb(cfg->nodes[pos].conninfo); + conn = MtmPQconnectdb(cfg->nodes[pos].conninfo); if (conn == NULL || PQstatus(conn) == CONNECTION_BAD) { diff --git a/src/pglogical_output.c b/src/pglogical_output.c index b1675f1a73..95bfa00540 100644 --- a/src/pglogical_output.c +++ b/src/pglogical_output.c @@ -57,6 +57,7 @@ #include "multimaster.h" #include "logger.h" #include "state.h" +#include "mtm_utils.h" extern void _PG_output_plugin_init(OutputPluginCallbacks *cb); @@ -143,6 +144,8 @@ _PG_output_plugin_init(OutputPluginCallbacks *cb) cb->shutdown_cb = pg_decode_shutdown; cb->message_cb = pg_decode_message; cb->caughtup_cb = pg_decode_caughtup; + + MtmDisableTimeouts(); } #if 0 diff --git a/src/pglogical_receiver.c b/src/pglogical_receiver.c index 95388fee27..ef30ed1c30 100644 --- a/src/pglogical_receiver.c +++ b/src/pglogical_receiver.c @@ -56,6 +56,7 @@ #include "compat.h" #include "syncpoint.h" #include "global_tx.h" +#include "mtm_utils.h" #define ERRCODE_DUPLICATE_OBJECT_STR "42710" @@ -584,6 +585,8 @@ pglogical_receiver_main(Datum main_arg) */ on_shmem_exit(pglogical_receiver_at_exit, PointerGetDatum(rctx)); + MtmDisableTimeouts(); + MtmIsReceiver = true; /* Run as replica session replication role. */ SetConfigOption("session_replication_role", "replica", diff --git a/src/resolver.c b/src/resolver.c index f6fccea9da..2c9933ff51 100644 --- a/src/resolver.c +++ b/src/resolver.c @@ -30,6 +30,7 @@ #include "commit.h" #include "global_tx.h" #include "messaging.h" +#include "mtm_utils.h" static MtmConfig *mtm_cfg = NULL; static bool send_requests; @@ -637,6 +638,8 @@ ResolverMain(Datum main_arg) Oid db_id, user_id; + MtmDisableTimeouts(); + /* init this worker */ pqsignal(SIGHUP, ResolverSigHupHandler); pqsignal(SIGTERM, die); diff --git a/src/state.c b/src/state.c index 53c8fa674b..ece378b1a1 100644 --- a/src/state.c +++ b/src/state.c @@ -45,6 +45,7 @@ #include "syncpoint.h" #include "logger.h" #include "messaging.h" +#include "mtm_utils.h" char const *const MtmNeighborEventMnem[] = { @@ -1672,6 +1673,8 @@ CampaignerMain(Datum main_arg) TimestampTz last_campaign_at = 0; int rc = WL_TIMEOUT; + MtmDisableTimeouts(); + MtmBackgroundWorker = true; mtm_log(MtmStateMessage, "campaigner started"); before_shmem_exit(CampaignerOnExit, (Datum) 0); @@ -3417,6 +3420,8 @@ ReplierMain(Datum main_arg) ALLOCSET_DEFAULT_SIZES); bool job_pending; + MtmDisableTimeouts(); + MtmBackgroundWorker = true; before_shmem_exit(ReplierOnExit, (Datum) 0); mtm_log(MtmStateMessage, "replier started"); From 2b5b567b30bbdb99590df0ca97d1e91208f0f8b6 Mon Sep 17 00:00:00 2001 From: Andrey Lepikhov Date: Tue, 1 Mar 2022 08:27:38 +0500 Subject: [PATCH 08/14] Fix fragile issue of DMQ sender service. Restart Campaigner at the DMQ sender service exit. Do it to ensure that critical data are cleaned before next voting. Tags: Multimaster --- src/dmq.c | 32 ++++++++++++-------------------- src/include/state.h | 1 + src/mtm_utils.c | 41 ++++++++++++----------------------------- src/multimaster.c | 2 +- src/state.c | 16 ++++++++++++++++ 5 files changed, 42 insertions(+), 50 deletions(-) diff --git a/src/dmq.c b/src/dmq.c index c655df3010..aa9eba62cb 100644 --- a/src/dmq.c +++ b/src/dmq.c @@ -32,6 +32,8 @@ #include "logger.h" #include "compat.h" #include "mtm_utils.h" +#include "multimaster.h" +#include "state.h" #include "access/transam.h" #include "libpq/libpq.h" @@ -52,23 +54,6 @@ #define DMQ_MQ_SIZE ((Size) 65536) #define DMQ_MQ_MAGIC 0x646d71 -/* XXX: move to common */ -#define BIT_CLEAR(mask, bit) ((mask) &= ~((uint64)1 << (bit))) -#define BIT_CHECK(mask, bit) (((mask) & ((uint64)1 << (bit))) != 0) -static int -first_set_bit(uint64 mask) -{ - int i; - - for (i = 0; i < DMQ_N_MASK_POS; i++) - { - if (BIT_CHECK(mask, i)) - return i; - } - return -1; -} - - /* * Shared data structures to hold current connections topology. * All that stuff can be moved to persistent tables to avoid hardcoded @@ -497,6 +482,12 @@ dmq_sender_at_exit(int status, Datum arg) } } LWLockRelease(dmq_state->lock); + + /* + * Restart the Campaigner to be sure that all critical data reset before the + * next voting. + */ + CampaignerStop(); } void @@ -1390,7 +1381,7 @@ dmq_receiver_loop(PG_FUNCTION_ARGS) void *extra = NULL; /* - * We do not call MtmDisbaleTimeouts() here because of connection to this + * We do not call MtmDisableTimeouts() here because of connection to this * client is made by MtmPQconnectPoll() that sets all needed timeouts. */ @@ -1660,7 +1651,7 @@ dmq_push_buffer(DmqDestinationId dest_id, char *stream_name, const void *payload res = shm_mq_send(dmq_local.mq_outh, buf.len, buf.data, false); pfree(buf.data); if (res != SHM_MQ_SUCCESS) - mtm_log(WARNING, "[DMQ] dmq_push: can't send to queue"); + mtm_log(ERROR, "[DMQ] dmq_push: can't send to queue"); } /* @@ -1776,7 +1767,8 @@ dmq_reattach_shm_mq(int handle_id) * from which receivers caller wants to get message and filters inhandles * through it. */ -void dmq_attach_receiver(char *sender_name, int8 mask_pos) +void +dmq_attach_receiver(char *sender_name, int8 mask_pos) { int i; int handle_id = -1; diff --git a/src/include/state.h b/src/include/state.h index d8565374ea..f361769dff 100644 --- a/src/include/state.h +++ b/src/include/state.h @@ -149,5 +149,6 @@ extern void MtmMonitorStart(Oid db_id, Oid user_id); extern void MtmRefreshClusterStatus(void); extern nodemask_t MtmGetDisabledNodeMask(void); extern nodemask_t MtmGetEnabledNodeMask(bool ignore_disabled); +extern void CampaignerStop(void); #endif diff --git a/src/mtm_utils.c b/src/mtm_utils.c index 57a4c62410..150e149ee4 100644 --- a/src/mtm_utils.c +++ b/src/mtm_utils.c @@ -22,42 +22,36 @@ * * This timeouts, when set in the postgres config file, affect all process. * The multimaster needs his sessions not to be interrupted, so we disable - * these timeouts. + * these timeouts. * * This function raises an error on PQExec failed. */ -static void +static bool disable_client_timeouts(PGconn *conn) { PGresult *res; res = PQexec(conn, "SET statement_timeout = 0"); if (PQresultStatus(res) != PGRES_COMMAND_OK) - { - char *msg = pchomp(PQerrorMessage(conn)); - mtm_log(ERROR, "failed to set statement_timeout: %s", msg); - } + mtm_log(ERROR, "failed to set statement_timeout: %s", + pchomp(PQerrorMessage(conn))); res = PQexec(conn, "SET lock_timeout = 0"); if (PQresultStatus(res) != PGRES_COMMAND_OK) - { - char *msg = pchomp(PQerrorMessage(conn)); - mtm_log(ERROR, "failed to set lock_timeout: %s", msg); - } + mtm_log(ERROR, "failed to set lock_timeout: %s", + pchomp(PQerrorMessage(conn))); res = PQexec(conn, "SET idle_in_transaction_session_timeout = 0"); if (PQresultStatus(res) != PGRES_COMMAND_OK) - { - char *msg = pchomp(PQerrorMessage(conn)); - mtm_log(ERROR, "failed to set idle_in_transaction_session_timeout: %s", msg); - } + mtm_log(ERROR, "failed to set idle_in_transaction_session_timeout: %s", + pchomp(PQerrorMessage(conn))); res = PQexec(conn, "SET idle_session_timeout = 0"); if (PQresultStatus(res) != PGRES_COMMAND_OK) - { - char *msg = pchomp(PQerrorMessage(conn)); - mtm_log(ERROR, "failed to set idle_session_timeout: %s", msg); - } + mtm_log(ERROR, "failed to set idle_session_timeout: %s", + pchomp(PQerrorMessage(conn))); + + return true; } /* @@ -73,24 +67,13 @@ extern void MtmDisableTimeouts(void) { if (get_timeout_active(STATEMENT_TIMEOUT)) - { disable_timeout(STATEMENT_TIMEOUT, false); - } - if (get_timeout_active(LOCK_TIMEOUT)) - { disable_timeout(LOCK_TIMEOUT, false); - } - if (get_timeout_active(IDLE_IN_TRANSACTION_SESSION_TIMEOUT)) - { disable_timeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, false); - } - if (get_timeout_active(IDLE_SESSION_TIMEOUT)) - { disable_timeout(IDLE_SESSION_TIMEOUT, false); - } } /* diff --git a/src/multimaster.c b/src/multimaster.c index 1ee7b60d6c..9165492afc 100644 --- a/src/multimaster.c +++ b/src/multimaster.c @@ -99,7 +99,6 @@ static void MtmShmemStartup(void); static void launcher_init(void); void launcher_main(Datum main_arg); -void drop_node_entry(int node_id); MtmShared *Mtm; @@ -1863,6 +1862,7 @@ launcher_main(Datum main_arg) /* init this worker */ pqsignal(SIGTERM, die); BackgroundWorkerUnblockSignals(); + MtmBackgroundWorker = true; memset(&hash_info, 0, sizeof(hash_info)); hash_info.entrysize = hash_info.keysize = sizeof(Oid); diff --git a/src/state.c b/src/state.c index ece378b1a1..01b502b775 100644 --- a/src/state.c +++ b/src/state.c @@ -882,6 +882,14 @@ CampaignerWake(void) kill(mtm_state->campaigner_pid, SIGHUP); } +/* Service to restart a campaigner process. */ +void +CampaignerStop(void) +{ + if (mtm_state->campaigner_pid != 0) + kill(mtm_state->campaigner_pid, SIGTERM); +} + /* campaigner never rereads PG config, but it currently it hardly needs to */ static void CampaignerSigHupHandler(SIGNAL_ARGS) @@ -3856,6 +3864,12 @@ stop_node_workers(int node_id, MtmConfig *new_cfg, Datum arg) pfree(bgws[node_id - 1].handle); bgws[node_id - 1].handle = NULL; + /* + * Only cleaning a name field guarantees that monitor wouldn't restart this + * receiver. + */ + bgws[node_id - 1].name[0] = '\0'; + /* delete recovery slot, was acquired by receiver */ ReplicationSlotDrop(filter_slot_name, true); @@ -4102,6 +4116,8 @@ MtmMonitor(Datum arg) * Note that if for some reason monitor wasn't running * (e.g. process killed) during node drop, cleanup in * stop_node_workers will be skipped. Very unlikely, but not nice. + * XXX: Should rethink this code, because problem, described above, + * has cought in PGPRO-6146. */ mtm_cfg = MtmReloadConfig(mtm_cfg, start_node_workers, stop_node_workers, PointerGetDatum(bgws), From 143cbc1daf2006ae4cef1dd45e5406795c429a06 Mon Sep 17 00:00:00 2001 From: Andrey Lepikhov Date: Thu, 3 Mar 2022 16:32:54 +0500 Subject: [PATCH 09/14] Avoid to produce an ERROR during establishing of intra-multimaster psql-connection if it's not really needed. Caused by stress tests when I found dangerous places: some services can send dmq messages to channel, subscribed by another service. Tags: Multimaster --- src/dmq.c | 2 +- src/mtm_utils.c | 29 +++++++++++++++++++++++------ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/dmq.c b/src/dmq.c index aa9eba62cb..c2d14fae28 100644 --- a/src/dmq.c +++ b/src/dmq.c @@ -1651,7 +1651,7 @@ dmq_push_buffer(DmqDestinationId dest_id, char *stream_name, const void *payload res = shm_mq_send(dmq_local.mq_outh, buf.len, buf.data, false); pfree(buf.data); if (res != SHM_MQ_SUCCESS) - mtm_log(ERROR, "[DMQ] dmq_push: can't send to queue"); + mtm_log(ERROR, "[DMQ] dmq_push: can't send to queue, status = %d", res); } /* diff --git a/src/mtm_utils.c b/src/mtm_utils.c index 150e149ee4..e01e5ce4bf 100644 --- a/src/mtm_utils.c +++ b/src/mtm_utils.c @@ -33,23 +33,35 @@ disable_client_timeouts(PGconn *conn) res = PQexec(conn, "SET statement_timeout = 0"); if (PQresultStatus(res) != PGRES_COMMAND_OK) - mtm_log(ERROR, "failed to set statement_timeout: %s", + { + mtm_log(WARNING, "failed to set statement_timeout: %s", pchomp(PQerrorMessage(conn))); + return false; + } res = PQexec(conn, "SET lock_timeout = 0"); if (PQresultStatus(res) != PGRES_COMMAND_OK) - mtm_log(ERROR, "failed to set lock_timeout: %s", + { + mtm_log(WARNING, "failed to set lock_timeout: %s", pchomp(PQerrorMessage(conn))); + return false; + } res = PQexec(conn, "SET idle_in_transaction_session_timeout = 0"); if (PQresultStatus(res) != PGRES_COMMAND_OK) - mtm_log(ERROR, "failed to set idle_in_transaction_session_timeout: %s", + { + mtm_log(WARNING, "failed to set idle_in_transaction_session_timeout: %s", pchomp(PQerrorMessage(conn))); + return false; + } res = PQexec(conn, "SET idle_session_timeout = 0"); if (PQresultStatus(res) != PGRES_COMMAND_OK) - mtm_log(ERROR, "failed to set idle_session_timeout: %s", + { + mtm_log(WARNING, "failed to set idle_session_timeout: %s", pchomp(PQerrorMessage(conn))); + return false; + } return true; } @@ -90,7 +102,8 @@ MtmPQconnectPoll(PGconn *conn) if (status != PGRES_POLLING_OK) return status; - disable_client_timeouts(conn); + if (!disable_client_timeouts(conn)) + status = PGRES_POLLING_FAILED; return status; } @@ -109,7 +122,11 @@ MtmPQconnectdb(const char *conninfo) if (PQstatus(conn) != CONNECTION_OK) return conn; - disable_client_timeouts(conn); + if (!disable_client_timeouts(conn)) + { + PQfinish(conn); + return NULL; + } return conn; } From b879d10aefb8beb6bc1a22fcad306b0df627fe05 Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Tue, 12 Apr 2022 10:29:50 +0700 Subject: [PATCH 10/14] add description of multimaster parameters The following parameters were discribed: multimaster.connect_timeout multimaster.ignore_tables_without_pk multimaster.syncpoint_interval multimaster.binary_basetypes multimaster.wait_peer_commits --- doc/multimaster.xml | 88 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/doc/multimaster.xml b/doc/multimaster.xml index 8e3eb2ff56..8fdec0f124 100644 --- a/doc/multimaster.xml +++ b/doc/multimaster.xml @@ -1255,19 +1255,83 @@ WARNING: mismatch in column 'b' of row 0: 256 on node0, 255 on node1 + + multimaster.break_connection + multimaster.break_connection + + + Break connection with clients connected to the node if this node disconnects + from the cluster. If this variable is set to false, the client stays + connected to the node but receives an error that the node is disabled. + + Default: false + + + + + multimaster.connect_timeout + multimaster.connect_timeout + + + + Maximum time to wait while connecting, in seconds. Zero, negative, or not specified means + wait indefinitely. The minimum allowed timeout is 2 seconds, therefore + a value of 1 is interpreted as 2. + + Default: 0 + + + + + multimaster.ignore_tables_without_pk + multimaster.ignore_tables_without_pk + + + + Do not replicate tables without primary key. When false, + such tables are replicated. + + Default: false + + + + + multimaster.syncpoint_interval + multimaster.syncpoint_interval + + + + Amount of WAL generated between synchronization points. + + Default: 10 MB + + + + + multimaster.binary_basetypes + multimaster.binary_basetypes + + + + Send data of built-in types in binary format. + + Default: true + + + + + multimaster.wait_peer_commits + multimaster.wait_peer_commits + + + + Wait until all peers commit the transaction before the command returns + a success indication to the client. + + Default: true + + - - multimaster.break_connection - multimaster.break_connection - - - Break connection with clients connected to the node if this node disconnects - from the cluster. If this variable is set to false, the client stays - connected to the node but receives an error that the node is disabled. - - Default: false - - From 3d6313fa84abeea0d23283fec54abca2d4031e8f Mon Sep 17 00:00:00 2001 From: Mikhail Rutman Date: Thu, 26 May 2022 17:14:39 +0700 Subject: [PATCH 11/14] remove test atx0 from regression tests for multimaster --- expected/regression_ee.diff | 22 +++++++++++++++++++++- t/001_regress.pl | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/expected/regression_ee.diff b/expected/regression_ee.diff index ebc60ab969..fd7a45e804 100644 --- a/expected/regression_ee.diff +++ b/expected/regression_ee.diff @@ -503,6 +503,26 @@ diff ../../../src/test/regress/expected/brin.out ../tmp_check/regress_outdir/res -- vacuum the table, to discard TOAST data VACUUM brintest_3; -- retry insert with a different random-looking (but deterministic) value +diff ../../../src/test/regress/expected/privileges.out ../tmp_check/regress_outdir/results/privileges.out +--- ../../../src/test/regress/expected/privileges.out CENSORED ++++ ../tmp_check/regress_outdir/results/privileges.out CENSORED +@@ -1437,11 +1437,16 @@ + -- Do the same concurrently + CREATE INDEX CONCURRENTLY sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))) + WHERE sro_ifun(a + 10) > sro_ifun(10); ++ERROR: multimaster doesn't support CREATE INDEX CONCURRENTLY + -- REINDEX + REINDEX TABLE sro_tab; ++NOTICE: table "sro_tab" has no indexes to reindex + REINDEX INDEX sro_idx; ++ERROR: relation "sro_idx" does not exist + REINDEX TABLE CONCURRENTLY sro_tab; ++NOTICE: table "sro_tab" has no indexes that can be reindexed concurrently + DROP INDEX sro_idx; ++ERROR: index "sro_idx" does not exist + -- CLUSTER + CREATE INDEX sro_cluster_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))); + CLUSTER sro_tab USING sro_cluster_idx; diff ../../../src/test/regress/expected/rowsecurity.out ../tmp_check/regress_outdir/results/rowsecurity.out --- ../../../src/test/regress/expected/rowsecurity.out CENSORED +++ ../tmp_check/regress_outdir/results/rowsecurity.out CENSORED @@ -597,7 +617,7 @@ diff ../../../src/test/regress/expected/atx.out ../tmp_check/regress_outdir/resu commit; drop function if exists error_function(); drop table if exists atx_tt2; -@@ -1074,6 +1074,7 @@ +@@ -1077,6 +1077,7 @@ RESET client_min_messages; create database regression_atx_test_database; ALTER DATABASE "regression_atx_test_database" SET lc_messages TO 'C'; diff --git a/t/001_regress.pl b/t/001_regress.pl index cbe1feaaa0..12ecdefa6d 100644 --- a/t/001_regress.pl +++ b/t/001_regress.pl @@ -89,6 +89,7 @@ $schedule =~ s/test: cfs/#test: cfs/g; $schedule =~ s/test: largeobject//; # serial schedule $schedule =~ s/largeobject//; # parallel schedule +$schedule =~ s/atx0//; # parallel schedule unlink('parallel_schedule'); TestLib::append_to_file('parallel_schedule', $schedule); From 62a5b52f1d5e81bc1f276c1108c410938653a048 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Fri, 8 Jul 2022 17:42:17 +0300 Subject: [PATCH 12/14] [PGPRO-6745] Added lo_unlink for some ATX tests --- expected/regression_ee.diff | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/expected/regression_ee.diff b/expected/regression_ee.diff index fd7a45e804..a54758b41f 100644 --- a/expected/regression_ee.diff +++ b/expected/regression_ee.diff @@ -590,7 +590,20 @@ diff ../../../src/test/regress/expected/rowsecurity.out ../tmp_check/regress_out diff ../../../src/test/regress/expected/atx.out ../tmp_check/regress_outdir/results/atx.out --- ../../../src/test/regress/expected/atx.out CENSORED +++ ../tmp_check/regress_outdir/results/atx.out CENSORED -@@ -851,6 +851,7 @@ +@@ -816,11 +816,7 @@ + (1 row) + + select lo_unlink(:my_loid); +- lo_unlink +------------ +- 1 +-(1 row) +- ++ERROR: [MTM] failed to prepare transaction at peer node + -- + DO $body$ + begin +@@ -857,6 +853,7 @@ declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); insert into atx_tt1 values(2); commit; @@ -598,15 +611,15 @@ diff ../../../src/test/regress/expected/atx.out ../tmp_check/regress_outdir/resu commit; begin; begin autonomous; -@@ -866,6 +867,7 @@ +@@ -872,6 +869,7 @@ drop function count_tt1_s(); drop table if exists atx_tt1; close c2; +ERROR: cursor "c2" does not exist - -- 13 + -- create table atx_13_t(i int); begin; -@@ -985,9 +987,7 @@ +@@ -991,9 +989,7 @@ insert into atx_tt2 values(1); declare c2 cursor with hold for select error_function(); commit; @@ -617,7 +630,7 @@ diff ../../../src/test/regress/expected/atx.out ../tmp_check/regress_outdir/resu commit; drop function if exists error_function(); drop table if exists atx_tt2; -@@ -1077,6 +1077,7 @@ +@@ -1083,6 +1079,7 @@ RESET client_min_messages; create database regression_atx_test_database; ALTER DATABASE "regression_atx_test_database" SET lc_messages TO 'C'; @@ -628,7 +641,7 @@ diff ../../../src/test/regress/expected/atx.out ../tmp_check/regress_outdir/resu diff ../../../src/test/regress/expected/atx5.out ../tmp_check/regress_outdir/results/atx5.out --- ../../../src/test/regress/expected/atx5.out CENSORED +++ ../tmp_check/regress_outdir/results/atx5.out CENSORED -@@ -24,10 +24,7 @@ +@@ -23,10 +23,7 @@ NOTICE: function atx_test_30_one() does not exist, skipping NOTICE: function atx_test_30_one() does not exist, skipping NOTICE: function atx_test_30_one() does not exist, skipping @@ -643,7 +656,7 @@ diff ../../../src/test/regress/expected/atx5.out ../tmp_check/regress_outdir/res diff ../../../src/test/regress/expected/atx9.out ../tmp_check/regress_outdir/results/atx9.out --- ../../../src/test/regress/expected/atx9.out CENSORED +++ ../tmp_check/regress_outdir/results/atx9.out CENSORED -@@ -29,50 +29,38 @@ +@@ -28,50 +28,38 @@ INSERT INTO abc VALUES (1); INSERT INTO abc VALUES (2); COMMIT AND CHAIN; -- TBLOCK_END @@ -703,7 +716,7 @@ diff ../../../src/test/regress/expected/atx9.out ../tmp_check/regress_outdir/res COMMIT; ROLLBACK; BEGIN; -@@ -144,24 +132,13 @@ +@@ -143,24 +131,13 @@ SAVEPOINT x; COMMIT AND CHAIN; -- TBLOCK_SUBCOMMIT @@ -732,7 +745,7 @@ diff ../../../src/test/regress/expected/atx9.out ../tmp_check/regress_outdir/res COMMIT; ROLLBACK; -- different mix of options just for fun -@@ -232,17 +209,14 @@ +@@ -231,17 +208,14 @@ COMMIT; -- not allowed outside a transaction block COMMIT AUTONOMOUS AND CHAIN; -- error From 9ebb737783b74f89024bf18aa528b599b9d32044 Mon Sep 17 00:00:00 2001 From: "Anton A. Melnikov" Date: Thu, 9 Jun 2022 16:24:15 +0300 Subject: [PATCH 13/14] [PGPRO-6607] Replace MaxBackends in dmq_shmem_size() with direct calculation. Tags: Multimaster --- src/dmq.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/dmq.c b/src/dmq.c index c2d14fae28..163e0a260b 100644 --- a/src/dmq.c +++ b/src/dmq.c @@ -44,7 +44,9 @@ #include "utils/builtins.h" #include "utils/timestamp.h" #include "storage/shm_toc.h" +#include "postmaster/autovacuum.h" #include "postmaster/interrupt.h" +#include "replication/walsender.h" #include "storage/shm_mq.h" #include "storage/ipc.h" #include "tcop/tcopprot.h" @@ -362,9 +364,13 @@ static Size dmq_shmem_size(void) { Size size = 0; + int maxbackends = 0; + + maxbackends = MaxConnections + autovacuum_max_workers + + max_worker_processes + max_wal_senders + 1; size = add_size(size, sizeof(struct DmqSharedState)); - size = add_size(size, hash_estimate_size(DMQ_MAX_SUBS_PER_BACKEND * MaxBackends, + size = add_size(size, hash_estimate_size(DMQ_MAX_SUBS_PER_BACKEND * maxbackends, sizeof(DmqStreamSubscription))); return MAXALIGN(size); } From baab9238f784d428481ecfa1294e3f9a3910b2d2 Mon Sep 17 00:00:00 2001 From: Marina Polyakova Date: Thu, 25 Aug 2022 19:43:07 +0300 Subject: [PATCH 14/14] PGPRO-7102: fix warning in the function handle_response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For a build without assertions we get the following warning: src/resolver.c: In function ‘handle_response’: src/resolver.c:616:37: error: ‘gid’ may be used uninitialized in this function [-Werror=maybe-uninitialized] --- src/resolver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolver.c b/src/resolver.c index 2c9933ff51..659e9a2276 100644 --- a/src/resolver.c +++ b/src/resolver.c @@ -450,7 +450,7 @@ handle_response(MtmConfig *mtm_cfg, MtmMessage *raw_msg) else if (raw_msg->tag == T_Mtm2AResponse) gid = ((Mtm2AResponse *) raw_msg)->gid; else - Assert(false); + mtm_log(ERROR, "Illegal message tag %d", raw_msg->tag); mtm_log(ResolverTx, "handle_response: got '%s'", MtmMesageToString(raw_msg));