PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_walinspect.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_walinspect.c
4 * Functions to inspect contents of PostgreSQL Write-Ahead Log
5 *
6 * Copyright (c) 2022-2026, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * contrib/pg_walinspect/pg_walinspect.c
10 *
11 *-------------------------------------------------------------------------
12 */
13#include "postgres.h"
14
15#include "access/htup_details.h"
16#include "access/xlog.h"
18#include "access/xlogreader.h"
19#include "access/xlogrecovery.h"
20#include "access/xlogstats.h"
21#include "access/xlogutils.h"
22#include "funcapi.h"
23#include "miscadmin.h"
24#include "port/pg_bitutils.h"
25#include "utils/array.h"
26#include "utils/builtins.h"
27#include "utils/pg_lsn.h"
28#include "utils/tuplestore.h"
29
30/*
31 * NOTE: For any code change or issue fix here, it is highly recommended to
32 * give a thought about doing the same in pg_waldump tool as well.
33 */
34
36 .name = "pg_walinspect",
37 .version = PG_VERSION
38);
39
46
47static void ValidateInputLSNs(XLogRecPtr start_lsn, XLogRecPtr *end_lsn);
48static XLogRecPtr GetCurrentLSN(void);
51static void GetWALRecordInfo(XLogReaderState *record, Datum *values,
52 bool *nulls, uint32 ncols);
53static void GetWALRecordsInfo(FunctionCallInfo fcinfo,
54 XLogRecPtr start_lsn,
55 XLogRecPtr end_lsn);
57 Datum *values, bool *nulls, uint32 ncols,
58 bool stats_per_record);
59static void FillXLogStatsRow(const char *name, uint64 n, uint64 total_count,
62 uint64 tot_len, uint64 total_len,
63 Datum *values, bool *nulls, uint32 ncols);
64static void GetWalStats(FunctionCallInfo fcinfo,
65 XLogRecPtr start_lsn,
66 XLogRecPtr end_lsn,
67 bool stats_per_record);
68static void GetWALBlockInfo(FunctionCallInfo fcinfo, XLogReaderState *record,
69 bool show_data);
70
71/*
72 * Return the LSN up to which the server has WAL.
73 */
74static XLogRecPtr
76{
78
79 /*
80 * We determine the current LSN of the server similar to how page_read
81 * callback read_local_xlog_page_no_wait does.
82 */
83 if (!RecoveryInProgress())
85 else
87
89
90 return curr_lsn;
91}
92
93/*
94 * Initialize WAL reader and identify first valid LSN.
95 */
96static XLogReaderState *
98{
100 ReadLocalXLogPageNoWaitPrivate *private_data;
102
103 /*
104 * Reading WAL below the first page of the first segments isn't allowed.
105 * This is a bootstrap WAL page and the page_read callback fails to read
106 * it.
107 */
108 if (lsn < XLOG_BLCKSZ)
111 errmsg("could not read WAL at LSN %X/%08X",
112 LSN_FORMAT_ARGS(lsn))));
113
115
118 .segment_open = &wal_segment_open,
119 .segment_close = &wal_segment_close),
120 private_data);
121
122 if (xlogreader == NULL)
125 errmsg("out of memory"),
126 errdetail("Failed while allocating a WAL reading processor.")));
127
128 /* first find a valid recptr to start from */
130
133 errmsg("could not find a valid record after %X/%08X",
134 LSN_FORMAT_ARGS(lsn)));
135
136 return xlogreader;
137}
138
139/*
140 * Read next WAL record.
141 *
142 * By design, to be less intrusive in a running system, no slot is allocated
143 * to reserve the WAL we're about to read. Therefore this function can
144 * encounter read errors for historical WAL.
145 *
146 * We guard against ordinary errors trying to read WAL that hasn't been
147 * written yet by limiting end_lsn to the flushed WAL, but that can also
148 * encounter errors if the flush pointer falls in the middle of a record. In
149 * that case we'll return NULL.
150 */
151static XLogRecord *
153{
154 XLogRecord *record;
155 char *errormsg;
156
157 record = XLogReadRecord(xlogreader, &errormsg);
158
159 if (record == NULL)
160 {
161 ReadLocalXLogPageNoWaitPrivate *private_data;
162
163 /* return NULL, if end of WAL is reached */
164 private_data = (ReadLocalXLogPageNoWaitPrivate *)
166
167 if (private_data->end_of_wal)
168 return NULL;
169
170 if (errormsg)
173 errmsg("could not read WAL at %X/%08X: %s",
174 LSN_FORMAT_ARGS(xlogreader->EndRecPtr), errormsg)));
175 else
178 errmsg("could not read WAL at %X/%08X",
180 }
181
182 return record;
183}
184
185/*
186 * Output values that make up a row describing caller's WAL record.
187 *
188 * This function leaks memory. Caller may need to use its own custom memory
189 * context.
190 *
191 * Keep this in sync with GetWALBlockInfo.
192 */
193static void
195 bool *nulls, uint32 ncols)
196{
197 const char *record_type;
198 RmgrData desc;
199 uint32 fpi_len = 0;
202 int i = 0;
203
204 desc = GetRmgr(XLogRecGetRmid(record));
205 record_type = desc.rm_identify(XLogRecGetInfo(record));
206
207 if (record_type == NULL)
208 record_type = psprintf("UNKNOWN (%x)", XLogRecGetInfo(record) & ~XLR_INFO_MASK);
209
211 desc.rm_desc(&rec_desc, record);
212
213 if (XLogRecHasAnyBlockRefs(record))
214 {
216 XLogRecGetBlockRefInfo(record, false, true, &rec_blk_ref, &fpi_len);
217 }
218
219 values[i++] = LSNGetDatum(record->ReadRecPtr);
220 values[i++] = LSNGetDatum(record->EndRecPtr);
221 values[i++] = LSNGetDatum(XLogRecGetPrev(record));
224 values[i++] = CStringGetTextDatum(record_type);
227 values[i++] = UInt32GetDatum(fpi_len);
228
229 if (rec_desc.len > 0)
231 else
232 nulls[i++] = true;
233
234 if (XLogRecHasAnyBlockRefs(record))
236 else
237 nulls[i++] = true;
238
239 Assert(i == ncols);
240}
241
242
243/*
244 * Output one or more rows in rsinfo tuple store, each describing a single
245 * block reference from caller's WAL record. (Should only be called with
246 * records that have block references.)
247 *
248 * This function leaks memory. Caller may need to use its own custom memory
249 * context.
250 *
251 * Keep this in sync with GetWALRecordInfo.
252 */
253static void
255 bool show_data)
256{
257#define PG_GET_WAL_BLOCK_INFO_COLS 20
258 int block_id;
260 RmgrData desc;
261 const char *record_type;
263
265
266 desc = GetRmgr(XLogRecGetRmid(record));
267 record_type = desc.rm_identify(XLogRecGetInfo(record));
268
269 if (record_type == NULL)
270 record_type = psprintf("UNKNOWN (%x)",
271 XLogRecGetInfo(record) & ~XLR_INFO_MASK);
272
274 desc.rm_desc(&rec_desc, record);
275
276 for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
277 {
279 BlockNumber blkno;
281 ForkNumber forknum;
283 bool nulls[PG_GET_WAL_BLOCK_INFO_COLS] = {0};
285 block_fpi_len = 0;
287 int i = 0;
288
289 if (!XLogRecHasBlockRef(record, block_id))
290 continue;
291
292 blk = XLogRecGetBlock(record, block_id);
293
295 &rnode, &forknum, &blkno, NULL);
296
297 /* Save block_data_len */
298 if (blk->has_data)
299 block_data_len = blk->data_len;
300
301 if (blk->has_image)
302 {
303 /* Block reference has an FPI, so prepare relevant output */
304 int bitcnt;
305 int cnt = 0;
306 Datum *flags;
307
308 /* Save block_fpi_len */
309 block_fpi_len = blk->bimg_len;
310
311 /* Construct and save block_fpi_info */
312 bitcnt = pg_popcount((const char *) &blk->bimg_info,
313 sizeof(uint8));
314 flags = palloc0_array(Datum, bitcnt);
315 if ((blk->bimg_info & BKPIMAGE_HAS_HOLE) != 0)
316 flags[cnt++] = CStringGetTextDatum("HAS_HOLE");
317 if (blk->apply_image)
318 flags[cnt++] = CStringGetTextDatum("APPLY");
319 if ((blk->bimg_info & BKPIMAGE_COMPRESS_PGLZ) != 0)
320 flags[cnt++] = CStringGetTextDatum("COMPRESS_PGLZ");
321 if ((blk->bimg_info & BKPIMAGE_COMPRESS_LZ4) != 0)
322 flags[cnt++] = CStringGetTextDatum("COMPRESS_LZ4");
323 if ((blk->bimg_info & BKPIMAGE_COMPRESS_ZSTD) != 0)
324 flags[cnt++] = CStringGetTextDatum("COMPRESS_ZSTD");
325
326 Assert(cnt <= bitcnt);
328 }
329
330 /* start_lsn, end_lsn, prev_lsn, and blockid outputs */
331 values[i++] = LSNGetDatum(record->ReadRecPtr);
332 values[i++] = LSNGetDatum(record->EndRecPtr);
333 values[i++] = LSNGetDatum(XLogRecGetPrev(record));
335
336 /* relfile and block related outputs */
337 values[i++] = ObjectIdGetDatum(blk->rlocator.spcOid);
338 values[i++] = ObjectIdGetDatum(blk->rlocator.dbOid);
339 values[i++] = ObjectIdGetDatum(blk->rlocator.relNumber);
340 values[i++] = Int16GetDatum(forknum);
341 values[i++] = Int64GetDatum((int64) blkno);
342
343 /* xid, resource_manager, and record_type outputs */
346 values[i++] = CStringGetTextDatum(record_type);
347
348 /*
349 * record_length, main_data_length, block_data_len, and
350 * block_fpi_length outputs
351 */
356
357 /* block_fpi_info (text array) output */
358 if (block_fpi_info)
360 else
361 nulls[i++] = true;
362
363 /* description output (describes WAL record) */
364 if (rec_desc.len > 0)
366 else
367 nulls[i++] = true;
368
369 /* block_data output */
370 if (blk->has_data && show_data)
371 {
373
378 }
379 else
380 nulls[i++] = true;
381
382 /* block_fpi_data output */
383 if (blk->has_image && show_data)
384 {
386 Page page;
388
389 page = (Page) buf.data;
390 if (!RestoreBlockImage(record, block_id, page))
393 errmsg_internal("%s", record->errormsg_buf)));
394
399 }
400 else
401 nulls[i++] = true;
402
404
405 /* Store a tuple for this block reference */
406 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
407 values, nulls);
408 }
409
410#undef PG_GET_WAL_BLOCK_INFO_COLS
411}
412
413/*
414 * Get WAL record info, unnested by block reference
415 */
416Datum
418{
419 XLogRecPtr start_lsn = PG_GETARG_LSN(0);
420 XLogRecPtr end_lsn = PG_GETARG_LSN(1);
421 bool show_data = PG_GETARG_BOOL(2);
424 MemoryContext tmp_cxt;
425
426 ValidateInputLSNs(start_lsn, &end_lsn);
427
428 InitMaterializedSRF(fcinfo, 0);
429
430 xlogreader = InitXLogReaderState(start_lsn);
431
433 "pg_get_wal_block_info temporary cxt",
435
437 xlogreader->EndRecPtr <= end_lsn)
438 {
440
442 continue;
443
444 /* Use the tmp context so we can clean up after each tuple is done */
446
448
449 /* clean up and switch back */
451 MemoryContextReset(tmp_cxt);
452 }
453
454 MemoryContextDelete(tmp_cxt);
457
459}
460
461/*
462 * Get WAL record info.
463 */
464Datum
466{
467#define PG_GET_WAL_RECORD_INFO_COLS 11
468 Datum result;
470 bool nulls[PG_GET_WAL_RECORD_INFO_COLS] = {0};
471 XLogRecPtr lsn;
474 TupleDesc tupdesc;
475 HeapTuple tuple;
476
477 lsn = PG_GETARG_LSN(0);
479
480 if (lsn > curr_lsn)
483 errmsg("WAL input LSN must be less than current LSN"),
484 errdetail("Current WAL LSN on the database system is at %X/%08X.",
486
487 /* Build a tuple descriptor for our result type. */
488 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
489 elog(ERROR, "return type must be a row type");
490
492
496 errmsg("could not read WAL at %X/%08X",
498
500
503
504 tuple = heap_form_tuple(tupdesc, values, nulls);
505 result = HeapTupleGetDatum(tuple);
506
507 PG_RETURN_DATUM(result);
508#undef PG_GET_WAL_RECORD_INFO_COLS
509}
510
511/*
512 * Validate start and end LSNs coming from the function inputs.
513 *
514 * If end_lsn is found to be higher than the current LSN reported by the
515 * cluster, use the current LSN as the upper bound.
516 */
517static void
519{
521
522 if (start_lsn > curr_lsn)
525 errmsg("WAL start LSN must be less than current LSN"),
526 errdetail("Current WAL LSN on the database system is at %X/%08X.",
528
529 if (start_lsn > *end_lsn)
532 errmsg("WAL start LSN must be less than end LSN")));
533
534 if (*end_lsn > curr_lsn)
535 *end_lsn = curr_lsn;
536}
537
538/*
539 * Get info of all WAL records between start LSN and end LSN.
540 */
541static void
543 XLogRecPtr end_lsn)
544{
545#define PG_GET_WAL_RECORDS_INFO_COLS 11
549 MemoryContext tmp_cxt;
550
551 Assert(start_lsn <= end_lsn);
552
553 InitMaterializedSRF(fcinfo, 0);
554
555 xlogreader = InitXLogReaderState(start_lsn);
556
558 "GetWALRecordsInfo temporary cxt",
560
562 xlogreader->EndRecPtr <= end_lsn)
563 {
565 bool nulls[PG_GET_WAL_RECORDS_INFO_COLS] = {0};
566
567 /* Use the tmp context so we can clean up after each tuple is done */
569
572
573 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
574 values, nulls);
575
576 /* clean up and switch back */
578 MemoryContextReset(tmp_cxt);
579
581 }
582
583 MemoryContextDelete(tmp_cxt);
586
587#undef PG_GET_WAL_RECORDS_INFO_COLS
588}
589
590/*
591 * Get info of all WAL records between start LSN and end LSN.
592 */
593Datum
595{
596 XLogRecPtr start_lsn = PG_GETARG_LSN(0);
597 XLogRecPtr end_lsn = PG_GETARG_LSN(1);
598
599 ValidateInputLSNs(start_lsn, &end_lsn);
600 GetWALRecordsInfo(fcinfo, start_lsn, end_lsn);
601
603}
604
605/*
606 * Fill single row of record counts and sizes for an rmgr or record.
607 */
608static void
611 uint64 rec_len, uint64 total_rec_len,
612 uint64 fpi_len, uint64 total_fpi_len,
613 uint64 tot_len, uint64 total_len,
614 Datum *values, bool *nulls, uint32 ncols)
615{
616 double n_pct,
620 int i = 0;
621
622 n_pct = 0;
623 if (total_count != 0)
624 n_pct = 100 * (double) n / total_count;
625
626 rec_len_pct = 0;
627 if (total_rec_len != 0)
628 rec_len_pct = 100 * (double) rec_len / total_rec_len;
629
630 fpi_len_pct = 0;
631 if (total_fpi_len != 0)
632 fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
633
634 tot_len_pct = 0;
635 if (total_len != 0)
636 tot_len_pct = 100 * (double) tot_len / total_len;
637
639 values[i++] = Int64GetDatum(n);
641 values[i++] = Int64GetDatum(rec_len);
643 values[i++] = Int64GetDatum(fpi_len);
647
648 Assert(i == ncols);
649}
650
651/*
652 * Get summary statistics about the records seen so far.
653 */
654static void
656 Datum *values, bool *nulls, uint32 ncols,
657 bool stats_per_record)
658{
660 MemoryContext tmp_cxt;
664 uint64 total_len = 0;
665 int ri;
666
667 /*
668 * Each row shows its percentages of the total, so make a first pass to
669 * calculate column totals.
670 */
671 for (ri = 0; ri <= RM_MAX_ID; ri++)
672 {
673 if (!RmgrIdIsValid(ri))
674 continue;
675
676 total_count += stats->rmgr_stats[ri].count;
679 }
680 total_len = total_rec_len + total_fpi_len;
681
683 "GetXLogSummaryStats temporary cxt",
685
686 for (ri = 0; ri <= RM_MAX_ID; ri++)
687 {
688 uint64 count;
689 uint64 rec_len;
690 uint64 fpi_len;
692 RmgrData desc;
693
694 if (!RmgrIdIsValid(ri))
695 continue;
696
697 if (!RmgrIdExists(ri))
698 continue;
699
700 desc = GetRmgr(ri);
701
702 if (stats_per_record)
703 {
704 int rj;
705
706 for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
707 {
708 const char *id;
709
710 count = stats->record_stats[ri][rj].count;
711 rec_len = stats->record_stats[ri][rj].rec_len;
712 fpi_len = stats->record_stats[ri][rj].fpi_len;
713 tot_len = rec_len + fpi_len;
714
715 /* Skip undefined combinations and ones that didn't occur */
716 if (count == 0)
717 continue;
718
720
721 /* the upper four bits in xl_info are the rmgr's */
722 id = desc.rm_identify(rj << 4);
723 if (id == NULL)
724 id = psprintf("UNKNOWN (%x)", rj << 4);
725
726 FillXLogStatsRow(psprintf("%s/%s", desc.rm_name, id), count,
727 total_count, rec_len, total_rec_len, fpi_len,
728 total_fpi_len, tot_len, total_len,
729 values, nulls, ncols);
730
731 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
732 values, nulls);
733
734 /* clean up and switch back */
736 MemoryContextReset(tmp_cxt);
737 }
738 }
739 else
740 {
741 count = stats->rmgr_stats[ri].count;
742 rec_len = stats->rmgr_stats[ri].rec_len;
743 fpi_len = stats->rmgr_stats[ri].fpi_len;
744 tot_len = rec_len + fpi_len;
745
747
748 FillXLogStatsRow(desc.rm_name, count, total_count, rec_len,
750 total_len, values, nulls, ncols);
751
752 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
753 values, nulls);
754
755 /* clean up and switch back */
757 MemoryContextReset(tmp_cxt);
758 }
759 }
760
761 MemoryContextDelete(tmp_cxt);
762}
763
764/*
765 * Get WAL stats between start LSN and end LSN.
766 */
767static void
769 bool stats_per_record)
770{
771#define PG_GET_WAL_STATS_COLS 9
773 XLogStats stats = {0};
776 bool nulls[PG_GET_WAL_STATS_COLS] = {0};
777
778 Assert(start_lsn <= end_lsn);
779
780 InitMaterializedSRF(fcinfo, 0);
781
782 xlogreader = InitXLogReaderState(start_lsn);
783
785 xlogreader->EndRecPtr <= end_lsn)
786 {
788
790 }
791
794
795 GetXLogSummaryStats(&stats, rsinfo, values, nulls,
797 stats_per_record);
798
799#undef PG_GET_WAL_STATS_COLS
800}
801
802/*
803 * Get stats of all WAL records between start LSN and end LSN.
804 */
805Datum
807{
808 XLogRecPtr start_lsn = PG_GETARG_LSN(0);
809 XLogRecPtr end_lsn = PG_GETARG_LSN(1);
810 bool stats_per_record = PG_GETARG_BOOL(2);
811
812 ValidateInputLSNs(start_lsn, &end_lsn);
813 GetWalStats(fcinfo, start_lsn, end_lsn, stats_per_record);
814
816}
817
818/*
819 * The following functions have been removed in newer versions in 1.1, but
820 * they are kept around for compatibility.
821 */
822Datum
824{
825 XLogRecPtr start_lsn = PG_GETARG_LSN(0);
826 XLogRecPtr end_lsn = GetCurrentLSN();
827
828 if (start_lsn > end_lsn)
831 errmsg("WAL start LSN must be less than current LSN"),
832 errdetail("Current WAL LSN on the database system is at %X/%08X.",
833 LSN_FORMAT_ARGS(end_lsn))));
834
835 GetWALRecordsInfo(fcinfo, start_lsn, end_lsn);
836
838}
839
840Datum
842{
843 XLogRecPtr start_lsn = PG_GETARG_LSN(0);
844 XLogRecPtr end_lsn = GetCurrentLSN();
845 bool stats_per_record = PG_GETARG_BOOL(1);
846
847 if (start_lsn > end_lsn)
850 errmsg("WAL start LSN must be less than current LSN"),
851 errdetail("Current WAL LSN on the database system is at %X/%08X.",
852 LSN_FORMAT_ARGS(end_lsn))));
853
854 GetWalStats(fcinfo, start_lsn, end_lsn, stats_per_record);
855
857}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
uint32 BlockNumber
Definition block.h:31
static Datum values[MAXATTR]
Definition bootstrap.c:188
PageData * Page
Definition bufpage.h:81
#define CStringGetTextDatum(s)
Definition builtins.h:98
uint8_t uint8
Definition c.h:616
#define VARHDRSZ
Definition c.h:783
#define Assert(condition)
Definition c.h:945
int64_t int64
Definition c.h:615
uint64_t uint64
Definition c.h:619
uint32_t uint32
Definition c.h:618
int errcode_for_file_access(void)
Definition elog.c:897
int errcode(int sqlerrcode)
Definition elog.c:874
int errdetail(const char *fmt,...) pg_attribute_printf(1
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define palloc0_object(type)
Definition fe_memutils.h:75
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_MODULE_MAGIC_EXT(...)
Definition fmgr.h:540
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_GETARG_BOOL(n)
Definition fmgr.h:274
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition funcapi.c:76
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition funcapi.h:149
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition funcapi.h:230
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1037
int i
Definition isn.c:77
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static uint64 pg_popcount(const char *buf, int bytes)
#define PG_GETARG_LSN(n)
Definition pg_lsn.h:36
static Datum LSNGetDatum(XLogRecPtr X)
Definition pg_lsn.h:31
static char buf[DEFAULT_XLOG_SEG_SIZE]
static void GetWALRecordInfo(XLogReaderState *record, Datum *values, bool *nulls, uint32 ncols)
#define PG_GET_WAL_STATS_COLS
Datum pg_get_wal_records_info(PG_FUNCTION_ARGS)
Datum pg_get_wal_stats(PG_FUNCTION_ARGS)
static void GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn, XLogRecPtr end_lsn, bool stats_per_record)
#define PG_GET_WAL_RECORDS_INFO_COLS
#define PG_GET_WAL_RECORD_INFO_COLS
static void GetWALBlockInfo(FunctionCallInfo fcinfo, XLogReaderState *record, bool show_data)
Datum pg_get_wal_block_info(PG_FUNCTION_ARGS)
static void GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
Datum pg_get_wal_records_info_till_end_of_wal(PG_FUNCTION_ARGS)
#define PG_GET_WAL_BLOCK_INFO_COLS
static XLogRecord * ReadNextXLogRecord(XLogReaderState *xlogreader)
static XLogReaderState * InitXLogReaderState(XLogRecPtr lsn)
Datum pg_get_wal_stats_till_end_of_wal(PG_FUNCTION_ARGS)
static void GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo, Datum *values, bool *nulls, uint32 ncols, bool stats_per_record)
static void FillXLogStatsRow(const char *name, uint64 n, uint64 total_count, uint64 rec_len, uint64 total_rec_len, uint64 fpi_len, uint64 total_fpi_len, uint64 tot_len, uint64 total_len, Datum *values, bool *nulls, uint32 ncols)
static void ValidateInputLSNs(XLogRecPtr start_lsn, XLogRecPtr *end_lsn)
Datum pg_get_wal_record_info(PG_FUNCTION_ARGS)
static XLogRecPtr GetCurrentLSN(void)
static Datum Int64GetDatum(int64 X)
Definition postgres.h:413
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Datum TransactionIdGetDatum(TransactionId X)
Definition postgres.h:292
static Datum Int16GetDatum(int16 X)
Definition postgres.h:172
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Datum Float8GetDatum(float8 X)
Definition postgres.h:502
static Datum UInt32GetDatum(uint32 X)
Definition postgres.h:232
static int fb(int x)
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
ForkNumber
Definition relpath.h:56
#define RmgrIdIsValid(rmid)
Definition rmgr.h:53
#define RM_MAX_ID
Definition rmgr.h:33
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
const char *(* rm_identify)(uint8 info)
const char * rm_name
void(* rm_desc)(StringInfo buf, XLogReaderState *record)
char * errormsg_buf
Definition xlogreader.h:310
XLogRecPtr EndRecPtr
Definition xlogreader.h:206
XLogRecPtr ReadRecPtr
Definition xlogreader.h:205
void * private_data
Definition xlogreader.h:195
uint64 count
Definition xlogstats.h:23
uint64 fpi_len
Definition xlogstats.h:25
uint64 rec_len
Definition xlogstats.h:24
XLogRecStats record_stats[RM_MAX_ID+1][MAX_XLINFO_TYPES]
Definition xlogstats.h:36
XLogRecStats rmgr_stats[RM_MAX_ID+1]
Definition xlogstats.h:35
Definition c.h:778
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:785
static char * VARDATA(const void *PTR)
Definition varatt.h:305
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432
const char * name
bool RecoveryInProgress(void)
Definition xlog.c:6444
int wal_segment_size
Definition xlog.c:147
XLogRecPtr GetFlushRecPtr(TimeLineID *insertTLI)
Definition xlog.c:6609
static RmgrData GetRmgr(RmgrId rmid)
static bool RmgrIdExists(RmgrId rmid)
#define XLogRecPtrIsValid(r)
Definition xlogdefs.h:29
#define LSN_FORMAT_ARGS(lsn)
Definition xlogdefs.h:47
uint64 XLogRecPtr
Definition xlogdefs.h:21
void XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty, bool detailed_format, StringInfo buf, uint32 *fpi_len)
Definition xlogdesc.c:249
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition xlogreader.c:108
XLogRecord * XLogReadRecord(XLogReaderState *state, char **errormsg)
Definition xlogreader.c:391
void XLogReaderFree(XLogReaderState *state)
Definition xlogreader.c:163
XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
#define XLogRecGetDataLen(decoder)
Definition xlogreader.h:415
#define XLogRecGetInfo(decoder)
Definition xlogreader.h:409
#define XLogRecGetRmid(decoder)
Definition xlogreader.h:410
#define XLogRecGetTotalLen(decoder)
Definition xlogreader.h:407
#define XLogRecGetXid(decoder)
Definition xlogreader.h:411
#define XLogRecGetBlock(decoder, i)
Definition xlogreader.h:418
#define XL_ROUTINE(...)
Definition xlogreader.h:117
#define XLogRecMaxBlockId(decoder)
Definition xlogreader.h:417
#define XLogRecHasBlockRef(decoder, block_id)
Definition xlogreader.h:419
#define XLogRecGetPrev(decoder)
Definition xlogreader.h:408
#define XLogRecHasAnyBlockRefs(decoder)
Definition xlogreader.h:416
#define BKPIMAGE_COMPRESS_ZSTD
Definition xlogrecord.h:162
#define BKPIMAGE_HAS_HOLE
Definition xlogrecord.h:157
#define BKPIMAGE_COMPRESS_LZ4
Definition xlogrecord.h:161
#define XLR_INFO_MASK
Definition xlogrecord.h:62
#define BKPIMAGE_COMPRESS_PGLZ
Definition xlogrecord.h:160
XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI)
static XLogReaderState * xlogreader
void XLogRecStoreStats(XLogStats *stats, XLogReaderState *record)
Definition xlogstats.c:54
#define MAX_XLINFO_TYPES
Definition xlogstats.h:19
void wal_segment_close(XLogReaderState *state)
Definition xlogutils.c:831
void wal_segment_open(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
Definition xlogutils.c:806
int read_local_xlog_page_no_wait(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *cur_page)
Definition xlogutils.c:857