LCOV - differential code coverage report
Current view: top level - src/backend/access/hash - hash_xlog.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB DCB
Current: b45a8d7d8b306b43f31a002f1b3f1dddc8defeaf vs 8767b449a3a1e75626dfb08f24da54933171d4c5 Lines: 84.9 % 471 400 1 70 11 389 1 11
Current Date: 2025-10-28 08:26:42 +0900 Functions: 93.3 % 15 14 1 7 7
Baseline: lcov-20251028-005825-baseline Branches: 61.9 % 226 140 1 85 1 139
Baseline Date: 2025-10-27 06:37:35 +0000 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
[..1] days: 100.0 % 3 3 3
(30,360] days: 88.9 % 9 8 1 8
(360..) days: 84.7 % 459 389 70 389
Function coverage date bins:
(360..) days: 93.3 % 15 14 1 7 7
Branch coverage date bins:
[..1] days: 50.0 % 2 1 1 1
(360..) days: 62.1 % 224 139 85 139

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

Generated by: LCOV version 2.4-beta