PostgreSQL Source Code  git master
xloginsert.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * xloginsert.c
4  * Functions for constructing WAL records
5  *
6  * Constructing a WAL record begins with a call to XLogBeginInsert,
7  * followed by a number of XLogRegister* calls. The registered data is
8  * collected in private working memory, and finally assembled into a chain
9  * of XLogRecData structs by a call to XLogRecordAssemble(). See
10  * access/transam/README for details.
11  *
12  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  * src/backend/access/transam/xloginsert.c
16  *
17  *-------------------------------------------------------------------------
18  */
19 
20 #include "postgres.h"
21 
22 #ifdef USE_LZ4
23 #include <lz4.h>
24 #endif
25 
26 #ifdef USE_ZSTD
27 #include <zstd.h>
28 #endif
29 
30 #include "access/xact.h"
31 #include "access/xlog.h"
32 #include "access/xlog_internal.h"
33 #include "access/xloginsert.h"
34 #include "catalog/pg_control.h"
35 #include "common/pg_lzcompress.h"
36 #include "executor/instrument.h"
37 #include "miscadmin.h"
38 #include "pg_trace.h"
39 #include "replication/origin.h"
40 #include "storage/bufmgr.h"
41 #include "storage/proc.h"
42 #include "utils/memutils.h"
43 
44 /*
45  * Guess the maximum buffer size required to store a compressed version of
46  * backup block image.
47  */
48 #ifdef USE_LZ4
49 #define LZ4_MAX_BLCKSZ LZ4_COMPRESSBOUND(BLCKSZ)
50 #else
51 #define LZ4_MAX_BLCKSZ 0
52 #endif
53 
54 #ifdef USE_ZSTD
55 #define ZSTD_MAX_BLCKSZ ZSTD_COMPRESSBOUND(BLCKSZ)
56 #else
57 #define ZSTD_MAX_BLCKSZ 0
58 #endif
59 
60 #define PGLZ_MAX_BLCKSZ PGLZ_MAX_OUTPUT(BLCKSZ)
61 
62 /* Buffer size required to store a compressed version of backup block image */
63 #define COMPRESS_BUFSIZE Max(Max(PGLZ_MAX_BLCKSZ, LZ4_MAX_BLCKSZ), ZSTD_MAX_BLCKSZ)
64 
65 /*
66  * For each block reference registered with XLogRegisterBuffer, we fill in
67  * a registered_buffer struct.
68  */
69 typedef struct
70 {
71  bool in_use; /* is this slot in use? */
72  uint8 flags; /* REGBUF_* flags */
73  RelFileLocator rlocator; /* identifies the relation and block */
76  Page page; /* page content */
77  uint32 rdata_len; /* total length of data in rdata chain */
78  XLogRecData *rdata_head; /* head of the chain of data registered with
79  * this block */
80  XLogRecData *rdata_tail; /* last entry in the chain, or &rdata_head if
81  * empty */
82 
83  XLogRecData bkp_rdatas[2]; /* temporary rdatas used to hold references to
84  * backup block data in XLogRecordAssemble() */
85 
86  /* buffer to store a compressed version of backup block image */
87  char compressed_page[COMPRESS_BUFSIZE];
89 
91 static int max_registered_buffers; /* allocated size */
92 static int max_registered_block_id = 0; /* highest block_id + 1 currently
93  * registered */
94 
95 /*
96  * A chain of XLogRecDatas to hold the "main data" of a WAL record, registered
97  * with XLogRegisterData(...).
98  */
101 static uint64 mainrdata_len; /* total # of bytes in chain */
102 
103 /* flags for the in-progress insertion */
105 
106 /*
107  * These are used to hold the record header while constructing a record.
108  * 'hdr_scratch' is not a plain variable, but is palloc'd at initialization,
109  * because we want it to be MAXALIGNed and padding bytes zeroed.
110  *
111  * For simplicity, it's allocated large enough to hold the headers for any
112  * WAL record.
113  */
115 static char *hdr_scratch = NULL;
116 
117 #define SizeOfXlogOrigin (sizeof(RepOriginId) + sizeof(char))
118 #define SizeOfXLogTransactionId (sizeof(TransactionId) + sizeof(char))
119 
120 #define HEADER_SCRATCH_SIZE \
121  (SizeOfXLogRecord + \
122  MaxSizeOfXLogRecordBlockHeader * (XLR_MAX_BLOCK_ID + 1) + \
123  SizeOfXLogRecordDataHeaderLong + SizeOfXlogOrigin + \
124  SizeOfXLogTransactionId)
125 
126 /*
127  * An array of XLogRecData structs, to hold registered data.
128  */
130 static int num_rdatas; /* entries currently used */
131 static int max_rdatas; /* allocated size */
132 
133 static bool begininsert_called = false;
134 
135 /* Memory context to hold the registered buffer and data references. */
137 
138 static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
140  XLogRecPtr *fpw_lsn, int *num_fpi,
141  bool *topxid_included);
142 static bool XLogCompressBackupBlock(char *page, uint16 hole_offset,
143  uint16 hole_length, char *dest, uint16 *dlen);
144 
145 /*
146  * Begin constructing a WAL record. This must be called before the
147  * XLogRegister* functions and XLogInsert().
148  */
149 void
151 {
154  Assert(mainrdata_len == 0);
155 
156  /* cross-check on whether we should be here or not */
157  if (!XLogInsertAllowed())
158  elog(ERROR, "cannot make new WAL entries during recovery");
159 
160  if (begininsert_called)
161  elog(ERROR, "XLogBeginInsert was already called");
162 
163  begininsert_called = true;
164 }
165 
166 /*
167  * Ensure that there are enough buffer and data slots in the working area,
168  * for subsequent XLogRegisterBuffer, XLogRegisterData and XLogRegisterBufData
169  * calls.
170  *
171  * There is always space for a small number of buffers and data chunks, enough
172  * for most record types. This function is for the exceptional cases that need
173  * more.
174  */
175 void
176 XLogEnsureRecordSpace(int max_block_id, int ndatas)
177 {
178  int nbuffers;
179 
180  /*
181  * This must be called before entering a critical section, because
182  * allocating memory inside a critical section can fail. repalloc() will
183  * check the same, but better to check it here too so that we fail
184  * consistently even if the arrays happen to be large enough already.
185  */
186  Assert(CritSectionCount == 0);
187 
188  /* the minimum values can't be decreased */
189  if (max_block_id < XLR_NORMAL_MAX_BLOCK_ID)
190  max_block_id = XLR_NORMAL_MAX_BLOCK_ID;
191  if (ndatas < XLR_NORMAL_RDATAS)
192  ndatas = XLR_NORMAL_RDATAS;
193 
194  if (max_block_id > XLR_MAX_BLOCK_ID)
195  elog(ERROR, "maximum number of WAL record block references exceeded");
196  nbuffers = max_block_id + 1;
197 
198  if (nbuffers > max_registered_buffers)
199  {
201  repalloc(registered_buffers, sizeof(registered_buffer) * nbuffers);
202 
203  /*
204  * At least the padding bytes in the structs must be zeroed, because
205  * they are included in WAL data, but initialize it all for tidiness.
206  */
208  (nbuffers - max_registered_buffers) * sizeof(registered_buffer));
209  max_registered_buffers = nbuffers;
210  }
211 
212  if (ndatas > max_rdatas)
213  {
214  rdatas = (XLogRecData *) repalloc(rdatas, sizeof(XLogRecData) * ndatas);
215  max_rdatas = ndatas;
216  }
217 }
218 
219 /*
220  * Reset WAL record construction buffers.
221  */
222 void
224 {
225  int i;
226 
227  for (i = 0; i < max_registered_block_id; i++)
228  registered_buffers[i].in_use = false;
229 
230  num_rdatas = 0;
232  mainrdata_len = 0;
234  curinsert_flags = 0;
235  begininsert_called = false;
236 }
237 
238 /*
239  * Register a reference to a buffer with the WAL record being constructed.
240  * This must be called for every page that the WAL-logged operation modifies.
241  */
242 void
243 XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
244 {
245  registered_buffer *regbuf;
246 
247  /* NO_IMAGE doesn't make sense with FORCE_IMAGE */
248  Assert(!((flags & REGBUF_FORCE_IMAGE) && (flags & (REGBUF_NO_IMAGE))));
250 
251  /*
252  * Ordinarily, buffer should be exclusive-locked and marked dirty before
253  * we get here, otherwise we could end up violating one of the rules in
254  * access/transam/README.
255  *
256  * Some callers intentionally register a clean page and never update that
257  * page's LSN; in that case they can pass the flag REGBUF_NO_CHANGE to
258  * bypass these checks.
259  */
260 #ifdef USE_ASSERT_CHECKING
261  if (!(flags & REGBUF_NO_CHANGE))
262  Assert(BufferIsExclusiveLocked(buffer) && BufferIsDirty(buffer));
263 #endif
264 
265  if (block_id >= max_registered_block_id)
266  {
267  if (block_id >= max_registered_buffers)
268  elog(ERROR, "too many registered buffers");
269  max_registered_block_id = block_id + 1;
270  }
271 
272  regbuf = &registered_buffers[block_id];
273 
274  BufferGetTag(buffer, &regbuf->rlocator, &regbuf->forkno, &regbuf->block);
275  regbuf->page = BufferGetPage(buffer);
276  regbuf->flags = flags;
277  regbuf->rdata_tail = (XLogRecData *) &regbuf->rdata_head;
278  regbuf->rdata_len = 0;
279 
280  /*
281  * Check that this page hasn't already been registered with some other
282  * block_id.
283  */
284 #ifdef USE_ASSERT_CHECKING
285  {
286  int i;
287 
288  for (i = 0; i < max_registered_block_id; i++)
289  {
290  registered_buffer *regbuf_old = &registered_buffers[i];
291 
292  if (i == block_id || !regbuf_old->in_use)
293  continue;
294 
295  Assert(!RelFileLocatorEquals(regbuf_old->rlocator, regbuf->rlocator) ||
296  regbuf_old->forkno != regbuf->forkno ||
297  regbuf_old->block != regbuf->block);
298  }
299  }
300 #endif
301 
302  regbuf->in_use = true;
303 }
304 
305 /*
306  * Like XLogRegisterBuffer, but for registering a block that's not in the
307  * shared buffer pool (i.e. when you don't have a Buffer for it).
308  */
309 void
310 XLogRegisterBlock(uint8 block_id, RelFileLocator *rlocator, ForkNumber forknum,
311  BlockNumber blknum, Page page, uint8 flags)
312 {
313  registered_buffer *regbuf;
314 
316 
317  if (block_id >= max_registered_block_id)
318  max_registered_block_id = block_id + 1;
319 
320  if (block_id >= max_registered_buffers)
321  elog(ERROR, "too many registered buffers");
322 
323  regbuf = &registered_buffers[block_id];
324 
325  regbuf->rlocator = *rlocator;
326  regbuf->forkno = forknum;
327  regbuf->block = blknum;
328  regbuf->page = page;
329  regbuf->flags = flags;
330  regbuf->rdata_tail = (XLogRecData *) &regbuf->rdata_head;
331  regbuf->rdata_len = 0;
332 
333  /*
334  * Check that this page hasn't already been registered with some other
335  * block_id.
336  */
337 #ifdef USE_ASSERT_CHECKING
338  {
339  int i;
340 
341  for (i = 0; i < max_registered_block_id; i++)
342  {
343  registered_buffer *regbuf_old = &registered_buffers[i];
344 
345  if (i == block_id || !regbuf_old->in_use)
346  continue;
347 
348  Assert(!RelFileLocatorEquals(regbuf_old->rlocator, regbuf->rlocator) ||
349  regbuf_old->forkno != regbuf->forkno ||
350  regbuf_old->block != regbuf->block);
351  }
352  }
353 #endif
354 
355  regbuf->in_use = true;
356 }
357 
358 /*
359  * Add data to the WAL record that's being constructed.
360  *
361  * The data is appended to the "main chunk", available at replay with
362  * XLogRecGetData().
363  */
364 void
366 {
367  XLogRecData *rdata;
368 
370 
371  if (num_rdatas >= max_rdatas)
372  ereport(ERROR,
373  (errmsg_internal("too much WAL data"),
374  errdetail_internal("%d out of %d data segments are already in use.",
376  rdata = &rdatas[num_rdatas++];
377 
378  rdata->data = data;
379  rdata->len = len;
380 
381  /*
382  * we use the mainrdata_last pointer to track the end of the chain, so no
383  * need to clear 'next' here.
384  */
385 
386  mainrdata_last->next = rdata;
387  mainrdata_last = rdata;
388 
389  mainrdata_len += len;
390 }
391 
392 /*
393  * Add buffer-specific data to the WAL record that's being constructed.
394  *
395  * Block_id must reference a block previously registered with
396  * XLogRegisterBuffer(). If this is called more than once for the same
397  * block_id, the data is appended.
398  *
399  * The maximum amount of data that can be registered per block is 65535
400  * bytes. That should be plenty; if you need more than BLCKSZ bytes to
401  * reconstruct the changes to the page, you might as well just log a full
402  * copy of it. (the "main data" that's not associated with a block is not
403  * limited)
404  */
405 void
407 {
408  registered_buffer *regbuf;
409  XLogRecData *rdata;
410 
412 
413  /* find the registered buffer struct */
414  regbuf = &registered_buffers[block_id];
415  if (!regbuf->in_use)
416  elog(ERROR, "no block with id %d registered with WAL insertion",
417  block_id);
418 
419  /*
420  * Check against max_rdatas and ensure we do not register more data per
421  * buffer than can be handled by the physical data format; i.e. that
422  * regbuf->rdata_len does not grow beyond what
423  * XLogRecordBlockHeader->data_length can hold.
424  */
425  if (num_rdatas >= max_rdatas)
426  ereport(ERROR,
427  (errmsg_internal("too much WAL data"),
428  errdetail_internal("%d out of %d data segments are already in use.",
430  if (regbuf->rdata_len + len > UINT16_MAX || len > UINT16_MAX)
431  ereport(ERROR,
432  (errmsg_internal("too much WAL data"),
433  errdetail_internal("Registering more than maximum %u bytes allowed to block %u: current %u bytes, adding %u bytes.",
434  UINT16_MAX, block_id, regbuf->rdata_len, len)));
435 
436  rdata = &rdatas[num_rdatas++];
437 
438  rdata->data = data;
439  rdata->len = len;
440 
441  regbuf->rdata_tail->next = rdata;
442  regbuf->rdata_tail = rdata;
443  regbuf->rdata_len += len;
444 }
445 
446 /*
447  * Set insert status flags for the upcoming WAL record.
448  *
449  * The flags that can be used here are:
450  * - XLOG_INCLUDE_ORIGIN, to determine if the replication origin should be
451  * included in the record.
452  * - XLOG_MARK_UNIMPORTANT, to signal that the record is not important for
453  * durability, which allows to avoid triggering WAL archiving and other
454  * background activity.
455  */
456 void
458 {
460  curinsert_flags |= flags;
461 }
462 
463 /*
464  * Insert an XLOG record having the specified RMID and info bytes, with the
465  * body of the record being the data and buffer references registered earlier
466  * with XLogRegister* calls.
467  *
468  * Returns XLOG pointer to end of record (beginning of next record).
469  * This can be used as LSN for data pages affected by the logged action.
470  * (LSN is the XLOG point up to which the XLOG must be flushed to disk
471  * before the data page can be written out. This implements the basic
472  * WAL rule "write the log before the data".)
473  */
476 {
477  XLogRecPtr EndPos;
478 
479  /* XLogBeginInsert() must have been called. */
480  if (!begininsert_called)
481  elog(ERROR, "XLogBeginInsert was not called");
482 
483  /*
484  * The caller can set rmgr bits, XLR_SPECIAL_REL_UPDATE and
485  * XLR_CHECK_CONSISTENCY; the rest are reserved for use by me.
486  */
487  if ((info & ~(XLR_RMGR_INFO_MASK |
489  XLR_CHECK_CONSISTENCY)) != 0)
490  elog(PANIC, "invalid xlog info mask %02X", info);
491 
492  TRACE_POSTGRESQL_WAL_INSERT(rmid, info);
493 
494  /*
495  * In bootstrap mode, we don't actually log anything but XLOG resources;
496  * return a phony record pointer.
497  */
498  if (IsBootstrapProcessingMode() && rmid != RM_XLOG_ID)
499  {
501  EndPos = SizeOfXLogLongPHD; /* start of 1st chkpt record */
502  return EndPos;
503  }
504 
505  do
506  {
508  bool doPageWrites;
509  bool topxid_included = false;
510  XLogRecPtr fpw_lsn;
511  XLogRecData *rdt;
512  int num_fpi = 0;
513 
514  /*
515  * Get values needed to decide whether to do full-page writes. Since
516  * we don't yet have an insertion lock, these could change under us,
517  * but XLogInsertRecord will recheck them once it has a lock.
518  */
520 
521  rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
522  &fpw_lsn, &num_fpi, &topxid_included);
523 
524  EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
525  topxid_included);
526  } while (EndPos == InvalidXLogRecPtr);
527 
529 
530  return EndPos;
531 }
532 
533 /*
534  * Assemble a WAL record from the registered data and buffers into an
535  * XLogRecData chain, ready for insertion with XLogInsertRecord().
536  *
537  * The record header fields are filled in, except for the xl_prev field. The
538  * calculated CRC does not include the record header yet.
539  *
540  * If there are any registered buffers, and a full-page image was not taken
541  * of all of them, *fpw_lsn is set to the lowest LSN among such pages. This
542  * signals that the assembled record is only good for insertion on the
543  * assumption that the RedoRecPtr and doPageWrites values were up-to-date.
544  *
545  * *topxid_included is set if the topmost transaction ID is logged with the
546  * current subtransaction.
547  */
548 static XLogRecData *
551  XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
552 {
553  XLogRecData *rdt;
554  uint64 total_len = 0;
555  int block_id;
556  pg_crc32c rdata_crc;
557  registered_buffer *prev_regbuf = NULL;
558  XLogRecData *rdt_datas_last;
559  XLogRecord *rechdr;
560  char *scratch = hdr_scratch;
561 
562  /*
563  * Note: this function can be called multiple times for the same record.
564  * All the modifications we do to the rdata chains below must handle that.
565  */
566 
567  /* The record begins with the fixed-size header */
568  rechdr = (XLogRecord *) scratch;
569  scratch += SizeOfXLogRecord;
570 
571  hdr_rdt.next = NULL;
572  rdt_datas_last = &hdr_rdt;
574 
575  /*
576  * Enforce consistency checks for this record if user is looking for it.
577  * Do this before at the beginning of this routine to give the possibility
578  * for callers of XLogInsert() to pass XLR_CHECK_CONSISTENCY directly for
579  * a record.
580  */
581  if (wal_consistency_checking[rmid])
582  info |= XLR_CHECK_CONSISTENCY;
583 
584  /*
585  * Make an rdata chain containing all the data portions of all block
586  * references. This includes the data for full-page images. Also append
587  * the headers for the block references in the scratch buffer.
588  */
589  *fpw_lsn = InvalidXLogRecPtr;
590  for (block_id = 0; block_id < max_registered_block_id; block_id++)
591  {
592  registered_buffer *regbuf = &registered_buffers[block_id];
593  bool needs_backup;
594  bool needs_data;
597  XLogRecordBlockCompressHeader cbimg = {0};
598  bool samerel;
599  bool is_compressed = false;
600  bool include_image;
601 
602  if (!regbuf->in_use)
603  continue;
604 
605  /* Determine if this block needs to be backed up */
606  if (regbuf->flags & REGBUF_FORCE_IMAGE)
607  needs_backup = true;
608  else if (regbuf->flags & REGBUF_NO_IMAGE)
609  needs_backup = false;
610  else if (!doPageWrites)
611  needs_backup = false;
612  else
613  {
614  /*
615  * We assume page LSN is first data on *every* page that can be
616  * passed to XLogInsert, whether it has the standard page layout
617  * or not.
618  */
619  XLogRecPtr page_lsn = PageGetLSN(regbuf->page);
620 
621  needs_backup = (page_lsn <= RedoRecPtr);
622  if (!needs_backup)
623  {
624  if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
625  *fpw_lsn = page_lsn;
626  }
627  }
628 
629  /* Determine if the buffer data needs to included */
630  if (regbuf->rdata_len == 0)
631  needs_data = false;
632  else if ((regbuf->flags & REGBUF_KEEP_DATA) != 0)
633  needs_data = true;
634  else
635  needs_data = !needs_backup;
636 
637  bkpb.id = block_id;
638  bkpb.fork_flags = regbuf->forkno;
639  bkpb.data_length = 0;
640 
641  if ((regbuf->flags & REGBUF_WILL_INIT) == REGBUF_WILL_INIT)
643 
644  /*
645  * If needs_backup is true or WAL checking is enabled for current
646  * resource manager, log a full-page write for the current block.
647  */
648  include_image = needs_backup || (info & XLR_CHECK_CONSISTENCY) != 0;
649 
650  if (include_image)
651  {
652  Page page = regbuf->page;
653  uint16 compressed_len = 0;
654 
655  /*
656  * The page needs to be backed up, so calculate its hole length
657  * and offset.
658  */
659  if (regbuf->flags & REGBUF_STANDARD)
660  {
661  /* Assume we can omit data between pd_lower and pd_upper */
662  uint16 lower = ((PageHeader) page)->pd_lower;
663  uint16 upper = ((PageHeader) page)->pd_upper;
664 
665  if (lower >= SizeOfPageHeaderData &&
666  upper > lower &&
667  upper <= BLCKSZ)
668  {
669  bimg.hole_offset = lower;
670  cbimg.hole_length = upper - lower;
671  }
672  else
673  {
674  /* No "hole" to remove */
675  bimg.hole_offset = 0;
676  cbimg.hole_length = 0;
677  }
678  }
679  else
680  {
681  /* Not a standard page header, don't try to eliminate "hole" */
682  bimg.hole_offset = 0;
683  cbimg.hole_length = 0;
684  }
685 
686  /*
687  * Try to compress a block image if wal_compression is enabled
688  */
690  {
691  is_compressed =
693  cbimg.hole_length,
694  regbuf->compressed_page,
695  &compressed_len);
696  }
697 
698  /*
699  * Fill in the remaining fields in the XLogRecordBlockHeader
700  * struct
701  */
703 
704  /* Report a full page image constructed for the WAL record */
705  *num_fpi += 1;
706 
707  /*
708  * Construct XLogRecData entries for the page content.
709  */
710  rdt_datas_last->next = &regbuf->bkp_rdatas[0];
711  rdt_datas_last = rdt_datas_last->next;
712 
713  bimg.bimg_info = (cbimg.hole_length == 0) ? 0 : BKPIMAGE_HAS_HOLE;
714 
715  /*
716  * If WAL consistency checking is enabled for the resource manager
717  * of this WAL record, a full-page image is included in the record
718  * for the block modified. During redo, the full-page is replayed
719  * only if BKPIMAGE_APPLY is set.
720  */
721  if (needs_backup)
722  bimg.bimg_info |= BKPIMAGE_APPLY;
723 
724  if (is_compressed)
725  {
726  /* The current compression is stored in the WAL record */
727  bimg.length = compressed_len;
728 
729  /* Set the compression method used for this block */
731  {
734  break;
735 
736  case WAL_COMPRESSION_LZ4:
737 #ifdef USE_LZ4
739 #else
740  elog(ERROR, "LZ4 is not supported by this build");
741 #endif
742  break;
743 
745 #ifdef USE_ZSTD
747 #else
748  elog(ERROR, "zstd is not supported by this build");
749 #endif
750  break;
751 
753  Assert(false); /* cannot happen */
754  break;
755  /* no default case, so that compiler will warn */
756  }
757 
758  rdt_datas_last->data = regbuf->compressed_page;
759  rdt_datas_last->len = compressed_len;
760  }
761  else
762  {
763  bimg.length = BLCKSZ - cbimg.hole_length;
764 
765  if (cbimg.hole_length == 0)
766  {
767  rdt_datas_last->data = page;
768  rdt_datas_last->len = BLCKSZ;
769  }
770  else
771  {
772  /* must skip the hole */
773  rdt_datas_last->data = page;
774  rdt_datas_last->len = bimg.hole_offset;
775 
776  rdt_datas_last->next = &regbuf->bkp_rdatas[1];
777  rdt_datas_last = rdt_datas_last->next;
778 
779  rdt_datas_last->data =
780  page + (bimg.hole_offset + cbimg.hole_length);
781  rdt_datas_last->len =
782  BLCKSZ - (bimg.hole_offset + cbimg.hole_length);
783  }
784  }
785 
786  total_len += bimg.length;
787  }
788 
789  if (needs_data)
790  {
791  /*
792  * When copying to XLogRecordBlockHeader, the length is narrowed
793  * to an uint16. Double-check that it is still correct.
794  */
795  Assert(regbuf->rdata_len <= UINT16_MAX);
796 
797  /*
798  * Link the caller-supplied rdata chain for this buffer to the
799  * overall list.
800  */
802  bkpb.data_length = (uint16) regbuf->rdata_len;
803  total_len += regbuf->rdata_len;
804 
805  rdt_datas_last->next = regbuf->rdata_head;
806  rdt_datas_last = regbuf->rdata_tail;
807  }
808 
809  if (prev_regbuf && RelFileLocatorEquals(regbuf->rlocator, prev_regbuf->rlocator))
810  {
811  samerel = true;
813  }
814  else
815  samerel = false;
816  prev_regbuf = regbuf;
817 
818  /* Ok, copy the header to the scratch buffer */
819  memcpy(scratch, &bkpb, SizeOfXLogRecordBlockHeader);
820  scratch += SizeOfXLogRecordBlockHeader;
821  if (include_image)
822  {
823  memcpy(scratch, &bimg, SizeOfXLogRecordBlockImageHeader);
825  if (cbimg.hole_length != 0 && is_compressed)
826  {
827  memcpy(scratch, &cbimg,
830  }
831  }
832  if (!samerel)
833  {
834  memcpy(scratch, &regbuf->rlocator, sizeof(RelFileLocator));
835  scratch += sizeof(RelFileLocator);
836  }
837  memcpy(scratch, &regbuf->block, sizeof(BlockNumber));
838  scratch += sizeof(BlockNumber);
839  }
840 
841  /* followed by the record's origin, if any */
844  {
845  *(scratch++) = (char) XLR_BLOCK_ID_ORIGIN;
846  memcpy(scratch, &replorigin_session_origin, sizeof(replorigin_session_origin));
847  scratch += sizeof(replorigin_session_origin);
848  }
849 
850  /* followed by toplevel XID, if not already included in previous record */
852  {
854 
855  /* Set the flag that the top xid is included in the WAL */
856  *topxid_included = true;
857 
858  *(scratch++) = (char) XLR_BLOCK_ID_TOPLEVEL_XID;
859  memcpy(scratch, &xid, sizeof(TransactionId));
860  scratch += sizeof(TransactionId);
861  }
862 
863  /* followed by main data, if any */
864  if (mainrdata_len > 0)
865  {
866  if (mainrdata_len > 255)
867  {
868  uint32 mainrdata_len_4b;
869 
871  ereport(ERROR,
872  (errmsg_internal("too much WAL data"),
873  errdetail_internal("Main data length is %llu bytes for a maximum of %u bytes.",
874  (unsigned long long) mainrdata_len,
875  PG_UINT32_MAX)));
876 
877  mainrdata_len_4b = (uint32) mainrdata_len;
878  *(scratch++) = (char) XLR_BLOCK_ID_DATA_LONG;
879  memcpy(scratch, &mainrdata_len_4b, sizeof(uint32));
880  scratch += sizeof(uint32);
881  }
882  else
883  {
884  *(scratch++) = (char) XLR_BLOCK_ID_DATA_SHORT;
885  *(scratch++) = (uint8) mainrdata_len;
886  }
887  rdt_datas_last->next = mainrdata_head;
888  rdt_datas_last = mainrdata_last;
889  total_len += mainrdata_len;
890  }
891  rdt_datas_last->next = NULL;
892 
893  hdr_rdt.len = (scratch - hdr_scratch);
894  total_len += hdr_rdt.len;
895 
896  /*
897  * Calculate CRC of the data
898  *
899  * Note that the record header isn't added into the CRC initially since we
900  * don't know the prev-link yet. Thus, the CRC will represent the CRC of
901  * the whole record in the order: rdata, then backup blocks, then record
902  * header.
903  */
904  INIT_CRC32C(rdata_crc);
906  for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
907  COMP_CRC32C(rdata_crc, rdt->data, rdt->len);
908 
909  /*
910  * Ensure that the XLogRecord is not too large.
911  *
912  * XLogReader machinery is only able to handle records up to a certain
913  * size (ignoring machine resource limitations), so make sure that we will
914  * not emit records larger than the sizes advertised to be supported.
915  */
916  if (total_len > XLogRecordMaxSize)
917  ereport(ERROR,
918  (errmsg_internal("oversized WAL record"),
919  errdetail_internal("WAL record would be %llu bytes (of maximum %u bytes); rmid %u flags %u.",
920  (unsigned long long) total_len, XLogRecordMaxSize, rmid, info)));
921 
922  /*
923  * Fill in the fields in the record header. Prev-link is filled in later,
924  * once we know where in the WAL the record will be inserted. The CRC does
925  * not include the record header yet.
926  */
928  rechdr->xl_tot_len = (uint32) total_len;
929  rechdr->xl_info = info;
930  rechdr->xl_rmid = rmid;
931  rechdr->xl_prev = InvalidXLogRecPtr;
932  rechdr->xl_crc = rdata_crc;
933 
934  return &hdr_rdt;
935 }
936 
937 /*
938  * Create a compressed version of a backup block image.
939  *
940  * Returns false if compression fails (i.e., compressed result is actually
941  * bigger than original). Otherwise, returns true and sets 'dlen' to
942  * the length of compressed block image.
943  */
944 static bool
945 XLogCompressBackupBlock(char *page, uint16 hole_offset, uint16 hole_length,
946  char *dest, uint16 *dlen)
947 {
948  int32 orig_len = BLCKSZ - hole_length;
949  int32 len = -1;
950  int32 extra_bytes = 0;
951  char *source;
952  PGAlignedBlock tmp;
953 
954  if (hole_length != 0)
955  {
956  /* must skip the hole */
957  source = tmp.data;
958  memcpy(source, page, hole_offset);
959  memcpy(source + hole_offset,
960  page + (hole_offset + hole_length),
961  BLCKSZ - (hole_length + hole_offset));
962 
963  /*
964  * Extra data needs to be stored in WAL record for the compressed
965  * version of block image if the hole exists.
966  */
968  }
969  else
970  source = page;
971 
973  {
976  break;
977 
978  case WAL_COMPRESSION_LZ4:
979 #ifdef USE_LZ4
980  len = LZ4_compress_default(source, dest, orig_len,
982  if (len <= 0)
983  len = -1; /* failure */
984 #else
985  elog(ERROR, "LZ4 is not supported by this build");
986 #endif
987  break;
988 
990 #ifdef USE_ZSTD
991  len = ZSTD_compress(dest, COMPRESS_BUFSIZE, source, orig_len,
992  ZSTD_CLEVEL_DEFAULT);
993  if (ZSTD_isError(len))
994  len = -1; /* failure */
995 #else
996  elog(ERROR, "zstd is not supported by this build");
997 #endif
998  break;
999 
1000  case WAL_COMPRESSION_NONE:
1001  Assert(false); /* cannot happen */
1002  break;
1003  /* no default case, so that compiler will warn */
1004  }
1005 
1006  /*
1007  * We recheck the actual size even if compression reports success and see
1008  * if the number of bytes saved by compression is larger than the length
1009  * of extra data needed for the compressed version of block image.
1010  */
1011  if (len >= 0 &&
1012  len + extra_bytes < orig_len)
1013  {
1014  *dlen = (uint16) len; /* successful compression */
1015  return true;
1016  }
1017  return false;
1018 }
1019 
1020 /*
1021  * Determine whether the buffer referenced has to be backed up.
1022  *
1023  * Since we don't yet have the insert lock, fullPageWrites and runningBackups
1024  * (which forces full-page writes) could change later, so the result should
1025  * be used for optimization purposes only.
1026  */
1027 bool
1029 {
1031  bool doPageWrites;
1032  Page page;
1033 
1035 
1036  page = BufferGetPage(buffer);
1037 
1038  if (doPageWrites && PageGetLSN(page) <= RedoRecPtr)
1039  return true; /* buffer requires backup */
1040 
1041  return false; /* buffer does not need to be backed up */
1042 }
1043 
1044 /*
1045  * Write a backup block if needed when we are setting a hint. Note that
1046  * this may be called for a variety of page types, not just heaps.
1047  *
1048  * Callable while holding just share lock on the buffer content.
1049  *
1050  * We can't use the plain backup block mechanism since that relies on the
1051  * Buffer being exclusively locked. Since some modifications (setting LSN, hint
1052  * bits) are allowed in a sharelocked buffer that can lead to wal checksum
1053  * failures. So instead we copy the page and insert the copied data as normal
1054  * record data.
1055  *
1056  * We only need to do something if page has not yet been full page written in
1057  * this checkpoint round. The LSN of the inserted wal record is returned if we
1058  * had to write, InvalidXLogRecPtr otherwise.
1059  *
1060  * It is possible that multiple concurrent backends could attempt to write WAL
1061  * records. In that case, multiple copies of the same block would be recorded
1062  * in separate WAL records by different backends, though that is still OK from
1063  * a correctness perspective.
1064  */
1065 XLogRecPtr
1066 XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
1067 {
1068  XLogRecPtr recptr = InvalidXLogRecPtr;
1069  XLogRecPtr lsn;
1071 
1072  /*
1073  * Ensure no checkpoint can change our view of RedoRecPtr.
1074  */
1076 
1077  /*
1078  * Update RedoRecPtr so that we can make the right decision
1079  */
1081 
1082  /*
1083  * We assume page LSN is first data on *every* page that can be passed to
1084  * XLogInsert, whether it has the standard page layout or not. Since we're
1085  * only holding a share-lock on the page, we must take the buffer header
1086  * lock when we look at the LSN.
1087  */
1088  lsn = BufferGetLSNAtomic(buffer);
1089 
1090  if (lsn <= RedoRecPtr)
1091  {
1092  int flags = 0;
1093  PGAlignedBlock copied_buffer;
1094  char *origdata = (char *) BufferGetBlock(buffer);
1095  RelFileLocator rlocator;
1096  ForkNumber forkno;
1097  BlockNumber blkno;
1098 
1099  /*
1100  * Copy buffer so we don't have to worry about concurrent hint bit or
1101  * lsn updates. We assume pd_lower/upper cannot be changed without an
1102  * exclusive lock, so the contents bkp are not racy.
1103  */
1104  if (buffer_std)
1105  {
1106  /* Assume we can omit data between pd_lower and pd_upper */
1107  Page page = BufferGetPage(buffer);
1108  uint16 lower = ((PageHeader) page)->pd_lower;
1109  uint16 upper = ((PageHeader) page)->pd_upper;
1110 
1111  memcpy(copied_buffer.data, origdata, lower);
1112  memcpy(copied_buffer.data + upper, origdata + upper, BLCKSZ - upper);
1113  }
1114  else
1115  memcpy(copied_buffer.data, origdata, BLCKSZ);
1116 
1117  XLogBeginInsert();
1118 
1119  if (buffer_std)
1120  flags |= REGBUF_STANDARD;
1121 
1122  BufferGetTag(buffer, &rlocator, &forkno, &blkno);
1123  XLogRegisterBlock(0, &rlocator, forkno, blkno, copied_buffer.data, flags);
1124 
1125  recptr = XLogInsert(RM_XLOG_ID, XLOG_FPI_FOR_HINT);
1126  }
1127 
1128  return recptr;
1129 }
1130 
1131 /*
1132  * Write a WAL record containing a full image of a page. Caller is responsible
1133  * for writing the page to disk after calling this routine.
1134  *
1135  * Note: If you're using this function, you should be building pages in private
1136  * memory and writing them directly to smgr. If you're using buffers, call
1137  * log_newpage_buffer instead.
1138  *
1139  * If the page follows the standard page layout, with a PageHeader and unused
1140  * space between pd_lower and pd_upper, set 'page_std' to true. That allows
1141  * the unused space to be left out from the WAL record, making it smaller.
1142  */
1143 XLogRecPtr
1145  Page page, bool page_std)
1146 {
1147  int flags;
1148  XLogRecPtr recptr;
1149 
1150  flags = REGBUF_FORCE_IMAGE;
1151  if (page_std)
1152  flags |= REGBUF_STANDARD;
1153 
1154  XLogBeginInsert();
1155  XLogRegisterBlock(0, rlocator, forknum, blkno, page, flags);
1156  recptr = XLogInsert(RM_XLOG_ID, XLOG_FPI);
1157 
1158  /*
1159  * The page may be uninitialized. If so, we can't set the LSN because that
1160  * would corrupt the page.
1161  */
1162  if (!PageIsNew(page))
1163  {
1164  PageSetLSN(page, recptr);
1165  }
1166 
1167  return recptr;
1168 }
1169 
1170 /*
1171  * Like log_newpage(), but allows logging multiple pages in one operation.
1172  * It is more efficient than calling log_newpage() for each page separately,
1173  * because we can write multiple pages in a single WAL record.
1174  */
1175 void
1176 log_newpages(RelFileLocator *rlocator, ForkNumber forknum, int num_pages,
1177  BlockNumber *blknos, Page *pages, bool page_std)
1178 {
1179  int flags;
1180  XLogRecPtr recptr;
1181  int i;
1182  int j;
1183 
1184  flags = REGBUF_FORCE_IMAGE;
1185  if (page_std)
1186  flags |= REGBUF_STANDARD;
1187 
1188  /*
1189  * Iterate over all the pages. They are collected into batches of
1190  * XLR_MAX_BLOCK_ID pages, and a single WAL-record is written for each
1191  * batch.
1192  */
1194 
1195  i = 0;
1196  while (i < num_pages)
1197  {
1198  int batch_start = i;
1199  int nbatch;
1200 
1201  XLogBeginInsert();
1202 
1203  nbatch = 0;
1204  while (nbatch < XLR_MAX_BLOCK_ID && i < num_pages)
1205  {
1206  XLogRegisterBlock(nbatch, rlocator, forknum, blknos[i], pages[i], flags);
1207  i++;
1208  nbatch++;
1209  }
1210 
1211  recptr = XLogInsert(RM_XLOG_ID, XLOG_FPI);
1212 
1213  for (j = batch_start; j < i; j++)
1214  {
1215  /*
1216  * The page may be uninitialized. If so, we can't set the LSN
1217  * because that would corrupt the page.
1218  */
1219  if (!PageIsNew(pages[j]))
1220  {
1221  PageSetLSN(pages[j], recptr);
1222  }
1223  }
1224  }
1225 }
1226 
1227 /*
1228  * Write a WAL record containing a full image of a page.
1229  *
1230  * Caller should initialize the buffer and mark it dirty before calling this
1231  * function. This function will set the page LSN.
1232  *
1233  * If the page follows the standard page layout, with a PageHeader and unused
1234  * space between pd_lower and pd_upper, set 'page_std' to true. That allows
1235  * the unused space to be left out from the WAL record, making it smaller.
1236  */
1237 XLogRecPtr
1238 log_newpage_buffer(Buffer buffer, bool page_std)
1239 {
1240  Page page = BufferGetPage(buffer);
1241  RelFileLocator rlocator;
1242  ForkNumber forknum;
1243  BlockNumber blkno;
1244 
1245  /* Shared buffers should be modified in a critical section. */
1246  Assert(CritSectionCount > 0);
1247 
1248  BufferGetTag(buffer, &rlocator, &forknum, &blkno);
1249 
1250  return log_newpage(&rlocator, forknum, blkno, page, page_std);
1251 }
1252 
1253 /*
1254  * WAL-log a range of blocks in a relation.
1255  *
1256  * An image of all pages with block numbers 'startblk' <= X < 'endblk' is
1257  * written to the WAL. If the range is large, this is done in multiple WAL
1258  * records.
1259  *
1260  * If all page follows the standard page layout, with a PageHeader and unused
1261  * space between pd_lower and pd_upper, set 'page_std' to true. That allows
1262  * the unused space to be left out from the WAL records, making them smaller.
1263  *
1264  * NOTE: This function acquires exclusive-locks on the pages. Typically, this
1265  * is used on a newly-built relation, and the caller is holding a
1266  * AccessExclusiveLock on it, so no other backend can be accessing it at the
1267  * same time. If that's not the case, you must ensure that this does not
1268  * cause a deadlock through some other means.
1269  */
1270 void
1272  BlockNumber startblk, BlockNumber endblk,
1273  bool page_std)
1274 {
1275  int flags;
1276  BlockNumber blkno;
1277 
1278  flags = REGBUF_FORCE_IMAGE;
1279  if (page_std)
1280  flags |= REGBUF_STANDARD;
1281 
1282  /*
1283  * Iterate over all the pages in the range. They are collected into
1284  * batches of XLR_MAX_BLOCK_ID pages, and a single WAL-record is written
1285  * for each batch.
1286  */
1288 
1289  blkno = startblk;
1290  while (blkno < endblk)
1291  {
1292  Buffer bufpack[XLR_MAX_BLOCK_ID];
1293  XLogRecPtr recptr;
1294  int nbufs;
1295  int i;
1296 
1298 
1299  /* Collect a batch of blocks. */
1300  nbufs = 0;
1301  while (nbufs < XLR_MAX_BLOCK_ID && blkno < endblk)
1302  {
1303  Buffer buf = ReadBufferExtended(rel, forknum, blkno,
1304  RBM_NORMAL, NULL);
1305 
1307 
1308  /*
1309  * Completely empty pages are not WAL-logged. Writing a WAL record
1310  * would change the LSN, and we don't want that. We want the page
1311  * to stay empty.
1312  */
1313  if (!PageIsNew(BufferGetPage(buf)))
1314  bufpack[nbufs++] = buf;
1315  else
1317  blkno++;
1318  }
1319 
1320  /* Nothing more to do if all remaining blocks were empty. */
1321  if (nbufs == 0)
1322  break;
1323 
1324  /* Write WAL record for this batch. */
1325  XLogBeginInsert();
1326 
1328  for (i = 0; i < nbufs; i++)
1329  {
1330  MarkBufferDirty(bufpack[i]);
1331  XLogRegisterBuffer(i, bufpack[i], flags);
1332  }
1333 
1334  recptr = XLogInsert(RM_XLOG_ID, XLOG_FPI);
1335 
1336  for (i = 0; i < nbufs; i++)
1337  {
1338  PageSetLSN(BufferGetPage(bufpack[i]), recptr);
1339  UnlockReleaseBuffer(bufpack[i]);
1340  }
1341  END_CRIT_SECTION();
1342  }
1343 }
1344 
1345 /*
1346  * Allocate working buffers needed for WAL record construction.
1347  */
1348 void
1350 {
1351 #ifdef USE_ASSERT_CHECKING
1352 
1353  /*
1354  * Check that any records assembled can be decoded. This is capped based
1355  * on what XLogReader would require at its maximum bound. The XLOG_BLCKSZ
1356  * addend covers the larger allocate_recordbuf() demand. This code path
1357  * is called once per backend, more than enough for this check.
1358  */
1359  size_t max_required =
1361 
1362  Assert(AllocSizeIsValid(max_required));
1363 #endif
1364 
1365  /* Initialize the working areas */
1366  if (xloginsert_cxt == NULL)
1367  {
1369  "WAL record construction",
1371  }
1372 
1373  if (registered_buffers == NULL)
1374  {
1377  sizeof(registered_buffer) * (XLR_NORMAL_MAX_BLOCK_ID + 1));
1379  }
1380  if (rdatas == NULL)
1381  {
1383  sizeof(XLogRecData) * XLR_NORMAL_RDATAS);
1385  }
1386 
1387  /*
1388  * Allocate a buffer to hold the header information for a WAL record.
1389  */
1390  if (hdr_scratch == NULL)
1393 }
uint32 BlockNumber
Definition: block.h:31
int Buffer
Definition: buf.h:23
bool BufferIsExclusiveLocked(Buffer buffer)
Definition: bufmgr.c:2129
void BufferGetTag(Buffer buffer, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum)
Definition: bufmgr.c:3399
bool BufferIsDirty(Buffer buffer)
Definition: bufmgr.c:2158
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3639
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4578
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2190
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4796
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:782
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
static Block BufferGetBlock(Buffer buffer)
Definition: bufmgr.h:317
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:159
@ RBM_NORMAL
Definition: bufmgr.h:44
PageHeaderData * PageHeader
Definition: bufpage.h:170
Pointer Page
Definition: bufpage.h:78
#define SizeOfPageHeaderData
Definition: bufpage.h:213
static bool PageIsNew(Page page)
Definition: bufpage.h:230
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:388
static XLogRecPtr PageGetLSN(Page page)
Definition: bufpage.h:383
unsigned short uint16
Definition: c.h:494
unsigned int uint32
Definition: c.h:495
#define PG_UINT32_MAX
Definition: c.h:579
signed int int32
Definition: c.h:483
unsigned char uint8
Definition: c.h:493
#define MemSet(start, val, len)
Definition: c.h:1009
uint32 TransactionId
Definition: c.h:641
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1162
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1235
#define PANIC
Definition: elog.h:42
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
volatile uint32 CritSectionCount
Definition: globals.c:43
int j
Definition: isn.c:74
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
MemoryContext TopMemoryContext
Definition: mcxt.c:141
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1077
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1451
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1034
#define AllocSetContextCreate
Definition: memutils.h:128
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:152
#define AllocSizeIsValid(size)
Definition: memutils.h:42
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:415
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:49
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:80
RepOriginId replorigin_session_origin
Definition: origin.c:156
#define InvalidRepOriginId
Definition: origin.h:33
#define XLOG_FPI
Definition: pg_control.h:78
#define XLOG_FPI_FOR_HINT
Definition: pg_control.h:77
uint32 pg_crc32c
Definition: pg_crc32c.h:38
#define COMP_CRC32C(crc, data, len)
Definition: pg_crc32c.h:98
#define INIT_CRC32C(crc)
Definition: pg_crc32c.h:41
const void size_t len
const void * data
const PGLZ_Strategy *const PGLZ_strategy_default
int32 pglz_compress(const char *source, int32 slen, char *dest, const PGLZ_Strategy *strategy)
static rewind_source * source
Definition: pg_rewind.c:89
static char * buf
Definition: pg_test_fsync.c:73
#define DELAY_CHKPT_START
Definition: proc.h:119
struct RelFileLocator RelFileLocator
#define RelFileLocatorEquals(locator1, locator2)
ForkNumber
Definition: relpath.h:48
uint8 RmgrId
Definition: rmgr.h:11
PGPROC * MyProc
Definition: proc.c:67
int delayChkptFlags
Definition: proc.h:231
struct XLogRecData * next
XLogRecPtr xl_prev
Definition: xlogrecord.h:45
pg_crc32c xl_crc
Definition: xlogrecord.h:49
uint8 xl_info
Definition: xlogrecord.h:46
uint32 xl_tot_len
Definition: xlogrecord.h:43
TransactionId xl_xid
Definition: xlogrecord.h:44
RmgrId xl_rmid
Definition: xlogrecord.h:47
XLogRecData bkp_rdatas[2]
Definition: xloginsert.c:83
char compressed_page[COMPRESS_BUFSIZE]
Definition: xloginsert.c:87
XLogRecData * rdata_tail
Definition: xloginsert.c:80
BlockNumber block
Definition: xloginsert.c:75
XLogRecData * rdata_head
Definition: xloginsert.c:78
ForkNumber forkno
Definition: xloginsert.c:74
RelFileLocator rlocator
Definition: xloginsert.c:73
char data[BLCKSZ]
Definition: c.h:1108
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:432
TransactionId GetCurrentTransactionIdIfAny(void)
Definition: xact.c:462
bool IsSubxactTopXidLogPending(void)
Definition: xact.c:550
void GetFullPageWriteInfo(XLogRecPtr *RedoRecPtr_p, bool *doPageWrites_p)
Definition: xlog.c:6344
XLogRecPtr GetRedoRecPtr(void)
Definition: xlog.c:6314
static XLogRecPtr RedoRecPtr
Definition: xlog.c:277
XLogRecPtr XLogInsertRecord(XLogRecData *rdata, XLogRecPtr fpw_lsn, uint8 flags, int num_fpi, bool topxid_included)
Definition: xlog.c:742
static bool doPageWrites
Definition: xlog.c:290
int wal_compression
Definition: xlog.c:128
bool XLogInsertAllowed(void)
Definition: xlog.c:6266
bool * wal_consistency_checking
Definition: xlog.c:130
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:152
WalCompression
Definition: xlog.h:79
@ WAL_COMPRESSION_NONE
Definition: xlog.h:80
@ WAL_COMPRESSION_LZ4
Definition: xlog.h:82
@ WAL_COMPRESSION_PGLZ
Definition: xlog.h:81
@ WAL_COMPRESSION_ZSTD
Definition: xlog.h:83
#define SizeOfXLogLongPHD
Definition: xlog_internal.h:69
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:365
static XLogRecData * mainrdata_head
Definition: xloginsert.c:99
void XLogRegisterBlock(uint8 block_id, RelFileLocator *rlocator, ForkNumber forknum, BlockNumber blknum, Page page, uint8 flags)
Definition: xloginsert.c:310
static int max_registered_buffers
Definition: xloginsert.c:91
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:475
static uint8 curinsert_flags
Definition: xloginsert.c:104
bool XLogCheckBufferNeedsBackup(Buffer buffer)
Definition: xloginsert.c:1028
static uint64 mainrdata_len
Definition: xloginsert.c:101
XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
Definition: xloginsert.c:1066
static bool begininsert_called
Definition: xloginsert.c:133
static int max_registered_block_id
Definition: xloginsert.c:92
XLogRecPtr log_newpage(RelFileLocator *rlocator, ForkNumber forknum, BlockNumber blkno, Page page, bool page_std)
Definition: xloginsert.c:1144
void InitXLogInsert(void)
Definition: xloginsert.c:1349
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:457
static int num_rdatas
Definition: xloginsert.c:130
void log_newpages(RelFileLocator *rlocator, ForkNumber forknum, int num_pages, BlockNumber *blknos, Page *pages, bool page_std)
Definition: xloginsert.c:1176
void XLogRegisterBufData(uint8 block_id, char *data, uint32 len)
Definition: xloginsert.c:406
static XLogRecData * mainrdata_last
Definition: xloginsert.c:100
static MemoryContext xloginsert_cxt
Definition: xloginsert.c:136
void log_newpage_range(Relation rel, ForkNumber forknum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1271
void XLogResetInsertion(void)
Definition: xloginsert.c:223
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)
Definition: xloginsert.c:1238
static XLogRecData hdr_rdt
Definition: xloginsert.c:114
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:243
static XLogRecData * XLogRecordAssemble(RmgrId rmid, uint8 info, XLogRecPtr RedoRecPtr, bool doPageWrites, XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
Definition: xloginsert.c:549
static char * hdr_scratch
Definition: xloginsert.c:115
static XLogRecData * rdatas
Definition: xloginsert.c:129
void XLogBeginInsert(void)
Definition: xloginsert.c:150
void XLogEnsureRecordSpace(int max_block_id, int ndatas)
Definition: xloginsert.c:176
#define COMPRESS_BUFSIZE
Definition: xloginsert.c:63
static registered_buffer * registered_buffers
Definition: xloginsert.c:90
static bool XLogCompressBackupBlock(char *page, uint16 hole_offset, uint16 hole_length, char *dest, uint16 *dlen)
Definition: xloginsert.c:945
static int max_rdatas
Definition: xloginsert.c:131
#define HEADER_SCRATCH_SIZE
Definition: xloginsert.c:120
#define REGBUF_NO_CHANGE
Definition: xloginsert.h:36
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define XLR_NORMAL_MAX_BLOCK_ID
Definition: xloginsert.h:27
#define REGBUF_FORCE_IMAGE
Definition: xloginsert.h:31
#define XLR_NORMAL_RDATAS
Definition: xloginsert.h:28
#define REGBUF_NO_IMAGE
Definition: xloginsert.h:32
#define REGBUF_KEEP_DATA
Definition: xloginsert.h:35
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33
size_t DecodeXLogRecordRequiredSpace(size_t xl_tot_len)
Definition: xlogreader.c:1631
#define SizeOfXLogRecordBlockImageHeader
Definition: xlogrecord.h:153
#define XLogRecordMaxSize
Definition: xlogrecord.h:74
#define BKPIMAGE_COMPRESS_ZSTD
Definition: xlogrecord.h:162
#define BKPBLOCK_HAS_DATA
Definition: xlogrecord.h:198
#define BKPIMAGE_APPLY
Definition: xlogrecord.h:158
#define BKPIMAGE_HAS_HOLE
Definition: xlogrecord.h:157
#define XLR_BLOCK_ID_DATA_LONG
Definition: xlogrecord.h:242
#define BKPBLOCK_WILL_INIT
Definition: xlogrecord.h:199
#define XLR_RMGR_INFO_MASK
Definition: xlogrecord.h:63
#define BKPIMAGE_COMPRESS_LZ4
Definition: xlogrecord.h:161
#define XLR_BLOCK_ID_TOPLEVEL_XID
Definition: xlogrecord.h:244
#define XLR_BLOCK_ID_DATA_SHORT
Definition: xlogrecord.h:241
#define XLR_MAX_BLOCK_ID
Definition: xlogrecord.h:239
#define SizeOfXLogRecordBlockCompressHeader
Definition: xlogrecord.h:177
#define BKPBLOCK_SAME_REL
Definition: xlogrecord.h:200
#define XLR_SPECIAL_REL_UPDATE
Definition: xlogrecord.h:82
#define SizeOfXLogRecordBlockHeader
Definition: xlogrecord.h:115
#define BKPIMAGE_COMPRESS_PGLZ
Definition: xlogrecord.h:160
#define XLR_BLOCK_ID_ORIGIN
Definition: xlogrecord.h:243
#define SizeOfXLogRecord
Definition: xlogrecord.h:55
#define BKPBLOCK_HAS_IMAGE
Definition: xlogrecord.h:197
#define XLR_CHECK_CONSISTENCY
Definition: xlogrecord.h:91