PostgreSQL Source Code  git master
generic_xlog.c File Reference
#include "postgres.h"
#include "access/bufmask.h"
#include "access/generic_xlog.h"
#include "access/xlogutils.h"
#include "miscadmin.h"
#include "utils/memutils.h"
Include dependency graph for generic_xlog.c:

Go to the source code of this file.

Data Structures

struct  PageData
 
struct  GenericXLogState
 

Macros

#define FRAGMENT_HEADER_SIZE   (2 * sizeof(OffsetNumber))
 
#define MATCH_THRESHOLD   FRAGMENT_HEADER_SIZE
 
#define MAX_DELTA_SIZE   (BLCKSZ + 2 * FRAGMENT_HEADER_SIZE)
 

Functions

static void writeFragment (PageData *pageData, OffsetNumber offset, OffsetNumber length, const char *data)
 
static void computeRegionDelta (PageData *pageData, const char *curpage, const char *targetpage, int targetStart, int targetEnd, int validStart, int validEnd)
 
static void computeDelta (PageData *pageData, Page curpage, Page targetpage)
 
static void applyPageRedo (Page page, const char *delta, Size deltaSize)
 
GenericXLogStateGenericXLogStart (Relation relation)
 
Page GenericXLogRegisterBuffer (GenericXLogState *state, Buffer buffer, int flags)
 
XLogRecPtr GenericXLogFinish (GenericXLogState *state)
 
void GenericXLogAbort (GenericXLogState *state)
 
void generic_redo (XLogReaderState *record)
 
void generic_mask (char *page, BlockNumber blkno)
 

Macro Definition Documentation

◆ FRAGMENT_HEADER_SIZE

#define FRAGMENT_HEADER_SIZE   (2 * sizeof(OffsetNumber))

Definition at line 46 of file generic_xlog.c.

◆ MATCH_THRESHOLD

#define MATCH_THRESHOLD   FRAGMENT_HEADER_SIZE

Definition at line 47 of file generic_xlog.c.

◆ MAX_DELTA_SIZE

#define MAX_DELTA_SIZE   (BLCKSZ + 2 * FRAGMENT_HEADER_SIZE)

Definition at line 48 of file generic_xlog.c.

Function Documentation

◆ applyPageRedo()

static void applyPageRedo ( Page  page,
const char *  delta,
Size  deltaSize 
)
static

Definition at line 458 of file generic_xlog.c.

459 {
460  const char *ptr = delta;
461  const char *end = delta + deltaSize;
462 
463  while (ptr < end)
464  {
465  OffsetNumber offset,
466  length;
467 
468  memcpy(&offset, ptr, sizeof(offset));
469  ptr += sizeof(offset);
470  memcpy(&length, ptr, sizeof(length));
471  ptr += sizeof(length);
472 
473  memcpy(page + offset, ptr, length);
474 
475  ptr += length;
476  }
477 }
uint16 OffsetNumber
Definition: off.h:24

Referenced by computeDelta(), and generic_redo().

◆ computeDelta()

static void computeDelta ( PageData pageData,
Page  curpage,
Page  targetpage 
)
static

Definition at line 229 of file generic_xlog.c.

230 {
231  int targetLower = ((PageHeader) targetpage)->pd_lower,
232  targetUpper = ((PageHeader) targetpage)->pd_upper,
233  curLower = ((PageHeader) curpage)->pd_lower,
234  curUpper = ((PageHeader) curpage)->pd_upper;
235 
236  pageData->deltaLen = 0;
237 
238  /* Compute delta records for lower part of page ... */
239  computeRegionDelta(pageData, curpage, targetpage,
240  0, targetLower,
241  0, curLower);
242  /* ... and for upper part, ignoring what's between */
243  computeRegionDelta(pageData, curpage, targetpage,
244  targetUpper, BLCKSZ,
245  curUpper, BLCKSZ);
246 
247  /*
248  * If xlog debug is enabled, then check produced delta. Result of delta
249  * application to curpage should be equivalent to targetpage.
250  */
251 #ifdef WAL_DEBUG
252  if (XLOG_DEBUG)
253  {
254  PGAlignedBlock tmp;
255 
256  memcpy(tmp.data, curpage, BLCKSZ);
257  applyPageRedo(tmp.data, pageData->delta, pageData->deltaLen);
258  if (memcmp(tmp.data, targetpage, targetLower) != 0 ||
259  memcmp(tmp.data + targetUpper, targetpage + targetUpper,
260  BLCKSZ - targetUpper) != 0)
261  elog(ERROR, "result of generic xlog apply does not match");
262  }
263 #endif
264 }
PageHeaderData * PageHeader
Definition: bufpage.h:170
#define ERROR
Definition: elog.h:39
static void computeRegionDelta(PageData *pageData, const char *curpage, const char *targetpage, int targetStart, int targetEnd, int validStart, int validEnd)
Definition: generic_xlog.c:122
static void applyPageRedo(Page page, const char *delta, Size deltaSize)
Definition: generic_xlog.c:458
char delta[MAX_DELTA_SIZE]
Definition: generic_xlog.c:58
int deltaLen
Definition: generic_xlog.c:55
char data[BLCKSZ]
Definition: c.h:1132

References applyPageRedo(), computeRegionDelta(), PGAlignedBlock::data, PageData::delta, PageData::deltaLen, elog(), and ERROR.

Referenced by GenericXLogFinish().

◆ computeRegionDelta()

static void computeRegionDelta ( PageData pageData,
const char *  curpage,
const char *  targetpage,
int  targetStart,
int  targetEnd,
int  validStart,
int  validEnd 
)
static

Definition at line 122 of file generic_xlog.c.

126 {
127  int i,
128  loopEnd,
129  fragmentBegin = -1,
130  fragmentEnd = -1;
131 
132  /* Deal with any invalid start region by including it in first fragment */
133  if (validStart > targetStart)
134  {
135  fragmentBegin = targetStart;
136  targetStart = validStart;
137  }
138 
139  /* We'll deal with any invalid end region after the main loop */
140  loopEnd = Min(targetEnd, validEnd);
141 
142  /* Examine all the potentially matchable bytes */
143  i = targetStart;
144  while (i < loopEnd)
145  {
146  if (curpage[i] != targetpage[i])
147  {
148  /* On unmatched byte, start new fragment if not already in one */
149  if (fragmentBegin < 0)
150  fragmentBegin = i;
151  /* Mark unmatched-data endpoint as uncertain */
152  fragmentEnd = -1;
153  /* Extend the fragment as far as possible in a tight loop */
154  i++;
155  while (i < loopEnd && curpage[i] != targetpage[i])
156  i++;
157  if (i >= loopEnd)
158  break;
159  }
160 
161  /* Found a matched byte, so remember end of unmatched fragment */
162  fragmentEnd = i;
163 
164  /*
165  * Extend the match as far as possible in a tight loop. (On typical
166  * workloads, this inner loop is the bulk of this function's runtime.)
167  */
168  i++;
169  while (i < loopEnd && curpage[i] == targetpage[i])
170  i++;
171 
172  /*
173  * There are several possible cases at this point:
174  *
175  * 1. We have no unwritten fragment (fragmentBegin < 0). There's
176  * nothing to write; and it doesn't matter what fragmentEnd is.
177  *
178  * 2. We found more than MATCH_THRESHOLD consecutive matching bytes.
179  * Dump out the unwritten fragment, stopping at fragmentEnd.
180  *
181  * 3. The match extends to loopEnd. We'll do nothing here, exit the
182  * loop, and then dump the unwritten fragment, after merging it with
183  * the invalid end region if any. If we don't so merge, fragmentEnd
184  * establishes how much the final writeFragment call needs to write.
185  *
186  * 4. We found an unmatched byte before loopEnd. The loop will repeat
187  * and will enter the unmatched-byte stanza above. So in this case
188  * also, it doesn't matter what fragmentEnd is. The matched bytes
189  * will get merged into the continuing unmatched fragment.
190  *
191  * Only in case 3 do we reach the bottom of the loop with a meaningful
192  * fragmentEnd value, which is why it's OK that we unconditionally
193  * assign "fragmentEnd = i" above.
194  */
195  if (fragmentBegin >= 0 && i - fragmentEnd > MATCH_THRESHOLD)
196  {
197  writeFragment(pageData, fragmentBegin,
198  fragmentEnd - fragmentBegin,
199  targetpage + fragmentBegin);
200  fragmentBegin = -1;
201  fragmentEnd = -1; /* not really necessary */
202  }
203  }
204 
205  /* Deal with any invalid end region by including it in final fragment */
206  if (loopEnd < targetEnd)
207  {
208  if (fragmentBegin < 0)
209  fragmentBegin = loopEnd;
210  fragmentEnd = targetEnd;
211  }
212 
213  /* Write final fragment if any */
214  if (fragmentBegin >= 0)
215  {
216  if (fragmentEnd < 0)
217  fragmentEnd = targetEnd;
218  writeFragment(pageData, fragmentBegin,
219  fragmentEnd - fragmentBegin,
220  targetpage + fragmentBegin);
221  }
222 }
#define Min(x, y)
Definition: c.h:993
static void writeFragment(PageData *pageData, OffsetNumber offset, OffsetNumber length, const char *data)
Definition: generic_xlog.c:91
#define MATCH_THRESHOLD
Definition: generic_xlog.c:47
int i
Definition: isn.c:73

References i, MATCH_THRESHOLD, Min, and writeFragment().

Referenced by computeDelta().

◆ generic_mask()

void generic_mask ( char *  page,
BlockNumber  blkno 
)

Definition at line 544 of file generic_xlog.c.

545 {
547 
548  mask_unused_space(page);
549 }
void mask_page_lsn_and_checksum(Page page)
Definition: bufmask.c:31
void mask_unused_space(Page page)
Definition: bufmask.c:71

References mask_page_lsn_and_checksum(), and mask_unused_space().

◆ generic_redo()

void generic_redo ( XLogReaderState record)

Definition at line 483 of file generic_xlog.c.

484 {
485  XLogRecPtr lsn = record->EndRecPtr;
487  uint8 block_id;
488 
489  /* Protect limited size of buffers[] array */
491 
492  /* Iterate over blocks */
493  for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
494  {
496 
497  if (!XLogRecHasBlockRef(record, block_id))
498  {
499  buffers[block_id] = InvalidBuffer;
500  continue;
501  }
502 
503  action = XLogReadBufferForRedo(record, block_id, &buffers[block_id]);
504 
505  /* Apply redo to given block if needed */
506  if (action == BLK_NEEDS_REDO)
507  {
508  Page page;
509  PageHeader pageHeader;
510  char *blockDelta;
511  Size blockDeltaSize;
512 
513  page = BufferGetPage(buffers[block_id]);
514  blockDelta = XLogRecGetBlockData(record, block_id, &blockDeltaSize);
515  applyPageRedo(page, blockDelta, blockDeltaSize);
516 
517  /*
518  * Since the delta contains no information about what's in the
519  * "hole" between pd_lower and pd_upper, set that to zero to
520  * ensure we produce the same page state that application of the
521  * logged action by GenericXLogFinish did.
522  */
523  pageHeader = (PageHeader) page;
524  memset(page + pageHeader->pd_lower, 0,
525  pageHeader->pd_upper - pageHeader->pd_lower);
526 
527  PageSetLSN(page, lsn);
528  MarkBufferDirty(buffers[block_id]);
529  }
530  }
531 
532  /* Changes are done: unlock and release all buffers */
533  for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
534  {
535  if (BufferIsValid(buffers[block_id]))
536  UnlockReleaseBuffer(buffers[block_id]);
537  }
538 }
int Buffer
Definition: buf.h:23
#define InvalidBuffer
Definition: buf.h:25
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4497
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2111
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:301
Pointer Page
Definition: bufpage.h:78
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:388
unsigned char uint8
Definition: c.h:493
size_t Size
Definition: c.h:594
#define MAX_GENERIC_XLOG_PAGES
Definition: generic_xlog.h:23
Assert(fmt[strlen(fmt) - 1] !='\n')
LocationIndex pd_upper
Definition: bufpage.h:163
LocationIndex pd_lower
Definition: bufpage.h:162
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
uint64 XLogRecPtr
Definition: xlogdefs.h:21
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:2033
#define XLogRecMaxBlockId(decoder)
Definition: xlogreader.h:418
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:420
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:317
XLogRedoAction
Definition: xlogutils.h:70
@ BLK_NEEDS_REDO
Definition: xlogutils.h:71

References generate_unaccent_rules::action, applyPageRedo(), Assert(), BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), XLogReaderState::EndRecPtr, InvalidBuffer, MarkBufferDirty(), MAX_GENERIC_XLOG_PAGES, PageSetLSN(), PageHeaderData::pd_lower, PageHeaderData::pd_upper, UnlockReleaseBuffer(), XLogReadBufferForRedo(), XLogRecGetBlockData(), XLogRecHasBlockRef, and XLogRecMaxBlockId.

◆ GenericXLogAbort()

void GenericXLogAbort ( GenericXLogState state)

Definition at line 449 of file generic_xlog.c.

450 {
451  pfree(state);
452 }
void pfree(void *pointer)
Definition: mcxt.c:1456
Definition: regguts.h:323

References pfree().

Referenced by blbulkdelete(), and blinsert().

◆ GenericXLogFinish()

XLogRecPtr GenericXLogFinish ( GenericXLogState state)

Definition at line 338 of file generic_xlog.c.

339 {
340  XLogRecPtr lsn;
341  int i;
342 
343  if (state->isLogged)
344  {
345  /* Logged relation: make xlog record in critical section. */
346  XLogBeginInsert();
347 
349 
350  for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
351  {
352  PageData *pageData = &state->pages[i];
353  Page page;
354  PageHeader pageHeader;
355 
356  if (BufferIsInvalid(pageData->buffer))
357  continue;
358 
359  page = BufferGetPage(pageData->buffer);
360  pageHeader = (PageHeader) pageData->image;
361 
362  if (pageData->flags & GENERIC_XLOG_FULL_IMAGE)
363  {
364  /*
365  * A full-page image does not require us to supply any xlog
366  * data. Just apply the image, being careful to zero the
367  * "hole" between pd_lower and pd_upper in order to avoid
368  * divergence between actual page state and what replay would
369  * produce.
370  */
371  memcpy(page, pageData->image, pageHeader->pd_lower);
372  memset(page + pageHeader->pd_lower, 0,
373  pageHeader->pd_upper - pageHeader->pd_lower);
374  memcpy(page + pageHeader->pd_upper,
375  pageData->image + pageHeader->pd_upper,
376  BLCKSZ - pageHeader->pd_upper);
377 
378  XLogRegisterBuffer(i, pageData->buffer,
380  }
381  else
382  {
383  /*
384  * In normal mode, calculate delta and write it as xlog data
385  * associated with this page.
386  */
387  computeDelta(pageData, page, (Page) pageData->image);
388 
389  /* Apply the image, with zeroed "hole" as above */
390  memcpy(page, pageData->image, pageHeader->pd_lower);
391  memset(page + pageHeader->pd_lower, 0,
392  pageHeader->pd_upper - pageHeader->pd_lower);
393  memcpy(page + pageHeader->pd_upper,
394  pageData->image + pageHeader->pd_upper,
395  BLCKSZ - pageHeader->pd_upper);
396 
398  XLogRegisterBufData(i, pageData->delta, pageData->deltaLen);
399  }
400  }
401 
402  /* Insert xlog record */
403  lsn = XLogInsert(RM_GENERIC_ID, 0);
404 
405  /* Set LSN and mark buffers dirty */
406  for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
407  {
408  PageData *pageData = &state->pages[i];
409 
410  if (BufferIsInvalid(pageData->buffer))
411  continue;
412  PageSetLSN(BufferGetPage(pageData->buffer), lsn);
413  MarkBufferDirty(pageData->buffer);
414  }
416  }
417  else
418  {
419  /* Unlogged relation: skip xlog-related stuff */
421  for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
422  {
423  PageData *pageData = &state->pages[i];
424 
425  if (BufferIsInvalid(pageData->buffer))
426  continue;
427  memcpy(BufferGetPage(pageData->buffer),
428  pageData->image,
429  BLCKSZ);
430  /* We don't worry about zeroing the "hole" in this case */
431  MarkBufferDirty(pageData->buffer);
432  }
434  /* We don't have a LSN to return, in this case */
435  lsn = InvalidXLogRecPtr;
436  }
437 
438  pfree(state);
439 
440  return lsn;
441 }
#define BufferIsInvalid(buffer)
Definition: buf.h:31
static void computeDelta(PageData *pageData, Page curpage, Page targetpage)
Definition: generic_xlog.c:229
#define GENERIC_XLOG_FULL_IMAGE
Definition: generic_xlog.h:26
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
#define START_CRIT_SECTION()
Definition: miscadmin.h:148
#define END_CRIT_SECTION()
Definition: miscadmin.h:150
char * image
Definition: generic_xlog.c:56
Buffer buffer
Definition: generic_xlog.c:53
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:461
void XLogRegisterBufData(uint8 block_id, char *data, uint32 len)
Definition: xloginsert.c:392
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:243
void XLogBeginInsert(void)
Definition: xloginsert.c:150
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define REGBUF_FORCE_IMAGE
Definition: xloginsert.h:31

References PageData::buffer, BufferGetPage(), BufferIsInvalid, computeDelta(), PageData::delta, PageData::deltaLen, END_CRIT_SECTION, PageData::flags, GENERIC_XLOG_FULL_IMAGE, i, if(), PageData::image, InvalidXLogRecPtr, MarkBufferDirty(), MAX_GENERIC_XLOG_PAGES, PageSetLSN(), PageHeaderData::pd_lower, PageHeaderData::pd_upper, pfree(), REGBUF_FORCE_IMAGE, REGBUF_STANDARD, START_CRIT_SECTION, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), and XLogRegisterBuffer().

Referenced by blbulkdelete(), blinsert(), BloomInitMetapage(), and flushCachedPage().

◆ GenericXLogRegisterBuffer()

Page GenericXLogRegisterBuffer ( GenericXLogState state,
Buffer  buffer,
int  flags 
)

Definition at line 300 of file generic_xlog.c.

301 {
302  int block_id;
303 
304  /* Search array for existing entry or first unused slot */
305  for (block_id = 0; block_id < MAX_GENERIC_XLOG_PAGES; block_id++)
306  {
307  PageData *page = &state->pages[block_id];
308 
309  if (BufferIsInvalid(page->buffer))
310  {
311  /* Empty slot, so use it (there cannot be a match later) */
312  page->buffer = buffer;
313  page->flags = flags;
314  memcpy(page->image, BufferGetPage(buffer), BLCKSZ);
315  return (Page) page->image;
316  }
317  else if (page->buffer == buffer)
318  {
319  /*
320  * Buffer is already registered. Just return the image, which is
321  * already prepared.
322  */
323  return (Page) page->image;
324  }
325  }
326 
327  elog(ERROR, "maximum number %d of generic xlog buffers is exceeded",
329  /* keep compiler quiet */
330  return NULL;
331 }

References PageData::buffer, BufferGetPage(), BufferIsInvalid, elog(), ERROR, PageData::flags, PageData::image, and MAX_GENERIC_XLOG_PAGES.

Referenced by blbulkdelete(), blinsert(), BloomInitMetapage(), and flushCachedPage().

◆ GenericXLogStart()

GenericXLogState* GenericXLogStart ( Relation  relation)

Definition at line 270 of file generic_xlog.c.

271 {
273  int i;
274 
277  0);
278  state->isLogged = RelationNeedsWAL(relation);
279 
280  for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
281  {
282  state->pages[i].image = state->images[i].data;
283  state->pages[i].buffer = InvalidBuffer;
284  }
285 
286  return state;
287 }
void * palloc_aligned(Size size, Size alignto, int flags)
Definition: mcxt.c:1446
#define PG_IO_ALIGN_SIZE
#define RelationNeedsWAL(relation)
Definition: rel.h:629

References i, InvalidBuffer, MAX_GENERIC_XLOG_PAGES, palloc_aligned(), PG_IO_ALIGN_SIZE, and RelationNeedsWAL.

Referenced by blbulkdelete(), blinsert(), BloomInitMetapage(), and flushCachedPage().

◆ writeFragment()

static void writeFragment ( PageData pageData,
OffsetNumber  offset,
OffsetNumber  length,
const char *  data 
)
static

Definition at line 91 of file generic_xlog.c.

93 {
94  char *ptr = pageData->delta + pageData->deltaLen;
95 
96  /* Verify we have enough space */
97  Assert(pageData->deltaLen + sizeof(offset) +
98  sizeof(length) + length <= sizeof(pageData->delta));
99 
100  /* Write fragment data */
101  memcpy(ptr, &offset, sizeof(offset));
102  ptr += sizeof(offset);
103  memcpy(ptr, &length, sizeof(length));
104  ptr += sizeof(length);
105  memcpy(ptr, data, length);
106  ptr += length;
107 
108  pageData->deltaLen = ptr - pageData->delta;
109 }
const void * data

References Assert(), data, PageData::delta, and PageData::deltaLen.

Referenced by computeRegionDelta().