LCOV - differential code coverage report
Current view: top level - src/backend/access/hash - hash_xlog.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB
Current: Differential Code Coverage HEAD vs 15 Lines: 72.4 % 463 335 5 5 79 39 9 128 198 77 132 3
Current Date: 2023-04-08 17:13:01 Functions: 80.0 % 15 12 3 8 1 3 3 8
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 0.0 % 3 0 3
Legend: Lines: hit not hit (120,180] days: 50.0 % 2 1 1 1 1
(240..) days: 72.9 % 458 334 1 5 79 39 9 127 198 77 131
Function coverage date bins:
(240..) days: 46.2 % 26 12 3 8 1 3 3 8

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * hash_xlog.c
                                  4                 :  *    WAL replay logic for hash 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/hash/hash_xlog.c
                                 12                 :  *
                                 13                 :  *-------------------------------------------------------------------------
                                 14                 :  */
                                 15                 : #include "postgres.h"
                                 16                 : 
                                 17                 : #include "access/bufmask.h"
                                 18                 : #include "access/hash.h"
                                 19                 : #include "access/hash_xlog.h"
                                 20                 : #include "access/transam.h"
                                 21                 : #include "access/xlog.h"
                                 22                 : #include "access/xlogutils.h"
                                 23                 : #include "miscadmin.h"
                                 24                 : #include "storage/procarray.h"
                                 25                 : 
                                 26                 : /*
                                 27                 :  * replay a hash index meta page
                                 28                 :  */
                                 29                 : static void
 2217 rhaas                      30 CBC          21 : hash_xlog_init_meta_page(XLogReaderState *record)
                                 31                 : {
                                 32              21 :     XLogRecPtr  lsn = record->EndRecPtr;
                                 33                 :     Page        page;
                                 34                 :     Buffer      metabuf;
                                 35                 :     ForkNumber  forknum;
                                 36                 : 
                                 37              21 :     xl_hash_init_meta_page *xlrec = (xl_hash_init_meta_page *) XLogRecGetData(record);
                                 38                 : 
                                 39                 :     /* create the index' metapage */
                                 40              21 :     metabuf = XLogInitBufferForRedo(record, 0);
                                 41              21 :     Assert(BufferIsValid(metabuf));
                                 42              21 :     _hash_init_metabuffer(metabuf, xlrec->num_tuples, xlrec->procid,
                                 43              21 :                           xlrec->ffactor, true);
                                 44              21 :     page = (Page) BufferGetPage(metabuf);
                                 45              21 :     PageSetLSN(page, lsn);
                                 46              21 :     MarkBufferDirty(metabuf);
                                 47                 : 
                                 48                 :     /*
                                 49                 :      * Force the on-disk state of init forks to always be in sync with the
                                 50                 :      * state in shared buffers.  See XLogReadBufferForRedoExtended.  We need
                                 51                 :      * special handling for init forks as create index operations don't log a
                                 52                 :      * full page image of the metapage.
                                 53                 :      */
 2092                            54              21 :     XLogRecGetBlockTag(record, 0, NULL, &forknum, NULL);
                                 55              21 :     if (forknum == INIT_FORKNUM)
                                 56               1 :         FlushOneBuffer(metabuf);
                                 57                 : 
                                 58                 :     /* all done */
 2217                            59              21 :     UnlockReleaseBuffer(metabuf);
                                 60              21 : }
                                 61                 : 
                                 62                 : /*
                                 63                 :  * replay a hash index bitmap page
                                 64                 :  */
                                 65                 : static void
                                 66              21 : hash_xlog_init_bitmap_page(XLogReaderState *record)
                                 67                 : {
                                 68              21 :     XLogRecPtr  lsn = record->EndRecPtr;
                                 69                 :     Buffer      bitmapbuf;
                                 70                 :     Buffer      metabuf;
                                 71                 :     Page        page;
                                 72                 :     HashMetaPage metap;
                                 73                 :     uint32      num_buckets;
                                 74                 :     ForkNumber  forknum;
                                 75                 : 
                                 76              21 :     xl_hash_init_bitmap_page *xlrec = (xl_hash_init_bitmap_page *) XLogRecGetData(record);
                                 77                 : 
                                 78                 :     /*
                                 79                 :      * Initialize bitmap page
                                 80                 :      */
                                 81              21 :     bitmapbuf = XLogInitBufferForRedo(record, 0);
                                 82              21 :     _hash_initbitmapbuffer(bitmapbuf, xlrec->bmsize, true);
                                 83              21 :     PageSetLSN(BufferGetPage(bitmapbuf), lsn);
                                 84              21 :     MarkBufferDirty(bitmapbuf);
                                 85                 : 
                                 86                 :     /*
                                 87                 :      * Force the on-disk state of init forks to always be in sync with the
                                 88                 :      * state in shared buffers.  See XLogReadBufferForRedoExtended.  We need
                                 89                 :      * special handling for init forks as create index operations don't log a
                                 90                 :      * full page image of the metapage.
                                 91                 :      */
 2092                            92              21 :     XLogRecGetBlockTag(record, 0, NULL, &forknum, NULL);
                                 93              21 :     if (forknum == INIT_FORKNUM)
                                 94               1 :         FlushOneBuffer(bitmapbuf);
 2217                            95              21 :     UnlockReleaseBuffer(bitmapbuf);
                                 96                 : 
                                 97                 :     /* add the new bitmap page to the metapage's list of bitmaps */
                                 98              21 :     if (XLogReadBufferForRedo(record, 1, &metabuf) == BLK_NEEDS_REDO)
                                 99                 :     {
                                100                 :         /*
                                101                 :          * Note: in normal operation, we'd update the metapage while still
                                102                 :          * holding lock on the bitmap page.  But during replay it's not
                                103                 :          * necessary to hold that lock, since nobody can see it yet; the
                                104                 :          * creating transaction hasn't yet committed.
                                105                 :          */
                                106              21 :         page = BufferGetPage(metabuf);
                                107              21 :         metap = HashPageGetMeta(page);
                                108                 : 
                                109              21 :         num_buckets = metap->hashm_maxbucket + 1;
                                110              21 :         metap->hashm_mapp[metap->hashm_nmaps] = num_buckets + 1;
                                111              21 :         metap->hashm_nmaps++;
                                112                 : 
                                113              21 :         PageSetLSN(page, lsn);
                                114              21 :         MarkBufferDirty(metabuf);
                                115                 : 
 2092                           116              21 :         XLogRecGetBlockTag(record, 1, NULL, &forknum, NULL);
                                117              21 :         if (forknum == INIT_FORKNUM)
                                118               1 :             FlushOneBuffer(metabuf);
                                119                 :     }
 2217                           120              21 :     if (BufferIsValid(metabuf))
                                121              21 :         UnlockReleaseBuffer(metabuf);
                                122              21 : }
                                123                 : 
                                124                 : /*
                                125                 :  * replay a hash index insert without split
                                126                 :  */
                                127                 : static void
                                128          113999 : hash_xlog_insert(XLogReaderState *record)
                                129                 : {
                                130                 :     HashMetaPage metap;
                                131          113999 :     XLogRecPtr  lsn = record->EndRecPtr;
                                132          113999 :     xl_hash_insert *xlrec = (xl_hash_insert *) XLogRecGetData(record);
                                133                 :     Buffer      buffer;
                                134                 :     Page        page;
                                135                 : 
                                136          113999 :     if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
                                137                 :     {
                                138                 :         Size        datalen;
                                139          113995 :         char       *datapos = XLogRecGetBlockData(record, 0, &datalen);
                                140                 : 
                                141          113995 :         page = BufferGetPage(buffer);
                                142                 : 
                                143          113995 :         if (PageAddItem(page, (Item) datapos, datalen, xlrec->offnum,
                                144                 :                         false, false) == InvalidOffsetNumber)
 2217 rhaas                     145 UBC           0 :             elog(PANIC, "hash_xlog_insert: failed to add item");
                                146                 : 
 2217 rhaas                     147 CBC      113995 :         PageSetLSN(page, lsn);
                                148          113995 :         MarkBufferDirty(buffer);
                                149                 :     }
                                150          113999 :     if (BufferIsValid(buffer))
                                151          113999 :         UnlockReleaseBuffer(buffer);
                                152                 : 
                                153          113999 :     if (XLogReadBufferForRedo(record, 1, &buffer) == BLK_NEEDS_REDO)
                                154                 :     {
                                155                 :         /*
                                156                 :          * Note: in normal operation, we'd update the metapage while still
                                157                 :          * holding lock on the page we inserted into.  But during replay it's
                                158                 :          * not necessary to hold that lock, since no other index updates can
                                159                 :          * be happening concurrently.
                                160                 :          */
                                161          113998 :         page = BufferGetPage(buffer);
                                162          113998 :         metap = HashPageGetMeta(page);
                                163          113998 :         metap->hashm_ntuples += 1;
                                164                 : 
                                165          113998 :         PageSetLSN(page, lsn);
                                166          113998 :         MarkBufferDirty(buffer);
                                167                 :     }
                                168          113999 :     if (BufferIsValid(buffer))
                                169          113999 :         UnlockReleaseBuffer(buffer);
                                170          113999 : }
                                171                 : 
                                172                 : /*
                                173                 :  * replay addition of overflow page for hash index
                                174                 :  */
                                175                 : static void
                                176              54 : hash_xlog_add_ovfl_page(XLogReaderState *record)
                                177                 : {
                                178              54 :     XLogRecPtr  lsn = record->EndRecPtr;
                                179              54 :     xl_hash_add_ovfl_page *xlrec = (xl_hash_add_ovfl_page *) XLogRecGetData(record);
                                180                 :     Buffer      leftbuf;
                                181                 :     Buffer      ovflbuf;
                                182                 :     Buffer      metabuf;
                                183                 :     BlockNumber leftblk;
                                184                 :     BlockNumber rightblk;
                                185              54 :     BlockNumber newmapblk = InvalidBlockNumber;
                                186                 :     Page        ovflpage;
                                187                 :     HashPageOpaque ovflopaque;
                                188                 :     uint32     *num_bucket;
                                189                 :     char       *data;
                                190                 :     Size        datalen PG_USED_FOR_ASSERTS_ONLY;
                                191              54 :     bool        new_bmpage = false;
                                192                 : 
                                193              54 :     XLogRecGetBlockTag(record, 0, NULL, NULL, &rightblk);
                                194              54 :     XLogRecGetBlockTag(record, 1, NULL, NULL, &leftblk);
                                195                 : 
                                196              54 :     ovflbuf = XLogInitBufferForRedo(record, 0);
                                197              54 :     Assert(BufferIsValid(ovflbuf));
                                198                 : 
                                199              54 :     data = XLogRecGetBlockData(record, 0, &datalen);
                                200              54 :     num_bucket = (uint32 *) data;
                                201              54 :     Assert(datalen == sizeof(uint32));
                                202              54 :     _hash_initbuf(ovflbuf, InvalidBlockNumber, *num_bucket, LH_OVERFLOW_PAGE,
                                203                 :                   true);
                                204                 :     /* update backlink */
                                205              54 :     ovflpage = BufferGetPage(ovflbuf);
  373 michael                   206              54 :     ovflopaque = HashPageGetOpaque(ovflpage);
 2217 rhaas                     207              54 :     ovflopaque->hasho_prevblkno = leftblk;
                                208                 : 
                                209              54 :     PageSetLSN(ovflpage, lsn);
                                210              54 :     MarkBufferDirty(ovflbuf);
                                211                 : 
                                212              54 :     if (XLogReadBufferForRedo(record, 1, &leftbuf) == BLK_NEEDS_REDO)
                                213                 :     {
                                214                 :         Page        leftpage;
                                215                 :         HashPageOpaque leftopaque;
                                216                 : 
                                217              54 :         leftpage = BufferGetPage(leftbuf);
  373 michael                   218              54 :         leftopaque = HashPageGetOpaque(leftpage);
 2217 rhaas                     219              54 :         leftopaque->hasho_nextblkno = rightblk;
                                220                 : 
                                221              54 :         PageSetLSN(leftpage, lsn);
                                222              54 :         MarkBufferDirty(leftbuf);
                                223                 :     }
                                224                 : 
                                225              54 :     if (BufferIsValid(leftbuf))
                                226              54 :         UnlockReleaseBuffer(leftbuf);
                                227              54 :     UnlockReleaseBuffer(ovflbuf);
                                228                 : 
                                229                 :     /*
                                230                 :      * Note: in normal operation, we'd update the bitmap and meta page while
                                231                 :      * still holding lock on the overflow pages.  But during replay it's not
                                232                 :      * necessary to hold those locks, since no other index updates can be
                                233                 :      * happening concurrently.
                                234                 :      */
                                235              54 :     if (XLogRecHasBlockRef(record, 2))
                                236                 :     {
                                237                 :         Buffer      mapbuffer;
                                238                 : 
                                239              12 :         if (XLogReadBufferForRedo(record, 2, &mapbuffer) == BLK_NEEDS_REDO)
                                240                 :         {
                                241              12 :             Page        mappage = (Page) BufferGetPage(mapbuffer);
                                242              12 :             uint32     *freep = NULL;
                                243                 :             uint32     *bitmap_page_bit;
 2217 rhaas                     244 ECB             : 
 2217 rhaas                     245 GIC          12 :             freep = HashPageGetBitmap(mappage);
 2217 rhaas                     246 ECB             : 
 2217 rhaas                     247 CBC          12 :             data = XLogRecGetBlockData(record, 2, &datalen);
 2217 rhaas                     248 GIC          12 :             bitmap_page_bit = (uint32 *) data;
 2217 rhaas                     249 ECB             : 
 2217 rhaas                     250 GIC          12 :             SETBIT(freep, *bitmap_page_bit);
 2217 rhaas                     251 ECB             : 
 2217 rhaas                     252 CBC          12 :             PageSetLSN(mappage, lsn);
 2217 rhaas                     253 GIC          12 :             MarkBufferDirty(mapbuffer);
 2217 rhaas                     254 ECB             :         }
 2217 rhaas                     255 CBC          12 :         if (BufferIsValid(mapbuffer))
 2217 rhaas                     256 GIC          12 :             UnlockReleaseBuffer(mapbuffer);
                                257                 :     }
 2217 rhaas                     258 ECB             : 
 2217 rhaas                     259 GIC          54 :     if (XLogRecHasBlockRef(record, 3))
                                260                 :     {
                                261                 :         Buffer      newmapbuf;
 2217 rhaas                     262 EUB             : 
 2217 rhaas                     263 UIC           0 :         newmapbuf = XLogInitBufferForRedo(record, 3);
 2217 rhaas                     264 EUB             : 
 2217 rhaas                     265 UIC           0 :         _hash_initbitmapbuffer(newmapbuf, xlrec->bmsize, true);
 2217 rhaas                     266 EUB             : 
 2217 rhaas                     267 UBC           0 :         new_bmpage = true;
 2217 rhaas                     268 UIC           0 :         newmapblk = BufferGetBlockNumber(newmapbuf);
 2217 rhaas                     269 EUB             : 
 2217 rhaas                     270 UBC           0 :         MarkBufferDirty(newmapbuf);
 2217 rhaas                     271 UIC           0 :         PageSetLSN(BufferGetPage(newmapbuf), lsn);
 2217 rhaas                     272 EUB             : 
 2217 rhaas                     273 UIC           0 :         UnlockReleaseBuffer(newmapbuf);
                                274                 :     }
 2217 rhaas                     275 ECB             : 
 2217 rhaas                     276 GIC          54 :     if (XLogReadBufferForRedo(record, 4, &metabuf) == BLK_NEEDS_REDO)
                                277                 :     {
                                278                 :         HashMetaPage metap;
                                279                 :         Page        page;
                                280                 :         uint32     *firstfree_ovflpage;
 2217 rhaas                     281 ECB             : 
 2217 rhaas                     282 CBC          54 :         data = XLogRecGetBlockData(record, 4, &datalen);
 2217 rhaas                     283 GIC          54 :         firstfree_ovflpage = (uint32 *) data;
 2217 rhaas                     284 ECB             : 
 2217 rhaas                     285 CBC          54 :         page = BufferGetPage(metabuf);
                                286              54 :         metap = HashPageGetMeta(page);
 2217 rhaas                     287 GIC          54 :         metap->hashm_firstfree = *firstfree_ovflpage;
 2217 rhaas                     288 ECB             : 
 2217 rhaas                     289 GIC          54 :         if (!xlrec->bmpage_found)
 2217 rhaas                     290 ECB             :         {
 2217 rhaas                     291 GIC          42 :             metap->hashm_spares[metap->hashm_ovflpoint]++;
 2217 rhaas                     292 ECB             : 
 2217 rhaas                     293 GIC          42 :             if (new_bmpage)
 2217 rhaas                     294 EUB             :             {
 2217 rhaas                     295 UIC           0 :                 Assert(BlockNumberIsValid(newmapblk));
 2217 rhaas                     296 EUB             : 
 2217 rhaas                     297 UBC           0 :                 metap->hashm_mapp[metap->hashm_nmaps] = newmapblk;
                                298               0 :                 metap->hashm_nmaps++;
 2217 rhaas                     299 UIC           0 :                 metap->hashm_spares[metap->hashm_ovflpoint]++;
                                300                 :             }
                                301                 :         }
 2217 rhaas                     302 ECB             : 
 2217 rhaas                     303 CBC          54 :         PageSetLSN(page, lsn);
 2217 rhaas                     304 GIC          54 :         MarkBufferDirty(metabuf);
 2217 rhaas                     305 ECB             :     }
 2217 rhaas                     306 CBC          54 :     if (BufferIsValid(metabuf))
                                307              54 :         UnlockReleaseBuffer(metabuf);
 2217 rhaas                     308 GIC          54 : }
                                309                 : 
                                310                 : /*
                                311                 :  * replay allocation of page for split operation
                                312                 :  */
 2217 rhaas                     313 ECB             : static void
 2217 rhaas                     314 GIC         221 : hash_xlog_split_allocate_page(XLogReaderState *record)
 2217 rhaas                     315 ECB             : {
 2217 rhaas                     316 CBC         221 :     XLogRecPtr  lsn = record->EndRecPtr;
 2217 rhaas                     317 GIC         221 :     xl_hash_split_allocate_page *xlrec = (xl_hash_split_allocate_page *) XLogRecGetData(record);
                                318                 :     Buffer      oldbuf;
                                319                 :     Buffer      newbuf;
                                320                 :     Buffer      metabuf;
                                321                 :     Size        datalen PG_USED_FOR_ASSERTS_ONLY;
                                322                 :     char       *data;
                                323                 :     XLogRedoAction action;
                                324                 : 
                                325                 :     /*
                                326                 :      * To be consistent with normal operation, here we take cleanup locks on
                                327                 :      * both the old and new buckets even though there can't be any concurrent
                                328                 :      * inserts.
                                329                 :      */
                                330                 : 
 2217 rhaas                     331 ECB             :     /* replay the record for old bucket */
 2217 rhaas                     332 GIC         221 :     action = XLogReadBufferForRedoExtended(record, 0, RBM_NORMAL, true, &oldbuf);
                                333                 : 
                                334                 :     /*
                                335                 :      * Note that we still update the page even if it was restored from a full
                                336                 :      * page image, because the special space is not included in the image.
 2217 rhaas                     337 ECB             :      */
 2217 rhaas                     338 GIC         221 :     if (action == BLK_NEEDS_REDO || action == BLK_RESTORED)
                                339                 :     {
                                340                 :         Page        oldpage;
                                341                 :         HashPageOpaque oldopaque;
 2217 rhaas                     342 ECB             : 
 2217 rhaas                     343 CBC         221 :         oldpage = BufferGetPage(oldbuf);
  373 michael                   344 GIC         221 :         oldopaque = HashPageGetOpaque(oldpage);
 2217 rhaas                     345 ECB             : 
 2217 rhaas                     346 CBC         221 :         oldopaque->hasho_flag = xlrec->old_bucket_flag;
 2217 rhaas                     347 GIC         221 :         oldopaque->hasho_prevblkno = xlrec->new_bucket;
 2217 rhaas                     348 ECB             : 
 2217 rhaas                     349 CBC         221 :         PageSetLSN(oldpage, lsn);
 2217 rhaas                     350 GIC         221 :         MarkBufferDirty(oldbuf);
                                351                 :     }
                                352                 : 
 2217 rhaas                     353 ECB             :     /* replay the record for new bucket */
  146 akapila                   354 GIC         221 :     XLogReadBufferForRedoExtended(record, 1, RBM_ZERO_AND_CLEANUP_LOCK, true,
  146 akapila                   355 ECB             :                                   &newbuf);
 2217 rhaas                     356 CBC         221 :     _hash_initbuf(newbuf, xlrec->new_bucket, xlrec->new_bucket,
                                357             221 :                   xlrec->new_bucket_flag, true);
                                358             221 :     MarkBufferDirty(newbuf);
 2217 rhaas                     359 GIC         221 :     PageSetLSN(BufferGetPage(newbuf), lsn);
                                360                 : 
                                361                 :     /*
                                362                 :      * We can release the lock on old bucket early as well but doing here to
                                363                 :      * consistent with normal operation.
 2217 rhaas                     364 ECB             :      */
 2217 rhaas                     365 CBC         221 :     if (BufferIsValid(oldbuf))
                                366             221 :         UnlockReleaseBuffer(oldbuf);
                                367             221 :     if (BufferIsValid(newbuf))
 2217 rhaas                     368 GIC         221 :         UnlockReleaseBuffer(newbuf);
                                369                 : 
                                370                 :     /*
                                371                 :      * Note: in normal operation, we'd update the meta page while still
                                372                 :      * holding lock on the old and new bucket pages.  But during replay it's
                                373                 :      * not necessary to hold those locks, since no other bucket splits can be
                                374                 :      * happening concurrently.
                                375                 :      */
                                376                 : 
 2217 rhaas                     377 ECB             :     /* replay the record for metapage changes */
 2217 rhaas                     378 GIC         221 :     if (XLogReadBufferForRedo(record, 2, &metabuf) == BLK_NEEDS_REDO)
                                379                 :     {
                                380                 :         Page        page;
                                381                 :         HashMetaPage metap;
 2217 rhaas                     382 ECB             : 
 2217 rhaas                     383 CBC         221 :         page = BufferGetPage(metabuf);
                                384             221 :         metap = HashPageGetMeta(page);
 2217 rhaas                     385 GIC         221 :         metap->hashm_maxbucket = xlrec->new_bucket;
 2217 rhaas                     386 ECB             : 
 2217 rhaas                     387 GIC         221 :         data = XLogRecGetBlockData(record, 2, &datalen);
 2217 rhaas                     388 ECB             : 
 2217 rhaas                     389 GIC         221 :         if (xlrec->flags & XLH_SPLIT_META_UPDATE_MASKS)
                                390                 :         {
                                391                 :             uint32      lowmask;
                                392                 :             uint32     *highmask;
                                393                 : 
 2217 rhaas                     394 ECB             :             /* extract low and high masks. */
 2217 rhaas                     395 CBC           3 :             memcpy(&lowmask, data, sizeof(uint32));
 2217 rhaas                     396 GIC           3 :             highmask = (uint32 *) ((char *) data + sizeof(uint32));
                                397                 : 
 2217 rhaas                     398 ECB             :             /* update metapage */
 2217 rhaas                     399 CBC           3 :             metap->hashm_lowmask = lowmask;
 2217 rhaas                     400 GIC           3 :             metap->hashm_highmask = *highmask;
 2217 rhaas                     401 ECB             : 
 2217 rhaas                     402 GIC           3 :             data += sizeof(uint32) * 2;
                                403                 :         }
 2217 rhaas                     404 ECB             : 
 2217 rhaas                     405 GIC         221 :         if (xlrec->flags & XLH_SPLIT_META_UPDATE_SPLITPOINT)
                                406                 :         {
                                407                 :             uint32      ovflpoint;
                                408                 :             uint32     *ovflpages;
                                409                 : 
 2217 rhaas                     410 ECB             :             /* extract information of overflow pages. */
 2217 rhaas                     411 CBC           9 :             memcpy(&ovflpoint, data, sizeof(uint32));
 2217 rhaas                     412 GIC           9 :             ovflpages = (uint32 *) ((char *) data + sizeof(uint32));
                                413                 : 
 2217 rhaas                     414 ECB             :             /* update metapage */
 2217 rhaas                     415 CBC           9 :             metap->hashm_spares[ovflpoint] = *ovflpages;
 2217 rhaas                     416 GIC           9 :             metap->hashm_ovflpoint = ovflpoint;
                                417                 :         }
 2217 rhaas                     418 ECB             : 
 2217 rhaas                     419 CBC         221 :         MarkBufferDirty(metabuf);
 2217 rhaas                     420 GIC         221 :         PageSetLSN(BufferGetPage(metabuf), lsn);
                                421                 :     }
 2217 rhaas                     422 ECB             : 
 2217 rhaas                     423 CBC         221 :     if (BufferIsValid(metabuf))
                                424             221 :         UnlockReleaseBuffer(metabuf);
 2217 rhaas                     425 GIC         221 : }
                                426                 : 
                                427                 : /*
                                428                 :  * replay of split operation
                                429                 :  */
 2217 rhaas                     430 ECB             : static void
 2217 rhaas                     431 GIC         234 : hash_xlog_split_page(XLogReaderState *record)
                                432                 : {
                                433                 :     Buffer      buf;
 2217 rhaas                     434 ECB             : 
 2217 rhaas                     435 GBC         234 :     if (XLogReadBufferForRedo(record, 0, &buf) != BLK_RESTORED)
 2217 rhaas                     436 UIC           0 :         elog(ERROR, "Hash split record did not contain a full-page image");
 2217 rhaas                     437 ECB             : 
 2217 rhaas                     438 CBC         234 :     UnlockReleaseBuffer(buf);
 2217 rhaas                     439 GIC         234 : }
                                440                 : 
                                441                 : /*
                                442                 :  * replay completion of split operation
                                443                 :  */
 2217 rhaas                     444 ECB             : static void
 2217 rhaas                     445 GIC         221 : hash_xlog_split_complete(XLogReaderState *record)
 2217 rhaas                     446 ECB             : {
 2217 rhaas                     447 CBC         221 :     XLogRecPtr  lsn = record->EndRecPtr;
 2217 rhaas                     448 GIC         221 :     xl_hash_split_complete *xlrec = (xl_hash_split_complete *) XLogRecGetData(record);
                                449                 :     Buffer      oldbuf;
                                450                 :     Buffer      newbuf;
                                451                 :     XLogRedoAction action;
                                452                 : 
 2217 rhaas                     453 ECB             :     /* replay the record for old bucket */
 2217 rhaas                     454 GIC         221 :     action = XLogReadBufferForRedo(record, 0, &oldbuf);
                                455                 : 
                                456                 :     /*
                                457                 :      * Note that we still update the page even if it was restored from a full
                                458                 :      * page image, because the bucket flag is not included in the image.
 2217 rhaas                     459 ECB             :      */
 2217 rhaas                     460 GIC         221 :     if (action == BLK_NEEDS_REDO || action == BLK_RESTORED)
                                461                 :     {
                                462                 :         Page        oldpage;
                                463                 :         HashPageOpaque oldopaque;
 2217 rhaas                     464 ECB             : 
 2217 rhaas                     465 CBC         221 :         oldpage = BufferGetPage(oldbuf);
  373 michael                   466 GIC         221 :         oldopaque = HashPageGetOpaque(oldpage);
 2217 rhaas                     467 ECB             : 
 2217 rhaas                     468 GIC         221 :         oldopaque->hasho_flag = xlrec->old_bucket_flag;
 2217 rhaas                     469 ECB             : 
 2217 rhaas                     470 CBC         221 :         PageSetLSN(oldpage, lsn);
 2217 rhaas                     471 GIC         221 :         MarkBufferDirty(oldbuf);
 2217 rhaas                     472 ECB             :     }
 2217 rhaas                     473 CBC         221 :     if (BufferIsValid(oldbuf))
 2217 rhaas                     474 GIC         221 :         UnlockReleaseBuffer(oldbuf);
                                475                 : 
 2217 rhaas                     476 ECB             :     /* replay the record for new bucket */
 2217 rhaas                     477 GIC         221 :     action = XLogReadBufferForRedo(record, 1, &newbuf);
                                478                 : 
                                479                 :     /*
                                480                 :      * Note that we still update the page even if it was restored from a full
                                481                 :      * page image, because the bucket flag is not included in the image.
 2217 rhaas                     482 ECB             :      */
 2217 rhaas                     483 GIC         221 :     if (action == BLK_NEEDS_REDO || action == BLK_RESTORED)
                                484                 :     {
                                485                 :         Page        newpage;
                                486                 :         HashPageOpaque nopaque;
 2217 rhaas                     487 ECB             : 
 2217 rhaas                     488 CBC         221 :         newpage = BufferGetPage(newbuf);
  373 michael                   489 GIC         221 :         nopaque = HashPageGetOpaque(newpage);
 2217 rhaas                     490 ECB             : 
 2217 rhaas                     491 GIC         221 :         nopaque->hasho_flag = xlrec->new_bucket_flag;
 2217 rhaas                     492 ECB             : 
 2217 rhaas                     493 CBC         221 :         PageSetLSN(newpage, lsn);
 2217 rhaas                     494 GIC         221 :         MarkBufferDirty(newbuf);
 2217 rhaas                     495 ECB             :     }
 2217 rhaas                     496 CBC         221 :     if (BufferIsValid(newbuf))
                                497             221 :         UnlockReleaseBuffer(newbuf);
 2217 rhaas                     498 GIC         221 : }
                                499                 : 
                                500                 : /*
                                501                 :  * replay move of page contents for squeeze operation of hash index
                                502                 :  */
 2217 rhaas                     503 EUB             : static void
 2217 rhaas                     504 UIC           0 : hash_xlog_move_page_contents(XLogReaderState *record)
 2217 rhaas                     505 EUB             : {
 2217 rhaas                     506 UBC           0 :     XLogRecPtr  lsn = record->EndRecPtr;
                                507               0 :     xl_hash_move_page_contents *xldata = (xl_hash_move_page_contents *) XLogRecGetData(record);
                                508               0 :     Buffer      bucketbuf = InvalidBuffer;
                                509               0 :     Buffer      writebuf = InvalidBuffer;
 2217 rhaas                     510 UIC           0 :     Buffer      deletebuf = InvalidBuffer;
                                511                 :     XLogRedoAction action;
                                512                 : 
                                513                 :     /*
                                514                 :      * Ensure we have a cleanup lock on primary bucket page before we start
                                515                 :      * with the actual replay operation.  This is to ensure that neither a
                                516                 :      * scan can start nor a scan can be already-in-progress during the replay
                                517                 :      * of this operation.  If we allow scans during this operation, then they
                                518                 :      * can miss some records or show the same record multiple times.
 2217 rhaas                     519 EUB             :      */
 2217 rhaas                     520 UBC           0 :     if (xldata->is_prim_bucket_same_wrt)
 2217 rhaas                     521 UIC           0 :         action = XLogReadBufferForRedoExtended(record, 1, RBM_NORMAL, true, &writebuf);
                                522                 :     else
                                523                 :     {
                                524                 :         /*
                                525                 :          * we don't care for return value as the purpose of reading bucketbuf
                                526                 :          * is to ensure a cleanup lock on primary bucket page.
 2217 rhaas                     527 EUB             :          */
 2217 rhaas                     528 UIC           0 :         (void) XLogReadBufferForRedoExtended(record, 0, RBM_NORMAL, true, &bucketbuf);
 2217 rhaas                     529 EUB             : 
 2217 rhaas                     530 UIC           0 :         action = XLogReadBufferForRedo(record, 1, &writebuf);
                                531                 :     }
                                532                 : 
 2217 rhaas                     533 EUB             :     /* replay the record for adding entries in overflow buffer */
 2217 rhaas                     534 UIC           0 :     if (action == BLK_NEEDS_REDO)
                                535                 :     {
                                536                 :         Page        writepage;
                                537                 :         char       *begin;
                                538                 :         char       *data;
 2217 rhaas                     539 EUB             :         Size        datalen;
 2217 rhaas                     540 UIC           0 :         uint16      ninserted = 0;
 2217 rhaas                     541 EUB             : 
 2217 rhaas                     542 UIC           0 :         data = begin = XLogRecGetBlockData(record, 1, &datalen);
 2217 rhaas                     543 EUB             : 
 2217 rhaas                     544 UIC           0 :         writepage = (Page) BufferGetPage(writebuf);
 2217 rhaas                     545 EUB             : 
 2217 rhaas                     546 UIC           0 :         if (xldata->ntups > 0)
 2217 rhaas                     547 EUB             :         {
 2217 rhaas                     548 UIC           0 :             OffsetNumber *towrite = (OffsetNumber *) data;
 2217 rhaas                     549 EUB             : 
 2217 rhaas                     550 UIC           0 :             data += sizeof(OffsetNumber) * xldata->ntups;
 2217 rhaas                     551 EUB             : 
 2217 rhaas                     552 UIC           0 :             while (data - begin < datalen)
 2217 rhaas                     553 EUB             :             {
 2217 rhaas                     554 UIC           0 :                 IndexTuple  itup = (IndexTuple) data;
                                555                 :                 Size        itemsz;
                                556                 :                 OffsetNumber l;
 2217 rhaas                     557 EUB             : 
 1866 tgl                       558 UBC           0 :                 itemsz = IndexTupleSize(itup);
 2217 rhaas                     559 UIC           0 :                 itemsz = MAXALIGN(itemsz);
 2217 rhaas                     560 EUB             : 
 2217 rhaas                     561 UIC           0 :                 data += itemsz;
 2217 rhaas                     562 EUB             : 
 2217 rhaas                     563 UBC           0 :                 l = PageAddItem(writepage, (Item) itup, itemsz, towrite[ninserted], false, false);
                                564               0 :                 if (l == InvalidOffsetNumber)
 2217 rhaas                     565 UIC           0 :                     elog(ERROR, "hash_xlog_move_page_contents: failed to add item to hash index page, size %d bytes",
                                566                 :                          (int) itemsz);
 2217 rhaas                     567 EUB             : 
 2217 rhaas                     568 UIC           0 :                 ninserted++;
                                569                 :             }
                                570                 :         }
                                571                 : 
                                572                 :         /*
                                573                 :          * number of tuples inserted must be same as requested in REDO record.
 2217 rhaas                     574 EUB             :          */
 2217 rhaas                     575 UIC           0 :         Assert(ninserted == xldata->ntups);
 2217 rhaas                     576 EUB             : 
 2217 rhaas                     577 UBC           0 :         PageSetLSN(writepage, lsn);
 2217 rhaas                     578 UIC           0 :         MarkBufferDirty(writebuf);
                                579                 :     }
                                580                 : 
 2217 rhaas                     581 EUB             :     /* replay the record for deleting entries from overflow buffer */
 2217 rhaas                     582 UIC           0 :     if (XLogReadBufferForRedo(record, 2, &deletebuf) == BLK_NEEDS_REDO)
                                583                 :     {
                                584                 :         Page        page;
                                585                 :         char       *ptr;
                                586                 :         Size        len;
 2217 rhaas                     587 EUB             : 
 2217 rhaas                     588 UIC           0 :         ptr = XLogRecGetBlockData(record, 2, &len);
 2217 rhaas                     589 EUB             : 
 2217 rhaas                     590 UIC           0 :         page = (Page) BufferGetPage(deletebuf);
 2217 rhaas                     591 EUB             : 
 2217 rhaas                     592 UIC           0 :         if (len > 0)
                                593                 :         {
                                594                 :             OffsetNumber *unused;
                                595                 :             OffsetNumber *unend;
 2217 rhaas                     596 EUB             : 
 2217 rhaas                     597 UBC           0 :             unused = (OffsetNumber *) ptr;
 2217 rhaas                     598 UIC           0 :             unend = (OffsetNumber *) ((char *) ptr + len);
 2217 rhaas                     599 EUB             : 
 2217 rhaas                     600 UBC           0 :             if ((unend - unused) > 0)
 2217 rhaas                     601 UIC           0 :                 PageIndexMultiDelete(page, unused, unend - unused);
                                602                 :         }
 2217 rhaas                     603 EUB             : 
 2217 rhaas                     604 UBC           0 :         PageSetLSN(page, lsn);
 2217 rhaas                     605 UIC           0 :         MarkBufferDirty(deletebuf);
                                606                 :     }
                                607                 : 
                                608                 :     /*
                                609                 :      * Replay is complete, now we can release the buffers. We release locks at
                                610                 :      * end of replay operation to ensure that we hold lock on primary bucket
                                611                 :      * page till end of operation.  We can optimize by releasing the lock on
                                612                 :      * write buffer as soon as the operation for same is complete, if it is
                                613                 :      * not same as primary bucket page, but that doesn't seem to be worth
                                614                 :      * complicating the code.
 2217 rhaas                     615 EUB             :      */
 2217 rhaas                     616 UBC           0 :     if (BufferIsValid(deletebuf))
 2217 rhaas                     617 UIC           0 :         UnlockReleaseBuffer(deletebuf);
 2217 rhaas                     618 EUB             : 
 2217 rhaas                     619 UBC           0 :     if (BufferIsValid(writebuf))
 2217 rhaas                     620 UIC           0 :         UnlockReleaseBuffer(writebuf);
 2217 rhaas                     621 EUB             : 
 2217 rhaas                     622 UBC           0 :     if (BufferIsValid(bucketbuf))
                                623               0 :         UnlockReleaseBuffer(bucketbuf);
 2217 rhaas                     624 UIC           0 : }
                                625                 : 
                                626                 : /*
                                627                 :  * replay squeeze page operation of hash index
                                628                 :  */
 2217 rhaas                     629 ECB             : static void
 2217 rhaas                     630 GIC          22 : hash_xlog_squeeze_page(XLogReaderState *record)
 2217 rhaas                     631 ECB             : {
 2217 rhaas                     632 CBC          22 :     XLogRecPtr  lsn = record->EndRecPtr;
                                633              22 :     xl_hash_squeeze_page *xldata = (xl_hash_squeeze_page *) XLogRecGetData(record);
 2217 rhaas                     634 GIC          22 :     Buffer      bucketbuf = InvalidBuffer;
                                635                 :     Buffer      writebuf;
 2217 rhaas                     636 ECB             :     Buffer      ovflbuf;
 2217 rhaas                     637 GIC          22 :     Buffer      prevbuf = InvalidBuffer;
                                638                 :     Buffer      mapbuf;
                                639                 :     XLogRedoAction action;
                                640                 : 
                                641                 :     /*
                                642                 :      * Ensure we have a cleanup lock on primary bucket page before we start
                                643                 :      * with the actual replay operation.  This is to ensure that neither a
                                644                 :      * scan can start nor a scan can be already-in-progress during the replay
                                645                 :      * of this operation.  If we allow scans during this operation, then they
                                646                 :      * can miss some records or show the same record multiple times.
 2217 rhaas                     647 ECB             :      */
 2217 rhaas                     648 CBC          22 :     if (xldata->is_prim_bucket_same_wrt)
 2217 rhaas                     649 GIC          21 :         action = XLogReadBufferForRedoExtended(record, 1, RBM_NORMAL, true, &writebuf);
                                650                 :     else
                                651                 :     {
                                652                 :         /*
                                653                 :          * we don't care for return value as the purpose of reading bucketbuf
                                654                 :          * is to ensure a cleanup lock on primary bucket page.
 2217 rhaas                     655 ECB             :          */
 2217 rhaas                     656 GIC           1 :         (void) XLogReadBufferForRedoExtended(record, 0, RBM_NORMAL, true, &bucketbuf);
 2217 rhaas                     657 ECB             : 
 2217 rhaas                     658 GIC           1 :         action = XLogReadBufferForRedo(record, 1, &writebuf);
                                659                 :     }
                                660                 : 
 2217 rhaas                     661 ECB             :     /* replay the record for adding entries in overflow buffer */
 2217 rhaas                     662 GIC          22 :     if (action == BLK_NEEDS_REDO)
                                663                 :     {
                                664                 :         Page        writepage;
                                665                 :         char       *begin;
                                666                 :         char       *data;
 2217 rhaas                     667 ECB             :         Size        datalen;
 2217 rhaas                     668 GIC          22 :         uint16      ninserted = 0;
 2217 rhaas                     669 ECB             : 
 2217 rhaas                     670 GIC          22 :         data = begin = XLogRecGetBlockData(record, 1, &datalen);
 2217 rhaas                     671 ECB             : 
 2217 rhaas                     672 GIC          22 :         writepage = (Page) BufferGetPage(writebuf);
 2217 rhaas                     673 ECB             : 
 2217 rhaas                     674 GIC          22 :         if (xldata->ntups > 0)
 2217 rhaas                     675 ECB             :         {
 2217 rhaas                     676 GIC          10 :             OffsetNumber *towrite = (OffsetNumber *) data;
 2217 rhaas                     677 ECB             : 
 2217 rhaas                     678 GIC          10 :             data += sizeof(OffsetNumber) * xldata->ntups;
 2217 rhaas                     679 ECB             : 
 2217 rhaas                     680 GIC         414 :             while (data - begin < datalen)
 2217 rhaas                     681 ECB             :             {
 2217 rhaas                     682 GIC         404 :                 IndexTuple  itup = (IndexTuple) data;
                                683                 :                 Size        itemsz;
                                684                 :                 OffsetNumber l;
 2217 rhaas                     685 ECB             : 
 1866 tgl                       686 CBC         404 :                 itemsz = IndexTupleSize(itup);
 2217 rhaas                     687 GIC         404 :                 itemsz = MAXALIGN(itemsz);
 2217 rhaas                     688 ECB             : 
 2217 rhaas                     689 GIC         404 :                 data += itemsz;
 2217 rhaas                     690 ECB             : 
 2217 rhaas                     691 CBC         404 :                 l = PageAddItem(writepage, (Item) itup, itemsz, towrite[ninserted], false, false);
 2217 rhaas                     692 GBC         404 :                 if (l == InvalidOffsetNumber)
 2217 rhaas                     693 UIC           0 :                     elog(ERROR, "hash_xlog_squeeze_page: failed to add item to hash index page, size %d bytes",
                                694                 :                          (int) itemsz);
 2217 rhaas                     695 ECB             : 
 2217 rhaas                     696 GIC         404 :                 ninserted++;
                                697                 :             }
                                698                 :         }
                                699                 : 
                                700                 :         /*
                                701                 :          * number of tuples inserted must be same as requested in REDO record.
 2217 rhaas                     702 ECB             :          */
 2217 rhaas                     703 GIC          22 :         Assert(ninserted == xldata->ntups);
                                704                 : 
                                705                 :         /*
                                706                 :          * if the page on which are adding tuples is a page previous to freed
                                707                 :          * overflow page, then update its nextblkno.
 2217 rhaas                     708 ECB             :          */
 2217 rhaas                     709 GIC          22 :         if (xldata->is_prev_bucket_same_wrt)
 2217 rhaas                     710 ECB             :         {
  373 michael                   711 GIC           9 :             HashPageOpaque writeopaque = HashPageGetOpaque(writepage);
 2217 rhaas                     712 ECB             : 
 2217 rhaas                     713 GIC           9 :             writeopaque->hasho_nextblkno = xldata->nextblkno;
                                714                 :         }
 2217 rhaas                     715 ECB             : 
 2217 rhaas                     716 CBC          22 :         PageSetLSN(writepage, lsn);
 2217 rhaas                     717 GIC          22 :         MarkBufferDirty(writebuf);
                                718                 :     }
                                719                 : 
 2217 rhaas                     720 ECB             :     /* replay the record for initializing overflow buffer */
 2217 rhaas                     721 GIC          22 :     if (XLogReadBufferForRedo(record, 2, &ovflbuf) == BLK_NEEDS_REDO)
                                722                 :     {
                                723                 :         Page        ovflpage;
                                724                 :         HashPageOpaque ovflopaque;
 2217 rhaas                     725 EUB             : 
 2217 rhaas                     726 UIC           0 :         ovflpage = BufferGetPage(ovflbuf);
 2217 rhaas                     727 EUB             : 
 2217 rhaas                     728 UIC           0 :         _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
 2217 rhaas                     729 EUB             : 
  373 michael                   730 UIC           0 :         ovflopaque = HashPageGetOpaque(ovflpage);
 2195 rhaas                     731 EUB             : 
 2195 rhaas                     732 UBC           0 :         ovflopaque->hasho_prevblkno = InvalidBlockNumber;
                                733               0 :         ovflopaque->hasho_nextblkno = InvalidBlockNumber;
  646 peter                     734               0 :         ovflopaque->hasho_bucket = InvalidBucket;
 2195 rhaas                     735               0 :         ovflopaque->hasho_flag = LH_UNUSED_PAGE;
 2195 rhaas                     736 UIC           0 :         ovflopaque->hasho_page_id = HASHO_PAGE_ID;
 2195 rhaas                     737 EUB             : 
 2217 rhaas                     738 UBC           0 :         PageSetLSN(ovflpage, lsn);
 2217 rhaas                     739 UIC           0 :         MarkBufferDirty(ovflbuf);
 2217 rhaas                     740 ECB             :     }
 2217 rhaas                     741 CBC          22 :     if (BufferIsValid(ovflbuf))
 2217 rhaas                     742 GIC          22 :         UnlockReleaseBuffer(ovflbuf);
                                743                 : 
 2217 rhaas                     744 ECB             :     /* replay the record for page previous to the freed overflow page */
 2217 rhaas                     745 CBC          35 :     if (!xldata->is_prev_bucket_same_wrt &&
 2217 rhaas                     746 GIC          13 :         XLogReadBufferForRedo(record, 3, &prevbuf) == BLK_NEEDS_REDO)
 2217 rhaas                     747 ECB             :     {
 2217 rhaas                     748 CBC          13 :         Page        prevpage = BufferGetPage(prevbuf);
  373 michael                   749 GIC          13 :         HashPageOpaque prevopaque = HashPageGetOpaque(prevpage);
 2217 rhaas                     750 ECB             : 
 2217 rhaas                     751 GIC          13 :         prevopaque->hasho_nextblkno = xldata->nextblkno;
 2217 rhaas                     752 ECB             : 
 2217 rhaas                     753 CBC          13 :         PageSetLSN(prevpage, lsn);
 2217 rhaas                     754 GIC          13 :         MarkBufferDirty(prevbuf);
 2217 rhaas                     755 ECB             :     }
 2217 rhaas                     756 CBC          22 :     if (BufferIsValid(prevbuf))
 2217 rhaas                     757 GIC          13 :         UnlockReleaseBuffer(prevbuf);
                                758                 : 
 2217 rhaas                     759 ECB             :     /* replay the record for page next to the freed overflow page */
 2217 rhaas                     760 GIC          22 :     if (XLogRecHasBlockRef(record, 4))
                                761                 :     {
                                762                 :         Buffer      nextbuf;
 2217 rhaas                     763 EUB             : 
 2217 rhaas                     764 UIC           0 :         if (XLogReadBufferForRedo(record, 4, &nextbuf) == BLK_NEEDS_REDO)
 2217 rhaas                     765 EUB             :         {
 2217 rhaas                     766 UBC           0 :             Page        nextpage = BufferGetPage(nextbuf);
  373 michael                   767 UIC           0 :             HashPageOpaque nextopaque = HashPageGetOpaque(nextpage);
 2217 rhaas                     768 EUB             : 
 2217 rhaas                     769 UIC           0 :             nextopaque->hasho_prevblkno = xldata->prevblkno;
 2217 rhaas                     770 EUB             : 
 2217 rhaas                     771 UBC           0 :             PageSetLSN(nextpage, lsn);
 2217 rhaas                     772 UIC           0 :             MarkBufferDirty(nextbuf);
 2217 rhaas                     773 EUB             :         }
 2217 rhaas                     774 UBC           0 :         if (BufferIsValid(nextbuf))
 2217 rhaas                     775 UIC           0 :             UnlockReleaseBuffer(nextbuf);
                                776                 :     }
 2217 rhaas                     777 ECB             : 
 2217 rhaas                     778 CBC          22 :     if (BufferIsValid(writebuf))
 2217 rhaas                     779 GIC          22 :         UnlockReleaseBuffer(writebuf);
 2217 rhaas                     780 ECB             : 
 2217 rhaas                     781 CBC          22 :     if (BufferIsValid(bucketbuf))
 2217 rhaas                     782 GIC           1 :         UnlockReleaseBuffer(bucketbuf);
                                783                 : 
                                784                 :     /*
                                785                 :      * Note: in normal operation, we'd update the bitmap and meta page while
                                786                 :      * still holding lock on the primary bucket page and overflow pages.  But
                                787                 :      * during replay it's not necessary to hold those locks, since no other
                                788                 :      * index updates can be happening concurrently.
                                789                 :      */
 2217 rhaas                     790 ECB             :     /* replay the record for bitmap page */
 2217 rhaas                     791 GIC          22 :     if (XLogReadBufferForRedo(record, 5, &mapbuf) == BLK_NEEDS_REDO)
 2217 rhaas                     792 ECB             :     {
 2217 rhaas                     793 CBC          21 :         Page        mappage = (Page) BufferGetPage(mapbuf);
 2217 rhaas                     794 GIC          21 :         uint32     *freep = NULL;
                                795                 :         char       *data;
                                796                 :         uint32     *bitmap_page_bit;
                                797                 :         Size        datalen;
 2217 rhaas                     798 ECB             : 
 2217 rhaas                     799 GIC          21 :         freep = HashPageGetBitmap(mappage);
 2217 rhaas                     800 ECB             : 
 2217 rhaas                     801 CBC          21 :         data = XLogRecGetBlockData(record, 5, &datalen);
 2217 rhaas                     802 GIC          21 :         bitmap_page_bit = (uint32 *) data;
 2217 rhaas                     803 ECB             : 
 2217 rhaas                     804 GIC          21 :         CLRBIT(freep, *bitmap_page_bit);
 2217 rhaas                     805 ECB             : 
 2217 rhaas                     806 CBC          21 :         PageSetLSN(mappage, lsn);
 2217 rhaas                     807 GIC          21 :         MarkBufferDirty(mapbuf);
 2217 rhaas                     808 ECB             :     }
 2217 rhaas                     809 CBC          22 :     if (BufferIsValid(mapbuf))
 2217 rhaas                     810 GIC          22 :         UnlockReleaseBuffer(mapbuf);
                                811                 : 
 2217 rhaas                     812 ECB             :     /* replay the record for meta page */
 2217 rhaas                     813 GIC          22 :     if (XLogRecHasBlockRef(record, 6))
                                814                 :     {
                                815                 :         Buffer      metabuf;
 2217 rhaas                     816 ECB             : 
 2217 rhaas                     817 GIC          21 :         if (XLogReadBufferForRedo(record, 6, &metabuf) == BLK_NEEDS_REDO)
                                818                 :         {
                                819                 :             HashMetaPage metap;
                                820                 :             Page        page;
                                821                 :             char       *data;
                                822                 :             uint32     *firstfree_ovflpage;
                                823                 :             Size        datalen;
 2217 rhaas                     824 ECB             : 
 2217 rhaas                     825 CBC          21 :             data = XLogRecGetBlockData(record, 6, &datalen);
 2217 rhaas                     826 GIC          21 :             firstfree_ovflpage = (uint32 *) data;
 2217 rhaas                     827 ECB             : 
 2217 rhaas                     828 CBC          21 :             page = BufferGetPage(metabuf);
                                829              21 :             metap = HashPageGetMeta(page);
 2217 rhaas                     830 GIC          21 :             metap->hashm_firstfree = *firstfree_ovflpage;
 2217 rhaas                     831 ECB             : 
 2217 rhaas                     832 CBC          21 :             PageSetLSN(page, lsn);
 2217 rhaas                     833 GIC          21 :             MarkBufferDirty(metabuf);
 2217 rhaas                     834 ECB             :         }
 2217 rhaas                     835 CBC          21 :         if (BufferIsValid(metabuf))
 2217 rhaas                     836 GIC          21 :             UnlockReleaseBuffer(metabuf);
 2217 rhaas                     837 ECB             :     }
 2217 rhaas                     838 GIC          22 : }
                                839                 : 
                                840                 : /*
                                841                 :  * replay delete operation of hash index
                                842                 :  */
 2217 rhaas                     843 ECB             : static void
 2217 rhaas                     844 GIC         244 : hash_xlog_delete(XLogReaderState *record)
 2217 rhaas                     845 ECB             : {
 2217 rhaas                     846 CBC         244 :     XLogRecPtr  lsn = record->EndRecPtr;
                                847             244 :     xl_hash_delete *xldata = (xl_hash_delete *) XLogRecGetData(record);
 2217 rhaas                     848 GIC         244 :     Buffer      bucketbuf = InvalidBuffer;
                                849                 :     Buffer      deletebuf;
                                850                 :     Page        page;
                                851                 :     XLogRedoAction action;
                                852                 : 
                                853                 :     /*
                                854                 :      * Ensure we have a cleanup lock on primary bucket page before we start
                                855                 :      * with the actual replay operation.  This is to ensure that neither a
                                856                 :      * scan can start nor a scan can be already-in-progress during the replay
                                857                 :      * of this operation.  If we allow scans during this operation, then they
                                858                 :      * can miss some records or show the same record multiple times.
 2217 rhaas                     859 ECB             :      */
 2217 rhaas                     860 CBC         244 :     if (xldata->is_primary_bucket_page)
 2217 rhaas                     861 GIC         222 :         action = XLogReadBufferForRedoExtended(record, 1, RBM_NORMAL, true, &deletebuf);
                                862                 :     else
                                863                 :     {
                                864                 :         /*
                                865                 :          * we don't care for return value as the purpose of reading bucketbuf
                                866                 :          * is to ensure a cleanup lock on primary bucket page.
 2217 rhaas                     867 ECB             :          */
 2217 rhaas                     868 GIC          22 :         (void) XLogReadBufferForRedoExtended(record, 0, RBM_NORMAL, true, &bucketbuf);
 2217 rhaas                     869 ECB             : 
 2217 rhaas                     870 GIC          22 :         action = XLogReadBufferForRedo(record, 1, &deletebuf);
                                871                 :     }
                                872                 : 
 2217 rhaas                     873 ECB             :     /* replay the record for deleting entries in bucket page */
 2217 rhaas                     874 GIC         244 :     if (action == BLK_NEEDS_REDO)
                                875                 :     {
                                876                 :         char       *ptr;
                                877                 :         Size        len;
 2217 rhaas                     878 ECB             : 
 2217 rhaas                     879 GIC         244 :         ptr = XLogRecGetBlockData(record, 1, &len);
 2217 rhaas                     880 ECB             : 
 2217 rhaas                     881 GIC         244 :         page = (Page) BufferGetPage(deletebuf);
 2217 rhaas                     882 ECB             : 
 2217 rhaas                     883 GIC         244 :         if (len > 0)
                                884                 :         {
                                885                 :             OffsetNumber *unused;
                                886                 :             OffsetNumber *unend;
 2217 rhaas                     887 ECB             : 
 2217 rhaas                     888 CBC         244 :             unused = (OffsetNumber *) ptr;
 2217 rhaas                     889 GIC         244 :             unend = (OffsetNumber *) ((char *) ptr + len);
 2217 rhaas                     890 ECB             : 
 2217 rhaas                     891 CBC         244 :             if ((unend - unused) > 0)
 2217 rhaas                     892 GIC         244 :                 PageIndexMultiDelete(page, unused, unend - unused);
                                893                 :         }
                                894                 : 
                                895                 :         /*
                                896                 :          * Mark the page as not containing any LP_DEAD items only if
                                897                 :          * clear_dead_marking flag is set to true. See comments in
                                898                 :          * hashbucketcleanup() for details.
 2211 rhaas                     899 ECB             :          */
 2211 rhaas                     900 GIC         244 :         if (xldata->clear_dead_marking)
                                901                 :         {
                                902                 :             HashPageOpaque pageopaque;
 2211 rhaas                     903 EUB             : 
  373 michael                   904 UBC           0 :             pageopaque = HashPageGetOpaque(page);
 2211 rhaas                     905 UIC           0 :             pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
                                906                 :         }
 2211 rhaas                     907 ECB             : 
 2217 rhaas                     908 CBC         244 :         PageSetLSN(page, lsn);
 2217 rhaas                     909 GIC         244 :         MarkBufferDirty(deletebuf);
 2217 rhaas                     910 ECB             :     }
 2217 rhaas                     911 CBC         244 :     if (BufferIsValid(deletebuf))
 2217 rhaas                     912 GIC         244 :         UnlockReleaseBuffer(deletebuf);
 2217 rhaas                     913 ECB             : 
 2217 rhaas                     914 CBC         244 :     if (BufferIsValid(bucketbuf))
                                915              22 :         UnlockReleaseBuffer(bucketbuf);
 2217 rhaas                     916 GIC         244 : }
                                917                 : 
                                918                 : /*
                                919                 :  * replay split cleanup flag operation for primary bucket page.
                                920                 :  */
 2217 rhaas                     921 ECB             : static void
 2217 rhaas                     922 GIC         221 : hash_xlog_split_cleanup(XLogReaderState *record)
 2217 rhaas                     923 ECB             : {
 2217 rhaas                     924 GIC         221 :     XLogRecPtr  lsn = record->EndRecPtr;
                                925                 :     Buffer      buffer;
                                926                 :     Page        page;
 2217 rhaas                     927 ECB             : 
 2217 rhaas                     928 GIC         221 :     if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
                                929                 :     {
                                930                 :         HashPageOpaque bucket_opaque;
 2217 rhaas                     931 ECB             : 
 2217 rhaas                     932 GIC         221 :         page = (Page) BufferGetPage(buffer);
 2217 rhaas                     933 ECB             : 
  373 michael                   934 CBC         221 :         bucket_opaque = HashPageGetOpaque(page);
 2217 rhaas                     935             221 :         bucket_opaque->hasho_flag &= ~LH_BUCKET_NEEDS_SPLIT_CLEANUP;
                                936             221 :         PageSetLSN(page, lsn);
 2217 rhaas                     937 GIC         221 :         MarkBufferDirty(buffer);
 2217 rhaas                     938 ECB             :     }
 2217 rhaas                     939 CBC         221 :     if (BufferIsValid(buffer))
                                940             221 :         UnlockReleaseBuffer(buffer);
 2217 rhaas                     941 GIC         221 : }
                                942                 : 
                                943                 : /*
                                944                 :  * replay for update meta page
                                945                 :  */
 2217 rhaas                     946 ECB             : static void
 2217 rhaas                     947 GIC           2 : hash_xlog_update_meta_page(XLogReaderState *record)
                                948                 : {
 2217 rhaas                     949 ECB             :     HashMetaPage metap;
 2217 rhaas                     950 CBC           2 :     XLogRecPtr  lsn = record->EndRecPtr;
 2217 rhaas                     951 GIC           2 :     xl_hash_update_meta_page *xldata = (xl_hash_update_meta_page *) XLogRecGetData(record);
                                952                 :     Buffer      metabuf;
                                953                 :     Page        page;
 2217 rhaas                     954 ECB             : 
 2217 rhaas                     955 GIC           2 :     if (XLogReadBufferForRedo(record, 0, &metabuf) == BLK_NEEDS_REDO)
 2217 rhaas                     956 ECB             :     {
 2217 rhaas                     957 CBC           2 :         page = BufferGetPage(metabuf);
 2217 rhaas                     958 GIC           2 :         metap = HashPageGetMeta(page);
 2217 rhaas                     959 ECB             : 
 2217 rhaas                     960 GIC           2 :         metap->hashm_ntuples = xldata->ntuples;
 2217 rhaas                     961 ECB             : 
 2217 rhaas                     962 CBC           2 :         PageSetLSN(page, lsn);
 2217 rhaas                     963 GIC           2 :         MarkBufferDirty(metabuf);
 2217 rhaas                     964 ECB             :     }
 2217 rhaas                     965 CBC           2 :     if (BufferIsValid(metabuf))
                                966               2 :         UnlockReleaseBuffer(metabuf);
 2217 rhaas                     967 GIC           2 : }
                                968                 : 
                                969                 : /*
                                970                 :  * replay delete operation in hash index to remove
                                971                 :  * tuples marked as DEAD during index tuple insertion.
                                972                 :  */
 2216 rhaas                     973 EUB             : static void
 2216 rhaas                     974 UIC           0 : hash_xlog_vacuum_one_page(XLogReaderState *record)
 2216 rhaas                     975 EUB             : {
 2153 bruce                     976 UIC           0 :     XLogRecPtr  lsn = record->EndRecPtr;
                                977                 :     xl_hash_vacuum_one_page *xldata;
                                978                 :     Buffer      buffer;
                                979                 :     Buffer      metabuf;
                                980                 :     Page        page;
                                981                 :     XLogRedoAction action;
                                982                 :     HashPageOpaque pageopaque;
                                983                 :     OffsetNumber *toDelete;
                                984                 : 
 2216 rhaas                     985 UBC           0 :     xldata = (xl_hash_vacuum_one_page *) XLogRecGetData(record);
    7 andres                    986 UNC           0 :     toDelete = xldata->offsets;
 2216 rhaas                     987 EUB             : 
                                988                 :     /*
                                989                 :      * If we have any conflict processing to do, it must happen before we
                                990                 :      * update the page.
                                991                 :      *
                                992                 :      * Hash index records that are marked as LP_DEAD and being removed during
                                993                 :      * hash index tuple insertion can conflict with standby queries. You might
                                994                 :      * think that vacuum records would conflict as well, but we've handled
                                995                 :      * that already.  XLOG_HEAP2_PRUNE records provide the highest xid cleaned
                                996                 :      * by the vacuum of the heap and so we can resolve any conflicts just once
                                997                 :      * when that arrives.  After that we know that no conflicts exist from
                                998                 :      * individual hash index vacuum records on that index.
                                999                 :      */
 2216 rhaas                    1000 UIC           0 :     if (InHotStandby)
 2216 rhaas                    1001 EUB             :     {
                               1002                 :         RelFileLocator rlocator;
                               1003                 : 
  277 rhaas                    1004 UNC           0 :         XLogRecGetBlockTag(record, 0, &rlocator, NULL, NULL);
  143 pg                       1005               0 :         ResolveRecoveryConflictWithSnapshot(xldata->snapshotConflictHorizon,
    2 andres                   1006               0 :                                             xldata->isCatalogRel,
                               1007                 :                                             rlocator);
 2216 rhaas                    1008 EUB             :     }
                               1009                 : 
 2216 rhaas                    1010 UIC           0 :     action = XLogReadBufferForRedoExtended(record, 0, RBM_NORMAL, true, &buffer);
                               1011                 : 
                               1012               0 :     if (action == BLK_NEEDS_REDO)
 2216 rhaas                    1013 EUB             :     {
 2216 rhaas                    1014 UIC           0 :         page = (Page) BufferGetPage(buffer);
 2216 rhaas                    1015 EUB             : 
    7 andres                   1016 UNC           0 :         PageIndexMultiDelete(page, toDelete, xldata->ntuples);
                               1017                 : 
 2211 rhaas                    1018 EUB             :         /*
 2153 bruce                    1019                 :          * Mark the page as not containing any LP_DEAD items. See comments in
                               1020                 :          * _hash_vacuum_one_page() for details.
 2211 rhaas                    1021                 :          */
  373 michael                  1022 UBC           0 :         pageopaque = HashPageGetOpaque(page);
 2211 rhaas                    1023 UIC           0 :         pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
 2211 rhaas                    1024 EUB             : 
 2216 rhaas                    1025 UBC           0 :         PageSetLSN(page, lsn);
 2216 rhaas                    1026 UIC           0 :         MarkBufferDirty(buffer);
 2216 rhaas                    1027 EUB             :     }
 2216 rhaas                    1028 UIC           0 :     if (BufferIsValid(buffer))
                               1029               0 :         UnlockReleaseBuffer(buffer);
                               1030                 : 
                               1031               0 :     if (XLogReadBufferForRedo(record, 1, &metabuf) == BLK_NEEDS_REDO)
 2216 rhaas                    1032 EUB             :     {
 2153 bruce                    1033                 :         Page        metapage;
                               1034                 :         HashMetaPage metap;
 2216 rhaas                    1035                 : 
 2216 rhaas                    1036 UIC           0 :         metapage = BufferGetPage(metabuf);
 2216 rhaas                    1037 UBC           0 :         metap = HashPageGetMeta(metapage);
 2216 rhaas                    1038 EUB             : 
 2216 rhaas                    1039 UIC           0 :         metap->hashm_ntuples -= xldata->ntuples;
 2216 rhaas                    1040 EUB             : 
 2216 rhaas                    1041 UBC           0 :         PageSetLSN(metapage, lsn);
                               1042               0 :         MarkBufferDirty(metabuf);
                               1043                 :     }
 2216 rhaas                    1044 UIC           0 :     if (BufferIsValid(metabuf))
 2216 rhaas                    1045 LBC           0 :         UnlockReleaseBuffer(metabuf);
 2216 rhaas                    1046 UIC           0 : }
 2216 rhaas                    1047 ECB             : 
                               1048                 : void
 2217 rhaas                    1049 CBC      115260 : hash_redo(XLogReaderState *record)
                               1050                 : {
                               1051          115260 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
 2217 rhaas                    1052 ECB             : 
 2217 rhaas                    1053 CBC      115260 :     switch (info)
 2217 rhaas                    1054 ECB             :     {
 2217 rhaas                    1055 CBC          21 :         case XLOG_HASH_INIT_META_PAGE:
                               1056              21 :             hash_xlog_init_meta_page(record);
                               1057              21 :             break;
                               1058              21 :         case XLOG_HASH_INIT_BITMAP_PAGE:
                               1059              21 :             hash_xlog_init_bitmap_page(record);
                               1060              21 :             break;
                               1061          113999 :         case XLOG_HASH_INSERT:
                               1062          113999 :             hash_xlog_insert(record);
                               1063          113999 :             break;
                               1064              54 :         case XLOG_HASH_ADD_OVFL_PAGE:
                               1065              54 :             hash_xlog_add_ovfl_page(record);
                               1066              54 :             break;
                               1067             221 :         case XLOG_HASH_SPLIT_ALLOCATE_PAGE:
                               1068             221 :             hash_xlog_split_allocate_page(record);
                               1069             221 :             break;
                               1070             234 :         case XLOG_HASH_SPLIT_PAGE:
                               1071             234 :             hash_xlog_split_page(record);
 2217 rhaas                    1072 GBC         234 :             break;
                               1073             221 :         case XLOG_HASH_SPLIT_COMPLETE:
                               1074             221 :             hash_xlog_split_complete(record);
 2217 rhaas                    1075 CBC         221 :             break;
 2217 rhaas                    1076 LBC           0 :         case XLOG_HASH_MOVE_PAGE_CONTENTS:
                               1077               0 :             hash_xlog_move_page_contents(record);
                               1078               0 :             break;
 2217 rhaas                    1079 CBC          22 :         case XLOG_HASH_SQUEEZE_PAGE:
                               1080              22 :             hash_xlog_squeeze_page(record);
                               1081              22 :             break;
                               1082             244 :         case XLOG_HASH_DELETE:
                               1083             244 :             hash_xlog_delete(record);
                               1084             244 :             break;
                               1085             221 :         case XLOG_HASH_SPLIT_CLEANUP:
                               1086             221 :             hash_xlog_split_cleanup(record);
 2217 rhaas                    1087 GBC         221 :             break;
                               1088               2 :         case XLOG_HASH_UPDATE_META_PAGE:
                               1089               2 :             hash_xlog_update_meta_page(record);
                               1090               2 :             break;
 2216 rhaas                    1091 UBC           0 :         case XLOG_HASH_VACUUM_ONE_PAGE:
 2216 rhaas                    1092 UIC           0 :             hash_xlog_vacuum_one_page(record);
 2216 rhaas                    1093 LBC           0 :             break;
 2217 rhaas                    1094 UIC           0 :         default:
                               1095               0 :             elog(PANIC, "hash_redo: unknown op code %u", info);
                               1096                 :     }
 2217 rhaas                    1097 GIC      115260 : }
                               1098                 : 
 2217 rhaas                    1099 EUB             : /*
                               1100                 :  * Mask a hash page before performing consistency checks on it.
                               1101                 :  */
                               1102                 : void
 2217 rhaas                    1103 UIC           0 : hash_mask(char *pagedata, BlockNumber blkno)
                               1104                 : {
 2217 rhaas                    1105 UBC           0 :     Page        page = (Page) pagedata;
                               1106                 :     HashPageOpaque opaque;
 2186 tgl                      1107 EUB             :     int         pagetype;
 2217 rhaas                    1108                 : 
 2025 rhaas                    1109 UIC           0 :     mask_page_lsn_and_checksum(page);
 2217 rhaas                    1110 EUB             : 
 2217 rhaas                    1111 UIC           0 :     mask_page_hint_bits(page);
 2217 rhaas                    1112 UBC           0 :     mask_unused_space(page);
 2217 rhaas                    1113 EUB             : 
  373 michael                  1114 UIC           0 :     opaque = HashPageGetOpaque(page);
                               1115                 : 
 2186 tgl                      1116               0 :     pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
                               1117               0 :     if (pagetype == LH_UNUSED_PAGE)
 2217 rhaas                    1118 EUB             :     {
                               1119                 :         /*
                               1120                 :          * Mask everything on a UNUSED page.
                               1121                 :          */
 2217 rhaas                    1122 UIC           0 :         mask_page_content(page);
                               1123                 :     }
 2186 tgl                      1124               0 :     else if (pagetype == LH_BUCKET_PAGE ||
                               1125                 :              pagetype == LH_OVERFLOW_PAGE)
                               1126                 :     {
                               1127                 :         /*
 2217 rhaas                    1128 EUB             :          * In hash bucket and overflow pages, it is possible to modify the
                               1129                 :          * LP_FLAGS without emitting any WAL record. Hence, mask the line
                               1130                 :          * pointer flags. See hashgettuple(), _hash_kill_items() for details.
                               1131                 :          */
 2217 rhaas                    1132 UIC           0 :         mask_lp_flags(page);
                               1133                 :     }
                               1134                 : 
 2211 rhaas                    1135 EUB             :     /*
                               1136                 :      * It is possible that the hint bit LH_PAGE_HAS_DEAD_TUPLES may remain
                               1137                 :      * unlogged. So, mask it. See _hash_kill_items() for details.
                               1138                 :      */
 2211 rhaas                    1139 UIC           0 :     opaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
 2217                          1140               0 : }
        

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