Skip to content

Commit 0bcb9d0

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 c1099dd commit 0bcb9d0

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
@@ -2782,6 +2782,9 @@ index_update_stats(Relation rel,
27822782
bool hasindex,
27832783
double reltuples)
27842784
{
2785+
bool update_stats;
2786+
BlockNumber relpages;
2787+
BlockNumber relallvisible;
27852788
Oid relid = RelationGetRelid(rel);
27862789
Relation pg_class;
27872790
ScanKeyData key[1];
@@ -2790,6 +2793,42 @@ index_update_stats(Relation rel,
27902793
Form_pg_class rd_rel;
27912794
bool dirty;
27922795

2796+
/*
2797+
* As a special hack, if we are dealing with an empty table and the
2798+
* existing reltuples is -1, we leave that alone. This ensures that
2799+
* creating an index as part of CREATE TABLE doesn't cause the table to
2800+
* prematurely look like it's been vacuumed. The rd_rel we modify may
2801+
* differ from rel->rd_rel due to e.g. commit of concurrent GRANT, but the
2802+
* commands that change reltuples take locks conflicting with ours. (Even
2803+
* if a command changed reltuples under a weaker lock, this affects only
2804+
* statistics for an empty table.)
2805+
*/
2806+
if (reltuples == 0 && rel->rd_rel->reltuples < 0)
2807+
reltuples = -1;
2808+
2809+
/*
2810+
* Don't update statistics during binary upgrade, because the indexes are
2811+
* created before the data is moved into place.
2812+
*/
2813+
update_stats = reltuples >= 0 && !IsBinaryUpgrade;
2814+
2815+
/*
2816+
* Finish I/O and visibility map buffer locks before
2817+
* systable_inplace_update_begin() locks the pg_class buffer. The rd_rel
2818+
* we modify may differ from rel->rd_rel due to e.g. commit of concurrent
2819+
* GRANT, but no command changes a relkind from non-index to index. (Even
2820+
* if one did, relallvisible doesn't break functionality.)
2821+
*/
2822+
if (update_stats)
2823+
{
2824+
relpages = RelationGetNumberOfBlocks(rel);
2825+
2826+
if (rel->rd_rel->relkind != RELKIND_INDEX)
2827+
visibilitymap_count(rel, &relallvisible, NULL);
2828+
else /* don't bother for indexes */
2829+
relallvisible = 0;
2830+
}
2831+
27932832
/*
27942833
* We always update the pg_class row using a non-transactional,
27952834
* overwrite-in-place update. There are several reasons for this:
@@ -2834,15 +2873,6 @@ index_update_stats(Relation rel,
28342873
/* Should this be a more comprehensive test? */
28352874
Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX);
28362875

2837-
/*
2838-
* As a special hack, if we are dealing with an empty table and the
2839-
* existing reltuples is -1, we leave that alone. This ensures that
2840-
* creating an index as part of CREATE TABLE doesn't cause the table to
2841-
* prematurely look like it's been vacuumed.
2842-
*/
2843-
if (reltuples == 0 && rd_rel->reltuples < 0)
2844-
reltuples = -1;
2845-
28462876
/* Apply required updates, if any, to copied tuple */
28472877

28482878
dirty = false;
@@ -2852,20 +2882,8 @@ index_update_stats(Relation rel,
28522882
dirty = true;
28532883
}
28542884

2855-
/*
2856-
* Avoid updating statistics during binary upgrade, because the indexes
2857-
* are created before the data is moved into place.
2858-
*/
2859-
if (reltuples >= 0 && !IsBinaryUpgrade)
2885+
if (update_stats)
28602886
{
2861-
BlockNumber relpages = RelationGetNumberOfBlocks(rel);
2862-
BlockNumber relallvisible;
2863-
2864-
if (rd_rel->relkind != RELKIND_INDEX)
2865-
visibilitymap_count(rel, &relallvisible, NULL);
2866-
else /* don't bother for indexes */
2867-
relallvisible = 0;
2868-
28692887
if (rd_rel->relpages != (int32) relpages)
28702888
{
28712889
rd_rel->relpages = (int32) relpages;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy