LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginxlog.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB
Current: Differential Code Coverage HEAD vs 15 Lines: 74.3 % 374 278 1 95 278 1
Current Date: 2023-04-08 17:13:01 Functions: 82.4 % 17 14 3 1 13
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (180,240] days: 0.0 % 1 0 1
Legend: Lines: hit not hit (240..) days: 74.5 % 373 278 1 94 278
Function coverage date bins:
(240..) days: 82.4 % 17 14 3 1 13

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * ginxlog.c
                                  4                 :  *    WAL replay logic for inverted index.
                                  5                 :  *
                                  6                 :  *
                                  7                 :  * Portions Copyright (c) 1996-2023, 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
 3062 heikki.linnakangas         25 CBC         139 : ginRedoClearIncompleteSplit(XLogReaderState *record, uint8 block_id)
                                 26                 : {
                                 27             139 :     XLogRecPtr  lsn = record->EndRecPtr;
                                 28                 :     Buffer      buffer;
                                 29                 :     Page        page;
                                 30                 : 
                                 31             139 :     if (XLogReadBufferForRedo(record, block_id, &buffer) == BLK_NEEDS_REDO)
                                 32                 :     {
 2545 kgrittn                    33             139 :         page = (Page) BufferGetPage(buffer);
 3420 heikki.linnakangas         34             139 :         GinPageGetOpaque(page)->flags &= ~GIN_INCOMPLETE_SPLIT;
                                 35                 : 
                                 36             139 :         PageSetLSN(page, lsn);
                                 37             139 :         MarkBufferDirty(buffer);
                                 38                 :     }
 3161                            39             139 :     if (BufferIsValid(buffer))
                                 40             139 :         UnlockReleaseBuffer(buffer);
 6186 teodor                     41             139 : }
                                 42                 : 
                                 43                 : static void
 3062 heikki.linnakangas         44               3 : ginRedoCreatePTree(XLogReaderState *record)
                                 45                 : {
                                 46               3 :     XLogRecPtr  lsn = record->EndRecPtr;
 6031 bruce                      47               3 :     ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree *) XLogRecGetData(record);
                                 48                 :     char       *ptr;
                                 49                 :     Buffer      buffer;
                                 50                 :     Page        page;
                                 51                 : 
 3062 heikki.linnakangas         52               3 :     buffer = XLogInitBufferForRedo(record, 0);
 2545 kgrittn                    53               3 :     page = (Page) BufferGetPage(buffer);
                                 54                 : 
 3364 heikki.linnakangas         55               3 :     GinInitBuffer(buffer, GIN_DATA | GIN_LEAF | GIN_COMPRESSED);
                                 56                 : 
                                 57               3 :     ptr = XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree);
                                 58                 : 
                                 59                 :     /* Place page data */
                                 60               3 :     memcpy(GinDataLeafPageGetPostingList(page), ptr, data->size);
                                 61                 : 
 3282                            62               3 :     GinDataPageSetDataSize(page, data->size);
                                 63                 : 
 6186 teodor                     64               3 :     PageSetLSN(page, lsn);
                                 65                 : 
                                 66               3 :     MarkBufferDirty(buffer);
                                 67               3 :     UnlockReleaseBuffer(buffer);
                                 68               3 : }
                                 69                 : 
                                 70                 : static void
 3364 heikki.linnakangas         71           23658 : ginRedoInsertEntry(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
                                 72                 : {
 2545 kgrittn                    73           23658 :     Page        page = BufferGetPage(buffer);
 3420 heikki.linnakangas         74           23658 :     ginxlogInsertEntry *data = (ginxlogInsertEntry *) rdata;
 3364                            75           23658 :     OffsetNumber offset = data->offset;
                                 76                 :     IndexTuple  itup;
                                 77                 : 
 3420                            78           23658 :     if (rightblkno != InvalidBlockNumber)
                                 79                 :     {
                                 80                 :         /* update link to right page after split */
                                 81             136 :         Assert(!GinPageIsLeaf(page));
                                 82             136 :         Assert(offset >= FirstOffsetNumber && offset <= PageGetMaxOffsetNumber(page));
                                 83             136 :         itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offset));
                                 84             136 :         GinSetDownlink(itup, rightblkno);
                                 85                 :     }
                                 86                 : 
                                 87           23658 :     if (data->isDelete)
                                 88                 :     {
                                 89            3660 :         Assert(GinPageIsLeaf(page));
                                 90            3660 :         Assert(offset >= FirstOffsetNumber && offset <= PageGetMaxOffsetNumber(page));
                                 91            3660 :         PageIndexTupleDelete(page, offset);
                                 92                 :     }
                                 93                 : 
                                 94           23658 :     itup = &data->tuple;
                                 95                 : 
                                 96           23658 :     if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), offset, false, false) == InvalidOffsetNumber)
                                 97                 :     {
                                 98                 :         RelFileLocator locator;
                                 99                 :         ForkNumber  forknum;
                                100                 :         BlockNumber blknum;
                                101                 : 
  277 rhaas                     102 UNC           0 :         BufferGetTag(buffer, &locator, &forknum, &blknum);
  193 rhaas                     103 UBC           0 :         elog(ERROR, "failed to add item to index page in %u/%u/%u",
                                104                 :              locator.spcOid, locator.dbOid, locator.relNumber);
                                105                 :     }
 3420 heikki.linnakangas        106 CBC       23658 : }
                                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                 :  */
                                116                 : static void
 3364                           117            3342 : ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
                                118                 : {
                                119                 :     int         actionno;
                                120                 :     int         segno;
                                121                 :     GinPostingList *oldseg;
                                122                 :     Pointer     segmentend;
                                123                 :     char       *walbuf;
                                124                 :     int         totalsize;
 1673 akorotkov                 125            3342 :     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                 :      */
 3296 heikki.linnakangas        132            3342 :     if (!GinPageIsCompressed(page))
                                133                 :     {
 3296 heikki.linnakangas        134 UBC           0 :         ItemPointer uncompressed = (ItemPointer) GinDataPageGetData(page);
                                135               0 :         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                 :          */
 1725 akorotkov                 144               0 :         if (nuncompressed > 0)
                                145                 :         {
                                146                 :             GinPostingList *plist;
                                147                 : 
                                148               0 :             plist = ginCompressPostingList(uncompressed, nuncompressed,
                                149                 :                                            BLCKSZ, &npacked);
                                150               0 :             totalsize = SizeOfGinPostingList(plist);
                                151                 : 
                                152               0 :             Assert(npacked == nuncompressed);
                                153                 : 
                                154               0 :             memcpy(GinDataLeafPageGetPostingList(page), plist, totalsize);
                                155                 :         }
                                156                 :         else
                                157                 :         {
                                158               0 :             totalsize = 0;
                                159                 :         }
                                160                 : 
 3282 heikki.linnakangas        161               0 :         GinDataPageSetDataSize(page, totalsize);
 3296                           162               0 :         GinPageSetCompressed(page);
                                163               0 :         GinPageGetOpaque(page)->maxoff = InvalidOffsetNumber;
                                164                 :     }
                                165                 : 
 3296 heikki.linnakangas        166 CBC        3342 :     oldseg = GinDataLeafPageGetPostingList(page);
 1673 akorotkov                 167            3342 :     writePtr = (Pointer) oldseg;
 3296 heikki.linnakangas        168            3342 :     segmentend = (Pointer) oldseg + GinDataLeafPageGetPostingListSize(page);
                                169            3342 :     segno = 0;
                                170                 : 
                                171            3342 :     walbuf = ((char *) data) + sizeof(ginxlogRecompressDataLeaf);
                                172            6687 :     for (actionno = 0; actionno < data->nactions; actionno++)
                                173                 :     {
                                174            3345 :         uint8       a_segno = *((uint8 *) (walbuf++));
                                175            3345 :         uint8       a_action = *((uint8 *) (walbuf++));
                                176            3345 :         GinPostingList *newseg = NULL;
                                177            3345 :         int         newsegsize = 0;
                                178            3345 :         ItemPointerData *items = NULL;
                                179            3345 :         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            3345 :         if (a_action == GIN_SEGMENT_INSERT ||
                                188                 :             a_action == GIN_SEGMENT_REPLACE)
                                189                 :         {
                                190              19 :             newseg = (GinPostingList *) walbuf;
                                191              19 :             newsegsize = SizeOfGinPostingList(newseg);
                                192              19 :             walbuf += SHORTALIGN(newsegsize);
                                193                 :         }
                                194                 : 
                                195            3345 :         if (a_action == GIN_SEGMENT_ADDITEMS)
                                196                 :         {
                                197            3326 :             memcpy(&nitems, walbuf, sizeof(uint16));
                                198            3326 :             walbuf += sizeof(uint16);
                                199            3326 :             items = (ItemPointerData *) walbuf;
                                200            3326 :             walbuf += nitems * sizeof(ItemPointerData);
                                201                 :         }
                                202                 : 
                                203                 :         /* Skip to the segment that this action concerns */
                                204            3345 :         Assert(segno <= a_segno);
                                205           59803 :         while (segno < a_segno)
                                206                 :         {
                                207                 :             /*
                                208                 :              * Once modification is started and page tail is copied, we've to
                                209                 :              * copy unmodified segments.
                                210                 :              */
 1673 akorotkov                 211           56458 :             segsize = SizeOfGinPostingList(oldseg);
                                212           56458 :             if (tailCopy)
                                213                 :             {
 1673 akorotkov                 214 UBC           0 :                 Assert(writePtr + segsize < PageGetSpecialPointer(page));
                                215               0 :                 memcpy(writePtr, (Pointer) oldseg, segsize);
                                216                 :             }
 1673 akorotkov                 217 CBC       56458 :             writePtr += segsize;
 3296 heikki.linnakangas        218           56458 :             oldseg = GinNextPostingListSegment(oldseg);
                                219           56458 :             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            3345 :         if (a_action == GIN_SEGMENT_ADDITEMS)
                                228                 :         {
                                229                 :             int         npacked;
                                230                 : 
                                231            3326 :             olditems = ginPostingListDecode(oldseg, &nolditems);
                                232                 : 
                                233            3326 :             newitems = ginMergeItemPointers(items, nitems,
                                234                 :                                             olditems, nolditems,
                                235                 :                                             &nnewitems);
                                236            3326 :             Assert(nnewitems == nolditems + nitems);
                                237                 : 
                                238            3326 :             newseg = ginCompressPostingList(newitems, nnewitems,
                                239                 :                                             BLCKSZ, &npacked);
                                240            3326 :             Assert(npacked == nnewitems);
                                241                 : 
                                242            3326 :             newsegsize = SizeOfGinPostingList(newseg);
                                243            3326 :             a_action = GIN_SEGMENT_REPLACE;
                                244                 :         }
                                245                 : 
                                246            3345 :         segptr = (Pointer) oldseg;
                                247            3345 :         if (segptr != segmentend)
                                248            3326 :             segsize = SizeOfGinPostingList(oldseg);
                                249                 :         else
                                250                 :         {
                                251                 :             /*
                                252                 :              * Positioned after the last existing segment. Only INSERTs
                                253                 :              * expected here.
                                254                 :              */
                                255              19 :             Assert(a_action == GIN_SEGMENT_INSERT);
                                256              19 :             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                 :          */
 1673 akorotkov                 263            3345 :         if (!tailCopy && segptr != segmentend)
                                264                 :         {
 1418 tgl                       265            3326 :             int         tailSize = segmentend - segptr;
                                266                 : 
 1673 akorotkov                 267            3326 :             tailCopy = (Pointer) palloc(tailSize);
                                268            3326 :             memcpy(tailCopy, segptr, tailSize);
                                269            3326 :             segptr = tailCopy;
                                270            3326 :             oldseg = (GinPostingList *) segptr;
                                271            3326 :             segmentend = segptr + tailSize;
                                272                 :         }
                                273                 : 
 3296 heikki.linnakangas        274            3345 :         switch (a_action)
                                275                 :         {
 3296 heikki.linnakangas        276 UBC           0 :             case GIN_SEGMENT_DELETE:
 1673 akorotkov                 277               0 :                 segptr += segsize;
 3296 heikki.linnakangas        278               0 :                 segno++;
                                279               0 :                 break;
                                280                 : 
 3296 heikki.linnakangas        281 CBC          19 :             case GIN_SEGMENT_INSERT:
                                282                 :                 /* copy the new segment in place */
 1673 akorotkov                 283              19 :                 Assert(writePtr + newsegsize <= PageGetSpecialPointer(page));
                                284              19 :                 memcpy(writePtr, newseg, newsegsize);
                                285              19 :                 writePtr += newsegsize;
 3296 heikki.linnakangas        286              19 :                 break;
                                287                 : 
                                288            3326 :             case GIN_SEGMENT_REPLACE:
                                289                 :                 /* copy the new version of segment in place */
 1673 akorotkov                 290            3326 :                 Assert(writePtr + newsegsize <= PageGetSpecialPointer(page));
                                291            3326 :                 memcpy(writePtr, newseg, newsegsize);
                                292            3326 :                 writePtr += newsegsize;
                                293            3326 :                 segptr += segsize;
 3296 heikki.linnakangas        294            3326 :                 segno++;
                                295            3326 :                 break;
                                296                 : 
 3296 heikki.linnakangas        297 UBC           0 :             default:
                                298               0 :                 elog(ERROR, "unexpected GIN leaf action: %u", a_action);
                                299                 :         }
 3296 heikki.linnakangas        300 CBC        3345 :         oldseg = (GinPostingList *) segptr;
                                301                 :     }
                                302                 : 
                                303                 :     /* Copy the rest of unmodified segments if any. */
 1673 akorotkov                 304            3342 :     segptr = (Pointer) oldseg;
                                305            3342 :     if (segptr != segmentend && tailCopy)
                                306                 :     {
 1418 tgl                       307 UBC           0 :         int         restSize = segmentend - segptr;
                                308                 : 
 1673 akorotkov                 309               0 :         Assert(writePtr + restSize <= PageGetSpecialPointer(page));
                                310               0 :         memcpy(writePtr, segptr, restSize);
                                311               0 :         writePtr += restSize;
                                312                 :     }
                                313                 : 
 1673 akorotkov                 314 CBC        3342 :     totalsize = writePtr - (Pointer) GinDataLeafPageGetPostingList(page);
 3282 heikki.linnakangas        315            3342 :     GinDataPageSetDataSize(page, totalsize);
 3364                           316            3342 : }
                                317                 : 
                                318                 : static void
                                319            3345 : ginRedoInsertData(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
                                320                 : {
 2545 kgrittn                   321            3345 :     Page        page = BufferGetPage(buffer);
                                322                 : 
 3364 heikki.linnakangas        323            3345 :     if (isLeaf)
                                324                 :     {
                                325            3342 :         ginxlogRecompressDataLeaf *data = (ginxlogRecompressDataLeaf *) rdata;
                                326                 : 
                                327            3342 :         Assert(GinPageIsLeaf(page));
                                328                 : 
                                329            3342 :         ginRedoRecompress(page, data);
                                330                 :     }
                                331                 :     else
                                332                 :     {
                                333               3 :         ginxlogInsertDataInternal *data = (ginxlogInsertDataInternal *) rdata;
                                334                 :         PostingItem *oldpitem;
                                335                 : 
                                336               3 :         Assert(!GinPageIsLeaf(page));
                                337                 : 
                                338                 :         /* update link to right page after split */
                                339               3 :         oldpitem = GinDataPageGetPostingItem(page, data->offset);
 3420                           340               3 :         PostingItemSetBlockNumber(oldpitem, rightblkno);
                                341                 : 
 3364                           342               3 :         GinDataPageAddPostingItem(page, &data->newitem, data->offset);
                                343                 :     }
 3420                           344            3345 : }
                                345                 : 
                                346                 : static void
 3062                           347           27004 : ginRedoInsert(XLogReaderState *record)
                                348                 : {
                                349           27004 :     XLogRecPtr  lsn = record->EndRecPtr;
 3420                           350           27004 :     ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record);
                                351                 :     Buffer      buffer;
                                352                 : #ifdef NOT_USED
                                353                 :     BlockNumber leftChildBlkno = InvalidBlockNumber;
                                354                 : #endif
                                355           27004 :     BlockNumber rightChildBlkno = InvalidBlockNumber;
                                356           27004 :     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           27004 :     if (!isLeaf)
                                363                 :     {
 3062                           364             139 :         char       *payload = XLogRecGetData(record) + sizeof(ginxlogInsert);
                                365                 : 
                                366                 : #ifdef NOT_USED
                                367                 :         leftChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
                                368                 : #endif
 3420                           369             139 :         payload += sizeof(BlockIdData);
                                370             139 :         rightChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
                                371             139 :         payload += sizeof(BlockIdData);
                                372                 : 
 3062                           373             139 :         ginRedoClearIncompleteSplit(record, 1);
                                374                 :     }
                                375                 : 
                                376           27004 :     if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
                                377                 :     {
 2545 kgrittn                   378           27003 :         Page        page = BufferGetPage(buffer);
                                379                 :         Size        len;
 3062 heikki.linnakangas        380           27003 :         char       *payload = XLogRecGetBlockData(record, 0, &len);
                                381                 : 
                                382                 :         /* How to insert the payload is tree-type specific */
 3420                           383           27003 :         if (data->flags & GIN_INSERT_ISDATA)
                                384                 :         {
 4563 tgl                       385            3345 :             Assert(GinPageIsData(page));
 3364 heikki.linnakangas        386            3345 :             ginRedoInsertData(buffer, isLeaf, rightChildBlkno, payload);
                                387                 :         }
                                388                 :         else
                                389                 :         {
 4563 tgl                       390           23658 :             Assert(!GinPageIsData(page));
 3364 heikki.linnakangas        391           23658 :             ginRedoInsertEntry(buffer, isLeaf, rightChildBlkno, payload);
                                392                 :         }
                                393                 : 
 3420                           394           27003 :         PageSetLSN(page, lsn);
                                395           27003 :         MarkBufferDirty(buffer);
                                396                 :     }
 3161                           397           27004 :     if (BufferIsValid(buffer))
                                398           27004 :         UnlockReleaseBuffer(buffer);
 3420                           399           27004 : }
                                400                 : 
                                401                 : static void
 3062                           402             142 : ginRedoSplit(XLogReaderState *record)
                                403                 : {
 6031 bruce                     404             142 :     ginxlogSplit *data = (ginxlogSplit *) XLogRecGetData(record);
                                405                 :     Buffer      lbuffer,
                                406                 :                 rbuffer,
                                407                 :                 rootbuf;
 3420 heikki.linnakangas        408             142 :     bool        isLeaf = (data->flags & GIN_INSERT_ISLEAF) != 0;
                                409             142 :     bool        isRoot = (data->flags & GIN_SPLIT_ROOT) != 0;
                                410                 : 
                                411                 :     /*
                                412                 :      * First clear incomplete-split flag on child page if this finishes a
                                413                 :      * split
                                414                 :      */
                                415             142 :     if (!isLeaf)
 3062 heikki.linnakangas        416 UBC           0 :         ginRedoClearIncompleteSplit(record, 3);
                                417                 : 
 3062 heikki.linnakangas        418 CBC         142 :     if (XLogReadBufferForRedo(record, 0, &lbuffer) != BLK_RESTORED)
 3062 heikki.linnakangas        419 UBC           0 :         elog(ERROR, "GIN split record did not contain a full-page image of left page");
                                420                 : 
 3062 heikki.linnakangas        421 CBC         142 :     if (XLogReadBufferForRedo(record, 1, &rbuffer) != BLK_RESTORED)
 3062 heikki.linnakangas        422 UBC           0 :         elog(ERROR, "GIN split record did not contain a full-page image of right page");
                                423                 : 
 3420 heikki.linnakangas        424 CBC         142 :     if (isRoot)
                                425                 :     {
 3062                           426               3 :         if (XLogReadBufferForRedo(record, 2, &rootbuf) != BLK_RESTORED)
 3062 heikki.linnakangas        427 UBC           0 :             elog(ERROR, "GIN split record did not contain a full-page image of root page");
 3062 heikki.linnakangas        428 CBC           3 :         UnlockReleaseBuffer(rootbuf);
                                429                 :     }
                                430                 : 
 6186 teodor                    431             142 :     UnlockReleaseBuffer(rbuffer);
                                432             142 :     UnlockReleaseBuffer(lbuffer);
                                433             142 : }
                                434                 : 
                                435                 : /*
                                436                 :  * VACUUM_PAGE record contains simply a full image of the page, similar to
                                437                 :  * an XLOG_FPI record.
                                438                 :  */
                                439                 : static void
 3062 heikki.linnakangas        440               2 : ginRedoVacuumPage(XLogReaderState *record)
                                441                 : {
                                442                 :     Buffer      buffer;
                                443                 : 
                                444               2 :     if (XLogReadBufferForRedo(record, 0, &buffer) != BLK_RESTORED)
                                445                 :     {
 3062 heikki.linnakangas        446 UBC           0 :         elog(ERROR, "replay of gin entry tree page vacuum did not restore the page");
                                447                 :     }
 3364 heikki.linnakangas        448 CBC           2 :     UnlockReleaseBuffer(buffer);
                                449               2 : }
                                450                 : 
                                451                 : static void
 3062 heikki.linnakangas        452 UBC           0 : ginRedoVacuumDataLeafPage(XLogReaderState *record)
                                453                 : {
                                454               0 :     XLogRecPtr  lsn = record->EndRecPtr;
                                455                 :     Buffer      buffer;
                                456                 : 
                                457               0 :     if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
                                458                 :     {
 2545 kgrittn                   459               0 :         Page        page = BufferGetPage(buffer);
                                460                 :         Size        len;
                                461                 :         ginxlogVacuumDataLeafPage *xlrec;
                                462                 : 
 3062 heikki.linnakangas        463               0 :         xlrec = (ginxlogVacuumDataLeafPage *) XLogRecGetBlockData(record, 0, &len);
                                464                 : 
 3161                           465               0 :         Assert(GinPageIsLeaf(page));
                                466               0 :         Assert(GinPageIsData(page));
                                467                 : 
 3364                           468               0 :         ginRedoRecompress(page, &xlrec->data);
 4563 tgl                       469               0 :         PageSetLSN(page, lsn);
                                470               0 :         MarkBufferDirty(buffer);
                                471                 :     }
 3161 heikki.linnakangas        472               0 :     if (BufferIsValid(buffer))
                                473               0 :         UnlockReleaseBuffer(buffer);
 6186 teodor                    474               0 : }
                                475                 : 
                                476                 : static void
 3062 heikki.linnakangas        477               0 : ginRedoDeletePage(XLogReaderState *record)
                                478                 : {
                                479               0 :     XLogRecPtr  lsn = record->EndRecPtr;
 6031 bruce                     480               0 :     ginxlogDeletePage *data = (ginxlogDeletePage *) XLogRecGetData(record);
                                481                 :     Buffer      dbuffer;
                                482                 :     Buffer      pbuffer;
                                483                 :     Buffer      lbuffer;
                                484                 :     Page        page;
                                485                 : 
                                486                 :     /*
                                487                 :      * Lock left page first in order to prevent possible deadlock with
                                488                 :      * ginStepRight().
                                489                 :      */
 1578 akorotkov                 490               0 :     if (XLogReadBufferForRedo(record, 2, &lbuffer) == BLK_NEEDS_REDO)
                                491                 :     {
                                492               0 :         page = BufferGetPage(lbuffer);
                                493               0 :         Assert(GinPageIsData(page));
                                494               0 :         GinPageGetOpaque(page)->rightlink = data->rightLink;
                                495               0 :         PageSetLSN(page, lsn);
                                496               0 :         MarkBufferDirty(lbuffer);
                                497                 :     }
                                498                 : 
 3062 heikki.linnakangas        499               0 :     if (XLogReadBufferForRedo(record, 0, &dbuffer) == BLK_NEEDS_REDO)
                                500                 :     {
 2545 kgrittn                   501               0 :         page = BufferGetPage(dbuffer);
 3161 heikki.linnakangas        502               0 :         Assert(GinPageIsData(page));
 1237 akorotkov                 503               0 :         GinPageSetDeleted(page);
 1578                           504               0 :         GinPageSetDeleteXid(page, data->deleteXid);
 3161 heikki.linnakangas        505               0 :         PageSetLSN(page, lsn);
                                506               0 :         MarkBufferDirty(dbuffer);
                                507                 :     }
                                508                 : 
 3062                           509               0 :     if (XLogReadBufferForRedo(record, 1, &pbuffer) == BLK_NEEDS_REDO)
                                510                 :     {
 2545 kgrittn                   511               0 :         page = BufferGetPage(pbuffer);
 3161 heikki.linnakangas        512               0 :         Assert(GinPageIsData(page));
                                513               0 :         Assert(!GinPageIsLeaf(page));
                                514               0 :         GinPageDeletePostingItem(page, data->parentOffset);
                                515               0 :         PageSetLSN(page, lsn);
                                516               0 :         MarkBufferDirty(pbuffer);
                                517                 :     }
                                518                 : 
                                519               0 :     if (BufferIsValid(lbuffer))
                                520               0 :         UnlockReleaseBuffer(lbuffer);
 3800 tgl                       521               0 :     if (BufferIsValid(pbuffer))
                                522               0 :         UnlockReleaseBuffer(pbuffer);
                                523               0 :     if (BufferIsValid(dbuffer))
                                524               0 :         UnlockReleaseBuffer(dbuffer);
 6186 teodor                    525               0 : }
                                526                 : 
                                527                 : static void
 3062 heikki.linnakangas        528 CBC       23943 : ginRedoUpdateMetapage(XLogReaderState *record)
                                529                 : {
                                530           23943 :     XLogRecPtr  lsn = record->EndRecPtr;
 5050 bruce                     531           23943 :     ginxlogUpdateMeta *data = (ginxlogUpdateMeta *) XLogRecGetData(record);
                                532                 :     Buffer      metabuffer;
                                533                 :     Page        metapage;
                                534                 :     Buffer      buffer;
                                535                 : 
                                536                 :     /*
                                537                 :      * Restore the metapage. This is essentially the same as a full-page
                                538                 :      * image, so restore the metapage unconditionally without looking at the
                                539                 :      * LSN, to avoid torn page hazards.
                                540                 :      */
 3062 heikki.linnakangas        541           23943 :     metabuffer = XLogInitBufferForRedo(record, 0);
                                542           23943 :     Assert(BufferGetBlockNumber(metabuffer) == GIN_METAPAGE_BLKNO);
 2545 kgrittn                   543           23943 :     metapage = BufferGetPage(metabuffer);
                                544                 : 
 1984 tgl                       545           23943 :     GinInitMetabuffer(metabuffer);
 3315 heikki.linnakangas        546           23943 :     memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
                                547           23943 :     PageSetLSN(metapage, lsn);
                                548           23943 :     MarkBufferDirty(metabuffer);
                                549                 : 
 5050 bruce                     550           23943 :     if (data->ntuples > 0)
                                551                 :     {
                                552                 :         /*
                                553                 :          * insert into tail page
                                554                 :          */
 3062 heikki.linnakangas        555           23756 :         if (XLogReadBufferForRedo(record, 1, &buffer) == BLK_NEEDS_REDO)
                                556                 :         {
 2545 kgrittn                   557           23755 :             Page        page = BufferGetPage(buffer);
                                558                 :             OffsetNumber off;
                                559                 :             int         i;
                                560                 :             Size        tupsize;
                                561                 :             char       *payload;
                                562                 :             IndexTuple  tuples;
                                563                 :             Size        totaltupsize;
                                564                 : 
 3062 heikki.linnakangas        565           23755 :             payload = XLogRecGetBlockData(record, 1, &totaltupsize);
                                566           23755 :             tuples = (IndexTuple) payload;
                                567                 : 
 3161                           568           23755 :             if (PageIsEmpty(page))
 3161 heikki.linnakangas        569 UBC           0 :                 off = FirstOffsetNumber;
                                570                 :             else
 3161 heikki.linnakangas        571 CBC       23755 :                 off = OffsetNumberNext(PageGetMaxOffsetNumber(page));
                                572                 : 
                                573           95012 :             for (i = 0; i < data->ntuples; i++)
                                574                 :             {
                                575           71257 :                 tupsize = IndexTupleSize(tuples);
                                576                 : 
                                577           71257 :                 if (PageAddItem(page, (Item) tuples, tupsize, off,
                                578                 :                                 false, false) == InvalidOffsetNumber)
 3161 heikki.linnakangas        579 UBC           0 :                     elog(ERROR, "failed to add item to index page");
                                580                 : 
 3161 heikki.linnakangas        581 CBC       71257 :                 tuples = (IndexTuple) (((char *) tuples) + tupsize);
                                582                 : 
                                583           71257 :                 off++;
                                584                 :             }
 3062                           585           23755 :             Assert(payload + totaltupsize == (char *) tuples);
                                586                 : 
                                587                 :             /*
                                588                 :              * Increase counter of heap tuples
                                589                 :              */
 3161                           590           23755 :             GinPageGetOpaque(page)->maxoff++;
                                591                 : 
                                592           23755 :             PageSetLSN(page, lsn);
                                593           23755 :             MarkBufferDirty(buffer);
                                594                 :         }
                                595           23756 :         if (BufferIsValid(buffer))
                                596           23756 :             UnlockReleaseBuffer(buffer);
                                597                 :     }
 5050 bruce                     598             187 :     else if (data->prevTail != InvalidBlockNumber)
                                599                 :     {
                                600                 :         /*
                                601                 :          * New tail
                                602                 :          */
 3062 heikki.linnakangas        603             174 :         if (XLogReadBufferForRedo(record, 1, &buffer) == BLK_NEEDS_REDO)
                                604                 :         {
 2545 kgrittn                   605             174 :             Page        page = BufferGetPage(buffer);
                                606                 : 
 3161 heikki.linnakangas        607             174 :             GinPageGetOpaque(page)->rightlink = data->newRightlink;
                                608                 : 
                                609             174 :             PageSetLSN(page, lsn);
                                610             174 :             MarkBufferDirty(buffer);
                                611                 :         }
                                612             174 :         if (BufferIsValid(buffer))
                                613             174 :             UnlockReleaseBuffer(buffer);
                                614                 :     }
                                615                 : 
 5129 tgl                       616           23943 :     UnlockReleaseBuffer(metabuffer);
                                617           23943 : }
                                618                 : 
                                619                 : static void
 3062 heikki.linnakangas        620             179 : ginRedoInsertListPage(XLogReaderState *record)
                                621                 : {
                                622             179 :     XLogRecPtr  lsn = record->EndRecPtr;
 5050 bruce                     623             179 :     ginxlogInsertListPage *data = (ginxlogInsertListPage *) XLogRecGetData(record);
                                624                 :     Buffer      buffer;
                                625                 :     Page        page;
                                626                 :     OffsetNumber l,
                                627             179 :                 off = FirstOffsetNumber;
                                628                 :     int         i,
                                629                 :                 tupsize;
                                630                 :     char       *payload;
                                631                 :     IndexTuple  tuples;
                                632                 :     Size        totaltupsize;
                                633                 : 
                                634                 :     /* We always re-initialize the page. */
 3062 heikki.linnakangas        635             179 :     buffer = XLogInitBufferForRedo(record, 0);
 2545 kgrittn                   636             179 :     page = BufferGetPage(buffer);
                                637                 : 
 5129 tgl                       638             179 :     GinInitBuffer(buffer, GIN_LIST);
                                639             179 :     GinPageGetOpaque(page)->rightlink = data->rightlink;
 5050 bruce                     640             179 :     if (data->rightlink == InvalidBlockNumber)
                                641                 :     {
                                642                 :         /* tail of sublist */
 5129 tgl                       643             179 :         GinPageSetFullRow(page);
                                644             179 :         GinPageGetOpaque(page)->maxoff = 1;
                                645                 :     }
                                646                 :     else
                                647                 :     {
 5129 tgl                       648 UBC           0 :         GinPageGetOpaque(page)->maxoff = 0;
                                649                 :     }
                                650                 : 
 3062 heikki.linnakangas        651 CBC         179 :     payload = XLogRecGetBlockData(record, 0, &totaltupsize);
                                652                 : 
                                653             179 :     tuples = (IndexTuple) payload;
 5050 bruce                     654             713 :     for (i = 0; i < data->ntuples; i++)
                                655                 :     {
 5129 tgl                       656             534 :         tupsize = IndexTupleSize(tuples);
                                657                 : 
 5050 bruce                     658             534 :         l = PageAddItem(page, (Item) tuples, tupsize, off, false, false);
                                659                 : 
 5129 tgl                       660             534 :         if (l == InvalidOffsetNumber)
 5129 tgl                       661 UBC           0 :             elog(ERROR, "failed to add item to index page");
                                662                 : 
 5050 bruce                     663 CBC         534 :         tuples = (IndexTuple) (((char *) tuples) + tupsize);
 3268 heikki.linnakangas        664             534 :         off++;
                                665                 :     }
 3062                           666             179 :     Assert((char *) tuples == payload + totaltupsize);
                                667                 : 
 5129 tgl                       668             179 :     PageSetLSN(page, lsn);
                                669             179 :     MarkBufferDirty(buffer);
                                670                 : 
                                671             179 :     UnlockReleaseBuffer(buffer);
                                672             179 : }
                                673                 : 
                                674                 : static void
 3062 heikki.linnakangas        675              13 : ginRedoDeleteListPages(XLogReaderState *record)
                                676                 : {
                                677              13 :     XLogRecPtr  lsn = record->EndRecPtr;
 5050 bruce                     678              13 :     ginxlogDeleteListPages *data = (ginxlogDeleteListPages *) XLogRecGetData(record);
                                679                 :     Buffer      metabuffer;
                                680                 :     Page        metapage;
                                681                 :     int         i;
                                682                 : 
 3062 heikki.linnakangas        683              13 :     metabuffer = XLogInitBufferForRedo(record, 0);
                                684              13 :     Assert(BufferGetBlockNumber(metabuffer) == GIN_METAPAGE_BLKNO);
 2545 kgrittn                   685              13 :     metapage = BufferGetPage(metabuffer);
                                686                 : 
 1984 tgl                       687              13 :     GinInitMetabuffer(metabuffer);
                                688                 : 
 3315 heikki.linnakangas        689              13 :     memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
                                690              13 :     PageSetLSN(metapage, lsn);
                                691              13 :     MarkBufferDirty(metabuffer);
                                692                 : 
                                693                 :     /*
                                694                 :      * In normal operation, shiftList() takes exclusive lock on all the
                                695                 :      * pages-to-be-deleted simultaneously.  During replay, however, it should
                                696                 :      * be all right to lock them one at a time.  This is dependent on the fact
                                697                 :      * that we are deleting pages from the head of the list, and that readers
                                698                 :      * share-lock the next page before releasing the one they are on. So we
                                699                 :      * cannot get past a reader that is on, or due to visit, any page we are
                                700                 :      * going to delete.  New incoming readers will block behind our metapage
                                701                 :      * lock and then see a fully updated page list.
                                702                 :      *
                                703                 :      * No full-page images are taken of the deleted pages. Instead, they are
                                704                 :      * re-initialized as empty, deleted pages. Their right-links don't need to
                                705                 :      * be preserved, because no new readers can see the pages, as explained
                                706                 :      * above.
                                707                 :      */
 5050 bruce                     708             191 :     for (i = 0; i < data->ndeleted; i++)
                                709                 :     {
                                710                 :         Buffer      buffer;
                                711                 :         Page        page;
                                712                 : 
 3062 heikki.linnakangas        713             178 :         buffer = XLogInitBufferForRedo(record, i + 1);
 2545 kgrittn                   714             178 :         page = BufferGetPage(buffer);
 3258 heikki.linnakangas        715             178 :         GinInitBuffer(buffer, GIN_DELETED);
                                716                 : 
                                717             178 :         PageSetLSN(page, lsn);
                                718             178 :         MarkBufferDirty(buffer);
                                719                 : 
                                720             178 :         UnlockReleaseBuffer(buffer);
                                721                 :     }
 5129 tgl                       722              13 :     UnlockReleaseBuffer(metabuffer);
                                723              13 : }
                                724                 : 
                                725                 : void
 3062 heikki.linnakangas        726           51286 : gin_redo(XLogReaderState *record)
                                727                 : {
                                728           51286 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
                                729                 :     MemoryContext oldCtx;
                                730                 : 
                                731                 :     /*
                                732                 :      * GIN indexes do not require any conflict processing. NB: If we ever
                                733                 :      * implement a similar optimization as we have in b-tree, and remove
                                734                 :      * killed tuples outside VACUUM, we'll need to handle that here.
                                735                 :      */
                                736                 : 
 3420                           737           51286 :     oldCtx = MemoryContextSwitchTo(opCtx);
 6031 bruce                     738           51286 :     switch (info)
                                739                 :     {
                                740               3 :         case XLOG_GIN_CREATE_PTREE:
 3062 heikki.linnakangas        741               3 :             ginRedoCreatePTree(record);
 6186 teodor                    742               3 :             break;
 6031 bruce                     743           27004 :         case XLOG_GIN_INSERT:
 3062 heikki.linnakangas        744           27004 :             ginRedoInsert(record);
 6186 teodor                    745           27004 :             break;
 6031 bruce                     746             142 :         case XLOG_GIN_SPLIT:
 3062 heikki.linnakangas        747             142 :             ginRedoSplit(record);
 6186 teodor                    748             142 :             break;
 6031 bruce                     749               2 :         case XLOG_GIN_VACUUM_PAGE:
 3062 heikki.linnakangas        750               2 :             ginRedoVacuumPage(record);
 6186 teodor                    751               2 :             break;
 3364 heikki.linnakangas        752 UBC           0 :         case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
 3062                           753               0 :             ginRedoVacuumDataLeafPage(record);
 3364                           754               0 :             break;
 6031 bruce                     755               0 :         case XLOG_GIN_DELETE_PAGE:
 3062 heikki.linnakangas        756               0 :             ginRedoDeletePage(record);
 6186 teodor                    757               0 :             break;
 5129 tgl                       758 CBC       23943 :         case XLOG_GIN_UPDATE_META_PAGE:
 3062 heikki.linnakangas        759           23943 :             ginRedoUpdateMetapage(record);
 5129 tgl                       760           23943 :             break;
                                761             179 :         case XLOG_GIN_INSERT_LISTPAGE:
 3062 heikki.linnakangas        762             179 :             ginRedoInsertListPage(record);
 5129 tgl                       763             179 :             break;
 5050 bruce                     764              13 :         case XLOG_GIN_DELETE_LISTPAGE:
 3062 heikki.linnakangas        765              13 :             ginRedoDeleteListPages(record);
 5129 tgl                       766              13 :             break;
 6186 teodor                    767 UBC           0 :         default:
                                768               0 :             elog(PANIC, "gin_redo: unknown op code %u", info);
                                769                 :     }
 3420 heikki.linnakangas        770 CBC       51286 :     MemoryContextSwitchTo(oldCtx);
 6186 teodor                    771           51286 :     MemoryContextReset(opCtx);
                                772           51286 : }
                                773                 : 
                                774                 : void
 6031 bruce                     775             141 : gin_xlog_startup(void)
                                776                 : {
 6186 teodor                    777             141 :     opCtx = AllocSetContextCreate(CurrentMemoryContext,
                                778                 :                                   "GIN recovery temporary context",
                                779                 :                                   ALLOCSET_DEFAULT_SIZES);
                                780             141 : }
                                781                 : 
                                782                 : void
 6031 bruce                     783             108 : gin_xlog_cleanup(void)
                                784                 : {
 6186 teodor                    785             108 :     MemoryContextDelete(opCtx);
 2416 tgl                       786             108 :     opCtx = NULL;
 6089                           787             108 : }
                                788                 : 
                                789                 : /*
                                790                 :  * Mask a GIN page before running consistency checks on it.
                                791                 :  */
                                792                 : void
 2251 rhaas                     793 UBC           0 : gin_mask(char *pagedata, BlockNumber blkno)
                                794                 : {
                                795               0 :     Page        page = (Page) pagedata;
 1984 tgl                       796               0 :     PageHeader  pagehdr = (PageHeader) page;
                                797                 :     GinPageOpaque opaque;
                                798                 : 
 2025 rhaas                     799               0 :     mask_page_lsn_and_checksum(page);
 2251                           800               0 :     opaque = GinPageGetOpaque(page);
                                801                 : 
                                802               0 :     mask_page_hint_bits(page);
                                803                 : 
                                804                 :     /*
                                805                 :      * For a GIN_DELETED page, the page is initialized to empty.  Hence, mask
                                806                 :      * the whole page content.  For other pages, mask the hole if pd_lower
                                807                 :      * appears to have been set correctly.
                                808                 :      */
 1984 tgl                       809               0 :     if (opaque->flags & GIN_DELETED)
                                810               0 :         mask_page_content(page);
                                811               0 :     else if (pagehdr->pd_lower > SizeOfPageHeaderData)
                                812               0 :         mask_unused_space(page);
 2251 rhaas                     813               0 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a