Add missing error codes to PANIC/FATAL error reports in xlog.c and relcache.c
Hi,
There is an ongoing thread [1]/messages/by-id/CAPMWgZ8g17Myb5ZRE5aTNowUohafk4j48mZ_5_Zn9JnR5p2u0w@mail.gmail.com for adding missing SQL error codes to
PANIC and FATAL error reports in xlogrecovery.c file. I did the same
but for xlog.c and relcache.c files.
I couldn't find a suitable error code for the "cache lookup failed for
relation" error in relcache.c and this error comes up in many places.
Would it be reasonable to create a new error code specifically for
this?
Any kind of feedback would be appreciated.
[1]: /messages/by-id/CAPMWgZ8g17Myb5ZRE5aTNowUohafk4j48mZ_5_Zn9JnR5p2u0w@mail.gmail.com
--
Regards,
Nazir Bilal Yavuz
Microsoft
Attachments:
v1-0001-xlog.c-Add-missing-error-codes-to-PANIC-FATAL-err.patchapplication/octet-stream; name=v1-0001-xlog.c-Add-missing-error-codes-to-PANIC-FATAL-err.patchDownload
From 804c2d87a2d0204c7e1996ed41fec326bc6d0d21 Mon Sep 17 00:00:00 2001
From: Nazir Bilal Yavuz <byavuz81@gmail.com>
Date: Mon, 4 Dec 2023 15:22:32 +0300
Subject: [PATCH v1 1/2] [xlog.c] Add missing error codes to PANIC/FATAL error
reports
---
src/backend/access/transam/xlog.c | 110 ++++++++++++++++++++----------
1 file changed, 74 insertions(+), 36 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 2d603d8dee..8cc2664db7 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1353,7 +1353,9 @@ CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
}
if (CurrPos != EndPos)
- elog(PANIC, "space reserved for WAL record does not match what was written");
+ ereport(PANIC,
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("space reserved for WAL record does not match what was written")));
}
/*
@@ -1502,7 +1504,9 @@ WaitXLogInsertionsToFinish(XLogRecPtr upto)
int i;
if (MyProc == NULL)
- elog(PANIC, "cannot wait without a PGPROC structure");
+ ereport(PANIC,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("cannot wait without a PGPROC structure")));
/* Read the current insert position */
SpinLockAcquire(&Insert->insertpos_lck);
@@ -1683,8 +1687,10 @@ GetXLogBuffer(XLogRecPtr ptr, TimeLineID tli)
endptr = XLogCtl->xlblocks[idx];
if (expectedEndPtr != endptr)
- elog(PANIC, "could not find WAL buffer for %X/%X",
- LSN_FORMAT_ARGS(ptr));
+ ereport(PANIC,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("could not find WAL buffer for %X/%X",
+ LSN_FORMAT_ARGS(ptr))));
}
else
{
@@ -2211,9 +2217,11 @@ XLogWrite(XLogwrtRqst WriteRqst, TimeLineID tli, bool flexible)
XLogRecPtr EndPtr = XLogCtl->xlblocks[curridx];
if (LogwrtResult.Write >= EndPtr)
- elog(PANIC, "xlog write request %X/%X is past end of log %X/%X",
- LSN_FORMAT_ARGS(LogwrtResult.Write),
- LSN_FORMAT_ARGS(EndPtr));
+ ereport(PANIC,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("xlog write request %X/%X is past end of log %X/%X",
+ LSN_FORMAT_ARGS(LogwrtResult.Write),
+ LSN_FORMAT_ARGS(EndPtr))));
/* Advance LogwrtResult.Write to end of current buffer page */
LogwrtResult.Write = EndPtr;
@@ -3891,7 +3899,8 @@ ValidateXLOGDirectoryStructure(void)
if (stat(XLOGDIR, &stat_buf) != 0 ||
!S_ISDIR(stat_buf.st_mode))
ereport(FATAL,
- (errmsg("required WAL directory \"%s\" does not exist",
+ (errcode_for_file_access(),
+ errmsg("required WAL directory \"%s\" does not exist",
XLOGDIR)));
/* Check for archive_status */
@@ -3901,7 +3910,8 @@ ValidateXLOGDirectoryStructure(void)
/* Check for weird cases where it exists but isn't a directory */
if (!S_ISDIR(stat_buf.st_mode))
ereport(FATAL,
- (errmsg("required WAL directory \"%s\" does not exist",
+ (errcode_for_file_access(),
+ errmsg("required WAL directory \"%s\" does not exist",
path)));
}
else
@@ -3910,7 +3920,8 @@ ValidateXLOGDirectoryStructure(void)
(errmsg("creating missing WAL directory \"%s\"", path)));
if (MakePGDirectory(path) < 0)
ereport(FATAL,
- (errmsg("could not create missing directory \"%s\": %m",
+ (errcode_for_file_access(),
+ errmsg("could not create missing directory \"%s\": %m",
path)));
}
}
@@ -4127,7 +4138,8 @@ ReadControlFile(void)
if (ControlFile->pg_control_version != PG_CONTROL_VERSION && ControlFile->pg_control_version % 65536 == 0 && ControlFile->pg_control_version / 65536 != 0)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with PG_CONTROL_VERSION %d (0x%08x),"
" but the server was compiled with PG_CONTROL_VERSION %d (0x%08x).",
ControlFile->pg_control_version, ControlFile->pg_control_version,
@@ -4136,7 +4148,8 @@ ReadControlFile(void)
if (ControlFile->pg_control_version != PG_CONTROL_VERSION)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with PG_CONTROL_VERSION %d,"
" but the server was compiled with PG_CONTROL_VERSION %d.",
ControlFile->pg_control_version, PG_CONTROL_VERSION),
@@ -4151,7 +4164,8 @@ ReadControlFile(void)
if (!EQ_CRC32C(crc, ControlFile->crc))
ereport(FATAL,
- (errmsg("incorrect checksum in control file")));
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("incorrect checksum in control file")));
/*
* Do compatibility checking immediately. If the database isn't
@@ -4160,68 +4174,78 @@ ReadControlFile(void)
*/
if (ControlFile->catalog_version_no != CATALOG_VERSION_NO)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with CATALOG_VERSION_NO %d,"
" but the server was compiled with CATALOG_VERSION_NO %d.",
ControlFile->catalog_version_no, CATALOG_VERSION_NO),
errhint("It looks like you need to initdb.")));
if (ControlFile->maxAlign != MAXIMUM_ALIGNOF)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with MAXALIGN %d,"
" but the server was compiled with MAXALIGN %d.",
ControlFile->maxAlign, MAXIMUM_ALIGNOF),
errhint("It looks like you need to initdb.")));
if (ControlFile->floatFormat != FLOATFORMAT_VALUE)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster appears to use a different floating-point number format than the server executable."),
errhint("It looks like you need to initdb.")));
if (ControlFile->blcksz != BLCKSZ)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with BLCKSZ %d,"
" but the server was compiled with BLCKSZ %d.",
ControlFile->blcksz, BLCKSZ),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->relseg_size != RELSEG_SIZE)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with RELSEG_SIZE %d,"
" but the server was compiled with RELSEG_SIZE %d.",
ControlFile->relseg_size, RELSEG_SIZE),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->xlog_blcksz != XLOG_BLCKSZ)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with XLOG_BLCKSZ %d,"
" but the server was compiled with XLOG_BLCKSZ %d.",
ControlFile->xlog_blcksz, XLOG_BLCKSZ),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->nameDataLen != NAMEDATALEN)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with NAMEDATALEN %d,"
" but the server was compiled with NAMEDATALEN %d.",
ControlFile->nameDataLen, NAMEDATALEN),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->indexMaxKeys != INDEX_MAX_KEYS)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with INDEX_MAX_KEYS %d,"
" but the server was compiled with INDEX_MAX_KEYS %d.",
ControlFile->indexMaxKeys, INDEX_MAX_KEYS),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->toast_max_chunk_size != TOAST_MAX_CHUNK_SIZE)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with TOAST_MAX_CHUNK_SIZE %d,"
" but the server was compiled with TOAST_MAX_CHUNK_SIZE %d.",
ControlFile->toast_max_chunk_size, (int) TOAST_MAX_CHUNK_SIZE),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->loblksize != LOBLKSIZE)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with LOBLKSIZE %d,"
" but the server was compiled with LOBLKSIZE %d.",
ControlFile->loblksize, (int) LOBLKSIZE),
@@ -4230,14 +4254,16 @@ ReadControlFile(void)
#ifdef USE_FLOAT8_BYVAL
if (ControlFile->float8ByVal != true)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized without USE_FLOAT8_BYVAL"
" but the server was compiled with USE_FLOAT8_BYVAL."),
errhint("It looks like you need to recompile or initdb.")));
#else
if (ControlFile->float8ByVal != false)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with USE_FLOAT8_BYVAL"
" but the server was compiled without USE_FLOAT8_BYVAL."),
errhint("It looks like you need to recompile or initdb.")));
@@ -5110,7 +5136,8 @@ CheckRequiredParameterValues(void)
if (ArchiveRecoveryRequested && ControlFile->wal_level == WAL_LEVEL_MINIMAL)
{
ereport(FATAL,
- (errmsg("WAL was generated with wal_level=minimal, cannot continue recovering"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("WAL was generated with wal_level=minimal, cannot continue recovering"),
errdetail("This happens if you temporarily set wal_level=minimal on the server."),
errhint("Use a backup taken after setting wal_level to higher than minimal.")));
}
@@ -5176,7 +5203,8 @@ StartupXLOG(void)
*/
if (!XRecOffIsValid(ControlFile->checkPoint))
ereport(FATAL,
- (errmsg("control file contains invalid checkpoint location")));
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("control file contains invalid checkpoint location")));
switch (ControlFile->state)
{
@@ -5227,7 +5255,8 @@ StartupXLOG(void)
default:
ereport(FATAL,
- (errmsg("control file contains invalid database cluster state")));
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("control file contains invalid database cluster state")));
}
/* This is just to allow attaching to startup process with a debugger */
@@ -5611,11 +5640,13 @@ StartupXLOG(void)
{
if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
ereport(FATAL,
- (errmsg("WAL ends before end of online backup"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("WAL ends before end of online backup"),
errhint("All WAL generated while online backup was taken must be available at recovery.")));
else
ereport(FATAL,
- (errmsg("WAL ends before consistent recovery point")));
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("WAL ends before consistent recovery point")));
}
}
@@ -6913,7 +6944,8 @@ CreateCheckPoint(int flags)
*/
if (shutdown && checkPoint.redo != ProcLastRecPtr)
ereport(PANIC,
- (errmsg("concurrent write-ahead log activity while database system is shutting down")));
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("concurrent write-ahead log activity while database system is shutting down")));
/*
* Remember the prior checkpoint's redo ptr for
@@ -7931,7 +7963,8 @@ xlog_redo(XLogReaderState *record)
!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
ereport(PANIC,
- (errmsg("online backup was canceled, recovery cannot continue")));
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("online backup was canceled, recovery cannot continue")));
/*
* If we see a shutdown checkpoint, we know that nothing was running
@@ -7988,7 +8021,8 @@ xlog_redo(XLogReaderState *record)
(void) GetCurrentReplayRecPtr(&replayTLI);
if (checkPoint.ThisTimeLineID != replayTLI)
ereport(PANIC,
- (errmsg("unexpected timeline ID %u (should be %u) in shutdown checkpoint record",
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("unexpected timeline ID %u (should be %u) in shutdown checkpoint record",
checkPoint.ThisTimeLineID, replayTLI)));
RecoveryRestartPoint(&checkPoint, record);
@@ -8046,7 +8080,8 @@ xlog_redo(XLogReaderState *record)
(void) GetCurrentReplayRecPtr(&replayTLI);
if (checkPoint.ThisTimeLineID != replayTLI)
ereport(PANIC,
- (errmsg("unexpected timeline ID %u (should be %u) in online checkpoint record",
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("unexpected timeline ID %u (should be %u) in online checkpoint record",
checkPoint.ThisTimeLineID, replayTLI)));
RecoveryRestartPoint(&checkPoint, record);
@@ -8075,7 +8110,8 @@ xlog_redo(XLogReaderState *record)
(void) GetCurrentReplayRecPtr(&replayTLI);
if (xlrec.ThisTimeLineID != replayTLI)
ereport(PANIC,
- (errmsg("unexpected timeline ID %u (should be %u) in end-of-recovery record",
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("unexpected timeline ID %u (should be %u) in end-of-recovery record",
xlrec.ThisTimeLineID, replayTLI)));
}
else if (info == XLOG_NOOP)
@@ -8359,7 +8395,9 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
Assert(false);
break;
default:
- elog(PANIC, "unrecognized wal_sync_method: %d", wal_sync_method);
+ ereport(PANIC,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized wal_sync_method: %d", wal_sync_method)));
break;
}
--
2.25.1
v1-0002-relcache.c-Add-missing-error-codes-to-PANIC-FATAL.patchapplication/octet-stream; name=v1-0002-relcache.c-Add-missing-error-codes-to-PANIC-FATAL.patchDownload
From abece22dcc24c20ce5c0275dc31bf1e7e607aa35 Mon Sep 17 00:00:00 2001
From: Nazir Bilal Yavuz <byavuz81@gmail.com>
Date: Wed, 6 Dec 2023 14:39:36 +0300
Subject: [PATCH v1 2/2] [relcache.c] Add missing error codes to PANIC/FATAL
error reports
---
src/backend/utils/cache/relcache.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index b3faccbefe..95e18eea94 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -351,7 +351,9 @@ ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
* it probably means a relcache entry that needs to be nailed isn't.
*/
if (!OidIsValid(MyDatabaseId))
- elog(FATAL, "cannot read pg_class without having selected a database");
+ ereport(FATAL,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("cannot read pg_class without having selected a database")));
/*
* form a scan key
@@ -4367,7 +4369,9 @@ load_critical_index(Oid indexoid, Oid heapoid)
LockRelationOid(indexoid, AccessShareLock);
ird = RelationBuildDesc(indexoid, true);
if (ird == NULL)
- elog(PANIC, "could not open critical system index %u", indexoid);
+ ereport(PANIC,
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("could not open critical system index %u", indexoid)));
ird->rd_isnailed = true;
ird->rd_refcnt = 1;
UnlockRelationOid(indexoid, AccessShareLock);
@@ -6530,7 +6534,9 @@ write_relcache_init_file(bool shared)
*/
magic = RELCACHE_INIT_FILEMAGIC;
if (fwrite(&magic, 1, sizeof(magic), fp) != sizeof(magic))
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("could not write init file")));
/*
* Write all the appropriate reldescs (in no particular order).
@@ -6631,7 +6637,9 @@ write_relcache_init_file(bool shared)
}
if (FreeFile(fp))
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("could not write init file")));
/*
* Now we have to check whether the data we've so painstakingly
@@ -6681,9 +6689,13 @@ static void
write_item(const void *data, Size len, FILE *fp)
{
if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("could not write init file")));
if (len > 0 && fwrite(data, 1, len, fp) != len)
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("could not write init file")));
}
/*
--
2.25.1
On 6 Dec 2023, at 14:03, Nazir Bilal Yavuz <byavuz81@gmail.com> wrote:
There is an ongoing thread [1] for adding missing SQL error codes to
PANIC and FATAL error reports in xlogrecovery.c file. I did the same
but for xlog.c and relcache.c files.
- elog(PANIC, "space reserved for WAL record does not match what was written");
+ ereport(PANIC,
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("space reserved for WAL record does not match what was written")));
elogs turned into ereports should use errmsg_internal() to keep the strings
from being translated.
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("could not write init file")));
Is it worthwhile adding %m on these to get a little more help when debugging
errors that shouldn't happen?
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ (errcode_for_file_access(),
The extra parenthesis are no longer needed, I don't know if we have a policy to
remove them when changing an ereport call but we should at least not introduce
new ones.
- elog(FATAL, "cannot read pg_class without having selected a database");
+ ereport(FATAL,
+ (errcode(ERRCODE_INTERNAL_ERROR),
ereport (and thus elog) already defaults to ERRCODE_INTERNAL_ERROR for ERROR or
higher, so unless there is a better errcode an elog() call if preferrable here.
I couldn't find a suitable error code for the "cache lookup failed for
relation" error in relcache.c and this error comes up in many places.
Would it be reasonable to create a new error code specifically for
this?
We use ERRCODE_UNDEFINED_OBJECT for similar errors elsewhere, perhaps we can
use that for these as well?
--
Daniel Gustafsson
Hi,
Thanks for the review!
On Thu, 22 Feb 2024 at 16:55, Daniel Gustafsson <daniel@yesql.se> wrote:
On 6 Dec 2023, at 14:03, Nazir Bilal Yavuz <byavuz81@gmail.com> wrote:
There is an ongoing thread [1] for adding missing SQL error codes to
PANIC and FATAL error reports in xlogrecovery.c file. I did the same
but for xlog.c and relcache.c files.- elog(PANIC, "space reserved for WAL record does not match what was written"); + ereport(PANIC, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("space reserved for WAL record does not match what was written")));elogs turned into ereports should use errmsg_internal() to keep the strings
from being translated.
Does errmsg_internal() need to be used all the time when turning elogs
into ereports? errmsg_internal()'s comment says that "This should be
used for "can't happen" cases that are probably not worth spending
translation effort on.". Is it enough to check if the error message
has a translation, and then decide the use of errmsg_internal() or
errmsg()?
- elog(FATAL, "could not write init file"); + ereport(FATAL, + (errcode_for_file_access(), + errmsg("could not write init file")));Is it worthwhile adding %m on these to get a little more help when debugging
errors that shouldn't happen?
I believe it is worthwhile, so I will add.
- elog(FATAL, "could not write init file"); + ereport(FATAL, + (errcode_for_file_access(),The extra parenthesis are no longer needed, I don't know if we have a policy to
remove them when changing an ereport call but we should at least not introduce
new ones.- elog(FATAL, "cannot read pg_class without having selected a database"); + ereport(FATAL, + (errcode(ERRCODE_INTERNAL_ERROR),ereport (and thus elog) already defaults to ERRCODE_INTERNAL_ERROR for ERROR or
higher, so unless there is a better errcode an elog() call if preferrable here.
I did not know these, thanks.
I couldn't find a suitable error code for the "cache lookup failed for
relation" error in relcache.c and this error comes up in many places.
Would it be reasonable to create a new error code specifically for
this?We use ERRCODE_UNDEFINED_OBJECT for similar errors elsewhere, perhaps we can
use that for these as well?
It looks okay to me, ERRCODE_UNDEFINED_OBJECT is mostly used for the
'not exist' errors and it seems the main reason for the 'cache lookup
failed for relation' error is because heap tuple does not exist
anymore.
--
Regards,
Nazir Bilal Yavuz
Microsoft
On 23 Feb 2024, at 13:09, Nazir Bilal Yavuz <byavuz81@gmail.com> wrote:
Does errmsg_internal() need to be used all the time when turning elogs
into ereports? errmsg_internal()'s comment says that "This should be
used for "can't happen" cases that are probably not worth spending
translation effort on.". Is it enough to check if the error message
has a translation, and then decide the use of errmsg_internal() or
errmsg()?
If it's an elog then it won't have a translation as none are included in the
translation set. If the errmsg is generic enough to be translated anyways via
another (un)related ereport call then we of course use that, but ideally not
create new ones.
--
Daniel Gustafsson
Hi,
On Fri, 23 Feb 2024 at 15:34, Daniel Gustafsson <daniel@yesql.se> wrote:
On 23 Feb 2024, at 13:09, Nazir Bilal Yavuz <byavuz81@gmail.com> wrote:
Does errmsg_internal() need to be used all the time when turning elogs
into ereports? errmsg_internal()'s comment says that "This should be
used for "can't happen" cases that are probably not worth spending
translation effort on.". Is it enough to check if the error message
has a translation, and then decide the use of errmsg_internal() or
errmsg()?If it's an elog then it won't have a translation as none are included in the
translation set. If the errmsg is generic enough to be translated anyways via
another (un)related ereport call then we of course use that, but ideally not
create new ones.
Thanks for the explanation.
All of your feedback is addressed in v2.
--
Regards,
Nazir Bilal Yavuz
Microsoft
Attachments:
v2-0001-xlog.c-Add-missing-error-codes-to-PANIC-FATAL-err.patchtext/x-diff; charset=US-ASCII; name=v2-0001-xlog.c-Add-missing-error-codes-to-PANIC-FATAL-err.patchDownload
From fa45a69731da1488560b2749023e9b9573231c2b Mon Sep 17 00:00:00 2001
From: Nazir Bilal Yavuz <byavuz81@gmail.com>
Date: Fri, 23 Feb 2024 16:49:10 +0300
Subject: [PATCH v2 1/2] (xlog.c) Add missing error codes to PANIC/FATAL error
reports
---
src/backend/access/transam/xlog.c | 77 +++++++++++++++++++++----------
1 file changed, 52 insertions(+), 25 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c1162d55bff..d295cef9606 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1354,7 +1354,9 @@ CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
}
if (CurrPos != EndPos)
- elog(PANIC, "space reserved for WAL record does not match what was written");
+ ereport(PANIC,
+ errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg_internal("space reserved for WAL record does not match what was written"));
}
/*
@@ -4040,7 +4042,8 @@ ValidateXLOGDirectoryStructure(void)
if (stat(XLOGDIR, &stat_buf) != 0 ||
!S_ISDIR(stat_buf.st_mode))
ereport(FATAL,
- (errmsg("required WAL directory \"%s\" does not exist",
+ (errcode_for_file_access(),
+ errmsg("required WAL directory \"%s\" does not exist",
XLOGDIR)));
/* Check for archive_status */
@@ -4050,7 +4053,8 @@ ValidateXLOGDirectoryStructure(void)
/* Check for weird cases where it exists but isn't a directory */
if (!S_ISDIR(stat_buf.st_mode))
ereport(FATAL,
- (errmsg("required WAL directory \"%s\" does not exist",
+ (errcode_for_file_access(),
+ errmsg("required WAL directory \"%s\" does not exist",
path)));
}
else
@@ -4059,7 +4063,8 @@ ValidateXLOGDirectoryStructure(void)
(errmsg("creating missing WAL directory \"%s\"", path)));
if (MakePGDirectory(path) < 0)
ereport(FATAL,
- (errmsg("could not create missing directory \"%s\": %m",
+ (errcode_for_file_access(),
+ errmsg("could not create missing directory \"%s\": %m",
path)));
}
@@ -4296,7 +4301,8 @@ ReadControlFile(void)
if (ControlFile->pg_control_version != PG_CONTROL_VERSION && ControlFile->pg_control_version % 65536 == 0 && ControlFile->pg_control_version / 65536 != 0)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with PG_CONTROL_VERSION %d (0x%08x),"
" but the server was compiled with PG_CONTROL_VERSION %d (0x%08x).",
ControlFile->pg_control_version, ControlFile->pg_control_version,
@@ -4305,7 +4311,8 @@ ReadControlFile(void)
if (ControlFile->pg_control_version != PG_CONTROL_VERSION)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with PG_CONTROL_VERSION %d,"
" but the server was compiled with PG_CONTROL_VERSION %d.",
ControlFile->pg_control_version, PG_CONTROL_VERSION),
@@ -4320,7 +4327,8 @@ ReadControlFile(void)
if (!EQ_CRC32C(crc, ControlFile->crc))
ereport(FATAL,
- (errmsg("incorrect checksum in control file")));
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("incorrect checksum in control file")));
/*
* Do compatibility checking immediately. If the database isn't
@@ -4329,68 +4337,78 @@ ReadControlFile(void)
*/
if (ControlFile->catalog_version_no != CATALOG_VERSION_NO)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with CATALOG_VERSION_NO %d,"
" but the server was compiled with CATALOG_VERSION_NO %d.",
ControlFile->catalog_version_no, CATALOG_VERSION_NO),
errhint("It looks like you need to initdb.")));
if (ControlFile->maxAlign != MAXIMUM_ALIGNOF)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with MAXALIGN %d,"
" but the server was compiled with MAXALIGN %d.",
ControlFile->maxAlign, MAXIMUM_ALIGNOF),
errhint("It looks like you need to initdb.")));
if (ControlFile->floatFormat != FLOATFORMAT_VALUE)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster appears to use a different floating-point number format than the server executable."),
errhint("It looks like you need to initdb.")));
if (ControlFile->blcksz != BLCKSZ)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with BLCKSZ %d,"
" but the server was compiled with BLCKSZ %d.",
ControlFile->blcksz, BLCKSZ),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->relseg_size != RELSEG_SIZE)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with RELSEG_SIZE %d,"
" but the server was compiled with RELSEG_SIZE %d.",
ControlFile->relseg_size, RELSEG_SIZE),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->xlog_blcksz != XLOG_BLCKSZ)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with XLOG_BLCKSZ %d,"
" but the server was compiled with XLOG_BLCKSZ %d.",
ControlFile->xlog_blcksz, XLOG_BLCKSZ),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->nameDataLen != NAMEDATALEN)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with NAMEDATALEN %d,"
" but the server was compiled with NAMEDATALEN %d.",
ControlFile->nameDataLen, NAMEDATALEN),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->indexMaxKeys != INDEX_MAX_KEYS)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with INDEX_MAX_KEYS %d,"
" but the server was compiled with INDEX_MAX_KEYS %d.",
ControlFile->indexMaxKeys, INDEX_MAX_KEYS),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->toast_max_chunk_size != TOAST_MAX_CHUNK_SIZE)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with TOAST_MAX_CHUNK_SIZE %d,"
" but the server was compiled with TOAST_MAX_CHUNK_SIZE %d.",
ControlFile->toast_max_chunk_size, (int) TOAST_MAX_CHUNK_SIZE),
errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->loblksize != LOBLKSIZE)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with LOBLKSIZE %d,"
" but the server was compiled with LOBLKSIZE %d.",
ControlFile->loblksize, (int) LOBLKSIZE),
@@ -4399,14 +4417,16 @@ ReadControlFile(void)
#ifdef USE_FLOAT8_BYVAL
if (ControlFile->float8ByVal != true)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized without USE_FLOAT8_BYVAL"
" but the server was compiled with USE_FLOAT8_BYVAL."),
errhint("It looks like you need to recompile or initdb.")));
#else
if (ControlFile->float8ByVal != false)
ereport(FATAL,
- (errmsg("database files are incompatible with server"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with USE_FLOAT8_BYVAL"
" but the server was compiled without USE_FLOAT8_BYVAL."),
errhint("It looks like you need to recompile or initdb.")));
@@ -5282,7 +5302,8 @@ CheckRequiredParameterValues(void)
if (ArchiveRecoveryRequested && ControlFile->wal_level == WAL_LEVEL_MINIMAL)
{
ereport(FATAL,
- (errmsg("WAL was generated with wal_level=minimal, cannot continue recovering"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("WAL was generated with wal_level=minimal, cannot continue recovering"),
errdetail("This happens if you temporarily set wal_level=minimal on the server."),
errhint("Use a backup taken after setting wal_level to higher than minimal.")));
}
@@ -5348,7 +5369,8 @@ StartupXLOG(void)
*/
if (!XRecOffIsValid(ControlFile->checkPoint))
ereport(FATAL,
- (errmsg("control file contains invalid checkpoint location")));
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("control file contains invalid checkpoint location")));
switch (ControlFile->state)
{
@@ -5399,7 +5421,8 @@ StartupXLOG(void)
default:
ereport(FATAL,
- (errmsg("control file contains invalid database cluster state")));
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("control file contains invalid database cluster state")));
}
/* This is just to allow attaching to startup process with a debugger */
@@ -5783,11 +5806,13 @@ StartupXLOG(void)
{
if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
ereport(FATAL,
- (errmsg("WAL ends before end of online backup"),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("WAL ends before end of online backup"),
errhint("All WAL generated while online backup was taken must be available at recovery.")));
else
ereport(FATAL,
- (errmsg("WAL ends before consistent recovery point")));
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("WAL ends before consistent recovery point")));
}
}
@@ -8564,7 +8589,9 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
Assert(false);
break;
default:
- elog(PANIC, "unrecognized wal_sync_method: %d", wal_sync_method);
+ ereport(PANIC,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg_internal("unrecognized wal_sync_method: %d", wal_sync_method));
break;
}
--
2.43.0
v2-0002-relcache.c-Add-missing-error-codes-to-PANIC-FATAL.patchtext/x-diff; charset=US-ASCII; name=v2-0002-relcache.c-Add-missing-error-codes-to-PANIC-FATAL.patchDownload
From df027460544a308766c2cc30459c82e7ba933c9d Mon Sep 17 00:00:00 2001
From: Nazir Bilal Yavuz <byavuz81@gmail.com>
Date: Fri, 23 Feb 2024 17:11:34 +0300
Subject: [PATCH v2 2/2] (relcache.c) Add missing error codes to PANIC/FATAL
error reports
---
src/backend/utils/cache/relcache.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 50acae45298..f503bca0fce 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -4215,8 +4215,10 @@ RelationCacheInitializePhase3(void)
htup = SearchSysCache1(RELOID,
ObjectIdGetDatum(RelationGetRelid(relation)));
if (!HeapTupleIsValid(htup))
- elog(FATAL, "cache lookup failed for relation %u",
- RelationGetRelid(relation));
+ ereport(FATAL,
+ errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg_internal("cache lookup failed for relation %u",
+ RelationGetRelid(relation)));
relp = (Form_pg_class) GETSTRUCT(htup);
/*
@@ -4349,7 +4351,9 @@ load_critical_index(Oid indexoid, Oid heapoid)
LockRelationOid(indexoid, AccessShareLock);
ird = RelationBuildDesc(indexoid, true);
if (ird == NULL)
- elog(PANIC, "could not open critical system index %u", indexoid);
+ ereport(PANIC,
+ errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg_internal("could not open critical system index %u", indexoid));
ird->rd_isnailed = true;
ird->rd_refcnt = 1;
UnlockRelationOid(indexoid, AccessShareLock);
@@ -6518,7 +6522,9 @@ write_relcache_init_file(bool shared)
*/
magic = RELCACHE_INIT_FILEMAGIC;
if (fwrite(&magic, 1, sizeof(magic), fp) != sizeof(magic))
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ errcode_for_file_access(),
+ errmsg_internal("could not write init file: %m"));
/*
* Write all the appropriate reldescs (in no particular order).
@@ -6619,7 +6625,9 @@ write_relcache_init_file(bool shared)
}
if (FreeFile(fp))
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ errcode_for_file_access(),
+ errmsg_internal("could not write init file: %m"));
/*
* Now we have to check whether the data we've so painstakingly
@@ -6669,9 +6677,13 @@ static void
write_item(const void *data, Size len, FILE *fp)
{
if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ errcode_for_file_access(),
+ errmsg_internal("could not write init file: %m"));
if (len > 0 && fwrite(data, 1, len, fp) != len)
- elog(FATAL, "could not write init file");
+ ereport(FATAL,
+ errcode_for_file_access(),
+ errmsg_internal("could not write init file: %m"));
}
/*
--
2.43.0
On 26 Feb 2024, at 13:42, Nazir Bilal Yavuz <byavuz81@gmail.com> wrote:
All of your feedback is addressed in v2.
Nothing sticks out from reading through these patches, they seem quite ready to
me. Being able to filter and analyze on errorcodes is likely to be more
important going forward as more are running fleets of instances. I'm marking
these Ready for Committer, unless there are objections I think we should go
ahead with these. There are probably more errors in the system which could
benefit from the same treatment, but we need to start somewhere.
--
Daniel Gustafsson
On 6 Mar 2024, at 09:59, Daniel Gustafsson <daniel@yesql.se> wrote:
Nothing sticks out from reading through these patches, they seem quite ready to
me.
Took another look at this today and committed it. Thanks!
--
Daniel Gustafsson
Hi,
On Wed, 3 Apr 2024 at 12:11, Daniel Gustafsson <daniel@yesql.se> wrote:
On 6 Mar 2024, at 09:59, Daniel Gustafsson <daniel@yesql.se> wrote:
Nothing sticks out from reading through these patches, they seem quite ready to
me.Took another look at this today and committed it. Thanks!
Thanks for the commit!
--
Regards,
Nazir Bilal Yavuz
Microsoft