reindexing an invalid index should not use ERRCODE_INDEX_CORRUPTED

Started by Andres Freundabout 2 years ago7 messages
#1Andres Freund
andres@anarazel.de

Hi,

We currently provide no way to learn about a postgres instance having
corruption than searching the logs for corruption events than matching by
sqlstate, for ERRCODE_DATA_CORRUPTED and ERRCODE_INDEX_CORRUPTED.

Unfortunately, there is a case of such an sqlstate that's not at all indicating
corruption, namely REINDEX CONCURRENTLY when the index is invalid:

if (!indexRelation->rd_index->indisvalid)
ereport(WARNING,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
get_namespace_name(get_rel_namespace(cellOid)),
get_rel_name(cellOid))));

The only thing required to get to this is an interrupted CREATE INDEX
CONCURRENTLY, which I don't think can be fairly characterized as "corruption".

ISTM something like ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE would be more
appropriate?

Greetings,

Andres Freund

#2Noah Misch
noah@leadboat.com
In reply to: Andres Freund (#1)
Re: reindexing an invalid index should not use ERRCODE_INDEX_CORRUPTED

On Sat, Nov 18, 2023 at 03:09:58PM -0800, Andres Freund wrote:

We currently provide no way to learn about a postgres instance having
corruption than searching the logs for corruption events than matching by
sqlstate, for ERRCODE_DATA_CORRUPTED and ERRCODE_INDEX_CORRUPTED.

Unfortunately, there is a case of such an sqlstate that's not at all indicating
corruption, namely REINDEX CONCURRENTLY when the index is invalid:

if (!indexRelation->rd_index->indisvalid)
ereport(WARNING,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
get_namespace_name(get_rel_namespace(cellOid)),
get_rel_name(cellOid))));

The only thing required to get to this is an interrupted CREATE INDEX
CONCURRENTLY, which I don't think can be fairly characterized as "corruption".

ISTM something like ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE would be more
appropriate?

+1, that's a clear improvement.

The "cannot" part of the message is also inaccurate, and it's not clear to me
why we have this specific restriction at all. REINDEX INDEX CONCURRENTLY
accepts such indexes, so I doubt it's an implementation gap. Since an INVALID
index often duplicates some valid index, I could see an argument that
reindexing INVALID indexes as part of a table-level REINDEX is wanted less
often than not. But that argument would be just as pertinent to REINDEX TABLE
(w/o CONCURRENTLY), which doesn't impose this restriction. Hmmm.

#3Michael Paquier
michael@paquier.xyz
In reply to: Noah Misch (#2)
1 attachment(s)
Re: reindexing an invalid index should not use ERRCODE_INDEX_CORRUPTED

On Sat, Nov 18, 2023 at 04:32:36PM -0800, Noah Misch wrote:

On Sat, Nov 18, 2023 at 03:09:58PM -0800, Andres Freund wrote:

Unfortunately, there is a case of such an sqlstate that's not at all indicating
corruption, namely REINDEX CONCURRENTLY when the index is invalid:

if (!indexRelation->rd_index->indisvalid)
ereport(WARNING,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
get_namespace_name(get_rel_namespace(cellOid)),
get_rel_name(cellOid))));

The only thing required to get to this is an interrupted CREATE INDEX
CONCURRENTLY, which I don't think can be fairly characterized as "corruption".

ISTM something like ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE would be more
appropriate?

+1, that's a clear improvement.

The same thing can be said a couple of lines above where the code uses
ERRCODE_FEATURE_NOT_SUPPORTED but your suggestion of
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE would be better.

Would the attached be OK for you?

The "cannot" part of the message is also inaccurate, and it's not clear to me
why we have this specific restriction at all. REINDEX INDEX CONCURRENTLY
accepts such indexes, so I doubt it's an implementation gap.

If you would reword that, what would you change?

Since an INVALID
index often duplicates some valid index, I could see an argument that
reindexing INVALID indexes as part of a table-level REINDEX is wanted less
often than not.

The argument behind this restriction is that repeated interruptions of
a table-level REINDEX CONCURRENTLY would bloat the entire relation in
index entries if invalid entries are rebuilt. This was discussed back
on the original thread back in 2019, around here:
/messages/by-id/20190411132704.GC30766@paquier.xyz
--
Michael

Attachments:

reindex-invalid-errcode.patchtext/x-diff; charset=us-asciiDownload
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 412e1ba84f..05570eb3f3 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -3524,7 +3524,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
 
 					if (!indexRelation->rd_index->indisvalid)
 						ereport(WARNING,
-								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 								 errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
 										get_namespace_name(get_rel_namespace(cellOid)),
 										get_rel_name(cellOid))));
@@ -3576,7 +3576,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
 
 						if (!indexRelation->rd_index->indisvalid)
 							ereport(WARNING,
-									(errcode(ERRCODE_INDEX_CORRUPTED),
+									(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 									 errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
 											get_namespace_name(get_rel_namespace(cellOid)),
 											get_rel_name(cellOid))));
#4Noah Misch
noah@leadboat.com
In reply to: Michael Paquier (#3)
Re: reindexing an invalid index should not use ERRCODE_INDEX_CORRUPTED

On Wed, Dec 06, 2023 at 03:17:12PM +0900, Michael Paquier wrote:

On Sat, Nov 18, 2023 at 04:32:36PM -0800, Noah Misch wrote:

On Sat, Nov 18, 2023 at 03:09:58PM -0800, Andres Freund wrote:

Unfortunately, there is a case of such an sqlstate that's not at all indicating
corruption, namely REINDEX CONCURRENTLY when the index is invalid:

if (!indexRelation->rd_index->indisvalid)
ereport(WARNING,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
get_namespace_name(get_rel_namespace(cellOid)),
get_rel_name(cellOid))));

The only thing required to get to this is an interrupted CREATE INDEX
CONCURRENTLY, which I don't think can be fairly characterized as "corruption".

ISTM something like ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE would be more
appropriate?

+1, that's a clear improvement.

The same thing can be said a couple of lines above where the code uses
ERRCODE_FEATURE_NOT_SUPPORTED but your suggestion of
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE would be better.

Would the attached be OK for you?

Okay.

The "cannot" part of the message is also inaccurate, and it's not clear to me
why we have this specific restriction at all. REINDEX INDEX CONCURRENTLY
accepts such indexes, so I doubt it's an implementation gap.

If you would reword that, what would you change?

I'd do "skipping reindex of invalid index \"%s.%s\"". If one wanted more,
errhint("Use DROP INDEX or REINDEX INDEX.") would fit.

#5Michael Paquier
michael@paquier.xyz
In reply to: Noah Misch (#4)
1 attachment(s)
Re: reindexing an invalid index should not use ERRCODE_INDEX_CORRUPTED

On Wed, Dec 06, 2023 at 04:33:33PM -0800, Noah Misch wrote:

On Wed, Dec 06, 2023 at 03:17:12PM +0900, Michael Paquier wrote:

The "cannot" part of the message is also inaccurate, and it's not clear to me
why we have this specific restriction at all. REINDEX INDEX CONCURRENTLY
accepts such indexes, so I doubt it's an implementation gap.

If you would reword that, what would you change?

I'd do "skipping reindex of invalid index \"%s.%s\"". If one wanted more,

In line with vacuum.c, that sounds like a good idea at the end.

errhint("Use DROP INDEX or REINDEX INDEX.") would fit.

I'm OK with this suggestion as well.
--
Michael

Attachments:

reindex-invalid-errcode-v2.patchtext/x-diff; charset=us-asciiDownload
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 4ee498d985..e56205abd8 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -3526,10 +3526,11 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
 
 					if (!indexRelation->rd_index->indisvalid)
 						ereport(WARNING,
-								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-								 errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("skipping reindex of invalid index \"%s.%s\"",
 										get_namespace_name(get_rel_namespace(cellOid)),
-										get_rel_name(cellOid))));
+										get_rel_name(cellOid)),
+								 errhint("Use DROP INDEX or REINDEX INDEX.")));
 					else if (indexRelation->rd_index->indisexclusion)
 						ereport(WARNING,
 								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -3578,10 +3579,11 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
 
 						if (!indexRelation->rd_index->indisvalid)
 							ereport(WARNING,
-									(errcode(ERRCODE_INDEX_CORRUPTED),
-									 errmsg("cannot reindex invalid index \"%s.%s\" concurrently, skipping",
+									(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+									 errmsg("skipping reindex of invalid index \"%s.%s\"",
 											get_namespace_name(get_rel_namespace(cellOid)),
-											get_rel_name(cellOid))));
+											get_rel_name(cellOid)),
+									 errhint("Use DROP INDEX or REINDEX INDEX.")));
 						else
 						{
 							ReindexIndexInfo *idx;
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index acfd9d1f4f..446cfa678b 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2581,7 +2581,8 @@ DROP INDEX concur_reindex_ind5_ccnew;
 DELETE FROM concur_reindex_tab4 WHERE c1 = 1;
 -- The invalid index is not processed when running REINDEX TABLE.
 REINDEX TABLE CONCURRENTLY concur_reindex_tab4;
-WARNING:  cannot reindex invalid index "public.concur_reindex_ind5" concurrently, skipping
+WARNING:  skipping reindex of invalid index "public.concur_reindex_ind5"
+HINT:  Use DROP INDEX or REINDEX INDEX.
 NOTICE:  table "concur_reindex_tab4" has no indexes that can be reindexed concurrently
 \d concur_reindex_tab4
         Table "public.concur_reindex_tab4"
#6Andres Freund
andres@anarazel.de
In reply to: Michael Paquier (#5)
Re: reindexing an invalid index should not use ERRCODE_INDEX_CORRUPTED

Hi,

This looks good to me!

Greetings,

Andres Freund

#7Michael Paquier
michael@paquier.xyz
In reply to: Andres Freund (#6)
Re: reindexing an invalid index should not use ERRCODE_INDEX_CORRUPTED

On Wed, Dec 06, 2023 at 05:40:44PM -0800, Andres Freund wrote:

This looks good to me!

Cool. I've applied this one, then.
--
Michael