Rework design of functions in pg_walinspect

This commit reworks a bit the set-returning functions of pg_walinspect,
making them more flexible regarding their end LSN:
- pg_get_wal_records_info()
- pg_get_wal_stats()
- pg_get_wal_block_info()

The end LSNs given to these functions is now handled so as a value
higher than the current LSN of the cluster (insert LSN for a primary, or
replay LSN for a standby) does not raise an error, giving more
flexibility to monitoring queries.  Instead, the functions return
results up to the current LSN, as found at the beginning of each
function call.

As an effect of that, pg_get_wal_records_info_till_end_of_wal() and
pg_get_wal_stats_till_end_of_wal() are now removed from 1.1, as the
existing, equivalent functions are able to offer the same
possibilities.

Author: Bharath Rupireddy
Discussion: https://postgr.es/m/CALj2ACU0_q-o4DSweyaW9NO1KBx-QkN6G_OzYQvpjf3CZVASkg@mail.gmail.com
This commit is contained in:
Michael Paquier 2023-03-14 20:13:02 +09:00
parent d5d574146d
commit 5c1b662807
7 changed files with 185 additions and 208 deletions

View File

@ -1,5 +1,7 @@
-- test old extension version entry points -- test old extension version entry points
CREATE EXTENSION pg_walinspect WITH VERSION '1.0'; CREATE EXTENSION pg_walinspect WITH VERSION '1.0';
-- Mask DETAIL messages as these could refer to current LSN positions.
\set VERBOSITY terse
-- List what version 1.0 contains -- List what version 1.0 contains
\dx+ pg_walinspect \dx+ pg_walinspect
Objects in extension "pg_walinspect" Objects in extension "pg_walinspect"
@ -12,19 +14,51 @@ CREATE EXTENSION pg_walinspect WITH VERSION '1.0';
function pg_get_wal_stats_till_end_of_wal(pg_lsn,boolean) function pg_get_wal_stats_till_end_of_wal(pg_lsn,boolean)
(5 rows) (5 rows)
-- Make sure checkpoints don't interfere with the test.
SELECT 'init' FROM pg_create_physical_replication_slot('regress_pg_walinspect_slot', true, false);
?column?
----------
init
(1 row)
CREATE TABLE sample_tbl(col1 int, col2 int);
SELECT pg_current_wal_lsn() AS wal_lsn1 \gset
INSERT INTO sample_tbl SELECT * FROM generate_series(1, 2);
-- Check bounds for these past functions.
SELECT COUNT(*) >= 1 AS ok FROM pg_get_wal_records_info_till_end_of_wal(:'wal_lsn1');
ok
----
t
(1 row)
SELECT COUNT(*) >= 1 AS ok FROM pg_get_wal_stats_till_end_of_wal(:'wal_lsn1');
ok
----
t
(1 row)
SELECT COUNT(*) >= 1 AS ok FROM pg_get_wal_records_info_till_end_of_wal('FFFFFFFF/FFFFFFFF');
ERROR: WAL start LSN must be less than current LSN
SELECT COUNT(*) >= 1 AS ok FROM pg_get_wal_stats_till_end_of_wal('FFFFFFFF/FFFFFFFF');
ERROR: WAL start LSN must be less than current LSN
-- Move to new version 1.1 -- Move to new version 1.1
ALTER EXTENSION pg_walinspect UPDATE TO '1.1'; ALTER EXTENSION pg_walinspect UPDATE TO '1.1';
-- List what version 1.1 contains -- List what version 1.1 contains
\dx+ pg_walinspect \dx+ pg_walinspect
Objects in extension "pg_walinspect" Objects in extension "pg_walinspect"
Object description Object description
----------------------------------------------------------- --------------------------------------------------
function pg_get_wal_block_info(pg_lsn,pg_lsn) function pg_get_wal_block_info(pg_lsn,pg_lsn)
function pg_get_wal_record_info(pg_lsn) function pg_get_wal_record_info(pg_lsn)
function pg_get_wal_records_info(pg_lsn,pg_lsn) function pg_get_wal_records_info(pg_lsn,pg_lsn)
function pg_get_wal_records_info_till_end_of_wal(pg_lsn)
function pg_get_wal_stats(pg_lsn,pg_lsn,boolean) function pg_get_wal_stats(pg_lsn,pg_lsn,boolean)
function pg_get_wal_stats_till_end_of_wal(pg_lsn,boolean) (4 rows)
(6 rows)
SELECT pg_drop_replication_slot('regress_pg_walinspect_slot');
pg_drop_replication_slot
--------------------------
(1 row)
DROP TABLE sample_tbl;
DROP EXTENSION pg_walinspect; DROP EXTENSION pg_walinspect;

View File

@ -36,25 +36,33 @@ SELECT * FROM pg_get_wal_block_info(:'wal_lsn2', :'wal_lsn1');
ERROR: WAL start LSN must be less than end LSN ERROR: WAL start LSN must be less than end LSN
-- LSNs with the highest value possible. -- LSNs with the highest value possible.
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_record_info('FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_record_info('FFFFFFFF/FFFFFFFF');
ERROR: cannot accept future input LSN ERROR: WAL input LSN must be less than current LSN
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info_till_end_of_wal('FFFFFFFF/FFFFFFFF'); -- Success with end LSNs.
ERROR: cannot accept future start LSN
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats_till_end_of_wal('FFFFFFFF/FFFFFFFF');
ERROR: cannot accept future start LSN
-- failures with end LSNs
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF');
ERROR: cannot accept future end LSN ok
----
t
(1 row)
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF');
ERROR: cannot accept future end LSN ok
----
t
(1 row)
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_block_info(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_block_info(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF');
ERROR: cannot accept future end LSN ok
----
t
(1 row)
-- failures with start LSNs -- failures with start LSNs
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info('FFFFFFFF/FFFFFFFE', 'FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info('FFFFFFFF/FFFFFFFE', 'FFFFFFFF/FFFFFFFF');
ERROR: cannot accept future start LSN ERROR: WAL start LSN must be less than current LSN
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats('FFFFFFFF/FFFFFFFE', 'FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats('FFFFFFFF/FFFFFFFE', 'FFFFFFFF/FFFFFFFF');
ERROR: cannot accept future start LSN ERROR: WAL start LSN must be less than current LSN
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_block_info('FFFFFFFF/FFFFFFFE', 'FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_block_info('FFFFFFFF/FFFFFFFE', 'FFFFFFFF/FFFFFFFF');
ERROR: cannot accept future start LSN ERROR: WAL start LSN must be less than current LSN
-- =================================================================== -- ===================================================================
-- Tests for all function executions -- Tests for all function executions
-- =================================================================== -- ===================================================================
@ -64,18 +72,6 @@ SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_record_info(:'wal_lsn1');
t t
(1 row) (1 row)
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info_till_end_of_wal(:'wal_lsn1');
ok
----
t
(1 row)
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats_till_end_of_wal(:'wal_lsn1');
ok
----
t
(1 row)
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn1', :'wal_lsn2'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn1', :'wal_lsn2');
ok ok
---- ----

View File

@ -3,6 +3,10 @@
-- complain if script is sourced in psql, rather than via ALTER EXTENSION -- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION pg_walinspect UPDATE TO '1.1'" to load this file. \quit \echo Use "ALTER EXTENSION pg_walinspect UPDATE TO '1.1'" to load this file. \quit
-- Unsupported functions after 1.1.
DROP FUNCTION pg_get_wal_records_info_till_end_of_wal(pg_lsn);
DROP FUNCTION pg_get_wal_stats_till_end_of_wal(pg_lsn, boolean);
-- --
-- pg_get_wal_block_info() -- pg_get_wal_block_info()
-- --

View File

@ -38,14 +38,14 @@ PG_FUNCTION_INFO_V1(pg_get_wal_records_info_till_end_of_wal);
PG_FUNCTION_INFO_V1(pg_get_wal_stats); 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 void ValidateInputLSNs(XLogRecPtr start_lsn, XLogRecPtr *end_lsn);
static XLogRecPtr GetCurrentLSN(void);
static XLogReaderState *InitXLogReaderState(XLogRecPtr lsn); static XLogReaderState *InitXLogReaderState(XLogRecPtr lsn);
static XLogRecord *ReadNextXLogRecord(XLogReaderState *xlogreader); static XLogRecord *ReadNextXLogRecord(XLogReaderState *xlogreader);
static void GetWALRecordInfo(XLogReaderState *record, Datum *values, static void GetWALRecordInfo(XLogReaderState *record, Datum *values,
bool *nulls, uint32 ncols); bool *nulls, uint32 ncols);
static XLogRecPtr ValidateInputLSNs(bool till_end_of_wal, static void GetWALRecordsInfo(FunctionCallInfo fcinfo,
XLogRecPtr start_lsn, XLogRecPtr end_lsn); XLogRecPtr start_lsn,
static void GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
XLogRecPtr end_lsn); XLogRecPtr end_lsn);
static void GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo, static void GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
Datum *values, bool *nulls, uint32 ncols, Datum *values, bool *nulls, uint32 ncols,
@ -55,32 +55,32 @@ static void FillXLogStatsRow(const char *name, uint64 n, uint64 total_count,
uint64 fpi_len, uint64 total_fpi_len, uint64 fpi_len, uint64 total_fpi_len,
uint64 tot_len, uint64 total_len, uint64 tot_len, uint64 total_len,
Datum *values, bool *nulls, uint32 ncols); Datum *values, bool *nulls, uint32 ncols);
static void GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn, static void GetWalStats(FunctionCallInfo fcinfo,
XLogRecPtr end_lsn, bool stats_per_record); XLogRecPtr start_lsn,
XLogRecPtr end_lsn,
bool stats_per_record);
static void GetWALBlockInfo(FunctionCallInfo fcinfo, XLogReaderState *record); static void GetWALBlockInfo(FunctionCallInfo fcinfo, XLogReaderState *record);
/* /*
* Check if the given LSN is in future. Also, return the LSN up to which the * Return the LSN up to which the server has WAL.
* server has WAL.
*/ */
static bool static XLogRecPtr
IsFutureLSN(XLogRecPtr lsn, XLogRecPtr *curr_lsn) GetCurrentLSN(void)
{ {
XLogRecPtr curr_lsn;
/* /*
* We determine the current LSN of the server similar to how page_read * We determine the current LSN of the server similar to how page_read
* callback read_local_xlog_page_no_wait does. * callback read_local_xlog_page_no_wait does.
*/ */
if (!RecoveryInProgress()) if (!RecoveryInProgress())
*curr_lsn = GetFlushRecPtr(NULL); curr_lsn = GetFlushRecPtr(NULL);
else else
*curr_lsn = GetXLogReplayRecPtr(NULL); curr_lsn = GetXLogReplayRecPtr(NULL);
Assert(!XLogRecPtrIsInvalid(*curr_lsn)); Assert(!XLogRecPtrIsInvalid(curr_lsn));
if (lsn >= *curr_lsn) return curr_lsn;
return true;
return false;
} }
/* /*
@ -354,23 +354,17 @@ GetWALBlockInfo(FunctionCallInfo fcinfo, XLogReaderState *record)
* their relation information, and the data saved in each block associated * their relation information, and the data saved in each block associated
* to a record. Decompression is applied to the full page images, if * to a record. Decompression is applied to the full page images, if
* necessary. * necessary.
*
* This function emits an error if a future start or end WAL LSN i.e. WAL LSN
* the database system doesn't know about is specified.
*/ */
Datum Datum
pg_get_wal_block_info(PG_FUNCTION_ARGS) pg_get_wal_block_info(PG_FUNCTION_ARGS)
{ {
XLogRecPtr start_lsn; XLogRecPtr start_lsn = PG_GETARG_LSN(0);
XLogRecPtr end_lsn; XLogRecPtr end_lsn = PG_GETARG_LSN(1);
XLogReaderState *xlogreader; XLogReaderState *xlogreader;
MemoryContext old_cxt; MemoryContext old_cxt;
MemoryContext tmp_cxt; MemoryContext tmp_cxt;
start_lsn = PG_GETARG_LSN(0); ValidateInputLSNs(start_lsn, &end_lsn);
end_lsn = PG_GETARG_LSN(1);
end_lsn = ValidateInputLSNs(false, start_lsn, end_lsn);
InitMaterializedSRF(fcinfo, 0); InitMaterializedSRF(fcinfo, 0);
@ -404,9 +398,6 @@ pg_get_wal_block_info(PG_FUNCTION_ARGS)
/* /*
* Get WAL record info. * Get WAL record info.
*
* This function emits an error if a future WAL LSN i.e. WAL LSN the database
* system doesn't know about is specified.
*/ */
Datum Datum
pg_get_wal_record_info(PG_FUNCTION_ARGS) pg_get_wal_record_info(PG_FUNCTION_ARGS)
@ -422,20 +413,14 @@ pg_get_wal_record_info(PG_FUNCTION_ARGS)
HeapTuple tuple; HeapTuple tuple;
lsn = PG_GETARG_LSN(0); lsn = PG_GETARG_LSN(0);
curr_lsn = GetCurrentLSN();
if (IsFutureLSN(lsn, &curr_lsn)) if (lsn > curr_lsn)
{
/*
* GetFlushRecPtr or GetXLogReplayRecPtr gives "end+1" LSN of the last
* record flushed or replayed respectively. But let's use the LSN up
* to "end" in user facing message.
*/
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot accept future input LSN"), errmsg("WAL input LSN must be less than current LSN"),
errdetail("Last known WAL LSN on the database system is at %X/%X.", errdetail("Current WAL LSN on the database system is at %X/%X.",
LSN_FORMAT_ARGS(curr_lsn)))); LSN_FORMAT_ARGS(curr_lsn))));
}
/* Build a tuple descriptor for our result type. */ /* Build a tuple descriptor for our result type. */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
@ -462,44 +447,30 @@ pg_get_wal_record_info(PG_FUNCTION_ARGS)
} }
/* /*
* Validate the input LSNs and compute end LSN for till_end_of_wal versions. * Validate start and end LSNs coming from the function inputs.
*
* If end_lsn is found to be higher than the current LSN reported by the
* cluster, use the current LSN as the upper bound.
*/ */
static XLogRecPtr static void
ValidateInputLSNs(bool till_end_of_wal, XLogRecPtr start_lsn, ValidateInputLSNs(XLogRecPtr start_lsn, XLogRecPtr *end_lsn)
XLogRecPtr end_lsn)
{ {
XLogRecPtr curr_lsn; XLogRecPtr curr_lsn = GetCurrentLSN();
if (IsFutureLSN(start_lsn, &curr_lsn)) if (start_lsn > curr_lsn)
{
/*
* GetFlushRecPtr or GetXLogReplayRecPtr gives "end+1" LSN of the last
* record flushed or replayed respectively. But let's use the LSN up
* to "end" in user facing message.
*/
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot accept future start LSN"), errmsg("WAL start LSN must be less than current LSN"),
errdetail("Last known WAL LSN on the database system is at %X/%X.", errdetail("Current WAL LSN on the database system is at %X/%X.",
LSN_FORMAT_ARGS(curr_lsn))));
}
if (till_end_of_wal)
end_lsn = curr_lsn;
if (end_lsn > curr_lsn)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot accept future end LSN"),
errdetail("Last known WAL LSN on the database system is at %X/%X.",
LSN_FORMAT_ARGS(curr_lsn)))); LSN_FORMAT_ARGS(curr_lsn))));
if (start_lsn >= end_lsn) if (start_lsn > *end_lsn)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("WAL start LSN must be less than end LSN"))); errmsg("WAL start LSN must be less than end LSN")));
return end_lsn; if (*end_lsn > curr_lsn)
*end_lsn = curr_lsn;
} }
/* /*
@ -517,6 +488,8 @@ GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
MemoryContext old_cxt; MemoryContext old_cxt;
MemoryContext tmp_cxt; MemoryContext tmp_cxt;
Assert(start_lsn <= end_lsn);
InitMaterializedSRF(fcinfo, 0); InitMaterializedSRF(fcinfo, 0);
xlogreader = InitXLogReaderState(start_lsn); xlogreader = InitXLogReaderState(start_lsn);
@ -553,42 +526,14 @@ GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
/* /*
* Get info and data of all WAL records between start LSN and end LSN. * Get info and data of all WAL records between start LSN and end LSN.
*
* This function emits an error if a future start or end WAL LSN i.e. WAL LSN
* the database system doesn't know about is specified.
*/ */
Datum Datum
pg_get_wal_records_info(PG_FUNCTION_ARGS) pg_get_wal_records_info(PG_FUNCTION_ARGS)
{ {
XLogRecPtr start_lsn; XLogRecPtr start_lsn = PG_GETARG_LSN(0);
XLogRecPtr end_lsn; XLogRecPtr end_lsn = PG_GETARG_LSN(1);
start_lsn = PG_GETARG_LSN(0);
end_lsn = PG_GETARG_LSN(1);
end_lsn = ValidateInputLSNs(false, start_lsn, end_lsn);
GetWALRecordsInfo(fcinfo, start_lsn, end_lsn);
PG_RETURN_VOID();
}
/*
* Get info and data of all WAL records from start LSN till end of WAL.
*
* This function emits an error if a future start i.e. WAL LSN the database
* system doesn't know about is specified.
*/
Datum
pg_get_wal_records_info_till_end_of_wal(PG_FUNCTION_ARGS)
{
XLogRecPtr start_lsn;
XLogRecPtr end_lsn = InvalidXLogRecPtr;
start_lsn = PG_GETARG_LSN(0);
end_lsn = ValidateInputLSNs(true, start_lsn, end_lsn);
ValidateInputLSNs(start_lsn, &end_lsn);
GetWALRecordsInfo(fcinfo, start_lsn, end_lsn); GetWALRecordsInfo(fcinfo, start_lsn, end_lsn);
PG_RETURN_VOID(); PG_RETURN_VOID();
@ -757,8 +702,8 @@ GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
* Get WAL stats between start LSN and end LSN. * Get WAL stats between start LSN and end LSN.
*/ */
static void static void
GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn, GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn, XLogRecPtr end_lsn,
XLogRecPtr end_lsn, bool stats_per_record) bool stats_per_record)
{ {
#define PG_GET_WAL_STATS_COLS 9 #define PG_GET_WAL_STATS_COLS 9
XLogReaderState *xlogreader; XLogReaderState *xlogreader;
@ -767,6 +712,8 @@ GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
Datum values[PG_GET_WAL_STATS_COLS] = {0}; Datum values[PG_GET_WAL_STATS_COLS] = {0};
bool nulls[PG_GET_WAL_STATS_COLS] = {0}; bool nulls[PG_GET_WAL_STATS_COLS] = {0};
Assert(start_lsn <= end_lsn);
InitMaterializedSRF(fcinfo, 0); InitMaterializedSRF(fcinfo, 0);
xlogreader = InitXLogReaderState(start_lsn); xlogreader = InitXLogReaderState(start_lsn);
@ -791,45 +738,55 @@ GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
/* /*
* Get stats of all WAL records between start LSN and end LSN. * Get stats of all WAL records between start LSN and end LSN.
*
* This function emits an error if a future start or end WAL LSN i.e. WAL LSN
* the database system doesn't know about is specified.
*/ */
Datum Datum
pg_get_wal_stats(PG_FUNCTION_ARGS) pg_get_wal_stats(PG_FUNCTION_ARGS)
{ {
XLogRecPtr start_lsn; XLogRecPtr start_lsn = PG_GETARG_LSN(0);
XLogRecPtr end_lsn; XLogRecPtr end_lsn = PG_GETARG_LSN(1);
bool stats_per_record; bool stats_per_record = PG_GETARG_BOOL(2);
start_lsn = PG_GETARG_LSN(0);
end_lsn = PG_GETARG_LSN(1);
stats_per_record = PG_GETARG_BOOL(2);
end_lsn = ValidateInputLSNs(false, start_lsn, end_lsn);
ValidateInputLSNs(start_lsn, &end_lsn);
GetWalStats(fcinfo, start_lsn, end_lsn, stats_per_record); GetWalStats(fcinfo, start_lsn, end_lsn, stats_per_record);
PG_RETURN_VOID(); PG_RETURN_VOID();
} }
/* /*
* Get stats of all WAL records from start LSN till end of WAL. * The following functions have been removed in newer versions in 1.1, but
* * they are kept around for compatibility.
* This function emits an error if a future start i.e. WAL LSN the database
* system doesn't know about is specified.
*/ */
Datum
pg_get_wal_records_info_till_end_of_wal(PG_FUNCTION_ARGS)
{
XLogRecPtr start_lsn = PG_GETARG_LSN(0);
XLogRecPtr end_lsn = GetCurrentLSN();
if (start_lsn > end_lsn)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("WAL start LSN must be less than current LSN"),
errdetail("Current WAL LSN on the database system is at %X/%X.",
LSN_FORMAT_ARGS(end_lsn))));
GetWALRecordsInfo(fcinfo, start_lsn, end_lsn);
PG_RETURN_VOID();
}
Datum Datum
pg_get_wal_stats_till_end_of_wal(PG_FUNCTION_ARGS) pg_get_wal_stats_till_end_of_wal(PG_FUNCTION_ARGS)
{ {
XLogRecPtr start_lsn; XLogRecPtr start_lsn = PG_GETARG_LSN(0);
XLogRecPtr end_lsn = InvalidXLogRecPtr; XLogRecPtr end_lsn = GetCurrentLSN();
bool stats_per_record; bool stats_per_record = PG_GETARG_BOOL(1);
start_lsn = PG_GETARG_LSN(0); if (start_lsn > end_lsn)
stats_per_record = PG_GETARG_BOOL(1); ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
end_lsn = ValidateInputLSNs(true, start_lsn, end_lsn); errmsg("WAL start LSN must be less than current LSN"),
errdetail("Current WAL LSN on the database system is at %X/%X.",
LSN_FORMAT_ARGS(end_lsn))));
GetWalStats(fcinfo, start_lsn, end_lsn, stats_per_record); GetWalStats(fcinfo, start_lsn, end_lsn, stats_per_record);

View File

@ -2,13 +2,32 @@
CREATE EXTENSION pg_walinspect WITH VERSION '1.0'; CREATE EXTENSION pg_walinspect WITH VERSION '1.0';
-- Mask DETAIL messages as these could refer to current LSN positions.
\set VERBOSITY terse
-- List what version 1.0 contains -- List what version 1.0 contains
\dx+ pg_walinspect \dx+ pg_walinspect
-- Make sure checkpoints don't interfere with the test.
SELECT 'init' FROM pg_create_physical_replication_slot('regress_pg_walinspect_slot', true, false);
CREATE TABLE sample_tbl(col1 int, col2 int);
SELECT pg_current_wal_lsn() AS wal_lsn1 \gset
INSERT INTO sample_tbl SELECT * FROM generate_series(1, 2);
-- Check bounds for these past functions.
SELECT COUNT(*) >= 1 AS ok FROM pg_get_wal_records_info_till_end_of_wal(:'wal_lsn1');
SELECT COUNT(*) >= 1 AS ok FROM pg_get_wal_stats_till_end_of_wal(:'wal_lsn1');
SELECT COUNT(*) >= 1 AS ok FROM pg_get_wal_records_info_till_end_of_wal('FFFFFFFF/FFFFFFFF');
SELECT COUNT(*) >= 1 AS ok FROM pg_get_wal_stats_till_end_of_wal('FFFFFFFF/FFFFFFFF');
-- Move to new version 1.1 -- Move to new version 1.1
ALTER EXTENSION pg_walinspect UPDATE TO '1.1'; ALTER EXTENSION pg_walinspect UPDATE TO '1.1';
-- List what version 1.1 contains -- List what version 1.1 contains
\dx+ pg_walinspect \dx+ pg_walinspect
SELECT pg_drop_replication_slot('regress_pg_walinspect_slot');
DROP TABLE sample_tbl;
DROP EXTENSION pg_walinspect; DROP EXTENSION pg_walinspect;

View File

@ -33,9 +33,7 @@ SELECT * FROM pg_get_wal_block_info(:'wal_lsn2', :'wal_lsn1');
-- LSNs with the highest value possible. -- LSNs with the highest value possible.
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_record_info('FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_record_info('FFFFFFFF/FFFFFFFF');
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info_till_end_of_wal('FFFFFFFF/FFFFFFFF'); -- Success with end LSNs.
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats_till_end_of_wal('FFFFFFFF/FFFFFFFF');
-- failures with end LSNs
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF');
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF');
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_block_info(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_block_info(:'wal_lsn1', 'FFFFFFFF/FFFFFFFF');
@ -49,8 +47,6 @@ SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_block_info('FFFFFFFF/FFFFFFFE', 'FFFF
-- =================================================================== -- ===================================================================
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_record_info(:'wal_lsn1'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_record_info(:'wal_lsn1');
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info_till_end_of_wal(:'wal_lsn1');
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats_till_end_of_wal(:'wal_lsn1');
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn1', :'wal_lsn2'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn1', :'wal_lsn2');
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats(:'wal_lsn1', :'wal_lsn2'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_stats(:'wal_lsn1', :'wal_lsn2');
SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_block_info(:'wal_lsn1', :'wal_lsn2'); SELECT COUNT(*) >= 0 AS ok FROM pg_get_wal_block_info(:'wal_lsn1', :'wal_lsn2');

View File

@ -94,9 +94,11 @@ block_ref | blkref #0: rel 1663/5/60221 fork main blk 2
<para> <para>
Gets information of all the valid WAL records between Gets information of all the valid WAL records between
<replaceable>start_lsn</replaceable> and <replaceable>end_lsn</replaceable>. <replaceable>start_lsn</replaceable> and <replaceable>end_lsn</replaceable>.
Returns one row per WAL record. If <replaceable>start_lsn</replaceable> Returns one row per WAL record. If a future
or <replaceable>end_lsn</replaceable> are not yet available, the <replaceable>end_lsn</replaceable> (i.e. ahead of the current LSN of
function will raise an error. For example: the server) is specified, it returns information until the end of WAL.
The function raises an error if <replaceable>start_lsn</replaceable>
is not available. For example, usage of the function is as follows:
<screen> <screen>
postgres=# SELECT * FROM pg_get_wal_records_info('0/1E913618', '0/1E913740') LIMIT 1; postgres=# SELECT * FROM pg_get_wal_records_info('0/1E913618', '0/1E913740') LIMIT 1;
-[ RECORD 1 ]----+-------------------------------------------------------------- -[ RECORD 1 ]----+--------------------------------------------------------------
@ -116,23 +118,6 @@ block_ref |
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry id="pgwalinspect-funcs-pg-get-wal-records-info-till-end-of-wal">
<term>
<function>
pg_get_wal_records_info_till_end_of_wal(start_lsn pg_lsn)
returns setof record
</function>
</term>
<listitem>
<para>
This function is the same as <function>pg_get_wal_records_info()</function>,
except that it gets information of all the valid WAL records from
<replaceable>start_lsn</replaceable> till the end of WAL.
</para>
</listitem>
</varlistentry>
<varlistentry id="pgwalinspect-funcs-pg-get-wal-stats"> <varlistentry id="pgwalinspect-funcs-pg-get-wal-stats">
<term> <term>
<function> <function>
@ -148,10 +133,11 @@ block_ref |
<replaceable>end_lsn</replaceable>. By default, it returns one row per <replaceable>end_lsn</replaceable>. By default, it returns one row per
<replaceable>resource_manager</replaceable> type. When <replaceable>resource_manager</replaceable> type. When
<replaceable>per_record</replaceable> is set to <literal>true</literal>, <replaceable>per_record</replaceable> is set to <literal>true</literal>,
it returns one row per <replaceable>record_type</replaceable>. it returns one row per <replaceable>record_type</replaceable>. If a
If <replaceable>start_lsn</replaceable> future <replaceable>end_lsn</replaceable> (i.e. ahead of the current
or <replaceable>end_lsn</replaceable> are not yet available, the LSN of the server) is specified, it returns statistics until the end
function will raise an error. For example: of WAL. An error is raised if <replaceable>start_lsn</replaceable> is
not available. For example, usage of the function is as follows:
<screen> <screen>
postgres=# SELECT * FROM pg_get_wal_stats('0/1E847D00', '0/1E84F500') postgres=# SELECT * FROM pg_get_wal_stats('0/1E847D00', '0/1E84F500')
WHERE count > 0 LIMIT 1 AND WHERE count > 0 LIMIT 1 AND
@ -171,23 +157,6 @@ combined_size_percentage | 2.8634072910530795
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry id="pgwalinspect-funcs-pg-get-wal-stats-till-end-of-wal">
<term>
<function>
pg_get_wal_stats_till_end_of_wal(start_lsn pg_lsn, per_record boolean DEFAULT false)
returns setof record
</function>
</term>
<listitem>
<para>
This function is the same as <function>pg_get_wal_stats()</function>,
except that it gets statistics of all the valid WAL records from
<replaceable>start_lsn</replaceable> till end of WAL.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<function>pg_get_wal_block_info(start_lsn pg_lsn, end_lsn pg_lsn) returns setof record</function> <function>pg_get_wal_block_info(start_lsn pg_lsn, end_lsn pg_lsn) returns setof record</function>
@ -202,9 +171,11 @@ combined_size_percentage | 2.8634072910530795
and their information associated with all the valid WAL records between and their information associated with all the valid WAL records between
<replaceable>start_lsn</replaceable> and <replaceable>start_lsn</replaceable> and
<replaceable>end_lsn</replaceable>. Returns one row per block registered <replaceable>end_lsn</replaceable>. Returns one row per block registered
in a WAL record. If <replaceable>start_lsn</replaceable> or in a WAL record. If a future <replaceable>end_lsn</replaceable> (i.e.
<replaceable>end_lsn</replaceable> are not yet available, the function ahead of the current LSN of the server) is specified, it returns
will raise an error. For example: statistics until the end of WAL. An error is raised if
<replaceable>start_lsn</replaceable> is not available. For example,
usage of the function is as follows:
<screen> <screen>
postgres=# SELECT lsn, blockid, reltablespace, reldatabase, relfilenode, postgres=# SELECT lsn, blockid, reltablespace, reldatabase, relfilenode,
relblocknumber, forkname, relblocknumber, forkname,