LCOV - differential code coverage report
Current view: top level - src/backend/access/hash - hash_xlog.c (source / functions) Coverage Total Hit UNC UBC GBC GNC CBC DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 82.4 % 471 388 83 45 11 332 3
Current Date: 2024-04-14 14:21:10 Functions: 86.7 % 15 13 1 1 1 1 11
Baseline: 16@8cea358b128 Branches: 56.6 % 226 128 1 97 19 9 100
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 100.0 % 7 7 7
(120,180] days: 100.0 % 4 4 4
(240..) days: 82.0 % 460 377 83 45 332
Function coverage date bins:
(240..) days: 86.7 % 15 13 1 1 1 1 11
Branch coverage date bins:
[..60] days: 83.3 % 6 5 1 5
(120,180] days: 100.0 % 4 4 4
(240..) days: 55.1 % 216 119 97 19 100

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

Generated by: LCOV version 2.1-beta2-3-g6141622