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

Commit b412f40

Browse files
committed
Move I/O before the index_update_stats() buffer lock region.
Commit a07e03f enlarged the work done here under the pg_class heap buffer lock. Two preexisting actions are best done before holding that lock. Both RelationGetNumberOfBlocks() and visibilitymap_count() do I/O, and the latter might exclusive-lock a visibility map buffer. Moving these reduces contention and risk of undetected LWLock deadlock. Back-patch to v12, like that commit. Discussion: https://postgr.es/m/20241031200139.b4@rfd.leadboat.com
1 parent 2fa255c commit b412f40

File tree

1 file changed

+40
-22
lines changed

1 file changed

+40
-22
lines changed

src/backend/catalog/index.c

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2806,6 +2806,9 @@ index_update_stats(Relation rel,
28062806
bool hasindex,
28072807
double reltuples)
28082808
{
2809+
bool update_stats;
2810+
BlockNumber relpages;
2811+
BlockNumber relallvisible;
28092812
Oid relid = RelationGetRelid(rel);
28102813
Relation pg_class;
28112814
ScanKeyData key[1];
@@ -2814,6 +2817,42 @@ index_update_stats(Relation rel,
28142817
Form_pg_class rd_rel;
28152818
bool dirty;
28162819

2820+
/*
2821+
* As a special hack, if we are dealing with an empty table and the
2822+
* existing reltuples is -1, we leave that alone. This ensures that
2823+
* creating an index as part of CREATE TABLE doesn't cause the table to
2824+
* prematurely look like it's been vacuumed. The rd_rel we modify may
2825+
* differ from rel->rd_rel due to e.g. commit of concurrent GRANT, but the
2826+
* commands that change reltuples take locks conflicting with ours. (Even
2827+
* if a command changed reltuples under a weaker lock, this affects only
2828+
* statistics for an empty table.)
2829+
*/
2830+
if (reltuples == 0 && rel->rd_rel->reltuples < 0)
2831+
reltuples = -1;
2832+
2833+
/*
2834+
* Don't update statistics during binary upgrade, because the indexes are
2835+
* created before the data is moved into place.
2836+
*/
2837+
update_stats = reltuples >= 0 && !IsBinaryUpgrade;
2838+
2839+
/*
2840+
* Finish I/O and visibility map buffer locks before
2841+
* systable_inplace_update_begin() locks the pg_class buffer. The rd_rel
2842+
* we modify may differ from rel->rd_rel due to e.g. commit of concurrent
2843+
* GRANT, but no command changes a relkind from non-index to index. (Even
2844+
* if one did, relallvisible doesn't break functionality.)
2845+
*/
2846+
if (update_stats)
2847+
{
2848+
relpages = RelationGetNumberOfBlocks(rel);
2849+
2850+
if (rel->rd_rel->relkind != RELKIND_INDEX)
2851+
visibilitymap_count(rel, &relallvisible, NULL);
2852+
else /* don't bother for indexes */
2853+
relallvisible = 0;
2854+
}
2855+
28172856
/*
28182857
* We always update the pg_class row using a non-transactional,
28192858
* overwrite-in-place update. There are several reasons for this:
@@ -2858,15 +2897,6 @@ index_update_stats(Relation rel,
28582897
/* Should this be a more comprehensive test? */
28592898
Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX);
28602899

2861-
/*
2862-
* As a special hack, if we are dealing with an empty table and the
2863-
* existing reltuples is -1, we leave that alone. This ensures that
2864-
* creating an index as part of CREATE TABLE doesn't cause the table to
2865-
* prematurely look like it's been vacuumed.
2866-
*/
2867-
if (reltuples == 0 && rd_rel->reltuples < 0)
2868-
reltuples = -1;
2869-
28702900
/* Apply required updates, if any, to copied tuple */
28712901

28722902
dirty = false;
@@ -2876,20 +2906,8 @@ index_update_stats(Relation rel,
28762906
dirty = true;
28772907
}
28782908

2879-
/*
2880-
* Avoid updating statistics during binary upgrade, because the indexes
2881-
* are created before the data is moved into place.
2882-
*/
2883-
if (reltuples >= 0 && !IsBinaryUpgrade)
2909+
if (update_stats)
28842910
{
2885-
BlockNumber relpages = RelationGetNumberOfBlocks(rel);
2886-
BlockNumber relallvisible;
2887-
2888-
if (rd_rel->relkind != RELKIND_INDEX)
2889-
visibilitymap_count(rel, &relallvisible, NULL);
2890-
else /* don't bother for indexes */
2891-
relallvisible = 0;
2892-
28932911
if (rd_rel->relpages != (int32) relpages)
28942912
{
28952913
rd_rel->relpages = (int32) relpages;

0 commit comments

Comments
 (0)