PostgreSQL Source Code  git master
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, 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/xlog.h"
16 #include "access/xlog_internal.h"
17 #include "access/xlogreader.h"
18 #include "access/xlogrecovery.h"
19 #include "access/xlogstats.h"
20 #include "access/xlogutils.h"
21 #include "funcapi.h"
22 #include "miscadmin.h"
23 #include "utils/builtins.h"
24 #include "utils/pg_lsn.h"
25 
26 /*
27  * NOTE: For any code change or issue fix here, it is highly recommended to
28  * give a thought about doing the same in pg_waldump tool as well.
29  */
30 
32 
38 
39 static bool IsFutureLSN(XLogRecPtr lsn, XLogRecPtr *curr_lsn);
41  XLogRecPtr *first_record);
43  XLogRecPtr first_record);
44 static void GetWALRecordInfo(XLogReaderState *record, XLogRecPtr lsn,
45  Datum *values, bool *nulls, uint32 ncols);
46 static XLogRecPtr ValidateInputLSNs(bool till_end_of_wal,
47  XLogRecPtr start_lsn, XLogRecPtr end_lsn);
48 static void GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
49  XLogRecPtr end_lsn);
50 static void GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
51  Datum *values, bool *nulls, uint32 ncols,
52  bool stats_per_record);
53 static void FillXLogStatsRow(const char *name, uint64 n, uint64 total_count,
54  uint64 rec_len, uint64 total_rec_len,
55  uint64 fpi_len, uint64 total_fpi_len,
56  uint64 tot_len, uint64 total_len,
57  Datum *values, bool *nulls, uint32 ncols);
58 static void GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
59  XLogRecPtr end_lsn, bool stats_per_record);
60 
61 /*
62  * Check if the given LSN is in future. Also, return the LSN up to which the
63  * server has WAL.
64  */
65 static bool
67 {
68  /*
69  * We determine the current LSN of the server similar to how page_read
70  * callback read_local_xlog_page_no_wait does.
71  */
72  if (!RecoveryInProgress())
73  *curr_lsn = GetFlushRecPtr(NULL);
74  else
75  *curr_lsn = GetXLogReplayRecPtr(NULL);
76 
77  Assert(!XLogRecPtrIsInvalid(*curr_lsn));
78 
79  if (lsn >= *curr_lsn)
80  return true;
81 
82  return false;
83 }
84 
85 /*
86  * Intialize WAL reader and identify first valid LSN.
87  */
88 static XLogReaderState *
90 {
92  ReadLocalXLogPageNoWaitPrivate *private_data;
93 
94  /*
95  * Reading WAL below the first page of the first segments isn't allowed.
96  * This is a bootstrap WAL page and the page_read callback fails to read
97  * it.
98  */
99  if (lsn < XLOG_BLCKSZ)
100  ereport(ERROR,
101  (errmsg("could not read WAL at LSN %X/%X",
102  LSN_FORMAT_ARGS(lsn))));
103 
104  private_data = (ReadLocalXLogPageNoWaitPrivate *)
106 
109  .segment_open = &wal_segment_open,
110  .segment_close = &wal_segment_close),
111  private_data);
112 
113  if (xlogreader == NULL)
114  ereport(ERROR,
115  (errcode(ERRCODE_OUT_OF_MEMORY),
116  errmsg("out of memory"),
117  errdetail("Failed while allocating a WAL reading processor.")));
118 
119  /* first find a valid recptr to start from */
120  *first_record = XLogFindNextRecord(xlogreader, lsn);
121 
122  if (XLogRecPtrIsInvalid(*first_record))
123  ereport(ERROR,
124  (errmsg("could not find a valid record after %X/%X",
125  LSN_FORMAT_ARGS(lsn))));
126 
127  return xlogreader;
128 }
129 
130 /*
131  * Read next WAL record.
132  *
133  * By design, to be less intrusive in a running system, no slot is allocated
134  * to reserve the WAL we're about to read. Therefore this function can
135  * encounter read errors for historical WAL.
136  *
137  * We guard against ordinary errors trying to read WAL that hasn't been
138  * written yet by limiting end_lsn to the flushed WAL, but that can also
139  * encounter errors if the flush pointer falls in the middle of a record. In
140  * that case we'll return NULL.
141  */
142 static XLogRecord *
144 {
145  XLogRecord *record;
146  char *errormsg;
147 
148  record = XLogReadRecord(xlogreader, &errormsg);
149 
150  if (record == NULL)
151  {
152  ReadLocalXLogPageNoWaitPrivate *private_data;
153 
154  /* return NULL, if end of WAL is reached */
155  private_data = (ReadLocalXLogPageNoWaitPrivate *)
157 
158  if (private_data->end_of_wal)
159  return NULL;
160 
161  if (errormsg)
162  ereport(ERROR,
164  errmsg("could not read WAL at %X/%X: %s",
165  LSN_FORMAT_ARGS(first_record), errormsg)));
166  else
167  ereport(ERROR,
169  errmsg("could not read WAL at %X/%X",
170  LSN_FORMAT_ARGS(first_record))));
171  }
172 
173  return record;
174 }
175 
176 /*
177  * Get a single WAL record info.
178  */
179 static void
181  Datum *values, bool *nulls, uint32 ncols)
182 {
183  const char *id;
184  RmgrData desc;
185  uint32 fpi_len = 0;
186  StringInfoData rec_desc;
187  StringInfoData rec_blk_ref;
188  uint32 main_data_len;
189  int i = 0;
190 
191  desc = GetRmgr(XLogRecGetRmid(record));
192  id = desc.rm_identify(XLogRecGetInfo(record));
193 
194  if (id == NULL)
195  id = psprintf("UNKNOWN (%x)", XLogRecGetInfo(record) & ~XLR_INFO_MASK);
196 
197  initStringInfo(&rec_desc);
198  desc.rm_desc(&rec_desc, record);
199 
200  /* Block references. */
201  initStringInfo(&rec_blk_ref);
202  XLogRecGetBlockRefInfo(record, false, true, &rec_blk_ref, &fpi_len);
203 
204  main_data_len = XLogRecGetDataLen(record);
205 
206  values[i++] = LSNGetDatum(lsn);
207  values[i++] = LSNGetDatum(record->EndRecPtr);
208  values[i++] = LSNGetDatum(XLogRecGetPrev(record));
210  values[i++] = CStringGetTextDatum(desc.rm_name);
211  values[i++] = CStringGetTextDatum(id);
213  values[i++] = UInt32GetDatum(main_data_len);
214  values[i++] = UInt32GetDatum(fpi_len);
215  values[i++] = CStringGetTextDatum(rec_desc.data);
216  values[i++] = CStringGetTextDatum(rec_blk_ref.data);
217 
218  Assert(i == ncols);
219 }
220 
221 /*
222  * Get WAL record info.
223  *
224  * This function emits an error if a future WAL LSN i.e. WAL LSN the database
225  * system doesn't know about is specified.
226  */
227 Datum
229 {
230 #define PG_GET_WAL_RECORD_INFO_COLS 11
231  Datum result;
233  bool nulls[PG_GET_WAL_RECORD_INFO_COLS];
234  XLogRecPtr lsn;
235  XLogRecPtr curr_lsn;
236  XLogRecPtr first_record;
238  TupleDesc tupdesc;
239  HeapTuple tuple;
240 
241  lsn = PG_GETARG_LSN(0);
242 
243  if (IsFutureLSN(lsn, &curr_lsn))
244  {
245  /*
246  * GetFlushRecPtr or GetXLogReplayRecPtr gives "end+1" LSN of the last
247  * record flushed or replayed respectively. But let's use the LSN up
248  * to "end" in user facing message.
249  */
250  ereport(ERROR,
251  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
252  errmsg("cannot accept future input LSN"),
253  errdetail("Last known WAL LSN on the database system is at %X/%X.",
254  LSN_FORMAT_ARGS(curr_lsn))));
255  }
256 
257  /* Build a tuple descriptor for our result type. */
258  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
259  elog(ERROR, "return type must be a row type");
260 
261  xlogreader = InitXLogReaderState(lsn, &first_record);
262 
263  if (!ReadNextXLogRecord(xlogreader, first_record))
264  ereport(ERROR,
265  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
266  errmsg("could not read WAL at %X/%X",
267  LSN_FORMAT_ARGS(first_record))));
268 
269  MemSet(values, 0, sizeof(values));
270  MemSet(nulls, 0, sizeof(nulls));
271 
272  GetWALRecordInfo(xlogreader, first_record, values, nulls,
274 
277 
278  tuple = heap_form_tuple(tupdesc, values, nulls);
279  result = HeapTupleGetDatum(tuple);
280 
281  PG_RETURN_DATUM(result);
282 #undef PG_GET_WAL_RECORD_INFO_COLS
283 }
284 
285 /*
286  * Validate the input LSNs and compute end LSN for till_end_of_wal versions.
287  */
288 static XLogRecPtr
289 ValidateInputLSNs(bool till_end_of_wal, XLogRecPtr start_lsn,
290  XLogRecPtr end_lsn)
291 {
292  XLogRecPtr curr_lsn;
293 
294  if (IsFutureLSN(start_lsn, &curr_lsn))
295  {
296  /*
297  * GetFlushRecPtr or GetXLogReplayRecPtr gives "end+1" LSN of the last
298  * record flushed or replayed respectively. But let's use the LSN up
299  * to "end" in user facing message.
300  */
301  ereport(ERROR,
302  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
303  errmsg("cannot accept future start LSN"),
304  errdetail("Last known WAL LSN on the database system is at %X/%X.",
305  LSN_FORMAT_ARGS(curr_lsn))));
306  }
307 
308  if (till_end_of_wal)
309  end_lsn = curr_lsn;
310 
311  if (end_lsn > curr_lsn)
312  ereport(ERROR,
313  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
314  errmsg("cannot accept future end LSN"),
315  errdetail("Last known WAL LSN on the database system is at %X/%X.",
316  LSN_FORMAT_ARGS(curr_lsn))));
317 
318  if (start_lsn >= end_lsn)
319  ereport(ERROR,
320  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
321  errmsg("WAL start LSN must be less than end LSN")));
322 
323  return end_lsn;
324 }
325 
326 /*
327  * Get info and data of all WAL records between start LSN and end LSN.
328  */
329 static void
331  XLogRecPtr end_lsn)
332 {
333 #define PG_GET_WAL_RECORDS_INFO_COLS 11
334  XLogRecPtr first_record;
336  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
338  bool nulls[PG_GET_WAL_RECORDS_INFO_COLS];
339 
340  SetSingleFuncCall(fcinfo, 0);
341 
342  xlogreader = InitXLogReaderState(start_lsn, &first_record);
343 
345 
346  MemSet(values, 0, sizeof(values));
347  MemSet(nulls, 0, sizeof(nulls));
348 
349  while (ReadNextXLogRecord(xlogreader, first_record) &&
350  xlogreader->EndRecPtr <= end_lsn)
351  {
354 
355  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
356  values, nulls);
357 
359  }
360 
363 
364 #undef PG_GET_WAL_RECORDS_INFO_COLS
365 }
366 
367 /*
368  * Get info and data of all WAL records between start LSN and end LSN.
369  *
370  * This function emits an error if a future start or end WAL LSN i.e. WAL LSN
371  * the database system doesn't know about is specified.
372  */
373 Datum
375 {
376  XLogRecPtr start_lsn;
377  XLogRecPtr end_lsn;
378 
379  start_lsn = PG_GETARG_LSN(0);
380  end_lsn = PG_GETARG_LSN(1);
381 
382  end_lsn = ValidateInputLSNs(false, start_lsn, end_lsn);
383 
384  GetWALRecordsInfo(fcinfo, start_lsn, end_lsn);
385 
386  PG_RETURN_VOID();
387 }
388 
389 /*
390  * Get info and data of all WAL records from start LSN till end of WAL.
391  *
392  * This function emits an error if a future start i.e. WAL LSN the database
393  * system doesn't know about is specified.
394  */
395 Datum
397 {
398  XLogRecPtr start_lsn;
399  XLogRecPtr end_lsn = InvalidXLogRecPtr;
400 
401  start_lsn = PG_GETARG_LSN(0);
402 
403  end_lsn = ValidateInputLSNs(true, start_lsn, end_lsn);
404 
405  GetWALRecordsInfo(fcinfo, start_lsn, end_lsn);
406 
407  PG_RETURN_VOID();
408 }
409 
410 /*
411  * Fill single row of record counts and sizes for an rmgr or record.
412  */
413 static void
414 FillXLogStatsRow(const char *name,
415  uint64 n, uint64 total_count,
416  uint64 rec_len, uint64 total_rec_len,
417  uint64 fpi_len, uint64 total_fpi_len,
418  uint64 tot_len, uint64 total_len,
419  Datum *values, bool *nulls, uint32 ncols)
420 {
421  double n_pct,
422  rec_len_pct,
423  fpi_len_pct,
424  tot_len_pct;
425  int i = 0;
426 
427  n_pct = 0;
428  if (total_count != 0)
429  n_pct = 100 * (double) n / total_count;
430 
431  rec_len_pct = 0;
432  if (total_rec_len != 0)
433  rec_len_pct = 100 * (double) rec_len / total_rec_len;
434 
435  fpi_len_pct = 0;
436  if (total_fpi_len != 0)
437  fpi_len_pct = 100 * (double) fpi_len / total_fpi_len;
438 
439  tot_len_pct = 0;
440  if (total_len != 0)
441  tot_len_pct = 100 * (double) tot_len / total_len;
442 
444  values[i++] = Int64GetDatum(n);
445  values[i++] = Float4GetDatum(n_pct);
446  values[i++] = Int64GetDatum(rec_len);
447  values[i++] = Float4GetDatum(rec_len_pct);
448  values[i++] = Int64GetDatum(fpi_len);
449  values[i++] = Float4GetDatum(fpi_len_pct);
450  values[i++] = Int64GetDatum(tot_len);
451  values[i++] = Float4GetDatum(tot_len_pct);
452 
453  Assert(i == ncols);
454 }
455 
456 /*
457  * Get summary statistics about the records seen so far.
458  */
459 static void
461  Datum *values, bool *nulls, uint32 ncols,
462  bool stats_per_record)
463 {
464  uint64 total_count = 0;
465  uint64 total_rec_len = 0;
466  uint64 total_fpi_len = 0;
467  uint64 total_len = 0;
468  int ri;
469 
470  /*
471  * Each row shows its percentages of the total, so make a first pass to
472  * calculate column totals.
473  */
474  for (ri = 0; ri <= RM_MAX_ID; ri++)
475  {
476  if (!RmgrIdIsValid(ri))
477  continue;
478 
479  total_count += stats->rmgr_stats[ri].count;
480  total_rec_len += stats->rmgr_stats[ri].rec_len;
481  total_fpi_len += stats->rmgr_stats[ri].fpi_len;
482  }
483  total_len = total_rec_len + total_fpi_len;
484 
485  for (ri = 0; ri <= RM_MAX_ID; ri++)
486  {
487  uint64 count;
488  uint64 rec_len;
489  uint64 fpi_len;
490  uint64 tot_len;
491  RmgrData desc;
492 
493  if (!RmgrIdIsValid(ri))
494  continue;
495 
496  if (!RmgrIdExists(ri))
497  continue;
498 
499  desc = GetRmgr(ri);
500 
501  if (stats_per_record)
502  {
503  int rj;
504 
505  for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
506  {
507  const char *id;
508 
509  count = stats->record_stats[ri][rj].count;
510  rec_len = stats->record_stats[ri][rj].rec_len;
511  fpi_len = stats->record_stats[ri][rj].fpi_len;
512  tot_len = rec_len + fpi_len;
513 
514  /* Skip undefined combinations and ones that didn't occur */
515  if (count == 0)
516  continue;
517 
518  /* the upper four bits in xl_info are the rmgr's */
519  id = desc.rm_identify(rj << 4);
520  if (id == NULL)
521  id = psprintf("UNKNOWN (%x)", rj << 4);
522 
523  FillXLogStatsRow(psprintf("%s/%s", desc.rm_name, id), count,
524  total_count, rec_len, total_rec_len, fpi_len,
525  total_fpi_len, tot_len, total_len,
526  values, nulls, ncols);
527 
528  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
529  values, nulls);
530  }
531  }
532  else
533  {
534  count = stats->rmgr_stats[ri].count;
535  rec_len = stats->rmgr_stats[ri].rec_len;
536  fpi_len = stats->rmgr_stats[ri].fpi_len;
537  tot_len = rec_len + fpi_len;
538 
539  FillXLogStatsRow(desc.rm_name, count, total_count, rec_len,
540  total_rec_len, fpi_len, total_fpi_len, tot_len,
541  total_len, values, nulls, ncols);
542 
543  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
544  values, nulls);
545  }
546  }
547 }
548 
549 /*
550  * Get WAL stats between start LSN and end LSN.
551  */
552 static void
554  XLogRecPtr end_lsn, bool stats_per_record)
555 {
556 #define PG_GET_WAL_STATS_COLS 9
557  XLogRecPtr first_record;
559  XLogStats stats;
560  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
562  bool nulls[PG_GET_WAL_STATS_COLS];
563 
564  SetSingleFuncCall(fcinfo, 0);
565 
566  xlogreader = InitXLogReaderState(start_lsn, &first_record);
567 
568  MemSet(&stats, 0, sizeof(stats));
569 
570  while (ReadNextXLogRecord(xlogreader, first_record) &&
571  xlogreader->EndRecPtr <= end_lsn)
572  {
573  XLogRecStoreStats(&stats, xlogreader);
574 
576  }
577 
580 
581  MemSet(values, 0, sizeof(values));
582  MemSet(nulls, 0, sizeof(nulls));
583 
584  GetXLogSummaryStats(&stats, rsinfo, values, nulls,
586  stats_per_record);
587 
588 #undef PG_GET_WAL_STATS_COLS
589 }
590 
591 /*
592  * Get stats of all WAL records between start LSN and end LSN.
593  *
594  * This function emits an error if a future start or end WAL LSN i.e. WAL LSN
595  * the database system doesn't know about is specified.
596  */
597 Datum
599 {
600  XLogRecPtr start_lsn;
601  XLogRecPtr end_lsn;
602  bool stats_per_record;
603 
604  start_lsn = PG_GETARG_LSN(0);
605  end_lsn = PG_GETARG_LSN(1);
606  stats_per_record = PG_GETARG_BOOL(2);
607 
608  end_lsn = ValidateInputLSNs(false, start_lsn, end_lsn);
609 
610  GetWalStats(fcinfo, start_lsn, end_lsn, stats_per_record);
611 
612  PG_RETURN_VOID();
613 }
614 
615 /*
616  * Get stats of all WAL records from start LSN till end of WAL.
617  *
618  * This function emits an error if a future start i.e. WAL LSN the database
619  * system doesn't know about is specified.
620  */
621 Datum
623 {
624  XLogRecPtr start_lsn;
625  XLogRecPtr end_lsn = InvalidXLogRecPtr;
626  bool stats_per_record;
627 
628  start_lsn = PG_GETARG_LSN(0);
629  stats_per_record = PG_GETARG_BOOL(1);
630 
631  end_lsn = ValidateInputLSNs(true, start_lsn, end_lsn);
632 
633  GetWalStats(fcinfo, start_lsn, end_lsn, stats_per_record);
634 
635  PG_RETURN_VOID();
636 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:85
unsigned int uint32
Definition: c.h:441
#define MemSet(start, val, len)
Definition: c.h:1008
int errcode_for_file_access(void)
Definition: elog.c:716
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define ereport(elevel,...)
Definition: elog.h:143
const char * name
Definition: encode.c:561
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1683
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
void SetSingleFuncCall(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
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
void pfree(void *pointer)
Definition: mcxt.c:1175
void * palloc0(Size size)
Definition: mcxt.c:1099
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
#define PG_GETARG_LSN(n)
Definition: pg_lsn.h:24
#define LSNGetDatum(X)
Definition: pg_lsn.h:22
PG_FUNCTION_INFO_V1(pg_get_wal_record_info)
static XLogRecord * ReadNextXLogRecord(XLogReaderState *xlogreader, XLogRecPtr first_record)
#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 GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
static bool IsFutureLSN(XLogRecPtr lsn, XLogRecPtr *curr_lsn)
Definition: pg_walinspect.c:66
Datum pg_get_wal_records_info_till_end_of_wal(PG_FUNCTION_ARGS)
PG_MODULE_MAGIC
Definition: pg_walinspect.c:31
static XLogReaderState * InitXLogReaderState(XLogRecPtr lsn, XLogRecPtr *first_record)
Definition: pg_walinspect.c:89
static void GetWALRecordInfo(XLogReaderState *record, XLogRecPtr lsn, Datum *values, bool *nulls, uint32 ncols)
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 XLogRecPtr ValidateInputLSNs(bool till_end_of_wal, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
Datum pg_get_wal_record_info(PG_FUNCTION_ARGS)
#define TransactionIdGetDatum(X)
Definition: postgres.h:565
#define UInt32GetDatum(X)
Definition: postgres.h:537
static Datum Float4GetDatum(float4 X)
Definition: postgres.h:725
uintptr_t Datum
Definition: postgres.h:411
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define RmgrIdIsValid(rmid)
Definition: rmgr.h:53
#define RM_MAX_ID
Definition: rmgr.h:33
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
fmNodePtr resultinfo
Definition: fmgr.h:89
TupleDesc setDesc
Definition: execnodes.h:317
Tuplestorestate * setResult
Definition: execnodes.h:316
const char *(* rm_identify)(uint8 info)
const char * rm_name
void(* rm_desc)(StringInfo buf, XLogReaderState *record)
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
XLogRecPtr currRecPtr
Definition: xlogreader.h:283
void * private_data
Definition: xlogreader.h:196
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
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
bool RecoveryInProgress(void)
Definition: xlog.c:5762
int wal_segment_size
Definition: xlog.c:144
XLogRecPtr GetFlushRecPtr(TimeLineID *insertTLI)
Definition: xlog.c:5927
static RmgrData GetRmgr(RmgrId rmid)
static bool RmgrIdExists(RmgrId rmid)
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:43
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
void XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty, bool detailed_format, StringInfo buf, uint32 *fpi_len)
Definition: xlogdesc.c:209
XLogRecord * XLogReadRecord(XLogReaderState *state, char **errormsg)
Definition: xlogreader.c:418
void XLogReaderFree(XLogReaderState *state)
Definition: xlogreader.c:170
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition: xlogreader.c:108
XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
Definition: xlogreader.c:1337
#define XLogRecGetDataLen(decoder)
Definition: xlogreader.h:414
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:408
#define XLogRecGetRmid(decoder)
Definition: xlogreader.h:409
#define XLogRecGetTotalLen(decoder)
Definition: xlogreader.h:406
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:410
#define XL_ROUTINE(...)
Definition: xlogreader.h:117
#define XLogRecGetPrev(decoder)
Definition: xlogreader.h:407
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI)
static XLogReaderState * xlogreader
Definition: xlogrecovery.c:185
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:856
void wal_segment_open(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
Definition: xlogutils.c:831
int read_local_xlog_page_no_wait(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *cur_page)
Definition: xlogutils.c:887