Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit27fafee

Browse files
committed
Fix publish_as_relid with multiple publications
Commit83fd453 allowed publishing of changes via ancestors, forpublications defined with publish_via_partition_root. But the waythe ancestor was determined in get_rel_sync_entry() was incorrect,simply updating the same variable. So with multiple publications,replicating different ancestors, the outcome depended on the orderof publications in the list - the value from the last loop was used,even if it wasn't the top-most ancestor.This is a probably rare situation, as in most cases publications donot overlap, so each partition has exactly one candidate ancestorto replicate as and there's no ambiguity.Fixed by tracking the "ancestor level" for each publication, andpicking the top-most ancestor. Adds a test case, verifying thecorrect ancestor is used for publishing the changes and that thisdoes not depend on order of publications in the list.Older releases have another bug in this loop - once all actions arereplicated, the loop is terminated, on the assumption that inspectingadditional publications is unecessary. But that misses the fact thatthose additional applications may replicate different ancestors.Fixed by removal of this break condition. We might still terminate theloop in some cases (e.g. when replicating all actions and the ancestoris the partition root).Backpatch to 13, where publish_via_partition_root was introduced.Initial report and fix by me, test added by Hou zj. Reviews andimprovements by Amit Kapila.Author: Tomas Vondra, Hou zj, Amit KapilaReviewed-by: Amit Kapila, Hou zjDiscussion:https://postgr.es/m/d26d24dd-2fab-3c48-0162-2b7f84a9c893%40enterprisedb.com
1 parentbad202c commit27fafee

File tree

2 files changed

+96
-8
lines changed

2 files changed

+96
-8
lines changed

‎src/backend/replication/pgoutput/pgoutput.c

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,7 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
701701
List*pubids=GetRelationPublications(relid);
702702
ListCell*lc;
703703
Oidpublish_as_relid=relid;
704+
intpublish_ancestor_level=0;
704705
boolam_partition=get_rel_relispartition(relid);
705706
charrelkind=get_rel_relkind(relid);
706707

@@ -729,11 +730,28 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
729730
Publication*pub=lfirst(lc);
730731
boolpublish= false;
731732

733+
/*
734+
* Under what relid should we publish changes in this publication?
735+
* We'll use the top-most relid across all publications. Also track
736+
* the ancestor level for this publication.
737+
*/
738+
Oidpub_relid=relid;
739+
intancestor_level=0;
740+
741+
/*
742+
* If this is a FOR ALL TABLES publication, pick the partition root
743+
* and set the ancestor level accordingly.
744+
*/
732745
if (pub->alltables)
733746
{
734747
publish= true;
735748
if (pub->pubviaroot&&am_partition)
736-
publish_as_relid=llast_oid(get_partition_ancestors(relid));
749+
{
750+
List*ancestors=get_partition_ancestors(relid);
751+
752+
pub_relid=llast_oid(ancestors);
753+
ancestor_level=list_length(ancestors);
754+
}
737755
}
738756

739757
if (!publish)
@@ -750,6 +768,7 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
750768
{
751769
List*ancestors=get_partition_ancestors(relid);
752770
ListCell*lc2;
771+
intlevel=0;
753772

754773
/*
755774
* Find the "topmost" ancestor that is in this
@@ -759,12 +778,17 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
759778
{
760779
Oidancestor=lfirst_oid(lc2);
761780

781+
level++;
782+
762783
if (list_member_oid(GetRelationPublications(ancestor),
763784
pub->oid))
764785
{
765786
ancestor_published= true;
766787
if (pub->pubviaroot)
767-
publish_as_relid=ancestor;
788+
{
789+
pub_relid=ancestor;
790+
ancestor_level=level;
791+
}
768792
}
769793
}
770794
}
@@ -785,11 +809,21 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
785809
entry->pubactions.pubupdate |=pub->pubactions.pubupdate;
786810
entry->pubactions.pubdelete |=pub->pubactions.pubdelete;
787811
entry->pubactions.pubtruncate |=pub->pubactions.pubtruncate;
788-
}
789812

790-
if (entry->pubactions.pubinsert&&entry->pubactions.pubupdate&&
791-
entry->pubactions.pubdelete&&entry->pubactions.pubtruncate)
792-
break;
813+
/*
814+
* We want to publish the changes as the top-most ancestor
815+
* across all publications. So we need to check if the
816+
* already calculated level is higher than the new one. If
817+
* yes, we can ignore the new value (as it's a child).
818+
* Otherwise the new value is an ancestor, so we keep it.
819+
*/
820+
if (publish_ancestor_level>ancestor_level)
821+
continue;
822+
823+
/* The new value is an ancestor, so let's keep it. */
824+
publish_as_relid=pub_relid;
825+
publish_ancestor_level=ancestor_level;
826+
}
793827
}
794828

795829
list_free(pubids);

‎src/test/subscription/t/013_partition.pl

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use warnings;
44
use PostgresNode;
55
use TestLib;
6-
use Test::Moretests=>63;
6+
use Test::Moretests=>67;
77

88
# setup
99

@@ -406,6 +406,12 @@ BEGIN
406406
"CREATE TABLE tab3 (a int PRIMARY KEY, b text) PARTITION BY LIST (a)");
407407
$node_publisher->safe_psql('postgres',
408408
"CREATE TABLE tab3_1 PARTITION OF tab3 FOR VALUES IN (0, 1, 2, 3, 5, 6)");
409+
$node_publisher->safe_psql('postgres',
410+
"CREATE TABLE tab4 (a int PRIMARY KEY) PARTITION BY LIST (a)");
411+
$node_publisher->safe_psql('postgres',
412+
"CREATE TABLE tab4_1 PARTITION OF tab4 FOR VALUES IN (0, 1) PARTITION BY LIST (a)");
413+
$node_publisher->safe_psql('postgres',
414+
"CREATE TABLE tab4_1_1 PARTITION OF tab4_1 FOR VALUES IN (0, 1)");
409415
$node_publisher->safe_psql('postgres',
410416
"ALTER PUBLICATION pub_all SET (publish_via_partition_root = true)");
411417
# Note: tab3_1's parent is not in the publication, in which case its
@@ -415,6 +421,9 @@ BEGIN
415421
$node_publisher->safe_psql('postgres',
416422
"CREATE PUBLICATION pub_viaroot FOR TABLE tab2, tab2_1, tab3_1 WITH (publish_via_partition_root = true)"
417423
);
424+
$node_publisher->safe_psql('postgres',
425+
"CREATE PUBLICATION pub_lower_level FOR TABLE tab4_1 WITH (publish_via_partition_root = true)"
426+
);
418427

419428
# prepare data for the initial sync
420429
$node_publisher->safe_psql('postgres',"INSERT INTO tab2 VALUES (1)");
@@ -459,10 +468,16 @@ BEGIN
459468
$node_subscriber2->safe_psql('postgres',
460469
"CREATE TABLE tab3_1 (a int PRIMARY KEY, c text DEFAULT 'sub2_tab3_1', b text)"
461470
);
471+
$node_subscriber2->safe_psql('postgres',
472+
"CREATE TABLE tab4 (a int PRIMARY KEY)"
473+
);
474+
$node_subscriber2->safe_psql('postgres',
475+
"CREATE TABLE tab4_1 (a int PRIMARY KEY)"
476+
);
462477
# Publication that sub2 points to now publishes via root, so must update
463478
# subscription target relations.
464479
$node_subscriber2->safe_psql('postgres',
465-
"ALTER SUBSCRIPTION sub2REFRESH PUBLICATION");
480+
"ALTER SUBSCRIPTION sub2SET PUBLICATION pub_lower_level, pub_all");
466481

467482
# Wait for initial sync of all subscriptions
468483
$node_subscriber1->poll_query_until('postgres',$synced_query)
@@ -483,6 +498,8 @@ BEGIN
483498
"INSERT INTO tab2 VALUES (0), (3), (5)");
484499
$node_publisher->safe_psql('postgres',
485500
"INSERT INTO tab3 VALUES (1), (0), (3), (5)");
501+
$node_publisher->safe_psql('postgres',
502+
"INSERT INTO tab4 VALUES (0)");
486503

487504
$node_publisher->wait_for_catchup('sub_viaroot');
488505
$node_publisher->wait_for_catchup('sub2');
@@ -522,6 +539,43 @@ BEGIN
522539
sub2_tab3|3
523540
sub2_tab3|5),'inserts into tab3 replicated');
524541

542+
$result =$node_subscriber2->safe_psql('postgres',
543+
"SELECT a FROM tab4 ORDER BY 1");
544+
is($result,qq(0),'inserts into tab4 replicated');
545+
546+
$result =$node_subscriber2->safe_psql('postgres',
547+
"SELECT a FROM tab4_1 ORDER BY 1");
548+
is($result,qq(),'inserts into tab4_1 replicated');
549+
550+
# now switch the order of publications in the list, try again, the result
551+
# should be the same (no dependence on order of pulications)
552+
$node_subscriber2->safe_psql('postgres',
553+
"ALTER SUBSCRIPTION sub2 SET PUBLICATION pub_all, pub_lower_level");
554+
555+
# make sure the subscription on the second subscriber is synced, before
556+
# continuing
557+
$node_subscriber2->poll_query_until('postgres',$synced_query)
558+
ordie"Timed out while waiting for subscriber to synchronize data";
559+
560+
# Insert a change into the leaf partition, should be replicated through
561+
# the partition root (thanks to the FOR ALL TABLES partition).
562+
$node_publisher->safe_psql('postgres',
563+
"INSERT INTO tab4 VALUES (1)");
564+
565+
$node_publisher->wait_for_catchup('sub2');
566+
567+
# tab4 change should be replicated through the root partition, which
568+
# maps to the tab4 relation on subscriber.
569+
$result =$node_subscriber2->safe_psql('postgres',
570+
"SELECT a FROM tab4 ORDER BY 1");
571+
is($result,qq(0
572+
1),'inserts into tab4 replicated');
573+
574+
$result =$node_subscriber2->safe_psql('postgres',
575+
"SELECT a FROM tab4_1 ORDER BY 1");
576+
is($result,qq(),'inserts into tab4_1 replicated');
577+
578+
525579
# update (replicated as update)
526580
$node_publisher->safe_psql('postgres',"UPDATE tab1 SET a = 6 WHERE a = 5");
527581
$node_publisher->safe_psql('postgres',"UPDATE tab2 SET a = 6 WHERE a = 5");

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp