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