LCOV - differential code coverage report
Current view: top level - src/backend/access/hash - hash_xlog.c (source / functions) Coverage Total Hit UBC CBC
Current: 77aeca80249c9e640c811e80633a2e334a9320de vs 38afc3dcb25c45b744d4025029ce0a6c90b7059f Lines: 91.2 % 466 425 41 425
Current Date: 2026-07-25 19:08:27 +0900 Functions: 100.0 % 15 15 15
Baseline: lcov-20260725-baseline Branches: 62.3 % 220 137 83 137
Baseline Date: 2026-07-25 19:09:19 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 3 3 3
(30,360] days: 91.7 % 24 22 2 22
(360..) days: 91.1 % 439 400 39 400
Function coverage date bins:
(360..) days: 100.0 % 15 15 15
Branch coverage date bins:
(30,360] days: 16.7 % 6 1 5 1
(360..) days: 63.6 % 214 136 78 136

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

Generated by: LCOV version 2.0-1