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

Commiteb89cb4

Browse files
author
Amit Kapila
committed
pgoutput: Fix memory leak due to RelationSyncEntry.map.
Release memory allocated when creating the tuple-conversion map and itscomponent TupleDescs when its owning sync entry is invalidated.TupleDescs must also be freed when no map is deemed necessary, to beginwith.Reported-by: Andres FreundAuthor: Amit LangoteReviewed-by: Takamichi Osumi, Amit KapilaBackpatch-through: 13, where it was introducedDiscussion:https://postgr.es/m/MEYP282MB166933B1AB02B4FE56E82453B64D9@MEYP282MB1669.AUSP282.PROD.OUTLOOK.COM
1 parenta40646e commiteb89cb4

File tree

2 files changed

+65
-9
lines changed

2 files changed

+65
-9
lines changed

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

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ static void send_relation_and_attrs(Relation relation, TransactionId xid,
7474
/*
7575
* Entry in the map used to remember which relation schemas we sent.
7676
*
77-
* The schema_sent flag determines if the current schema record was already
77+
* The schema_sent flag determines if the current schema record for the
78+
* relation (and for its ancestor if publish_as_relid is set) was already
7879
* sent to the subscriber (in which case we don't need to send it again).
7980
*
8081
* The schema cache on downstream is however updated only at commit time,
@@ -92,10 +93,6 @@ typedef struct RelationSyncEntry
9293
{
9394
Oidrelid;/* relation oid */
9495

95-
/*
96-
* Did we send the schema? If ancestor relid is set, its schema must also
97-
* have been sent for this to be true.
98-
*/
9996
boolschema_sent;
10097
List*streamed_txns;/* streamed toplevel transactions with this
10198
* schema */
@@ -437,10 +434,17 @@ maybe_send_schema(LogicalDecodingContext *ctx,
437434
else
438435
schema_sent=relentry->schema_sent;
439436

437+
/* Nothing to do if we already sent the schema. */
440438
if (schema_sent)
441439
return;
442440

443-
/* If needed, send the ancestor's schema first. */
441+
/*
442+
* Nope, so send the schema. If the changes will be published using an
443+
* ancestor's schema, not the relation's own, send that ancestor's schema
444+
* before sending relation's own (XXX - maybe sending only the former
445+
* suffices?). This is also a good place to set the map that will be used
446+
* to convert the relation's tuples into the ancestor's format, if needed.
447+
*/
444448
if (relentry->publish_as_relid!=RelationGetRelid(relation))
445449
{
446450
Relationancestor=RelationIdGetRelation(relentry->publish_as_relid);
@@ -450,8 +454,21 @@ maybe_send_schema(LogicalDecodingContext *ctx,
450454

451455
/* Map must live as long as the session does. */
452456
oldctx=MemoryContextSwitchTo(CacheMemoryContext);
453-
relentry->map=convert_tuples_by_name(CreateTupleDescCopy(indesc),
454-
CreateTupleDescCopy(outdesc));
457+
458+
/*
459+
* Make copies of the TupleDescs that will live as long as the map
460+
* does before putting into the map.
461+
*/
462+
indesc=CreateTupleDescCopy(indesc);
463+
outdesc=CreateTupleDescCopy(outdesc);
464+
relentry->map=convert_tuples_by_name(indesc,outdesc);
465+
if (relentry->map==NULL)
466+
{
467+
/* Map not necessary, so free the TupleDescs too. */
468+
FreeTupleDesc(indesc);
469+
FreeTupleDesc(outdesc);
470+
}
471+
455472
MemoryContextSwitchTo(oldctx);
456473
send_relation_and_attrs(ancestor,xid,ctx);
457474
RelationClose(ancestor);
@@ -1011,6 +1028,7 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
10111028
entry->pubactions.pubinsert=entry->pubactions.pubupdate=
10121029
entry->pubactions.pubdelete=entry->pubactions.pubtruncate= false;
10131030
entry->publish_as_relid=InvalidOid;
1031+
entry->map=NULL;/* will be set by maybe_send_schema() if needed */
10141032
}
10151033

10161034
/* Validate the entry */
@@ -1191,12 +1209,24 @@ rel_sync_cache_relation_cb(Datum arg, Oid relid)
11911209

11921210
/*
11931211
* Reset schema sent status as the relation definition may have changed.
1212+
* Also free any objects that depended on the earlier definition.
11941213
*/
11951214
if (entry!=NULL)
11961215
{
11971216
entry->schema_sent= false;
11981217
list_free(entry->streamed_txns);
11991218
entry->streamed_txns=NIL;
1219+
if (entry->map)
1220+
{
1221+
/*
1222+
* Must free the TupleDescs contained in the map explicitly,
1223+
* because free_conversion_map() doesn't.
1224+
*/
1225+
FreeTupleDesc(entry->map->indesc);
1226+
FreeTupleDesc(entry->map->outdesc);
1227+
free_conversion_map(entry->map);
1228+
}
1229+
entry->map=NULL;
12001230
}
12011231
}
12021232

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use warnings;
77
use PostgresNode;
88
use TestLib;
9-
use Test::Moretests=>54;
9+
use Test::Moretests=>56;
1010

1111
# setup
1212

@@ -624,3 +624,29 @@ BEGIN
624624

625625
$result =$node_subscriber2->safe_psql('postgres',"SELECT a FROM tab3_1");
626626
is($result,qq(),'truncate of tab3_1 replicated');
627+
628+
# check that the map to convert tuples from leaf partition to the root
629+
# table is correctly rebuilt when a new column is added
630+
$node_publisher->safe_psql('postgres',
631+
"ALTER TABLE tab2 DROP b, ADD COLUMN c text DEFAULT 'pub_tab2', ADD b text");
632+
$node_publisher->safe_psql('postgres',
633+
"INSERT INTO tab2 (a, b) VALUES (1, 'xxx'), (3, 'yyy'), (5, 'zzz')");
634+
$node_publisher->safe_psql('postgres',
635+
"INSERT INTO tab2 (a, b, c) VALUES (6, 'aaa', 'xxx_c')");
636+
637+
$node_publisher->wait_for_catchup('sub_viaroot');
638+
$node_publisher->wait_for_catchup('sub2');
639+
640+
$result =$node_subscriber1->safe_psql('postgres',
641+
"SELECT c, a, b FROM tab2 ORDER BY 1, 2");
642+
is($result,qq(pub_tab2|1|xxx
643+
pub_tab2|3|yyy
644+
pub_tab2|5|zzz
645+
xxx_c|6|aaa),'inserts into tab2 replicated');
646+
647+
$result =$node_subscriber2->safe_psql('postgres',
648+
"SELECT c, a, b FROM tab2 ORDER BY 1, 2");
649+
is($result,qq(pub_tab2|1|xxx
650+
pub_tab2|3|yyy
651+
pub_tab2|5|zzz
652+
xxx_c|6|aaa),'inserts into tab2 replicated');

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp