20
20
#include "access/xlogutils.h"
21
21
#include "funcapi.h"
22
22
#include "miscadmin.h"
23
+ #include "utils/array.h"
23
24
#include "utils/builtins.h"
24
25
#include "utils/pg_lsn.h"
25
26
30
31
31
32
PG_MODULE_MAGIC ;
32
33
33
- PG_FUNCTION_INFO_V1 (pg_get_wal_fpi_info );
34
+ PG_FUNCTION_INFO_V1 (pg_get_wal_block_info );
34
35
PG_FUNCTION_INFO_V1 (pg_get_wal_record_info );
35
36
PG_FUNCTION_INFO_V1 (pg_get_wal_records_info );
36
37
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,
56
57
Datum * values , bool * nulls , uint32 ncols );
57
58
static void GetWalStats (FunctionCallInfo fcinfo , XLogRecPtr start_lsn ,
58
59
XLogRecPtr end_lsn , bool stats_per_record );
59
- static void GetWALFPIInfo (FunctionCallInfo fcinfo , XLogReaderState * record );
60
+ static void GetWALBlockInfo (FunctionCallInfo fcinfo , XLogReaderState * record );
60
61
61
62
/*
62
63
* 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,
221
222
222
223
223
224
/*
224
- * Store a set of full page images from a single record.
225
+ * Store a set of block information from a single record (FPI and block
226
+ * information).
225
227
*/
226
228
static void
227
- GetWALFPIInfo (FunctionCallInfo fcinfo , XLogReaderState * record )
229
+ GetWALBlockInfo (FunctionCallInfo fcinfo , XLogReaderState * record )
228
230
{
229
- #define PG_GET_WAL_FPI_INFO_COLS 7
231
+ #define PG_GET_WAL_BLOCK_INFO_COLS 11
230
232
int block_id ;
231
233
ReturnSetInfo * rsinfo = (ReturnSetInfo * ) fcinfo -> resultinfo ;
232
234
233
235
for (block_id = 0 ; block_id <= XLogRecMaxBlockId (record ); block_id ++ )
234
236
{
235
- PGAlignedBlock buf ;
236
- Page page ;
237
- bytea * raw_page ;
238
- BlockNumber blk ;
237
+ DecodedBkpBlock * blk ;
238
+ BlockNumber blkno ;
239
239
RelFileLocator rnode ;
240
240
ForkNumber fork ;
241
- Datum values [PG_GET_WAL_FPI_INFO_COLS ] = {0 };
242
- bool nulls [PG_GET_WAL_FPI_INFO_COLS ] = {0 };
241
+ Datum values [PG_GET_WAL_BLOCK_INFO_COLS ] = {0 };
242
+ bool nulls [PG_GET_WAL_BLOCK_INFO_COLS ] = {0 };
243
243
int i = 0 ;
244
244
245
245
if (!XLogRecHasBlockRef (record , block_id ))
246
246
continue ;
247
247
248
- if (!XLogRecHasBlockImage (record , block_id ))
249
- continue ;
250
-
251
- page = (Page ) buf .data ;
252
-
253
- if (!RestoreBlockImage (record , block_id , page ))
254
- ereport (ERROR ,
255
- (errcode (ERRCODE_INTERNAL_ERROR ),
256
- errmsg_internal ("%s" , record -> errormsg_buf )));
248
+ blk = XLogRecGetBlock (record , block_id );
257
249
258
- /* Full page exists, so let's save it. */
259
250
(void ) XLogRecGetBlockTagExtended (record , block_id ,
260
- & rnode , & fork , & blk , NULL );
251
+ & rnode , & fork , & blkno , NULL );
261
252
262
253
values [i ++ ] = LSNGetDatum (record -> ReadRecPtr );
263
- values [i ++ ] = ObjectIdGetDatum (rnode .spcOid );
264
- values [i ++ ] = ObjectIdGetDatum (rnode .dbOid );
265
- values [i ++ ] = ObjectIdGetDatum (rnode .relNumber );
266
- values [i ++ ] = Int64GetDatum ((int64 ) blk );
254
+ values [i ++ ] = Int16GetDatum (block_id );
255
+ values [i ++ ] = ObjectIdGetDatum (blk -> rlocator .spcOid );
256
+ values [i ++ ] = ObjectIdGetDatum (blk -> rlocator .dbOid );
257
+ values [i ++ ] = ObjectIdGetDatum (blk -> rlocator .relNumber );
258
+ values [i ++ ] = Int64GetDatum ((int64 ) blkno );
267
259
268
260
if (fork >= 0 && fork <= MAX_FORKNUM )
269
261
values [i ++ ] = CStringGetTextDatum (forkNames [fork ]);
@@ -272,34 +264,102 @@ GetWALFPIInfo(FunctionCallInfo fcinfo, XLogReaderState *record)
272
264
(errcode (ERRCODE_INTERNAL_ERROR ),
273
265
errmsg_internal ("invalid fork number: %u" , fork )));
274
266
275
- /* Initialize bytea buffer to copy the FPI to. */
276
- raw_page = (bytea * ) palloc (BLCKSZ + VARHDRSZ );
277
- SET_VARSIZE (raw_page , BLCKSZ + VARHDRSZ );
267
+ /* Block data */
268
+ if (blk -> has_data )
269
+ {
270
+ bytea * raw_data ;
271
+
272
+ /* Initialize bytea buffer to copy the data to */
273
+ raw_data = (bytea * ) palloc (blk -> data_len + VARHDRSZ );
274
+ SET_VARSIZE (raw_data , blk -> data_len + VARHDRSZ );
278
275
279
- /* Take a verbatim copy of the FPI. */
280
- memcpy (VARDATA (raw_page ), page , BLCKSZ );
276
+ /* Copy the data */
277
+ memcpy (VARDATA (raw_data ), blk -> data , blk -> data_len );
278
+ values [i ++ ] = PointerGetDatum (raw_data );
279
+ }
280
+ else
281
+ {
282
+ /* No data, so set this field to NULL */
283
+ nulls [i ++ ] = true;
284
+ }
281
285
282
- values [i ++ ] = PointerGetDatum (raw_page );
286
+ if (blk -> has_image )
287
+ {
288
+ PGAlignedBlock buf ;
289
+ Page page ;
290
+ bytea * raw_page ;
291
+ int bitcnt ;
292
+ int cnt = 0 ;
293
+ Datum * flags ;
294
+ ArrayType * a ;
295
+
296
+ page = (Page ) buf .data ;
297
+
298
+ /* Full page image exists, so let's save it */
299
+ if (!RestoreBlockImage (record , block_id , page ))
300
+ ereport (ERROR ,
301
+ (errcode (ERRCODE_INTERNAL_ERROR ),
302
+ errmsg_internal ("%s" , record -> errormsg_buf )));
303
+
304
+ /* Initialize bytea buffer to copy the FPI to */
305
+ raw_page = (bytea * ) palloc (BLCKSZ + VARHDRSZ );
306
+ SET_VARSIZE (raw_page , BLCKSZ + VARHDRSZ );
307
+
308
+ /* Take a verbatim copy of the FPI */
309
+ memcpy (VARDATA (raw_page ), page , BLCKSZ );
310
+
311
+ values [i ++ ] = PointerGetDatum (raw_page );
312
+ values [i ++ ] = UInt32GetDatum (blk -> bimg_len );
313
+
314
+ /* FPI flags */
315
+ bitcnt = pg_popcount ((const char * ) & blk -> bimg_info ,
316
+ sizeof (uint8 ));
317
+ /* Build set of raw flags */
318
+ flags = (Datum * ) palloc0 (sizeof (Datum ) * bitcnt );
319
+
320
+ if ((blk -> bimg_info & BKPIMAGE_HAS_HOLE ) != 0 )
321
+ flags [cnt ++ ] = CStringGetTextDatum ("HAS_HOLE" );
322
+ if (blk -> apply_image )
323
+ flags [cnt ++ ] = CStringGetTextDatum ("APPLY" );
324
+ if ((blk -> bimg_info & BKPIMAGE_COMPRESS_PGLZ ) != 0 )
325
+ flags [cnt ++ ] = CStringGetTextDatum ("COMPRESS_PGLZ" );
326
+ if ((blk -> bimg_info & BKPIMAGE_COMPRESS_LZ4 ) != 0 )
327
+ flags [cnt ++ ] = CStringGetTextDatum ("COMPRESS_LZ4" );
328
+ if ((blk -> bimg_info & BKPIMAGE_COMPRESS_ZSTD ) != 0 )
329
+ flags [cnt ++ ] = CStringGetTextDatum ("COMPRESS_ZSTD" );
330
+
331
+ Assert (cnt <= bitcnt );
332
+ a = construct_array_builtin (flags , cnt , TEXTOID );
333
+ values [i ++ ] = PointerGetDatum (a );
334
+ }
335
+ else
336
+ {
337
+ /* No full page image, so store NULLs for all its fields */
338
+ memset (& nulls [i ], true, 3 * sizeof (bool ));
339
+ i += 3 ;
340
+ }
283
341
284
- Assert (i == PG_GET_WAL_FPI_INFO_COLS );
342
+ Assert (i == PG_GET_WAL_BLOCK_INFO_COLS );
285
343
286
344
tuplestore_putvalues (rsinfo -> setResult , rsinfo -> setDesc ,
287
345
values , nulls );
288
346
}
289
347
290
- #undef PG_GET_WAL_FPI_INFO_COLS
348
+ #undef PG_GET_WAL_FPI_BLOCK_COLS
291
349
}
292
350
293
351
/*
294
- * Get full page images with their relation information for all the WAL
295
- * records between start and end LSNs. Decompression is applied to the
296
- * blocks, if necessary.
352
+ * Get information about all the blocks saved in WAL records between start
353
+ * and end LSNs. This produces information about the full page images with
354
+ * their relation information, and the data saved in each block associated
355
+ * to a record. Decompression is applied to the full page images, if
356
+ * necessary.
297
357
*
298
358
* This function emits an error if a future start or end WAL LSN i.e. WAL LSN
299
359
* the database system doesn't know about is specified.
300
360
*/
301
361
Datum
302
- pg_get_wal_fpi_info (PG_FUNCTION_ARGS )
362
+ pg_get_wal_block_info (PG_FUNCTION_ARGS )
303
363
{
304
364
XLogRecPtr start_lsn ;
305
365
XLogRecPtr end_lsn ;
@@ -317,7 +377,7 @@ pg_get_wal_fpi_info(PG_FUNCTION_ARGS)
317
377
xlogreader = InitXLogReaderState (start_lsn );
318
378
319
379
tmp_cxt = AllocSetContextCreate (CurrentMemoryContext ,
320
- "pg_get_wal_fpi_info temporary cxt" ,
380
+ "pg_get_block_fpi_info temporary cxt" ,
321
381
ALLOCSET_DEFAULT_SIZES );
322
382
323
383
while (ReadNextXLogRecord (xlogreader ) &&
@@ -326,7 +386,7 @@ pg_get_wal_fpi_info(PG_FUNCTION_ARGS)
326
386
/* Use the tmp context so we can clean up after each tuple is done */
327
387
old_cxt = MemoryContextSwitchTo (tmp_cxt );
328
388
329
- GetWALFPIInfo (fcinfo , xlogreader );
389
+ GetWALBlockInfo (fcinfo , xlogreader );
330
390
331
391
/* clean up and switch back */
332
392
MemoryContextSwitchTo (old_cxt );
0 commit comments