mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-27 07:21:09 +08:00
Use correct LSN for error reporting in pg_walinspect
Usage of ReadNextXLogRecord()'s first_record parameter for error reporting isn't always correct. For instance, in GetWALRecordsInfo() and GetWalStats(), we're reading multiple records, and first_record is always passed as the LSN of the first record which is then used for error reporting for later WAL record read failures. This isn't correct. The correct parameter to use for error reports in case of WAL reading failures is xlogreader->EndRecPtr. This change fixes it. While on it, removed an unnecessary Assert in pg_walinspect code. Reported-by: Robert Haas Author: Bharath Rupireddy Reviewed-by: Robert Haas Discussion: https://www.postgresql.org/message-id/CA%2BTgmoZAOGzPUifrcZRjFZ2vbtcw3mp-mN6UgEoEcQg6bY3OVg%40mail.gmail.com Backpatch-through: 15
This commit is contained in:
parent
9288c2e6f8
commit
d9fbb88629
@ -37,12 +37,10 @@ PG_FUNCTION_INFO_V1(pg_get_wal_stats);
|
|||||||
PG_FUNCTION_INFO_V1(pg_get_wal_stats_till_end_of_wal);
|
PG_FUNCTION_INFO_V1(pg_get_wal_stats_till_end_of_wal);
|
||||||
|
|
||||||
static bool IsFutureLSN(XLogRecPtr lsn, XLogRecPtr *curr_lsn);
|
static bool IsFutureLSN(XLogRecPtr lsn, XLogRecPtr *curr_lsn);
|
||||||
static XLogReaderState *InitXLogReaderState(XLogRecPtr lsn,
|
static XLogReaderState *InitXLogReaderState(XLogRecPtr lsn);
|
||||||
XLogRecPtr *first_record);
|
static XLogRecord *ReadNextXLogRecord(XLogReaderState *xlogreader);
|
||||||
static XLogRecord *ReadNextXLogRecord(XLogReaderState *xlogreader,
|
static void GetWALRecordInfo(XLogReaderState *record, Datum *values,
|
||||||
XLogRecPtr first_record);
|
bool *nulls, uint32 ncols);
|
||||||
static void GetWALRecordInfo(XLogReaderState *record, XLogRecPtr lsn,
|
|
||||||
Datum *values, bool *nulls, uint32 ncols);
|
|
||||||
static XLogRecPtr ValidateInputLSNs(bool till_end_of_wal,
|
static XLogRecPtr ValidateInputLSNs(bool till_end_of_wal,
|
||||||
XLogRecPtr start_lsn, XLogRecPtr end_lsn);
|
XLogRecPtr start_lsn, XLogRecPtr end_lsn);
|
||||||
static void GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
|
static void GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
|
||||||
@ -86,10 +84,11 @@ IsFutureLSN(XLogRecPtr lsn, XLogRecPtr *curr_lsn)
|
|||||||
* Intialize WAL reader and identify first valid LSN.
|
* Intialize WAL reader and identify first valid LSN.
|
||||||
*/
|
*/
|
||||||
static XLogReaderState *
|
static XLogReaderState *
|
||||||
InitXLogReaderState(XLogRecPtr lsn, XLogRecPtr *first_record)
|
InitXLogReaderState(XLogRecPtr lsn)
|
||||||
{
|
{
|
||||||
XLogReaderState *xlogreader;
|
XLogReaderState *xlogreader;
|
||||||
ReadLocalXLogPageNoWaitPrivate *private_data;
|
ReadLocalXLogPageNoWaitPrivate *private_data;
|
||||||
|
XLogRecPtr first_valid_record;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reading WAL below the first page of the first segments isn't allowed.
|
* Reading WAL below the first page of the first segments isn't allowed.
|
||||||
@ -117,9 +116,9 @@ InitXLogReaderState(XLogRecPtr lsn, XLogRecPtr *first_record)
|
|||||||
errdetail("Failed while allocating a WAL reading processor.")));
|
errdetail("Failed while allocating a WAL reading processor.")));
|
||||||
|
|
||||||
/* first find a valid recptr to start from */
|
/* first find a valid recptr to start from */
|
||||||
*first_record = XLogFindNextRecord(xlogreader, lsn);
|
first_valid_record = XLogFindNextRecord(xlogreader, lsn);
|
||||||
|
|
||||||
if (XLogRecPtrIsInvalid(*first_record))
|
if (XLogRecPtrIsInvalid(first_valid_record))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmsg("could not find a valid record after %X/%X",
|
(errmsg("could not find a valid record after %X/%X",
|
||||||
LSN_FORMAT_ARGS(lsn))));
|
LSN_FORMAT_ARGS(lsn))));
|
||||||
@ -140,7 +139,7 @@ InitXLogReaderState(XLogRecPtr lsn, XLogRecPtr *first_record)
|
|||||||
* that case we'll return NULL.
|
* that case we'll return NULL.
|
||||||
*/
|
*/
|
||||||
static XLogRecord *
|
static XLogRecord *
|
||||||
ReadNextXLogRecord(XLogReaderState *xlogreader, XLogRecPtr first_record)
|
ReadNextXLogRecord(XLogReaderState *xlogreader)
|
||||||
{
|
{
|
||||||
XLogRecord *record;
|
XLogRecord *record;
|
||||||
char *errormsg;
|
char *errormsg;
|
||||||
@ -162,12 +161,12 @@ ReadNextXLogRecord(XLogReaderState *xlogreader, XLogRecPtr first_record)
|
|||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode_for_file_access(),
|
(errcode_for_file_access(),
|
||||||
errmsg("could not read WAL at %X/%X: %s",
|
errmsg("could not read WAL at %X/%X: %s",
|
||||||
LSN_FORMAT_ARGS(first_record), errormsg)));
|
LSN_FORMAT_ARGS(xlogreader->EndRecPtr), errormsg)));
|
||||||
else
|
else
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode_for_file_access(),
|
(errcode_for_file_access(),
|
||||||
errmsg("could not read WAL at %X/%X",
|
errmsg("could not read WAL at %X/%X",
|
||||||
LSN_FORMAT_ARGS(first_record))));
|
LSN_FORMAT_ARGS(xlogreader->EndRecPtr))));
|
||||||
}
|
}
|
||||||
|
|
||||||
return record;
|
return record;
|
||||||
@ -177,8 +176,8 @@ ReadNextXLogRecord(XLogReaderState *xlogreader, XLogRecPtr first_record)
|
|||||||
* Get a single WAL record info.
|
* Get a single WAL record info.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
GetWALRecordInfo(XLogReaderState *record, XLogRecPtr lsn,
|
GetWALRecordInfo(XLogReaderState *record, Datum *values,
|
||||||
Datum *values, bool *nulls, uint32 ncols)
|
bool *nulls, uint32 ncols)
|
||||||
{
|
{
|
||||||
const char *id;
|
const char *id;
|
||||||
RmgrData desc;
|
RmgrData desc;
|
||||||
@ -203,7 +202,7 @@ GetWALRecordInfo(XLogReaderState *record, XLogRecPtr lsn,
|
|||||||
|
|
||||||
main_data_len = XLogRecGetDataLen(record);
|
main_data_len = XLogRecGetDataLen(record);
|
||||||
|
|
||||||
values[i++] = LSNGetDatum(lsn);
|
values[i++] = LSNGetDatum(record->ReadRecPtr);
|
||||||
values[i++] = LSNGetDatum(record->EndRecPtr);
|
values[i++] = LSNGetDatum(record->EndRecPtr);
|
||||||
values[i++] = LSNGetDatum(XLogRecGetPrev(record));
|
values[i++] = LSNGetDatum(XLogRecGetPrev(record));
|
||||||
values[i++] = TransactionIdGetDatum(XLogRecGetXid(record));
|
values[i++] = TransactionIdGetDatum(XLogRecGetXid(record));
|
||||||
@ -233,7 +232,6 @@ pg_get_wal_record_info(PG_FUNCTION_ARGS)
|
|||||||
bool nulls[PG_GET_WAL_RECORD_INFO_COLS] = {0};
|
bool nulls[PG_GET_WAL_RECORD_INFO_COLS] = {0};
|
||||||
XLogRecPtr lsn;
|
XLogRecPtr lsn;
|
||||||
XLogRecPtr curr_lsn;
|
XLogRecPtr curr_lsn;
|
||||||
XLogRecPtr first_record;
|
|
||||||
XLogReaderState *xlogreader;
|
XLogReaderState *xlogreader;
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
@ -258,16 +256,15 @@ pg_get_wal_record_info(PG_FUNCTION_ARGS)
|
|||||||
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
||||||
elog(ERROR, "return type must be a row type");
|
elog(ERROR, "return type must be a row type");
|
||||||
|
|
||||||
xlogreader = InitXLogReaderState(lsn, &first_record);
|
xlogreader = InitXLogReaderState(lsn);
|
||||||
|
|
||||||
if (!ReadNextXLogRecord(xlogreader, first_record))
|
if (!ReadNextXLogRecord(xlogreader))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("could not read WAL at %X/%X",
|
errmsg("could not read WAL at %X/%X",
|
||||||
LSN_FORMAT_ARGS(first_record))));
|
LSN_FORMAT_ARGS(xlogreader->EndRecPtr))));
|
||||||
|
|
||||||
GetWALRecordInfo(xlogreader, first_record, values, nulls,
|
GetWALRecordInfo(xlogreader, values, nulls, PG_GET_WAL_RECORD_INFO_COLS);
|
||||||
PG_GET_WAL_RECORD_INFO_COLS);
|
|
||||||
|
|
||||||
pfree(xlogreader->private_data);
|
pfree(xlogreader->private_data);
|
||||||
XLogReaderFree(xlogreader);
|
XLogReaderFree(xlogreader);
|
||||||
@ -328,7 +325,6 @@ GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
|
|||||||
XLogRecPtr end_lsn)
|
XLogRecPtr end_lsn)
|
||||||
{
|
{
|
||||||
#define PG_GET_WAL_RECORDS_INFO_COLS 11
|
#define PG_GET_WAL_RECORDS_INFO_COLS 11
|
||||||
XLogRecPtr first_record;
|
|
||||||
XLogReaderState *xlogreader;
|
XLogReaderState *xlogreader;
|
||||||
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||||
Datum values[PG_GET_WAL_RECORDS_INFO_COLS] = {0};
|
Datum values[PG_GET_WAL_RECORDS_INFO_COLS] = {0};
|
||||||
@ -336,14 +332,12 @@ GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
|
|||||||
|
|
||||||
SetSingleFuncCall(fcinfo, 0);
|
SetSingleFuncCall(fcinfo, 0);
|
||||||
|
|
||||||
xlogreader = InitXLogReaderState(start_lsn, &first_record);
|
xlogreader = InitXLogReaderState(start_lsn);
|
||||||
|
|
||||||
Assert(xlogreader);
|
while (ReadNextXLogRecord(xlogreader) &&
|
||||||
|
|
||||||
while (ReadNextXLogRecord(xlogreader, first_record) &&
|
|
||||||
xlogreader->EndRecPtr <= end_lsn)
|
xlogreader->EndRecPtr <= end_lsn)
|
||||||
{
|
{
|
||||||
GetWALRecordInfo(xlogreader, xlogreader->currRecPtr, values, nulls,
|
GetWALRecordInfo(xlogreader, values, nulls,
|
||||||
PG_GET_WAL_RECORDS_INFO_COLS);
|
PG_GET_WAL_RECORDS_INFO_COLS);
|
||||||
|
|
||||||
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
|
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
|
||||||
@ -548,7 +542,6 @@ GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
|
|||||||
XLogRecPtr end_lsn, bool stats_per_record)
|
XLogRecPtr end_lsn, bool stats_per_record)
|
||||||
{
|
{
|
||||||
#define PG_GET_WAL_STATS_COLS 9
|
#define PG_GET_WAL_STATS_COLS 9
|
||||||
XLogRecPtr first_record;
|
|
||||||
XLogReaderState *xlogreader;
|
XLogReaderState *xlogreader;
|
||||||
XLogStats stats = {0};
|
XLogStats stats = {0};
|
||||||
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||||
@ -557,9 +550,9 @@ GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
|
|||||||
|
|
||||||
SetSingleFuncCall(fcinfo, 0);
|
SetSingleFuncCall(fcinfo, 0);
|
||||||
|
|
||||||
xlogreader = InitXLogReaderState(start_lsn, &first_record);
|
xlogreader = InitXLogReaderState(start_lsn);
|
||||||
|
|
||||||
while (ReadNextXLogRecord(xlogreader, first_record) &&
|
while (ReadNextXLogRecord(xlogreader) &&
|
||||||
xlogreader->EndRecPtr <= end_lsn)
|
xlogreader->EndRecPtr <= end_lsn)
|
||||||
{
|
{
|
||||||
XLogRecStoreStats(&stats, xlogreader);
|
XLogRecStoreStats(&stats, xlogreader);
|
||||||
|
Loading…
Reference in New Issue
Block a user