Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 79e37a9

Browse files
committed
Fixed bug "Update triggers sometimes don't fire due to tablesync".
Now we wait in add_node until tablesync is completed, so we don't lose updates on tables with metadata.
1 parent be4020d commit 79e37a9

File tree

4 files changed

+74
-26
lines changed

4 files changed

+74
-26
lines changed

init.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ BEGIN
312312
END LOOP;
313313
IF shardman.my_id() IS NOT NULL THEN
314314
-- otherwise we will hang
315-
SET LOCAL synchronous_commit TO local;
315+
SET LOCAL synchronous_commit TO LOCAL;
316316
-- TODO: remove only shardman's standbys
317317
PERFORM shardman.set_sync_standbys('');
318318
END IF;

src/copypart.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,6 @@ static int cp_finalize(CopyPartState *cpts);
128128
static int ensure_pqconn_cp(CopyPartState *cpts, int nodes);
129129
static int ensure_pqconn(PGconn **conn, const char *connstr,
130130
CopyPartState *cps);
131-
static void reset_pqconn(PGconn **conn);
132-
static void reset_pqconn_and_res(PGconn **conn, PGresult *res);
133131
static void configure_retry(CopyPartState *cpts, int millis);
134132
static struct timespec timespec_now_plus_millis(int millis);
135133
struct timespec timespec_now(void);
@@ -1065,20 +1063,6 @@ ensure_pqconn(PGconn **conn, const char *connstr,
10651063
return 0;
10661064
}
10671065

1068-
/*
1069-
* Finish pq connection and set ptr to NULL. You must be sure that the
1070-
* connection exists!
1071-
*/
1072-
void
1073-
reset_pqconn(PGconn **conn) { PQfinish(*conn); *conn = NULL; }
1074-
/* Same, but also clear res. You must be sure it exists */
1075-
void
1076-
reset_pqconn_and_res(PGconn **conn, PGresult *res)
1077-
{
1078-
PQclear(res); reset_pqconn(conn);
1079-
}
1080-
1081-
10821066
/*
10831067
* Configure cps so that main loop wakes us again after given retry millis.
10841068
*/

src/include/pg_shardman.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <signal.h>
55

66
#include "miscadmin.h"
7+
#include "libpq-fe.h"
78

89
#define shmn_elog(level,fmt,...) elog(level, "[SHARDMAN] " fmt, ## __VA_ARGS__)
910

@@ -34,7 +35,8 @@ do { \
3435
} while (0)
3536
/*
3637
* Additionally check for SIGUSR1; if it has arrived, mark cmd as canceled and
37-
* return from current function.
38+
* return from current function. Used to save typing void funcs where we don't
39+
* need to do anything before 'return'.
3840
*/
3941
#define SHMN_CHECK_FOR_INTERRUPTS_CMD(cmd) \
4042
do { \
@@ -81,6 +83,8 @@ extern void shardlord_main(Datum main_arg);
8183
extern bool signal_pending(void);
8284
extern void check_for_sigterm(void);
8385
extern void cmd_canceled(Cmd *cmd);
86+
extern void reset_pqconn(PGconn **conn);
87+
extern void reset_pqconn_and_res(PGconn **conn, PGresult *res);
8488
extern uint64 void_spi(char *sql);
8589
extern void update_cmd_status(int64 id, const char *new_status);
8690
extern char *get_worker_node_connstr(int32 node_id);

src/pg_shardman.c

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ cmd_canceled(Cmd *cmd)
473473
* - recreating repslot
474474
* - recreating subscription
475475
* - setting node id on the node itself
476+
* - waiting for initial tablesync
476477
* - marking node as active and cmd as success
477478
* We do all this stuff to make all actions are idempodent to be able to retry
478479
* them in case of any failure.
@@ -487,6 +488,7 @@ add_node(Cmd *cmd)
487488
bool pg_shardman_installed;
488489
int32 node_id;
489490
char *sql;
491+
bool tablesync_done = false;
490492

491493
shmn_elog(INFO, "Adding node %s", connstr);
492494
/* Try to execute command indefinitely until it succeeded or canceled */
@@ -577,15 +579,63 @@ add_node(Cmd *cmd)
577579
"select shardman.set_node_id(%d);",
578580
shardman_shardlord_connstring, node_id, node_id);
579581
res = PQexec(conn, sql);
582+
pfree(sql);
580583
if (PQresultStatus(res) != PGRES_TUPLES_OK)
581584
{
582585
shmn_elog(NOTICE, "Failed to create subscription and set node id, %s",
583586
PQerrorMessage(conn));
584587
goto attempt_failed;
585588
}
586-
587589
PQclear(res);
588-
PQfinish(conn);
590+
591+
/*
592+
* Wait until initial tablesync is completed. This is necessary as
593+
* e.g. we might miss UPDATE statements on partitions table, triggers
594+
* on newly added node won't fire and metadata would be inconsistent.
595+
*/
596+
sql =
597+
"select srrelid, srsubstate from pg_subscription_rel srel join"
598+
" pg_subscription s on srel.srsubid = s.oid where"
599+
" subname = 'shardman_meta_sub';";
600+
while (!tablesync_done)
601+
{
602+
int i;
603+
604+
res = PQexec(conn, sql);
605+
if (PQresultStatus(res) != PGRES_TUPLES_OK)
606+
{
607+
shmn_elog(NOTICE, "Adding node %s: failed to learn sub status, %s ",
608+
connstr, PQerrorMessage(conn));
609+
goto attempt_failed;
610+
}
611+
612+
tablesync_done = true;
613+
for (i = 0; i < PQntuples(res); i++)
614+
{
615+
char *subrelid = PQgetvalue(res, i, 0);
616+
char subrelstate = PQgetvalue(res, i, 1)[0];
617+
if (subrelstate != 'r')
618+
{
619+
tablesync_done = false;
620+
shmn_elog(DEBUG1,
621+
"adding node %s: init sync is not yet finished"
622+
" for rel %s, its state is %c",
623+
connstr, subrelid, subrelstate);
624+
pg_usleep(shardman_poll_interval * 1000L);
625+
SHMN_CHECK_FOR_INTERRUPTS();
626+
if (got_sigusr1)
627+
{
628+
reset_pqconn_and_res(&conn, res);
629+
cmd_canceled(cmd);
630+
return;
631+
}
632+
break;
633+
}
634+
}
635+
PQclear(res);
636+
}
637+
638+
reset_pqconn(&conn);
589639

590640
/*
591641
* Mark add_node cmd as success and node as active, we must do that in
@@ -604,11 +654,7 @@ add_node(Cmd *cmd)
604654
return;
605655

606656
attempt_failed: /* clean resources, sleep, check sigusr1 and try again */
607-
if (res != NULL)
608-
PQclear(res);
609-
if (conn != NULL)
610-
PQfinish(conn);
611-
657+
reset_pqconn_and_res(&conn, res);
612658
shmn_elog(LOG, "Attempt to execute add_node failed, sleeping and retrying");
613659
/* TODO: sleep using waitlatch? */
614660
pg_usleep(shardman_cmd_retry_naptime * 1000L);
@@ -711,7 +757,21 @@ rm_node(Cmd *cmd)
711757
elog(INFO, "Node %d successfully removed", node_id);
712758
}
713759

714-
760+
/*
761+
* Finish pq connection and set ptr to NULL. You must be sure that the
762+
* connection exists!
763+
*/
764+
void
765+
reset_pqconn(PGconn **conn) { PQfinish(*conn); *conn = NULL; }
766+
/*
767+
* Same, but also clear res. You must be sure that both connection and res
768+
* exist.
769+
*/
770+
void
771+
reset_pqconn_and_res(PGconn **conn, PGresult *res)
772+
{
773+
PQclear(res); reset_pqconn(conn);
774+
}
715775

716776
/*
717777
* Get connstr of worker node with id node_id. Memory is palloc'ed.

0 commit comments

Comments
 (0)