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

Commite7eea52

Browse files
author
Amit Kapila
committed
Fix Logical Replication of Truncate in synchronous commit mode.
The Truncate operation acquires an exclusive lock on the target relationand indexes. It then waits for logical replication of the operation tofinish at commit. Now because we are acquiring the shared lock on thetarget index to get index attributes in pgoutput while sending thechanges for the Truncate operation, it leads to a deadlock.Actually, we don't need to acquire a lock on the target index as we buildthe cache entry using a historic snapshot and all the later changes areabsorbed while decoding WAL. So, we wrote a special purpose function forlogical replication to get a bitmap of replica identity attribute numberswhere we get that information without locking the target index.We decided not to backpatch this as there doesn't seem to be any fieldcomplaint about this issue since it was introduced in commit5dfd1e5 inv11.Reported-by: Haiying TangAuthor: Takamichi Osumi, test case by Li JapinReviewed-by: Amit Kapila, Ajin CherianDiscussion:https://postgr.es/m/OS0PR01MB6113C2499C7DC70EE55ADB82FB759@OS0PR01MB6113.jpnprd01.prod.outlook.com
1 parent6dd1042 commite7eea52

File tree

4 files changed

+104
-3
lines changed

4 files changed

+104
-3
lines changed

‎src/backend/replication/logical/proto.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -668,8 +668,7 @@ logicalrep_write_attrs(StringInfo out, Relation rel)
668668
/* fetch bitmap of REPLICATION IDENTITY attributes */
669669
replidentfull= (rel->rd_rel->relreplident==REPLICA_IDENTITY_FULL);
670670
if (!replidentfull)
671-
idattrs=RelationGetIndexAttrBitmap(rel,
672-
INDEX_ATTR_BITMAP_IDENTITY_KEY);
671+
idattrs=RelationGetIdentityKeyBitmap(rel);
673672

674673
/* send the attributes */
675674
for (i=0;i<desc->natts;i++)

‎src/backend/utils/cache/relcache.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5206,6 +5206,81 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
52065206
}
52075207
}
52085208

5209+
/*
5210+
* RelationGetIdentityKeyBitmap -- get a bitmap of replica identity attribute
5211+
* numbers
5212+
*
5213+
* A bitmap of index attribute numbers for the configured replica identity
5214+
* index is returned.
5215+
*
5216+
* See also comments of RelationGetIndexAttrBitmap().
5217+
*
5218+
* This is a special purpose function used during logical replication. Here,
5219+
* unlike RelationGetIndexAttrBitmap(), we don't acquire a lock on the required
5220+
* index as we build the cache entry using a historic snapshot and all the
5221+
* later changes are absorbed while decoding WAL. Due to this reason, we don't
5222+
* need to retry here in case of a change in the set of indexes.
5223+
*/
5224+
Bitmapset*
5225+
RelationGetIdentityKeyBitmap(Relationrelation)
5226+
{
5227+
Bitmapset*idindexattrs=NULL;/* columns in the replica identity */
5228+
List*indexoidlist;
5229+
RelationindexDesc;
5230+
inti;
5231+
MemoryContextoldcxt;
5232+
5233+
/* Quick exit if we already computed the result */
5234+
if (relation->rd_idattr!=NULL)
5235+
returnbms_copy(relation->rd_idattr);
5236+
5237+
/* Fast path if definitely no indexes */
5238+
if (!RelationGetForm(relation)->relhasindex)
5239+
returnNULL;
5240+
5241+
/* Historic snapshot must be set. */
5242+
Assert(HistoricSnapshotActive());
5243+
5244+
indexoidlist=RelationGetIndexList(relation);
5245+
5246+
/* Fall out if no indexes (but relhasindex was set) */
5247+
if (indexoidlist==NIL)
5248+
returnNULL;
5249+
5250+
/* Add referenced attributes to idindexattrs */
5251+
indexDesc=RelationIdGetRelation(relation->rd_replidindex);
5252+
for (i=0;i<indexDesc->rd_index->indnatts;i++)
5253+
{
5254+
intattrnum=indexDesc->rd_index->indkey.values[i];
5255+
5256+
/*
5257+
* We don't include non-key columns into idindexattrs bitmaps. See
5258+
* RelationGetIndexAttrBitmap.
5259+
*/
5260+
if (attrnum!=0)
5261+
{
5262+
if (i<indexDesc->rd_index->indnkeyatts)
5263+
idindexattrs=bms_add_member(idindexattrs,
5264+
attrnum-FirstLowInvalidHeapAttributeNumber);
5265+
}
5266+
}
5267+
5268+
RelationClose(indexDesc);
5269+
list_free(indexoidlist);
5270+
5271+
/* Don't leak the old values of these bitmaps, if any */
5272+
bms_free(relation->rd_idattr);
5273+
relation->rd_idattr=NULL;
5274+
5275+
/* Now save copy of the bitmap in the relcache entry */
5276+
oldcxt=MemoryContextSwitchTo(CacheMemoryContext);
5277+
relation->rd_idattr=bms_copy(idindexattrs);
5278+
MemoryContextSwitchTo(oldcxt);
5279+
5280+
/* We return our original working copy for caller to play with */
5281+
returnidindexattrs;
5282+
}
5283+
52095284
/*
52105285
* RelationGetExclusionInfo -- get info about index's exclusion constraint
52115286
*

‎src/include/utils/relcache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ typedef enum IndexAttrBitmapKind
6565
externBitmapset*RelationGetIndexAttrBitmap(Relationrelation,
6666
IndexAttrBitmapKindattrKind);
6767

68+
externBitmapset*RelationGetIdentityKeyBitmap(Relationrelation);
69+
6870
externvoidRelationGetExclusionInfo(RelationindexRelation,
6971
Oid**operators,
7072
Oid**procs,

‎src/test/subscription/t/010_truncate.pl

Lines changed: 26 additions & 1 deletion
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=>9;
6+
use Test::Moretests=>11;
77

88
# setup
99

@@ -158,3 +158,28 @@
158158
$result =$node_subscriber->safe_psql('postgres',
159159
"SELECT count(*), min(a), max(a) FROM tab2");
160160
is($result,qq(3|1|3),'truncate of multiple tables some not published');
161+
162+
# Test that truncate works for synchronous logical replication
163+
164+
$node_publisher->safe_psql('postgres',
165+
"ALTER SYSTEM SET synchronous_standby_names TO 'sub1'");
166+
$node_publisher->safe_psql('postgres',"SELECT pg_reload_conf()");
167+
168+
# insert data to truncate
169+
170+
$node_publisher->safe_psql('postgres',
171+
"INSERT INTO tab1 VALUES (1), (2), (3)");
172+
173+
$node_publisher->wait_for_catchup('sub1');
174+
175+
$result =$node_subscriber->safe_psql('postgres',
176+
"SELECT count(*), min(a), max(a) FROM tab1");
177+
is($result,qq(3|1|3),'check synchronous logical replication');
178+
179+
$node_publisher->safe_psql('postgres',"TRUNCATE tab1");
180+
181+
$node_publisher->wait_for_catchup('sub1');
182+
183+
$result =$node_subscriber->safe_psql('postgres',
184+
"SELECT count(*), min(a), max(a) FROM tab1");
185+
is($result,qq(0||),'truncate replicated in synchronous logical replication');

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp