pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Tom Lane <tgl@sss.pgh.pa.us>
To: Andres Freund <andres@anarazel.de>
Cc: Michael Paquier <michael@paquier.xyz>
Cc: Postgres hackers <pgsql-hackers@lists.postgresql.org>
Subject: Re: REINDEX INDEX results in a crash for an index of pg_class since 9.6
Date: Wed, 01 May 2019 22:01:53 -0400
Message-ID: <27459.1556762513@sss.pgh.pa.us> (raw)
In-Reply-To: <20190502012520.eyfhhn5ix2ooflys@alap3.anarazel.de>
References: <20190430221045.6slpi2vm2noda5jb@alap3.anarazel.de>
	<28313.1556663080@sss.pgh.pa.us>
	<28926.1556664156@sss.pgh.pa.us>
	<20190430225307.lvfvcf2776iywhw4@alap3.anarazel.de>
	<20190501013638.7u7fwr4zktbyyng5@alap3.anarazel.de>
	<25049.1556727622@sss.pgh.pa.us>
	<20190501170603.hx6r3ztyvi3rlgq6@alap3.anarazel.de>
	<20190501172115.4cvz3rp6np43odut@alap3.anarazel.de>
	<5483.1556737736@sss.pgh.pa.us>
	<16043.1556754084@sss.pgh.pa.us>
	<20190502012520.eyfhhn5ix2ooflys@alap3.anarazel.de>

Andres Freund <andres@anarazel.de> writes:
> On 2019-05-01 19:41:24 -0400, Tom Lane wrote:
>> OK, so per the other thread, it seems like the error recovery problem
>> isn't going to affect this directly.  However, I still don't like this
>> proposal much; the reason being that it's a rather fundamental change
>> in the API of RelationSetNewRelfilenode.  This will certainly break
>> any external callers of that function --- and silently, too.

> Couldn't we just address that by adding a new
> RelationSetNewRelfilenodeInternal() that's then wrapped by
> RelationSetNewRelfilenode() which just does
> RelationSetNewRelfilenodeInternal();CCI();?

That's just adding more ugliness ...

>> The solution I'm thinking of should have much more localized effects,
>> basically just in reindex_index and RelationSetNewRelfilenode, which is
>> why I like it better.

> Well, as I said before, I think hiding the to-be-rebuilt index from the
> list of indexes is dangerous too - if somebody added an actual
> CatalogUpdate/Insert (rather than inplace_update) anywhere along the
> index_build() path, we'd not get an assertion failure anymore, but just
> an index without the new entry. And given the fragility with HOT hiding
> that a lot of the time, that seems dangerous to me.

I think that argument is pretty pointless considering that "REINDEX TABLE
pg_class" does it this way, and that code is nearly old enough to vote.
Perhaps there'd be value in rewriting things so that we don't need
RelationSetIndexList at all, but it's not real clear to me what we'd do
instead, and in any case I don't agree with back-patching such a change.
In the near term it seems better to me to make "REINDEX INDEX
some-pg_class-index" handle this problem the same way "REINDEX TABLE
pg_class" has been doing for many years.

Attached is a draft patch for this.  It passes check-world with
xxx_FORCE_RELEASE, and gets through reindexing pg_class with
CLOBBER_CACHE_ALWAYS, but I've not completed a full CCA run.

			regards, tom lane

Attachments:

  [text/x-diff] fix-reindex-on-pg-class.patch (3.3K, ../27459.1556762513@sss.pgh.pa.us/2-fix-reindex-on-pg-class.patch)
  download | inline diff:
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index ce02410..1af959c 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3261,6 +3261,9 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 				heapRelation;
 	Oid			heapId;
 	IndexInfo  *indexInfo;
+	bool		is_pg_class;
+	List	   *allIndexIds = NIL;
+	List	   *otherIndexIds = NIL;
 	volatile bool skipped_constraint = false;
 	PGRUsage	ru0;
 
@@ -3331,19 +3334,52 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	}
 
 	/*
-	 * Build a new physical relation for the index. Need to do that before
-	 * "officially" starting the reindexing with SetReindexProcessing -
-	 * otherwise the necessary pg_class changes cannot be made with
-	 * encountering assertions.
+	 * RelationSetNewRelfilenode will need to update the index's pg_class row.
+	 * If we are reindexing some index of pg_class, that creates a problem;
+	 * once we call SetReindexProcessing, the index support will complain if
+	 * we try to insert a new index entry.  But we can't do that in the other
+	 * order without creating other problems.  We solve this by temporarily
+	 * removing the target index from pg_class's index list.  It won't get
+	 * updated during RelationSetNewRelfilenode, but that's fine because the
+	 * subsequent index build will include the new entry.  (There are more
+	 * comments about this in reindex_relation.)
+	 *
+	 * If we are doing one index for reindex_relation, then we will find that
+	 * the index is already not present in the index list.  In that case we
+	 * don't have to do anything to the index list here, which we mark by
+	 * clearing is_pg_class.
 	 */
-	RelationSetNewRelfilenode(iRel, persistence);
+	is_pg_class = (RelationGetRelid(heapRelation) == RelationRelationId);
+	if (is_pg_class)
+	{
+		allIndexIds = RelationGetIndexList(heapRelation);
+		if (list_member_oid(allIndexIds, indexId))
+		{
+			otherIndexIds = list_delete_oid(list_copy(allIndexIds), indexId);
+			/* Ensure rd_indexattr is valid; see comments for RelationSetIndexList */
+			(void) RelationGetIndexAttrBitmap(heapRelation, INDEX_ATTR_BITMAP_ALL);
+		}
+		else
+			is_pg_class = false;
+	}
 
-	/* ensure SetReindexProcessing state isn't leaked */
+	/*
+	 * Ensure SetReindexProcessing state isn't leaked.  (We don't have to
+	 * clean up the RelationSetIndexList state on error, though; transaction
+	 * abort knows about fixing that.)
+	 */
 	PG_TRY();
 	{
 		/* Suppress use of the target index while rebuilding it */
 		SetReindexProcessing(heapId, indexId);
 
+		/* ... and suppress updating it too, if necessary */
+		if (is_pg_class)
+			RelationSetIndexList(heapRelation, otherIndexIds);
+
+		/* Build a new physical relation for the index */
+		RelationSetNewRelfilenode(iRel, persistence);
+
 		/* Initialize the index and rebuild */
 		/* Note: we do not need to re-establish pkey setting */
 		index_build(heapRelation, iRel, indexInfo, true, true);
@@ -3357,6 +3393,9 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	PG_END_TRY();
 	ResetReindexProcessing();
 
+	if (is_pg_class)
+		RelationSetIndexList(heapRelation, allIndexIds);
+
 	/*
 	 * If the index is marked invalid/not-ready/dead (ie, it's from a failed
 	 * CREATE INDEX CONCURRENTLY, or a DROP INDEX CONCURRENTLY failed midway),

view thread (82+ messages)  latest in thread

Message-ID: <27459.1556762513@sss.pgh.pa.us>
Permalink:  ../27459.1556762513@sss.pgh.pa.us/
Also on:    postgresql.org/message-id/27459.1556762513@sss.pgh.pa.us

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: tgl@sss.pgh.pa.us, andres@anarazel.de, michael@paquier.xyz, pgsql-hackers@lists.postgresql.org
  Subject: Re: REINDEX INDEX results in a crash for an index of pg_class since 9.6
  In-Reply-To: <27459.1556762513@sss.pgh.pa.us>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox