PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
ginxlog.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * ginxlog.c
4  * WAL replay logic for inverted index.
5  *
6  *
7  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/access/gin/ginxlog.c
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "access/bufmask.h"
17 #include "access/gin_private.h"
18 #include "access/ginxlog.h"
19 #include "access/xlogutils.h"
20 #include "utils/memutils.h"
21 
22 static MemoryContext opCtx; /* working memory for operations */
23 
24 static void
26 {
27  XLogRecPtr lsn = record->EndRecPtr;
28  Buffer buffer;
29  Page page;
30 
31  if (XLogReadBufferForRedo(record, block_id, &buffer) == BLK_NEEDS_REDO)
32  {
33  page = (Page) BufferGetPage(buffer);
34  GinPageGetOpaque(page)->flags &= ~GIN_INCOMPLETE_SPLIT;
35 
36  PageSetLSN(page, lsn);
37  MarkBufferDirty(buffer);
38  }
39  if (BufferIsValid(buffer))
40  UnlockReleaseBuffer(buffer);
41 }
42 
43 static void
45 {
46  XLogRecPtr lsn = record->EndRecPtr;
47  Buffer RootBuffer,
48  MetaBuffer;
49  Page page;
50 
51  MetaBuffer = XLogInitBufferForRedo(record, 0);
53  page = (Page) BufferGetPage(MetaBuffer);
54 
55  GinInitMetabuffer(MetaBuffer);
56 
57  PageSetLSN(page, lsn);
58  MarkBufferDirty(MetaBuffer);
59 
60  RootBuffer = XLogInitBufferForRedo(record, 1);
62  page = (Page) BufferGetPage(RootBuffer);
63 
64  GinInitBuffer(RootBuffer, GIN_LEAF);
65 
66  PageSetLSN(page, lsn);
67  MarkBufferDirty(RootBuffer);
68 
69  UnlockReleaseBuffer(RootBuffer);
70  UnlockReleaseBuffer(MetaBuffer);
71 }
72 
73 static void
75 {
76  XLogRecPtr lsn = record->EndRecPtr;
78  char *ptr;
79  Buffer buffer;
80  Page page;
81 
82  buffer = XLogInitBufferForRedo(record, 0);
83  page = (Page) BufferGetPage(buffer);
84 
86 
87  ptr = XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree);
88 
89  /* Place page data */
90  memcpy(GinDataLeafPageGetPostingList(page), ptr, data->size);
91 
92  GinDataPageSetDataSize(page, data->size);
93 
94  PageSetLSN(page, lsn);
95 
96  MarkBufferDirty(buffer);
97  UnlockReleaseBuffer(buffer);
98 }
99 
100 static void
101 ginRedoInsertEntry(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
102 {
103  Page page = BufferGetPage(buffer);
104  ginxlogInsertEntry *data = (ginxlogInsertEntry *) rdata;
105  OffsetNumber offset = data->offset;
106  IndexTuple itup;
107 
108  if (rightblkno != InvalidBlockNumber)
109  {
110  /* update link to right page after split */
111  Assert(!GinPageIsLeaf(page));
112  Assert(offset >= FirstOffsetNumber && offset <= PageGetMaxOffsetNumber(page));
113  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offset));
114  GinSetDownlink(itup, rightblkno);
115  }
116 
117  if (data->isDelete)
118  {
119  Assert(GinPageIsLeaf(page));
120  Assert(offset >= FirstOffsetNumber && offset <= PageGetMaxOffsetNumber(page));
121  PageIndexTupleDelete(page, offset);
122  }
123 
124  itup = &data->tuple;
125 
126  if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), offset, false, false) == InvalidOffsetNumber)
127  {
128  RelFileNode node;
129  ForkNumber forknum;
130  BlockNumber blknum;
131 
132  BufferGetTag(buffer, &node, &forknum, &blknum);
133  elog(ERROR, "failed to add item to index page in %u/%u/%u",
134  node.spcNode, node.dbNode, node.relNode);
135  }
136 }
137 
138 static void
140 {
141  int actionno;
142  int segno;
143  GinPostingList *oldseg;
144  Pointer segmentend;
145  char *walbuf;
146  int totalsize;
147 
148  /*
149  * If the page is in pre-9.4 format, convert to new format first.
150  */
151  if (!GinPageIsCompressed(page))
152  {
153  ItemPointer uncompressed = (ItemPointer) GinDataPageGetData(page);
154  int nuncompressed = GinPageGetOpaque(page)->maxoff;
155  int npacked;
156  GinPostingList *plist;
157 
158  plist = ginCompressPostingList(uncompressed, nuncompressed,
159  BLCKSZ, &npacked);
160  Assert(npacked == nuncompressed);
161 
162  totalsize = SizeOfGinPostingList(plist);
163 
164  memcpy(GinDataLeafPageGetPostingList(page), plist, totalsize);
165  GinDataPageSetDataSize(page, totalsize);
166  GinPageSetCompressed(page);
167  GinPageGetOpaque(page)->maxoff = InvalidOffsetNumber;
168  }
169 
170  oldseg = GinDataLeafPageGetPostingList(page);
171  segmentend = (Pointer) oldseg + GinDataLeafPageGetPostingListSize(page);
172  segno = 0;
173 
174  walbuf = ((char *) data) + sizeof(ginxlogRecompressDataLeaf);
175  for (actionno = 0; actionno < data->nactions; actionno++)
176  {
177  uint8 a_segno = *((uint8 *) (walbuf++));
178  uint8 a_action = *((uint8 *) (walbuf++));
179  GinPostingList *newseg = NULL;
180  int newsegsize = 0;
181  ItemPointerData *items = NULL;
182  uint16 nitems = 0;
183  ItemPointerData *olditems;
184  int nolditems;
185  ItemPointerData *newitems;
186  int nnewitems;
187  int segsize;
188  Pointer segptr;
189  int szleft;
190 
191  /* Extract all the information we need from the WAL record */
192  if (a_action == GIN_SEGMENT_INSERT ||
193  a_action == GIN_SEGMENT_REPLACE)
194  {
195  newseg = (GinPostingList *) walbuf;
196  newsegsize = SizeOfGinPostingList(newseg);
197  walbuf += SHORTALIGN(newsegsize);
198  }
199 
200  if (a_action == GIN_SEGMENT_ADDITEMS)
201  {
202  memcpy(&nitems, walbuf, sizeof(uint16));
203  walbuf += sizeof(uint16);
204  items = (ItemPointerData *) walbuf;
205  walbuf += nitems * sizeof(ItemPointerData);
206  }
207 
208  /* Skip to the segment that this action concerns */
209  Assert(segno <= a_segno);
210  while (segno < a_segno)
211  {
212  oldseg = GinNextPostingListSegment(oldseg);
213  segno++;
214  }
215 
216  /*
217  * ADDITEMS action is handled like REPLACE, but the new segment to
218  * replace the old one is reconstructed using the old segment from
219  * disk and the new items from the WAL record.
220  */
221  if (a_action == GIN_SEGMENT_ADDITEMS)
222  {
223  int npacked;
224 
225  olditems = ginPostingListDecode(oldseg, &nolditems);
226 
227  newitems = ginMergeItemPointers(items, nitems,
228  olditems, nolditems,
229  &nnewitems);
230  Assert(nnewitems == nolditems + nitems);
231 
232  newseg = ginCompressPostingList(newitems, nnewitems,
233  BLCKSZ, &npacked);
234  Assert(npacked == nnewitems);
235 
236  newsegsize = SizeOfGinPostingList(newseg);
237  a_action = GIN_SEGMENT_REPLACE;
238  }
239 
240  segptr = (Pointer) oldseg;
241  if (segptr != segmentend)
242  segsize = SizeOfGinPostingList(oldseg);
243  else
244  {
245  /*
246  * Positioned after the last existing segment. Only INSERTs
247  * expected here.
248  */
249  Assert(a_action == GIN_SEGMENT_INSERT);
250  segsize = 0;
251  }
252  szleft = segmentend - segptr;
253 
254  switch (a_action)
255  {
256  case GIN_SEGMENT_DELETE:
257  memmove(segptr, segptr + segsize, szleft - segsize);
258  segmentend -= segsize;
259 
260  segno++;
261  break;
262 
263  case GIN_SEGMENT_INSERT:
264  /* make room for the new segment */
265  memmove(segptr + newsegsize, segptr, szleft);
266  /* copy the new segment in place */
267  memcpy(segptr, newseg, newsegsize);
268  segmentend += newsegsize;
269  segptr += newsegsize;
270  break;
271 
272  case GIN_SEGMENT_REPLACE:
273  /* shift the segments that follow */
274  memmove(segptr + newsegsize,
275  segptr + segsize,
276  szleft - segsize);
277  /* copy the replacement segment in place */
278  memcpy(segptr, newseg, newsegsize);
279  segmentend -= segsize;
280  segmentend += newsegsize;
281  segptr += newsegsize;
282  segno++;
283  break;
284 
285  default:
286  elog(ERROR, "unexpected GIN leaf action: %u", a_action);
287  }
288  oldseg = (GinPostingList *) segptr;
289  }
290 
291  totalsize = segmentend - (Pointer) GinDataLeafPageGetPostingList(page);
292  GinDataPageSetDataSize(page, totalsize);
293 }
294 
295 static void
296 ginRedoInsertData(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
297 {
298  Page page = BufferGetPage(buffer);
299 
300  if (isLeaf)
301  {
303 
304  Assert(GinPageIsLeaf(page));
305 
306  ginRedoRecompress(page, data);
307  }
308  else
309  {
311  PostingItem *oldpitem;
312 
313  Assert(!GinPageIsLeaf(page));
314 
315  /* update link to right page after split */
316  oldpitem = GinDataPageGetPostingItem(page, data->offset);
317  PostingItemSetBlockNumber(oldpitem, rightblkno);
318 
319  GinDataPageAddPostingItem(page, &data->newitem, data->offset);
320  }
321 }
322 
323 static void
325 {
326  XLogRecPtr lsn = record->EndRecPtr;
327  ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record);
328  Buffer buffer;
329 #ifdef NOT_USED
330  BlockNumber leftChildBlkno = InvalidBlockNumber;
331 #endif
332  BlockNumber rightChildBlkno = InvalidBlockNumber;
333  bool isLeaf = (data->flags & GIN_INSERT_ISLEAF) != 0;
334 
335  /*
336  * First clear incomplete-split flag on child page if this finishes a
337  * split.
338  */
339  if (!isLeaf)
340  {
341  char *payload = XLogRecGetData(record) + sizeof(ginxlogInsert);
342 
343 #ifdef NOT_USED
344  leftChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
345 #endif
346  payload += sizeof(BlockIdData);
347  rightChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
348  payload += sizeof(BlockIdData);
349 
350  ginRedoClearIncompleteSplit(record, 1);
351  }
352 
353  if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
354  {
355  Page page = BufferGetPage(buffer);
356  Size len;
357  char *payload = XLogRecGetBlockData(record, 0, &len);
358 
359  /* How to insert the payload is tree-type specific */
360  if (data->flags & GIN_INSERT_ISDATA)
361  {
362  Assert(GinPageIsData(page));
363  ginRedoInsertData(buffer, isLeaf, rightChildBlkno, payload);
364  }
365  else
366  {
367  Assert(!GinPageIsData(page));
368  ginRedoInsertEntry(buffer, isLeaf, rightChildBlkno, payload);
369  }
370 
371  PageSetLSN(page, lsn);
372  MarkBufferDirty(buffer);
373  }
374  if (BufferIsValid(buffer))
375  UnlockReleaseBuffer(buffer);
376 }
377 
378 static void
380 {
381  ginxlogSplit *data = (ginxlogSplit *) XLogRecGetData(record);
382  Buffer lbuffer,
383  rbuffer,
384  rootbuf;
385  bool isLeaf = (data->flags & GIN_INSERT_ISLEAF) != 0;
386  bool isRoot = (data->flags & GIN_SPLIT_ROOT) != 0;
387 
388  /*
389  * First clear incomplete-split flag on child page if this finishes a
390  * split
391  */
392  if (!isLeaf)
393  ginRedoClearIncompleteSplit(record, 3);
394 
395  if (XLogReadBufferForRedo(record, 0, &lbuffer) != BLK_RESTORED)
396  elog(ERROR, "GIN split record did not contain a full-page image of left page");
397 
398  if (XLogReadBufferForRedo(record, 1, &rbuffer) != BLK_RESTORED)
399  elog(ERROR, "GIN split record did not contain a full-page image of right page");
400 
401  if (isRoot)
402  {
403  if (XLogReadBufferForRedo(record, 2, &rootbuf) != BLK_RESTORED)
404  elog(ERROR, "GIN split record did not contain a full-page image of root page");
405  UnlockReleaseBuffer(rootbuf);
406  }
407 
408  UnlockReleaseBuffer(rbuffer);
409  UnlockReleaseBuffer(lbuffer);
410 }
411 
412 /*
413  * VACUUM_PAGE record contains simply a full image of the page, similar to
414  * an XLOG_FPI record.
415  */
416 static void
418 {
419  Buffer buffer;
420 
421  if (XLogReadBufferForRedo(record, 0, &buffer) != BLK_RESTORED)
422  {
423  elog(ERROR, "replay of gin entry tree page vacuum did not restore the page");
424  }
425  UnlockReleaseBuffer(buffer);
426 }
427 
428 static void
430 {
431  XLogRecPtr lsn = record->EndRecPtr;
432  Buffer buffer;
433 
434  if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
435  {
436  Page page = BufferGetPage(buffer);
437  Size len;
439 
440  xlrec = (ginxlogVacuumDataLeafPage *) XLogRecGetBlockData(record, 0, &len);
441 
442  Assert(GinPageIsLeaf(page));
443  Assert(GinPageIsData(page));
444 
445  ginRedoRecompress(page, &xlrec->data);
446  PageSetLSN(page, lsn);
447  MarkBufferDirty(buffer);
448  }
449  if (BufferIsValid(buffer))
450  UnlockReleaseBuffer(buffer);
451 }
452 
453 static void
455 {
456  XLogRecPtr lsn = record->EndRecPtr;
458  Buffer dbuffer;
459  Buffer pbuffer;
460  Buffer lbuffer;
461  Page page;
462 
463  if (XLogReadBufferForRedo(record, 0, &dbuffer) == BLK_NEEDS_REDO)
464  {
465  page = BufferGetPage(dbuffer);
466  Assert(GinPageIsData(page));
467  GinPageGetOpaque(page)->flags = GIN_DELETED;
468  PageSetLSN(page, lsn);
469  MarkBufferDirty(dbuffer);
470  }
471 
472  if (XLogReadBufferForRedo(record, 1, &pbuffer) == BLK_NEEDS_REDO)
473  {
474  page = BufferGetPage(pbuffer);
475  Assert(GinPageIsData(page));
476  Assert(!GinPageIsLeaf(page));
478  PageSetLSN(page, lsn);
479  MarkBufferDirty(pbuffer);
480  }
481 
482  if (XLogReadBufferForRedo(record, 2, &lbuffer) == BLK_NEEDS_REDO)
483  {
484  page = BufferGetPage(lbuffer);
485  Assert(GinPageIsData(page));
486  GinPageGetOpaque(page)->rightlink = data->rightLink;
487  PageSetLSN(page, lsn);
488  MarkBufferDirty(lbuffer);
489  }
490 
491  if (BufferIsValid(lbuffer))
492  UnlockReleaseBuffer(lbuffer);
493  if (BufferIsValid(pbuffer))
494  UnlockReleaseBuffer(pbuffer);
495  if (BufferIsValid(dbuffer))
496  UnlockReleaseBuffer(dbuffer);
497 }
498 
499 static void
501 {
502  XLogRecPtr lsn = record->EndRecPtr;
504  Buffer metabuffer;
505  Page metapage;
506  Buffer buffer;
507 
508  /*
509  * Restore the metapage. This is essentially the same as a full-page
510  * image, so restore the metapage unconditionally without looking at the
511  * LSN, to avoid torn page hazards.
512  */
513  metabuffer = XLogInitBufferForRedo(record, 0);
515  metapage = BufferGetPage(metabuffer);
516 
517  GinInitPage(metapage, GIN_META, BufferGetPageSize(metabuffer));
518  memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
519  PageSetLSN(metapage, lsn);
520  MarkBufferDirty(metabuffer);
521 
522  if (data->ntuples > 0)
523  {
524  /*
525  * insert into tail page
526  */
527  if (XLogReadBufferForRedo(record, 1, &buffer) == BLK_NEEDS_REDO)
528  {
529  Page page = BufferGetPage(buffer);
530  OffsetNumber off;
531  int i;
532  Size tupsize;
533  char *payload;
534  IndexTuple tuples;
535  Size totaltupsize;
536 
537  payload = XLogRecGetBlockData(record, 1, &totaltupsize);
538  tuples = (IndexTuple) payload;
539 
540  if (PageIsEmpty(page))
541  off = FirstOffsetNumber;
542  else
544 
545  for (i = 0; i < data->ntuples; i++)
546  {
547  tupsize = IndexTupleSize(tuples);
548 
549  if (PageAddItem(page, (Item) tuples, tupsize, off,
550  false, false) == InvalidOffsetNumber)
551  elog(ERROR, "failed to add item to index page");
552 
553  tuples = (IndexTuple) (((char *) tuples) + tupsize);
554 
555  off++;
556  }
557  Assert(payload + totaltupsize == (char *) tuples);
558 
559  /*
560  * Increase counter of heap tuples
561  */
562  GinPageGetOpaque(page)->maxoff++;
563 
564  PageSetLSN(page, lsn);
565  MarkBufferDirty(buffer);
566  }
567  if (BufferIsValid(buffer))
568  UnlockReleaseBuffer(buffer);
569  }
570  else if (data->prevTail != InvalidBlockNumber)
571  {
572  /*
573  * New tail
574  */
575  if (XLogReadBufferForRedo(record, 1, &buffer) == BLK_NEEDS_REDO)
576  {
577  Page page = BufferGetPage(buffer);
578 
579  GinPageGetOpaque(page)->rightlink = data->newRightlink;
580 
581  PageSetLSN(page, lsn);
582  MarkBufferDirty(buffer);
583  }
584  if (BufferIsValid(buffer))
585  UnlockReleaseBuffer(buffer);
586  }
587 
588  UnlockReleaseBuffer(metabuffer);
589 }
590 
591 static void
593 {
594  XLogRecPtr lsn = record->EndRecPtr;
596  Buffer buffer;
597  Page page;
598  OffsetNumber l,
599  off = FirstOffsetNumber;
600  int i,
601  tupsize;
602  char *payload;
603  IndexTuple tuples;
604  Size totaltupsize;
605 
606  /* We always re-initialize the page. */
607  buffer = XLogInitBufferForRedo(record, 0);
608  page = BufferGetPage(buffer);
609 
610  GinInitBuffer(buffer, GIN_LIST);
611  GinPageGetOpaque(page)->rightlink = data->rightlink;
612  if (data->rightlink == InvalidBlockNumber)
613  {
614  /* tail of sublist */
615  GinPageSetFullRow(page);
616  GinPageGetOpaque(page)->maxoff = 1;
617  }
618  else
619  {
620  GinPageGetOpaque(page)->maxoff = 0;
621  }
622 
623  payload = XLogRecGetBlockData(record, 0, &totaltupsize);
624 
625  tuples = (IndexTuple) payload;
626  for (i = 0; i < data->ntuples; i++)
627  {
628  tupsize = IndexTupleSize(tuples);
629 
630  l = PageAddItem(page, (Item) tuples, tupsize, off, false, false);
631 
632  if (l == InvalidOffsetNumber)
633  elog(ERROR, "failed to add item to index page");
634 
635  tuples = (IndexTuple) (((char *) tuples) + tupsize);
636  off++;
637  }
638  Assert((char *) tuples == payload + totaltupsize);
639 
640  PageSetLSN(page, lsn);
641  MarkBufferDirty(buffer);
642 
643  UnlockReleaseBuffer(buffer);
644 }
645 
646 static void
648 {
649  XLogRecPtr lsn = record->EndRecPtr;
651  Buffer metabuffer;
652  Page metapage;
653  int i;
654 
655  metabuffer = XLogInitBufferForRedo(record, 0);
657  metapage = BufferGetPage(metabuffer);
658 
659  GinInitPage(metapage, GIN_META, BufferGetPageSize(metabuffer));
660 
661  memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
662  PageSetLSN(metapage, lsn);
663  MarkBufferDirty(metabuffer);
664 
665  /*
666  * In normal operation, shiftList() takes exclusive lock on all the
667  * pages-to-be-deleted simultaneously. During replay, however, it should
668  * be all right to lock them one at a time. This is dependent on the fact
669  * that we are deleting pages from the head of the list, and that readers
670  * share-lock the next page before releasing the one they are on. So we
671  * cannot get past a reader that is on, or due to visit, any page we are
672  * going to delete. New incoming readers will block behind our metapage
673  * lock and then see a fully updated page list.
674  *
675  * No full-page images are taken of the deleted pages. Instead, they are
676  * re-initialized as empty, deleted pages. Their right-links don't need to
677  * be preserved, because no new readers can see the pages, as explained
678  * above.
679  */
680  for (i = 0; i < data->ndeleted; i++)
681  {
682  Buffer buffer;
683  Page page;
684 
685  buffer = XLogInitBufferForRedo(record, i + 1);
686  page = BufferGetPage(buffer);
687  GinInitBuffer(buffer, GIN_DELETED);
688 
689  PageSetLSN(page, lsn);
690  MarkBufferDirty(buffer);
691 
692  UnlockReleaseBuffer(buffer);
693  }
694  UnlockReleaseBuffer(metabuffer);
695 }
696 
697 void
699 {
700  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
701  MemoryContext oldCtx;
702 
703  /*
704  * GIN indexes do not require any conflict processing. NB: If we ever
705  * implement a similar optimization as we have in b-tree, and remove
706  * killed tuples outside VACUUM, we'll need to handle that here.
707  */
708 
709  oldCtx = MemoryContextSwitchTo(opCtx);
710  switch (info)
711  {
713  ginRedoCreateIndex(record);
714  break;
716  ginRedoCreatePTree(record);
717  break;
718  case XLOG_GIN_INSERT:
719  ginRedoInsert(record);
720  break;
721  case XLOG_GIN_SPLIT:
722  ginRedoSplit(record);
723  break;
725  ginRedoVacuumPage(record);
726  break;
729  break;
731  ginRedoDeletePage(record);
732  break;
734  ginRedoUpdateMetapage(record);
735  break;
737  ginRedoInsertListPage(record);
738  break;
740  ginRedoDeleteListPages(record);
741  break;
742  default:
743  elog(PANIC, "gin_redo: unknown op code %u", info);
744  }
745  MemoryContextSwitchTo(oldCtx);
746  MemoryContextReset(opCtx);
747 }
748 
749 void
751 {
753  "GIN recovery temporary context",
755 }
756 
757 void
759 {
760  MemoryContextDelete(opCtx);
761  opCtx = NULL;
762 }
763 
764 /*
765  * Mask a GIN page before running consistency checks on it.
766  */
767 void
768 gin_mask(char *pagedata, BlockNumber blkno)
769 {
770  Page page = (Page) pagedata;
771  GinPageOpaque opaque;
772 
773  mask_page_lsn(page);
774  opaque = GinPageGetOpaque(page);
775 
776  mask_page_hint_bits(page);
777 
778  /*
779  * GIN metapage doesn't use pd_lower/pd_upper. Other page types do. Hence,
780  * we need to apply masking for those pages.
781  */
782  if (opaque->flags != GIN_META)
783  {
784  /*
785  * For GIN_DELETED page, the page is initialized to empty. Hence, mask
786  * the page content.
787  */
788  if (opaque->flags & GIN_DELETED)
789  mask_page_content(page);
790  else
791  mask_unused_space(page);
792  }
793 }
BlockNumber prevTail
Definition: ginxlog.h:173
#define GIN_DELETED
Definition: ginblock.h:41
#define BlockIdGetBlockNumber(blockId)
Definition: block.h:115
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:179
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:357
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
static void ginRedoUpdateMetapage(XLogReaderState *record)
Definition: ginxlog.c:500
#define PageIsEmpty(page)
Definition: bufpage.h:219
struct ginxlogCreatePostingTree ginxlogCreatePostingTree
BlockNumber rightlink
Definition: ginxlog.h:185
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:338
void gin_xlog_startup(void)
Definition: ginxlog.c:750
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded)
static void ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
Definition: ginxlog.c:139
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:727
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
OffsetNumber offset
Definition: ginxlog.h:101
BlockNumber rightLink
Definition: ginxlog.h:160
static void ginRedoSplit(XLogReaderState *record)
Definition: ginxlog.c:379
static MemoryContext opCtx
Definition: ginxlog.c:22
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned char uint8
Definition: c.h:266
Pointer Item
Definition: item.h:17
void mask_page_hint_bits(Page page)
Definition: bufmask.c:44
#define GinDataPageGetData(page)
Definition: ginblock.h:279
static void ginRedoInsertEntry(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
Definition: ginxlog.c:101
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:413
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define GIN_METAPAGE_BLKNO
Definition: ginblock.h:50
void gin_xlog_cleanup(void)
Definition: ginxlog.c:758
ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb, int *nmerged)
#define GIN_SPLIT_ROOT
Definition: ginxlog.h:128
#define GIN_INSERT_ISLEAF
Definition: ginxlog.h:127
OffsetNumber parentOffset
Definition: ginxlog.h:159
#define PANIC
Definition: elog.h:53
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
#define GIN_COMPRESSED
Definition: ginblock.h:47
#define GinPageIsCompressed(page)
Definition: ginblock.h:120
#define GinSetDownlink(itup, blkno)
Definition: ginblock.h:242
uint16 flags
Definition: ginxlog.h:41
ginxlogRecompressDataLeaf data
Definition: ginxlog.h:147
#define GIN_SEGMENT_INSERT
Definition: ginxlog.h:95
void mask_unused_space(Page page)
Definition: bufmask.c:69
XLogRecPtr EndRecPtr
Definition: xlogreader.h:115
uint16 OffsetNumber
Definition: off.h:24
ItemPointerData * ItemPointer
Definition: itemptr.h:48
#define XLOG_GIN_INSERT_LISTPAGE
Definition: ginxlog.h:181
#define GIN_DATA
Definition: ginblock.h:39
GinMetaPageData metadata
Definition: ginxlog.h:206
void mask_page_content(Page page)
Definition: bufmask.c:117
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:293
unsigned short uint16
Definition: c.h:267
char * Pointer
Definition: c.h:245
#define XLogRecGetData(decoder)
Definition: xlogreader.h:218
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:376
#define GIN_SEGMENT_REPLACE
Definition: ginxlog.h:96
static void ginRedoDeleteListPages(XLogReaderState *record)
Definition: ginxlog.c:647
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:327
#define GinPageSetCompressed(page)
Definition: ginblock.h:121
#define ERROR
Definition: elog.h:43
#define GIN_META
Definition: ginblock.h:42
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:21
void mask_page_lsn(Page page)
Definition: bufmask.c:30
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:264
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:282
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:302
static void ginRedoVacuumDataLeafPage(XLogReaderState *record)
Definition: ginxlog.c:429
#define XLOG_GIN_UPDATE_META_PAGE
Definition: ginxlog.h:163
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
BlockNumber blkno
Definition: ginvacuum.c:118
#define GIN_LIST
Definition: ginblock.h:43
#define GIN_INSERT_ISDATA
Definition: ginxlog.h:126
#define memmove(d, s, c)
Definition: c.h:1058
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define GIN_SEGMENT_ADDITEMS
Definition: ginxlog.h:97
void gin_mask(char *pagedata, BlockNumber blkno)
Definition: ginxlog.c:768
#define GIN_SEGMENT_DELETE
Definition: ginxlog.h:94
void gin_redo(XLogReaderState *record)
Definition: ginxlog.c:698
static void ginRedoCreatePTree(XLogReaderState *record)
Definition: ginxlog.c:74
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
static uint64 totalsize
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:214
BlockNumber newRightlink
Definition: ginxlog.h:174
ForkNumber
Definition: relpath.h:24
#define XLOG_GIN_CREATE_INDEX
Definition: ginxlog.h:19
#define XLOG_GIN_VACUUM_DATA_LEAF_PAGE
Definition: ginxlog.h:143
#define GinPageSetFullRow(page)
Definition: ginblock.h:119
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
#define XLOG_GIN_VACUUM_PAGE
Definition: ginxlog.h:137
static void ginRedoInsert(XLogReaderState *record)
Definition: ginxlog.c:324
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:1331
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:262
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
void GinPageDeletePostingItem(Page page, OffsetNumber offset)
Definition: gindatapage.c:413
static void ginRedoClearIncompleteSplit(XLogReaderState *record, uint8 block_id)
Definition: ginxlog.c:25
IndexTupleData tuple
Definition: ginxlog.h:63
static void ginRedoVacuumPage(XLogReaderState *record)
Definition: ginxlog.c:417
#define InvalidOffsetNumber
Definition: off.h:26
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:290
GinMetaPageData metadata
Definition: ginxlog.h:172
#define GinPageIsData(page)
Definition: ginblock.h:114
struct BlockIdData BlockIdData
OffsetNumber offset
Definition: ginxlog.h:61
#define NULL
Definition: c.h:229
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:207
struct ItemPointerData ItemPointerData
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
size_t Size
Definition: c.h:356
#define InvalidBlockNumber
Definition: block.h:33
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:351
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
#define GIN_INCOMPLETE_SPLIT
Definition: ginblock.h:45
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define XLOG_GIN_INSERT
Definition: ginxlog.h:37
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:326
int i
static void ginRedoDeletePage(XLogReaderState *record)
Definition: ginxlog.c:454
#define GinPageGetMeta(p)
Definition: ginblock.h:103
#define elog
Definition: elog.h:219
static void ginRedoInsertListPage(XLogReaderState *record)
Definition: ginxlog.c:592
#define SHORTALIGN(LEN)
Definition: c.h:584
void BufferGetTag(Buffer buffer, RelFileNode *rnode, ForkNumber *forknum, BlockNumber *blknum)
Definition: bufmgr.c:2626
#define XLOG_GIN_DELETE_PAGE
Definition: ginxlog.h:155
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
static void ginRedoInsertData(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
Definition: ginxlog.c:296
int Buffer
Definition: buf.h:23
uint16 flags
Definition: ginxlog.h:120
static void ginRedoCreateIndex(XLogReaderState *record)
Definition: ginxlog.c:44
#define XLOG_GIN_SPLIT
Definition: ginxlog.h:111
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
#define GIN_ROOT_BLKNO
Definition: ginblock.h:51
Pointer Page
Definition: bufpage.h:74
#define IndexTupleSize(itup)
Definition: itup.h:70
#define GIN_LEAF
Definition: ginblock.h:40
#define XLOG_GIN_DELETE_LISTPAGE
Definition: ginxlog.h:195