LCOV - code coverage report
Current view: top level - src/backend/access/brin - brin_xlog.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 146 151 96.7 %
Date: 2024-12-12 16:15:21 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * brin_xlog.c
       3             :  *      XLog replay routines for BRIN indexes
       4             :  *
       5             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       6             :  * Portions Copyright (c) 1994, Regents of the University of California
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *    src/backend/access/brin/brin_xlog.c
      10             :  */
      11             : #include "postgres.h"
      12             : 
      13             : #include "access/brin_page.h"
      14             : #include "access/brin_pageops.h"
      15             : #include "access/brin_xlog.h"
      16             : #include "access/bufmask.h"
      17             : #include "access/xlogutils.h"
      18             : 
      19             : 
      20             : /*
      21             :  * xlog replay routines
      22             :  */
      23             : static void
      24          76 : brin_xlog_createidx(XLogReaderState *record)
      25             : {
      26          76 :     XLogRecPtr  lsn = record->EndRecPtr;
      27          76 :     xl_brin_createidx *xlrec = (xl_brin_createidx *) XLogRecGetData(record);
      28             :     Buffer      buf;
      29             :     Page        page;
      30             : 
      31             :     /* create the index' metapage */
      32          76 :     buf = XLogInitBufferForRedo(record, 0);
      33             :     Assert(BufferIsValid(buf));
      34          76 :     page = (Page) BufferGetPage(buf);
      35          76 :     brin_metapage_init(page, xlrec->pagesPerRange, xlrec->version);
      36          76 :     PageSetLSN(page, lsn);
      37          76 :     MarkBufferDirty(buf);
      38          76 :     UnlockReleaseBuffer(buf);
      39          76 : }
      40             : 
      41             : /*
      42             :  * Common part of an insert or update. Inserts the new tuple and updates the
      43             :  * revmap.
      44             :  */
      45             : static void
      46         858 : brin_xlog_insert_update(XLogReaderState *record,
      47             :                         xl_brin_insert *xlrec)
      48             : {
      49         858 :     XLogRecPtr  lsn = record->EndRecPtr;
      50             :     Buffer      buffer;
      51             :     BlockNumber regpgno;
      52             :     Page        page;
      53             :     XLogRedoAction action;
      54             : 
      55             :     /*
      56             :      * If we inserted the first and only tuple on the page, re-initialize the
      57             :      * page from scratch.
      58             :      */
      59         858 :     if (XLogRecGetInfo(record) & XLOG_BRIN_INIT_PAGE)
      60             :     {
      61         118 :         buffer = XLogInitBufferForRedo(record, 0);
      62         118 :         page = BufferGetPage(buffer);
      63         118 :         brin_page_init(page, BRIN_PAGETYPE_REGULAR);
      64         118 :         action = BLK_NEEDS_REDO;
      65             :     }
      66             :     else
      67             :     {
      68         740 :         action = XLogReadBufferForRedo(record, 0, &buffer);
      69             :     }
      70             : 
      71             :     /* need this page's blkno to store in revmap */
      72         858 :     regpgno = BufferGetBlockNumber(buffer);
      73             : 
      74             :     /* insert the index item into the page */
      75         858 :     if (action == BLK_NEEDS_REDO)
      76             :     {
      77             :         OffsetNumber offnum;
      78             :         BrinTuple  *tuple;
      79             :         Size        tuplen;
      80             : 
      81         856 :         tuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
      82             : 
      83             :         Assert(tuple->bt_blkno == xlrec->heapBlk);
      84             : 
      85         856 :         page = (Page) BufferGetPage(buffer);
      86         856 :         offnum = xlrec->offnum;
      87         856 :         if (PageGetMaxOffsetNumber(page) + 1 < offnum)
      88           0 :             elog(PANIC, "brin_xlog_insert_update: invalid max offset number");
      89             : 
      90         856 :         offnum = PageAddItem(page, (Item) tuple, tuplen, offnum, true, false);
      91         856 :         if (offnum == InvalidOffsetNumber)
      92           0 :             elog(PANIC, "brin_xlog_insert_update: failed to add tuple");
      93             : 
      94         856 :         PageSetLSN(page, lsn);
      95         856 :         MarkBufferDirty(buffer);
      96             :     }
      97         858 :     if (BufferIsValid(buffer))
      98         858 :         UnlockReleaseBuffer(buffer);
      99             : 
     100             :     /* update the revmap */
     101         858 :     action = XLogReadBufferForRedo(record, 1, &buffer);
     102         858 :     if (action == BLK_NEEDS_REDO)
     103             :     {
     104             :         ItemPointerData tid;
     105             : 
     106         858 :         ItemPointerSet(&tid, regpgno, xlrec->offnum);
     107         858 :         page = (Page) BufferGetPage(buffer);
     108             : 
     109         858 :         brinSetHeapBlockItemptr(buffer, xlrec->pagesPerRange, xlrec->heapBlk,
     110             :                                 tid);
     111         858 :         PageSetLSN(page, lsn);
     112         858 :         MarkBufferDirty(buffer);
     113             :     }
     114         858 :     if (BufferIsValid(buffer))
     115         858 :         UnlockReleaseBuffer(buffer);
     116             : 
     117             :     /* XXX no FSM updates here ... */
     118         858 : }
     119             : 
     120             : /*
     121             :  * replay a BRIN index insertion
     122             :  */
     123             : static void
     124         850 : brin_xlog_insert(XLogReaderState *record)
     125             : {
     126         850 :     xl_brin_insert *xlrec = (xl_brin_insert *) XLogRecGetData(record);
     127             : 
     128         850 :     brin_xlog_insert_update(record, xlrec);
     129         850 : }
     130             : 
     131             : /*
     132             :  * replay a BRIN index update
     133             :  */
     134             : static void
     135           8 : brin_xlog_update(XLogReaderState *record)
     136             : {
     137           8 :     XLogRecPtr  lsn = record->EndRecPtr;
     138           8 :     xl_brin_update *xlrec = (xl_brin_update *) XLogRecGetData(record);
     139             :     Buffer      buffer;
     140             :     XLogRedoAction action;
     141             : 
     142             :     /* First remove the old tuple */
     143           8 :     action = XLogReadBufferForRedo(record, 2, &buffer);
     144           8 :     if (action == BLK_NEEDS_REDO)
     145             :     {
     146             :         Page        page;
     147             :         OffsetNumber offnum;
     148             : 
     149           8 :         page = (Page) BufferGetPage(buffer);
     150             : 
     151           8 :         offnum = xlrec->oldOffnum;
     152             : 
     153           8 :         PageIndexTupleDeleteNoCompact(page, offnum);
     154             : 
     155           8 :         PageSetLSN(page, lsn);
     156           8 :         MarkBufferDirty(buffer);
     157             :     }
     158             : 
     159             :     /* Then insert the new tuple and update revmap, like in an insertion. */
     160           8 :     brin_xlog_insert_update(record, &xlrec->insert);
     161             : 
     162           8 :     if (BufferIsValid(buffer))
     163           8 :         UnlockReleaseBuffer(buffer);
     164           8 : }
     165             : 
     166             : /*
     167             :  * Update a tuple on a single page.
     168             :  */
     169             : static void
     170        1230 : brin_xlog_samepage_update(XLogReaderState *record)
     171             : {
     172        1230 :     XLogRecPtr  lsn = record->EndRecPtr;
     173             :     xl_brin_samepage_update *xlrec;
     174             :     Buffer      buffer;
     175             :     XLogRedoAction action;
     176             : 
     177        1230 :     xlrec = (xl_brin_samepage_update *) XLogRecGetData(record);
     178        1230 :     action = XLogReadBufferForRedo(record, 0, &buffer);
     179        1230 :     if (action == BLK_NEEDS_REDO)
     180             :     {
     181             :         Size        tuplen;
     182             :         BrinTuple  *brintuple;
     183             :         Page        page;
     184             :         OffsetNumber offnum;
     185             : 
     186        1198 :         brintuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
     187             : 
     188        1198 :         page = (Page) BufferGetPage(buffer);
     189             : 
     190        1198 :         offnum = xlrec->offnum;
     191             : 
     192        1198 :         if (!PageIndexTupleOverwrite(page, offnum, (Item) brintuple, tuplen))
     193           0 :             elog(PANIC, "brin_xlog_samepage_update: failed to replace tuple");
     194             : 
     195        1198 :         PageSetLSN(page, lsn);
     196        1198 :         MarkBufferDirty(buffer);
     197             :     }
     198        1230 :     if (BufferIsValid(buffer))
     199        1230 :         UnlockReleaseBuffer(buffer);
     200             : 
     201             :     /* XXX no FSM updates here ... */
     202        1230 : }
     203             : 
     204             : /*
     205             :  * Replay a revmap page extension
     206             :  */
     207             : static void
     208          76 : brin_xlog_revmap_extend(XLogReaderState *record)
     209             : {
     210          76 :     XLogRecPtr  lsn = record->EndRecPtr;
     211             :     xl_brin_revmap_extend *xlrec;
     212             :     Buffer      metabuf;
     213             :     Buffer      buf;
     214             :     Page        page;
     215             :     BlockNumber targetBlk;
     216             :     XLogRedoAction action;
     217             : 
     218          76 :     xlrec = (xl_brin_revmap_extend *) XLogRecGetData(record);
     219             : 
     220          76 :     XLogRecGetBlockTag(record, 1, NULL, NULL, &targetBlk);
     221             :     Assert(xlrec->targetBlk == targetBlk);
     222             : 
     223             :     /* Update the metapage */
     224          76 :     action = XLogReadBufferForRedo(record, 0, &metabuf);
     225          76 :     if (action == BLK_NEEDS_REDO)
     226             :     {
     227             :         Page        metapg;
     228             :         BrinMetaPageData *metadata;
     229             : 
     230          76 :         metapg = BufferGetPage(metabuf);
     231          76 :         metadata = (BrinMetaPageData *) PageGetContents(metapg);
     232             : 
     233             :         Assert(metadata->lastRevmapPage == xlrec->targetBlk - 1);
     234          76 :         metadata->lastRevmapPage = xlrec->targetBlk;
     235             : 
     236          76 :         PageSetLSN(metapg, lsn);
     237             : 
     238             :         /*
     239             :          * Set pd_lower just past the end of the metadata.  This is essential,
     240             :          * because without doing so, metadata will be lost if xlog.c
     241             :          * compresses the page.  (We must do this here because pre-v11
     242             :          * versions of PG did not set the metapage's pd_lower correctly, so a
     243             :          * pg_upgraded index might contain the wrong value.)
     244             :          */
     245          76 :         ((PageHeader) metapg)->pd_lower =
     246          76 :             ((char *) metadata + sizeof(BrinMetaPageData)) - (char *) metapg;
     247             : 
     248          76 :         MarkBufferDirty(metabuf);
     249             :     }
     250             : 
     251             :     /*
     252             :      * Re-init the target block as a revmap page.  There's never a full- page
     253             :      * image here.
     254             :      */
     255             : 
     256          76 :     buf = XLogInitBufferForRedo(record, 1);
     257          76 :     page = (Page) BufferGetPage(buf);
     258          76 :     brin_page_init(page, BRIN_PAGETYPE_REVMAP);
     259             : 
     260          76 :     PageSetLSN(page, lsn);
     261          76 :     MarkBufferDirty(buf);
     262             : 
     263          76 :     UnlockReleaseBuffer(buf);
     264          76 :     if (BufferIsValid(metabuf))
     265          76 :         UnlockReleaseBuffer(metabuf);
     266          76 : }
     267             : 
     268             : static void
     269          14 : brin_xlog_desummarize_page(XLogReaderState *record)
     270             : {
     271          14 :     XLogRecPtr  lsn = record->EndRecPtr;
     272             :     xl_brin_desummarize *xlrec;
     273             :     Buffer      buffer;
     274             :     XLogRedoAction action;
     275             : 
     276          14 :     xlrec = (xl_brin_desummarize *) XLogRecGetData(record);
     277             : 
     278             :     /* Update the revmap */
     279          14 :     action = XLogReadBufferForRedo(record, 0, &buffer);
     280          14 :     if (action == BLK_NEEDS_REDO)
     281             :     {
     282             :         ItemPointerData iptr;
     283             : 
     284           8 :         ItemPointerSetInvalid(&iptr);
     285           8 :         brinSetHeapBlockItemptr(buffer, xlrec->pagesPerRange, xlrec->heapBlk, iptr);
     286             : 
     287           8 :         PageSetLSN(BufferGetPage(buffer), lsn);
     288           8 :         MarkBufferDirty(buffer);
     289             :     }
     290          14 :     if (BufferIsValid(buffer))
     291          14 :         UnlockReleaseBuffer(buffer);
     292             : 
     293             :     /* remove the leftover entry from the regular page */
     294          14 :     action = XLogReadBufferForRedo(record, 1, &buffer);
     295          14 :     if (action == BLK_NEEDS_REDO)
     296             :     {
     297          10 :         Page        regPg = BufferGetPage(buffer);
     298             : 
     299          10 :         PageIndexTupleDeleteNoCompact(regPg, xlrec->regOffset);
     300             : 
     301          10 :         PageSetLSN(regPg, lsn);
     302          10 :         MarkBufferDirty(buffer);
     303             :     }
     304          14 :     if (BufferIsValid(buffer))
     305          14 :         UnlockReleaseBuffer(buffer);
     306          14 : }
     307             : 
     308             : void
     309        2254 : brin_redo(XLogReaderState *record)
     310             : {
     311        2254 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
     312             : 
     313        2254 :     switch (info & XLOG_BRIN_OPMASK)
     314             :     {
     315          76 :         case XLOG_BRIN_CREATE_INDEX:
     316          76 :             brin_xlog_createidx(record);
     317          76 :             break;
     318         850 :         case XLOG_BRIN_INSERT:
     319         850 :             brin_xlog_insert(record);
     320         850 :             break;
     321           8 :         case XLOG_BRIN_UPDATE:
     322           8 :             brin_xlog_update(record);
     323           8 :             break;
     324        1230 :         case XLOG_BRIN_SAMEPAGE_UPDATE:
     325        1230 :             brin_xlog_samepage_update(record);
     326        1230 :             break;
     327          76 :         case XLOG_BRIN_REVMAP_EXTEND:
     328          76 :             brin_xlog_revmap_extend(record);
     329          76 :             break;
     330          14 :         case XLOG_BRIN_DESUMMARIZE:
     331          14 :             brin_xlog_desummarize_page(record);
     332          14 :             break;
     333           0 :         default:
     334           0 :             elog(PANIC, "brin_redo: unknown op code %u", info);
     335             :     }
     336        2254 : }
     337             : 
     338             : /*
     339             :  * Mask a BRIN page before doing consistency checks.
     340             :  */
     341             : void
     342        6332 : brin_mask(char *pagedata, BlockNumber blkno)
     343             : {
     344        6332 :     Page        page = (Page) pagedata;
     345        6332 :     PageHeader  pagehdr = (PageHeader) page;
     346             : 
     347        6332 :     mask_page_lsn_and_checksum(page);
     348             : 
     349        6332 :     mask_page_hint_bits(page);
     350             : 
     351             :     /*
     352             :      * Regular brin pages contain unused space which needs to be masked.
     353             :      * Similarly for meta pages, but mask it only if pd_lower appears to have
     354             :      * been set correctly.
     355             :      */
     356        6332 :     if (BRIN_IS_REGULAR_PAGE(page) ||
     357        2188 :         (BRIN_IS_META_PAGE(page) && pagehdr->pd_lower > SizeOfPageHeaderData))
     358             :     {
     359        4448 :         mask_unused_space(page);
     360             :     }
     361             : 
     362             :     /*
     363             :      * BRIN_EVACUATE_PAGE is not WAL-logged, since it's of no use in recovery.
     364             :      * Mask it.  See brin_start_evacuating_page() for details.
     365             :      */
     366        6332 :     BrinPageFlags(page) &= ~BRIN_EVACUATE_PAGE;
     367        6332 : }

Generated by: LCOV version 1.14