aboutsummaryrefslogtreecommitdiff
path: root/contrib/pg_walinspect/pg_walinspect.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pg_walinspect/pg_walinspect.c')
-rw-r--r--contrib/pg_walinspect/pg_walinspect.c140
1 files changed, 100 insertions, 40 deletions
diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index b7b0a805ee8..ee88dc49921 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -20,6 +20,7 @@
#include "access/xlogutils.h"
#include "funcapi.h"
#include "miscadmin.h"
+#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/pg_lsn.h"
@@ -30,7 +31,7 @@
PG_MODULE_MAGIC;
-PG_FUNCTION_INFO_V1(pg_get_wal_fpi_info);
+PG_FUNCTION_INFO_V1(pg_get_wal_block_info);
PG_FUNCTION_INFO_V1(pg_get_wal_record_info);
PG_FUNCTION_INFO_V1(pg_get_wal_records_info);
PG_FUNCTION_INFO_V1(pg_get_wal_records_info_till_end_of_wal);
@@ -56,7 +57,7 @@ static void FillXLogStatsRow(const char *name, uint64 n, uint64 total_count,
Datum *values, bool *nulls, uint32 ncols);
static void GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
XLogRecPtr end_lsn, bool stats_per_record);
-static void GetWALFPIInfo(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
@@ -221,49 +222,40 @@ GetWALRecordInfo(XLogReaderState *record, Datum *values,
/*
- * Store a set of full page images from a single record.
+ * Store a set of block information from a single record (FPI and block
+ * information).
*/
static void
-GetWALFPIInfo(FunctionCallInfo fcinfo, XLogReaderState *record)
+GetWALBlockInfo(FunctionCallInfo fcinfo, XLogReaderState *record)
{
-#define PG_GET_WAL_FPI_INFO_COLS 7
+#define PG_GET_WAL_BLOCK_INFO_COLS 11
int block_id;
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
{
- PGAlignedBlock buf;
- Page page;
- bytea *raw_page;
- BlockNumber blk;
+ DecodedBkpBlock *blk;
+ BlockNumber blkno;
RelFileLocator rnode;
ForkNumber fork;
- Datum values[PG_GET_WAL_FPI_INFO_COLS] = {0};
- bool nulls[PG_GET_WAL_FPI_INFO_COLS] = {0};
+ Datum values[PG_GET_WAL_BLOCK_INFO_COLS] = {0};
+ bool nulls[PG_GET_WAL_BLOCK_INFO_COLS] = {0};
int i = 0;
if (!XLogRecHasBlockRef(record, block_id))
continue;
- if (!XLogRecHasBlockImage(record, block_id))
- continue;
-
- page = (Page) buf.data;
-
- if (!RestoreBlockImage(record, block_id, page))
- ereport(ERROR,
- (errcode(ERRCODE_INTERNAL_ERROR),
- errmsg_internal("%s", record->errormsg_buf)));
+ blk = XLogRecGetBlock(record, block_id);
- /* Full page exists, so let's save it. */
(void) XLogRecGetBlockTagExtended(record, block_id,
- &rnode, &fork, &blk, NULL);
+ &rnode, &fork, &blkno, NULL);
values[i++] = LSNGetDatum(record->ReadRecPtr);
- values[i++] = ObjectIdGetDatum(rnode.spcOid);
- values[i++] = ObjectIdGetDatum(rnode.dbOid);
- values[i++] = ObjectIdGetDatum(rnode.relNumber);
- values[i++] = Int64GetDatum((int64) blk);
+ values[i++] = Int16GetDatum(block_id);
+ values[i++] = ObjectIdGetDatum(blk->rlocator.spcOid);
+ values[i++] = ObjectIdGetDatum(blk->rlocator.dbOid);
+ values[i++] = ObjectIdGetDatum(blk->rlocator.relNumber);
+ values[i++] = Int64GetDatum((int64) blkno);
if (fork >= 0 && fork <= MAX_FORKNUM)
values[i++] = CStringGetTextDatum(forkNames[fork]);
@@ -272,34 +264,102 @@ GetWALFPIInfo(FunctionCallInfo fcinfo, XLogReaderState *record)
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg_internal("invalid fork number: %u", fork)));
- /* Initialize bytea buffer to copy the FPI to. */
- raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ);
- SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ);
+ /* Block data */
+ if (blk->has_data)
+ {
+ bytea *raw_data;
+
+ /* Initialize bytea buffer to copy the data to */
+ raw_data = (bytea *) palloc(blk->data_len + VARHDRSZ);
+ SET_VARSIZE(raw_data, blk->data_len + VARHDRSZ);
- /* Take a verbatim copy of the FPI. */
- memcpy(VARDATA(raw_page), page, BLCKSZ);
+ /* Copy the data */
+ memcpy(VARDATA(raw_data), blk->data, blk->data_len);
+ values[i++] = PointerGetDatum(raw_data);
+ }
+ else
+ {
+ /* No data, so set this field to NULL */
+ nulls[i++] = true;
+ }
- values[i++] = PointerGetDatum(raw_page);
+ if (blk->has_image)
+ {
+ PGAlignedBlock buf;
+ Page page;
+ bytea *raw_page;
+ int bitcnt;
+ int cnt = 0;
+ Datum *flags;
+ ArrayType *a;
+
+ page = (Page) buf.data;
+
+ /* Full page image exists, so let's save it */
+ if (!RestoreBlockImage(record, block_id, page))
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg_internal("%s", record->errormsg_buf)));
+
+ /* Initialize bytea buffer to copy the FPI to */
+ raw_page = (bytea *) palloc(BLCKSZ + VARHDRSZ);
+ SET_VARSIZE(raw_page, BLCKSZ + VARHDRSZ);
+
+ /* Take a verbatim copy of the FPI */
+ memcpy(VARDATA(raw_page), page, BLCKSZ);
+
+ values[i++] = PointerGetDatum(raw_page);
+ values[i++] = UInt32GetDatum(blk->bimg_len);
+
+ /* FPI flags */
+ bitcnt = pg_popcount((const char *) &blk->bimg_info,
+ sizeof(uint8));
+ /* Build set of raw flags */
+ flags = (Datum *) palloc0(sizeof(Datum) * bitcnt);
+
+ if ((blk->bimg_info & BKPIMAGE_HAS_HOLE) != 0)
+ flags[cnt++] = CStringGetTextDatum("HAS_HOLE");
+ if (blk->apply_image)
+ flags[cnt++] = CStringGetTextDatum("APPLY");
+ if ((blk->bimg_info & BKPIMAGE_COMPRESS_PGLZ) != 0)
+ flags[cnt++] = CStringGetTextDatum("COMPRESS_PGLZ");
+ if ((blk->bimg_info & BKPIMAGE_COMPRESS_LZ4) != 0)
+ flags[cnt++] = CStringGetTextDatum("COMPRESS_LZ4");
+ if ((blk->bimg_info & BKPIMAGE_COMPRESS_ZSTD) != 0)
+ flags[cnt++] = CStringGetTextDatum("COMPRESS_ZSTD");
+
+ Assert(cnt <= bitcnt);
+ a = construct_array_builtin(flags, cnt, TEXTOID);
+ values[i++] = PointerGetDatum(a);
+ }
+ else
+ {
+ /* No full page image, so store NULLs for all its fields */
+ memset(&nulls[i], true, 3 * sizeof(bool));
+ i += 3;
+ }
- Assert(i == PG_GET_WAL_FPI_INFO_COLS);
+ Assert(i == PG_GET_WAL_BLOCK_INFO_COLS);
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
values, nulls);
}
-#undef PG_GET_WAL_FPI_INFO_COLS
+#undef PG_GET_WAL_FPI_BLOCK_COLS
}
/*
- * Get full page images with their relation information for all the WAL
- * records between start and end LSNs. Decompression is applied to the
- * blocks, if necessary.
+ * Get information about all the blocks saved in WAL records between start
+ * and end LSNs. This produces information about the full page images with
+ * their relation information, and the data saved in each block associated
+ * to a record. Decompression is applied to the full page images, if
+ * 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
-pg_get_wal_fpi_info(PG_FUNCTION_ARGS)
+pg_get_wal_block_info(PG_FUNCTION_ARGS)
{
XLogRecPtr start_lsn;
XLogRecPtr end_lsn;
@@ -317,7 +377,7 @@ pg_get_wal_fpi_info(PG_FUNCTION_ARGS)
xlogreader = InitXLogReaderState(start_lsn);
tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
- "pg_get_wal_fpi_info temporary cxt",
+ "pg_get_block_fpi_info temporary cxt",
ALLOCSET_DEFAULT_SIZES);
while (ReadNextXLogRecord(xlogreader) &&
@@ -326,7 +386,7 @@ pg_get_wal_fpi_info(PG_FUNCTION_ARGS)
/* Use the tmp context so we can clean up after each tuple is done */
old_cxt = MemoryContextSwitchTo(tmp_cxt);
- GetWALFPIInfo(fcinfo, xlogreader);
+ GetWALBlockInfo(fcinfo, xlogreader);
/* clean up and switch back */
MemoryContextSwitchTo(old_cxt);