LCOV - differential code coverage report
Current view: top level - src/backend/access/transam - generic_xlog.c (source / functions) Coverage Total Hit LBC UIC UBC GIC GNC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 75.2 % 161 121 1 30 9 65 1 55 31 65
Current Date: 2023-04-08 17:13:01 Functions: 70.0 % 10 7 3 7 3 7
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 100.0 % 1 1 1
Legend: Lines: hit not hit (240..) days: 75.0 % 160 120 1 30 9 65 55 28 65
Function coverage date bins:
(240..) days: 35.0 % 20 7 3 7 3 7

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * generic_xlog.c
                                  4                 :  *   Implementation of generic xlog records.
                                  5                 :  *
                                  6                 :  *
                                  7                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  8                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  9                 :  *
                                 10                 :  * src/backend/access/transam/generic_xlog.c
                                 11                 :  *
                                 12                 :  *-------------------------------------------------------------------------
                                 13                 :  */
                                 14                 : #include "postgres.h"
                                 15                 : 
                                 16                 : #include "access/bufmask.h"
                                 17                 : #include "access/generic_xlog.h"
                                 18                 : #include "access/xlogutils.h"
                                 19                 : #include "miscadmin.h"
                                 20                 : #include "utils/memutils.h"
                                 21                 : 
                                 22                 : /*-------------------------------------------------------------------------
                                 23                 :  * Internally, a delta between pages consists of a set of fragments.  Each
                                 24                 :  * fragment represents changes made in a given region of a page.  A fragment
                                 25                 :  * is made up as follows:
                                 26                 :  *
                                 27                 :  * - offset of page region (OffsetNumber)
                                 28                 :  * - length of page region (OffsetNumber)
                                 29                 :  * - data - the data to place into the region ('length' number of bytes)
                                 30                 :  *
                                 31                 :  * Unchanged regions of a page are not represented in its delta.  As a result,
                                 32                 :  * a delta can be more compact than the full page image.  But having an
                                 33                 :  * unchanged region between two fragments that is smaller than the fragment
                                 34                 :  * header (offset+length) does not pay off in terms of the overall size of
                                 35                 :  * the delta.  For this reason, we merge adjacent fragments if the unchanged
                                 36                 :  * region between them is <= MATCH_THRESHOLD bytes.
                                 37                 :  *
                                 38                 :  * We do not bother to merge fragments across the "lower" and "upper" parts
                                 39                 :  * of a page; it's very seldom the case that pd_lower and pd_upper are within
                                 40                 :  * MATCH_THRESHOLD bytes of each other, and handling that infrequent case
                                 41                 :  * would complicate and slow down the delta-computation code unduly.
                                 42                 :  * Therefore, the worst-case delta size includes two fragment headers plus
                                 43                 :  * a full page's worth of data.
                                 44                 :  *-------------------------------------------------------------------------
                                 45                 :  */
                                 46                 : #define FRAGMENT_HEADER_SIZE    (2 * sizeof(OffsetNumber))
                                 47                 : #define MATCH_THRESHOLD         FRAGMENT_HEADER_SIZE
                                 48                 : #define MAX_DELTA_SIZE          (BLCKSZ + 2 * FRAGMENT_HEADER_SIZE)
                                 49                 : 
                                 50                 : /* Struct of generic xlog data for single page */
                                 51                 : typedef struct
                                 52                 : {
                                 53                 :     Buffer      buffer;         /* registered buffer */
                                 54                 :     int         flags;          /* flags for this buffer */
                                 55                 :     int         deltaLen;       /* space consumed in delta field */
                                 56                 :     char       *image;          /* copy of page image for modification, do not
                                 57                 :                                  * do it in-place to have aligned memory chunk */
                                 58                 :     char        delta[MAX_DELTA_SIZE];  /* delta between page images */
                                 59                 : } PageData;
                                 60                 : 
                                 61                 : /*
                                 62                 :  * State of generic xlog record construction.  Must be allocated at an I/O
                                 63                 :  * aligned address.
                                 64                 :  */
                                 65                 : struct GenericXLogState
                                 66                 : {
                                 67                 :     /* Page images (properly aligned, must be first) */
                                 68                 :     PGIOAlignedBlock images[MAX_GENERIC_XLOG_PAGES];
                                 69                 :     /* Info about each page, see above */
                                 70                 :     PageData    pages[MAX_GENERIC_XLOG_PAGES];
                                 71                 :     bool        isLogged;
                                 72                 : };
                                 73                 : 
                                 74                 : static void writeFragment(PageData *pageData, OffsetNumber offset,
                                 75                 :                           OffsetNumber length, const char *data);
                                 76                 : static void computeRegionDelta(PageData *pageData,
                                 77                 :                                const char *curpage, const char *targetpage,
                                 78                 :                                int targetStart, int targetEnd,
                                 79                 :                                int validStart, int validEnd);
                                 80                 : static void computeDelta(PageData *pageData, Page curpage, Page targetpage);
                                 81                 : static void applyPageRedo(Page page, const char *delta, Size deltaSize);
                                 82                 : 
                                 83                 : 
                                 84                 : /*
                                 85                 :  * Write next fragment into pageData's delta.
                                 86                 :  *
                                 87                 :  * The fragment has the given offset and length, and data points to the
                                 88                 :  * actual data (of length length).
                                 89                 :  */
                                 90                 : static void
 2564 teodor                     91 GIC      579357 : writeFragment(PageData *pageData, OffsetNumber offset, OffsetNumber length,
                                 92                 :               const char *data)
                                 93                 : {
 2556 tgl                        94 CBC      579357 :     char       *ptr = pageData->delta + pageData->deltaLen;
                                 95                 : 
                                 96                 :     /* Verify we have enough space */
                                 97          579357 :     Assert(pageData->deltaLen + sizeof(offset) +
                                 98                 :            sizeof(length) + length <= sizeof(pageData->delta));
                                 99                 : 
 2564 teodor                    100 ECB             :     /* Write fragment data */
 2564 teodor                    101 GIC      579357 :     memcpy(ptr, &offset, sizeof(offset));
                                102          579357 :     ptr += sizeof(offset);
                                103          579357 :     memcpy(ptr, &length, sizeof(length));
 2564 teodor                    104 CBC      579357 :     ptr += sizeof(length);
                                105          579357 :     memcpy(ptr, data, length);
                                106          579357 :     ptr += length;
 2564 teodor                    107 ECB             : 
 2556 tgl                       108 CBC      579357 :     pageData->deltaLen = ptr - pageData->delta;
 2564 teodor                    109          579357 : }
                                110                 : 
 2564 teodor                    111 ECB             : /*
 2556 tgl                       112                 :  * Compute the XLOG fragments needed to transform a region of curpage into the
                                113                 :  * corresponding region of targetpage, and append them to pageData's delta
                                114                 :  * field.  The region to transform runs from targetStart to targetEnd-1.
                                115                 :  * Bytes in curpage outside the range validStart to validEnd-1 should be
                                116                 :  * considered invalid, and always overwritten with target data.
                                117                 :  *
                                118                 :  * This function is a hot spot, so it's worth being as tense as possible
                                119                 :  * about the data-matching loops.
                                120                 :  */
                                121                 : static void
 2556 tgl                       122 GIC      214150 : computeRegionDelta(PageData *pageData,
                                123                 :                    const char *curpage, const char *targetpage,
                                124                 :                    int targetStart, int targetEnd,
 2556 tgl                       125 ECB             :                    int validStart, int validEnd)
                                126                 : {
                                127                 :     int         i,
                                128                 :                 loopEnd,
 2556 tgl                       129 GIC      214150 :                 fragmentBegin = -1,
                                130          214150 :                 fragmentEnd = -1;
                                131                 : 
 2556 tgl                       132 ECB             :     /* Deal with any invalid start region by including it in first fragment */
 2556 tgl                       133 CBC      214150 :     if (validStart > targetStart)
                                134                 :     {
 2556 tgl                       135 UIC           0 :         fragmentBegin = targetStart;
 2556 tgl                       136 LBC           0 :         targetStart = validStart;
                                137                 :     }
 2564 teodor                    138 EUB             : 
 2556 tgl                       139                 :     /* We'll deal with any invalid end region after the main loop */
 2556 tgl                       140 GIC      214150 :     loopEnd = Min(targetEnd, validEnd);
                                141                 : 
                                142                 :     /* Examine all the potentially matchable bytes */
 2556 tgl                       143 CBC      214150 :     i = targetStart;
 2556 tgl                       144 GIC     3351954 :     while (i < loopEnd)
                                145                 :     {
 2556 tgl                       146 CBC     3138966 :         if (curpage[i] != targetpage[i])
 2564 teodor                    147 ECB             :         {
                                148                 :             /* On unmatched byte, start new fragment if not already in one */
 2564 teodor                    149 CBC     3030592 :             if (fragmentBegin < 0)
 2564 teodor                    150 GIC      475362 :                 fragmentBegin = i;
                                151                 :             /* Mark unmatched-data endpoint as uncertain */
 2564 teodor                    152 CBC     3030592 :             fragmentEnd = -1;
 2556 tgl                       153 ECB             :             /* Extend the fragment as far as possible in a tight loop */
 2556 tgl                       154 GIC     3030592 :             i++;
 2556 tgl                       155 CBC     5093436 :             while (i < loopEnd && curpage[i] != targetpage[i])
 2556 tgl                       156 GIC     2062844 :                 i++;
 2556 tgl                       157 CBC     3030592 :             if (i >= loopEnd)
                                158            1162 :                 break;
 2556 tgl                       159 ECB             :         }
                                160                 : 
                                161                 :         /* Found a matched byte, so remember end of unmatched fragment */
 2556 tgl                       162 GIC     3137804 :         fragmentEnd = i;
                                163                 : 
                                164                 :         /*
 2556 tgl                       165 ECB             :          * Extend the match as far as possible in a tight loop.  (On typical
                                166                 :          * workloads, this inner loop is the bulk of this function's runtime.)
                                167                 :          */
 2556 tgl                       168 GIC     3137804 :         i++;
                                169       775485060 :         while (i < loopEnd && curpage[i] == targetpage[i])
                                170       772347256 :             i++;
 2556 tgl                       171 ECB             : 
                                172                 :         /*
                                173                 :          * There are several possible cases at this point:
                                174                 :          *
                                175                 :          * 1. We have no unwritten fragment (fragmentBegin < 0).  There's
                                176                 :          * nothing to write; and it doesn't matter what fragmentEnd is.
                                177                 :          *
                                178                 :          * 2. We found more than MATCH_THRESHOLD consecutive matching bytes.
                                179                 :          * Dump out the unwritten fragment, stopping at fragmentEnd.
                                180                 :          *
                                181                 :          * 3. The match extends to loopEnd.  We'll do nothing here, exit the
                                182                 :          * loop, and then dump the unwritten fragment, after merging it with
                                183                 :          * the invalid end region if any.  If we don't so merge, fragmentEnd
                                184                 :          * establishes how much the final writeFragment call needs to write.
                                185                 :          *
                                186                 :          * 4. We found an unmatched byte before loopEnd.  The loop will repeat
                                187                 :          * and will enter the unmatched-byte stanza above.  So in this case
                                188                 :          * also, it doesn't matter what fragmentEnd is.  The matched bytes
                                189                 :          * will get merged into the continuing unmatched fragment.
                                190                 :          *
                                191                 :          * Only in case 3 do we reach the bottom of the loop with a meaningful
                                192                 :          * fragmentEnd value, which is why it's OK that we unconditionally
                                193                 :          * assign "fragmentEnd = i" above.
                                194                 :          */
 2556 tgl                       195 GIC     3137804 :         if (fragmentBegin >= 0 && i - fragmentEnd > MATCH_THRESHOLD)
                                196                 :         {
                                197          473596 :             writeFragment(pageData, fragmentBegin,
 2556 tgl                       198 CBC      473596 :                           fragmentEnd - fragmentBegin,
                                199                 :                           targetpage + fragmentBegin);
                                200          473596 :             fragmentBegin = -1;
                                201          473596 :             fragmentEnd = -1;   /* not really necessary */
                                202                 :         }
 2564 teodor                    203 ECB             :     }
                                204                 : 
                                205                 :     /* Deal with any invalid end region by including it in final fragment */
 2556 tgl                       206 GIC      214150 :     if (loopEnd < targetEnd)
                                207                 :     {
                                208          103995 :         if (fragmentBegin < 0)
 2556 tgl                       209 CBC      103995 :             fragmentBegin = loopEnd;
 2556 tgl                       210 GIC      103995 :         fragmentEnd = targetEnd;
 2556 tgl                       211 ECB             :     }
                                212                 : 
                                213                 :     /* Write final fragment if any */
 2564 teodor                    214 GIC      214150 :     if (fragmentBegin >= 0)
                                215                 :     {
 2556 tgl                       216          105761 :         if (fragmentEnd < 0)
 2556 tgl                       217 CBC        1162 :             fragmentEnd = targetEnd;
 2564 teodor                    218 GIC      105761 :         writeFragment(pageData, fragmentBegin,
 2556 tgl                       219 CBC      105761 :                       fragmentEnd - fragmentBegin,
 2556 tgl                       220 ECB             :                       targetpage + fragmentBegin);
                                221                 :     }
 2556 tgl                       222 CBC      214150 : }
                                223                 : 
                                224                 : /*
 2556 tgl                       225 ECB             :  * Compute the XLOG delta record needed to transform curpage into targetpage,
                                226                 :  * and store it in pageData's delta field.
                                227                 :  */
                                228                 : static void
 2556 tgl                       229 GIC      107075 : computeDelta(PageData *pageData, Page curpage, Page targetpage)
                                230                 : {
                                231          107075 :     int         targetLower = ((PageHeader) targetpage)->pd_lower,
 2556 tgl                       232 CBC      107075 :                 targetUpper = ((PageHeader) targetpage)->pd_upper,
 2556 tgl                       233 GIC      107075 :                 curLower = ((PageHeader) curpage)->pd_lower,
 2556 tgl                       234 CBC      107075 :                 curUpper = ((PageHeader) curpage)->pd_upper;
 2556 tgl                       235 ECB             : 
 2556 tgl                       236 CBC      107075 :     pageData->deltaLen = 0;
 2556 tgl                       237 ECB             : 
                                238                 :     /* Compute delta records for lower part of page ... */
 2556 tgl                       239 CBC      107075 :     computeRegionDelta(pageData, curpage, targetpage,
                                240                 :                        0, targetLower,
                                241                 :                        0, curLower);
 2556 tgl                       242 ECB             :     /* ... and for upper part, ignoring what's between */
 2556 tgl                       243 GIC      107075 :     computeRegionDelta(pageData, curpage, targetpage,
                                244                 :                        targetUpper, BLCKSZ,
                                245                 :                        curUpper, BLCKSZ);
 2564 teodor                    246 ECB             : 
                                247                 :     /*
                                248                 :      * If xlog debug is enabled, then check produced delta.  Result of delta
                                249                 :      * application to curpage should be equivalent to targetpage.
                                250                 :      */
                                251                 : #ifdef WAL_DEBUG
                                252                 :     if (XLOG_DEBUG)
                                253                 :     {
                                254                 :         PGAlignedBlock tmp;
                                255                 : 
                                256                 :         memcpy(tmp.data, curpage, BLCKSZ);
                                257                 :         applyPageRedo(tmp.data, pageData->delta, pageData->deltaLen);
                                258                 :         if (memcmp(tmp.data, targetpage, targetLower) != 0 ||
                                259                 :             memcmp(tmp.data + targetUpper, targetpage + targetUpper,
                                260                 :                    BLCKSZ - targetUpper) != 0)
                                261                 :             elog(ERROR, "result of generic xlog apply does not match");
                                262                 :     }
                                263                 : #endif
 2564 teodor                    264 GIC      107075 : }
                                265                 : 
                                266                 : /*
 2556 tgl                       267 ECB             :  * Start new generic xlog record for modifications to specified relation.
                                268                 :  */
                                269                 : GenericXLogState *
 2564 teodor                    270 GIC      107305 : GenericXLogStart(Relation relation)
                                271                 : {
                                272                 :     GenericXLogState *state;
 2556 tgl                       273 ECB             :     int         i;
                                274                 : 
    1 tmunro                    275 GNC      107305 :     state = (GenericXLogState *) palloc_aligned(sizeof(GenericXLogState),
                                276                 :                                                 PG_IO_ALIGN_SIZE,
                                277                 :                                                 0);
 2564 teodor                    278 GIC      107305 :     state->isLogged = RelationNeedsWAL(relation);
                                279                 : 
 2564 teodor                    280 CBC      536525 :     for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
                                281                 :     {
 1681 tgl                       282 GIC      429220 :         state->pages[i].image = state->images[i].data;
 2564 teodor                    283 CBC      429220 :         state->pages[i].buffer = InvalidBuffer;
                                284                 :     }
 2564 teodor                    285 ECB             : 
 2564 teodor                    286 GIC      107305 :     return state;
 2564 teodor                    287 ECB             : }
                                288                 : 
                                289                 : /*
                                290                 :  * Register new buffer for generic xlog record.
 2556 tgl                       291                 :  *
                                292                 :  * Returns pointer to the page's image in the GenericXLogState, which
                                293                 :  * is what the caller should modify.
                                294                 :  *
                                295                 :  * If the buffer is already registered, just return its existing entry.
                                296                 :  * (It's not very clear what to do with the flags in such a case, but
                                297                 :  * for now we stay with the original flags.)
                                298                 :  */
                                299                 : Page
 2553 tgl                       300 GIC      108593 : GenericXLogRegisterBuffer(GenericXLogState *state, Buffer buffer, int flags)
                                301                 : {
                                302                 :     int         block_id;
                                303                 : 
                                304                 :     /* Search array for existing entry or first unused slot */
 2564 teodor                    305 CBC      109881 :     for (block_id = 0; block_id < MAX_GENERIC_XLOG_PAGES; block_id++)
                                306                 :     {
 2556 tgl                       307 GIC      109881 :         PageData   *page = &state->pages[block_id];
                                308                 : 
 2564 teodor                    309          109881 :         if (BufferIsInvalid(page->buffer))
 2564 teodor                    310 ECB             :         {
                                311                 :             /* Empty slot, so use it (there cannot be a match later) */
 2564 teodor                    312 CBC      108593 :             page->buffer = buffer;
 2553 tgl                       313 GIC      108593 :             page->flags = flags;
 2545 kgrittn                   314 CBC      108593 :             memcpy(page->image, BufferGetPage(buffer), BLCKSZ);
 2556 tgl                       315 GIC      108593 :             return (Page) page->image;
                                316                 :         }
 2564 teodor                    317 CBC        1288 :         else if (page->buffer == buffer)
 2564 teodor                    318 ECB             :         {
                                319                 :             /*
                                320                 :              * Buffer is already registered.  Just return the image, which is
                                321                 :              * already prepared.
                                322                 :              */
 2556 tgl                       323 UIC           0 :             return (Page) page->image;
                                324                 :         }
                                325                 :     }
                                326                 : 
                                327               0 :     elog(ERROR, "maximum number %d of generic xlog buffers is exceeded",
 2564 teodor                    328 EUB             :          MAX_GENERIC_XLOG_PAGES);
                                329                 :     /* keep compiler quiet */
                                330                 :     return NULL;
                                331                 : }
                                332                 : 
                                333                 : /*
                                334                 :  * Apply changes represented by GenericXLogState to the actual buffers,
                                335                 :  * and emit a generic xlog record.
                                336                 :  */
                                337                 : XLogRecPtr
 2564 teodor                    338 GIC      106010 : GenericXLogFinish(GenericXLogState *state)
                                339                 : {
                                340                 :     XLogRecPtr  lsn;
                                341                 :     int         i;
                                342                 : 
 2564 teodor                    343 CBC      106010 :     if (state->isLogged)
                                344                 :     {
                                345                 :         /* Logged relation: make xlog record in critical section. */
 2564 teodor                    346 GIC      106005 :         XLogBeginInsert();
                                347                 : 
 2564 teodor                    348 CBC      106005 :         START_CRIT_SECTION();
                                349                 : 
 2564 teodor                    350 GIC      530025 :         for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
 2564 teodor                    351 ECB             :         {
 2556 tgl                       352 GIC      424020 :             PageData   *pageData = &state->pages[i];
 2556 tgl                       353 ECB             :             Page        page;
                                354                 :             PageHeader  pageHeader;
 2564 teodor                    355                 : 
 2556 tgl                       356 GIC      424020 :             if (BufferIsInvalid(pageData->buffer))
 2564 teodor                    357 CBC      316727 :                 continue;
                                358                 : 
 2545 kgrittn                   359 GIC      107293 :             page = BufferGetPage(pageData->buffer);
 2553 tgl                       360          107293 :             pageHeader = (PageHeader) pageData->image;
 2556 tgl                       361 ECB             : 
 2553 tgl                       362 CBC      107293 :             if (pageData->flags & GENERIC_XLOG_FULL_IMAGE)
                                363                 :             {
 2553 tgl                       364 ECB             :                 /*
                                365                 :                  * A full-page image does not require us to supply any xlog
                                366                 :                  * data.  Just apply the image, being careful to zero the
                                367                 :                  * "hole" between pd_lower and pd_upper in order to avoid
                                368                 :                  * divergence between actual page state and what replay would
                                369                 :                  * produce.
                                370                 :                  */
 2553 tgl                       371 GIC         218 :                 memcpy(page, pageData->image, pageHeader->pd_lower);
                                372             218 :                 memset(page + pageHeader->pd_lower, 0,
                                373             218 :                        pageHeader->pd_upper - pageHeader->pd_lower);
                                374             218 :                 memcpy(page + pageHeader->pd_upper,
                                375             218 :                        pageData->image + pageHeader->pd_upper,
 2553 tgl                       376 CBC         218 :                        BLCKSZ - pageHeader->pd_upper);
 2553 tgl                       377 ECB             : 
 2555 tgl                       378 CBC         218 :                 XLogRegisterBuffer(i, pageData->buffer,
 2555 tgl                       379 ECB             :                                    REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
 2564 teodor                    380                 :             }
                                381                 :             else
                                382                 :             {
                                383                 :                 /*
                                384                 :                  * In normal mode, calculate delta and write it as xlog data
                                385                 :                  * associated with this page.
                                386                 :                  */
 2556 tgl                       387 GIC      107075 :                 computeDelta(pageData, page, (Page) pageData->image);
                                388                 : 
                                389                 :                 /* Apply the image, with zeroed "hole" as above */
 2553                           390          107075 :                 memcpy(page, pageData->image, pageHeader->pd_lower);
                                391          107075 :                 memset(page + pageHeader->pd_lower, 0,
 2553 tgl                       392 CBC      107075 :                        pageHeader->pd_upper - pageHeader->pd_lower);
 2553 tgl                       393 GIC      107075 :                 memcpy(page + pageHeader->pd_upper,
                                394          107075 :                        pageData->image + pageHeader->pd_upper,
 2553 tgl                       395 CBC      107075 :                        BLCKSZ - pageHeader->pd_upper);
 2553 tgl                       396 ECB             : 
 2556 tgl                       397 CBC      107075 :                 XLogRegisterBuffer(i, pageData->buffer, REGBUF_STANDARD);
                                398          107075 :                 XLogRegisterBufData(i, pageData->delta, pageData->deltaLen);
 2564 teodor                    399 ECB             :             }
                                400                 :         }
                                401                 : 
                                402                 :         /* Insert xlog record */
 2564 teodor                    403 CBC      106005 :         lsn = XLogInsert(RM_GENERIC_ID, 0);
                                404                 : 
                                405                 :         /* Set LSN and mark buffers dirty */
 2564 teodor                    406 GIC      530025 :         for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
                                407                 :         {
 2556 tgl                       408 CBC      424020 :             PageData   *pageData = &state->pages[i];
                                409                 : 
 2556 tgl                       410 GIC      424020 :             if (BufferIsInvalid(pageData->buffer))
 2564 teodor                    411 CBC      316727 :                 continue;
 2545 kgrittn                   412 GIC      107293 :             PageSetLSN(BufferGetPage(pageData->buffer), lsn);
 2556 tgl                       413 CBC      107293 :             MarkBufferDirty(pageData->buffer);
                                414                 :         }
 2564 teodor                    415          106005 :         END_CRIT_SECTION();
 2564 teodor                    416 ECB             :     }
                                417                 :     else
                                418                 :     {
                                419                 :         /* Unlogged relation: skip xlog-related stuff */
 2564 teodor                    420 CBC           5 :         START_CRIT_SECTION();
 2564 teodor                    421 GIC          25 :         for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
                                422                 :         {
 2556 tgl                       423              20 :             PageData   *pageData = &state->pages[i];
                                424                 : 
 2556 tgl                       425 CBC          20 :             if (BufferIsInvalid(pageData->buffer))
 2564 teodor                    426              15 :                 continue;
 2545 kgrittn                   427 GIC          10 :             memcpy(BufferGetPage(pageData->buffer),
 2556 tgl                       428 CBC           5 :                    pageData->image,
                                429                 :                    BLCKSZ);
 2553 tgl                       430 ECB             :             /* We don't worry about zeroing the "hole" in this case */
 2556 tgl                       431 CBC           5 :             MarkBufferDirty(pageData->buffer);
 2564 teodor                    432 ECB             :         }
 2564 teodor                    433 CBC           5 :         END_CRIT_SECTION();
                                434                 :         /* We don't have a LSN to return, in this case */
 2556 tgl                       435 GIC           5 :         lsn = InvalidXLogRecPtr;
 2564 teodor                    436 ECB             :     }
                                437                 : 
 2564 teodor                    438 CBC      106010 :     pfree(state);
                                439                 : 
                                440          106010 :     return lsn;
                                441                 : }
                                442                 : 
 2564 teodor                    443 ECB             : /*
                                444                 :  * Abort generic xlog record construction.  No changes are applied to buffers.
 2556 tgl                       445                 :  *
                                446                 :  * Note: caller is responsible for releasing locks/pins on buffers, if needed.
                                447                 :  */
                                448                 : void
 2564 teodor                    449 GIC        1295 : GenericXLogAbort(GenericXLogState *state)
                                450                 : {
                                451            1295 :     pfree(state);
                                452            1295 : }
                                453                 : 
 2564 teodor                    454 ECB             : /*
                                455                 :  * Apply delta to given page image.
                                456                 :  */
                                457                 : static void
 2556 tgl                       458 UIC           0 : applyPageRedo(Page page, const char *delta, Size deltaSize)
                                459                 : {
                                460               0 :     const char *ptr = delta;
                                461               0 :     const char *end = delta + deltaSize;
                                462                 : 
 2564 teodor                    463 UBC           0 :     while (ptr < end)
                                464                 :     {
 2556 tgl                       465 EUB             :         OffsetNumber offset,
                                466                 :                     length;
                                467                 : 
 2564 teodor                    468 UBC           0 :         memcpy(&offset, ptr, sizeof(offset));
 2564 teodor                    469 UIC           0 :         ptr += sizeof(offset);
                                470               0 :         memcpy(&length, ptr, sizeof(length));
                                471               0 :         ptr += sizeof(length);
                                472                 : 
 2564 teodor                    473 UBC           0 :         memcpy(page + offset, ptr, length);
 2564 teodor                    474 EUB             : 
 2564 teodor                    475 UBC           0 :         ptr += length;
 2564 teodor                    476 EUB             :     }
 2564 teodor                    477 UIC           0 : }
 2564 teodor                    478 EUB             : 
                                479                 : /*
                                480                 :  * Redo function for generic xlog record.
                                481                 :  */
                                482                 : void
 2564 teodor                    483 UIC           0 : generic_redo(XLogReaderState *record)
                                484                 : {
                                485               0 :     XLogRecPtr  lsn = record->EndRecPtr;
                                486                 :     Buffer      buffers[MAX_GENERIC_XLOG_PAGES];
                                487                 :     uint8       block_id;
 2564 teodor                    488 EUB             : 
                                489                 :     /* Protect limited size of buffers[] array */
  387 tmunro                    490 UBC           0 :     Assert(XLogRecMaxBlockId(record) < MAX_GENERIC_XLOG_PAGES);
                                491                 : 
                                492                 :     /* Iterate over blocks */
  387 tmunro                    493 UIC           0 :     for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
                                494                 :     {
 2564 teodor                    495 EUB             :         XLogRedoAction action;
                                496                 : 
 2564 teodor                    497 UIC           0 :         if (!XLogRecHasBlockRef(record, block_id))
 2556 tgl                       498 EUB             :         {
 2556 tgl                       499 UIC           0 :             buffers[block_id] = InvalidBuffer;
 2564 teodor                    500               0 :             continue;
                                501                 :         }
 2564 teodor                    502 EUB             : 
 2564 teodor                    503 UIC           0 :         action = XLogReadBufferForRedo(record, block_id, &buffers[block_id]);
 2564 teodor                    504 EUB             : 
                                505                 :         /* Apply redo to given block if needed */
 2564 teodor                    506 UIC           0 :         if (action == BLK_NEEDS_REDO)
                                507                 :         {
 2556 tgl                       508 EUB             :             Page        page;
                                509                 :             PageHeader  pageHeader;
                                510                 :             char       *blockDelta;
                                511                 :             Size        blockDeltaSize;
                                512                 : 
 2545 kgrittn                   513 UIC           0 :             page = BufferGetPage(buffers[block_id]);
 2556 tgl                       514               0 :             blockDelta = XLogRecGetBlockData(record, block_id, &blockDeltaSize);
                                515               0 :             applyPageRedo(page, blockDelta, blockDeltaSize);
                                516                 : 
                                517                 :             /*
 2553 tgl                       518 EUB             :              * Since the delta contains no information about what's in the
                                519                 :              * "hole" between pd_lower and pd_upper, set that to zero to
                                520                 :              * ensure we produce the same page state that application of the
                                521                 :              * logged action by GenericXLogFinish did.
                                522                 :              */
 2553 tgl                       523 UIC           0 :             pageHeader = (PageHeader) page;
                                524               0 :             memset(page + pageHeader->pd_lower, 0,
                                525               0 :                    pageHeader->pd_upper - pageHeader->pd_lower);
                                526                 : 
 2564 teodor                    527               0 :             PageSetLSN(page, lsn);
 2564 teodor                    528 UBC           0 :             MarkBufferDirty(buffers[block_id]);
 2564 teodor                    529 EUB             :         }
                                530                 :     }
                                531                 : 
                                532                 :     /* Changes are done: unlock and release all buffers */
  387 tmunro                    533 UBC           0 :     for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
                                534                 :     {
 2564 teodor                    535 UIC           0 :         if (BufferIsValid(buffers[block_id]))
                                536               0 :             UnlockReleaseBuffer(buffers[block_id]);
                                537                 :     }
 2564 teodor                    538 UBC           0 : }
                                539                 : 
 2251 rhaas                     540 EUB             : /*
                                541                 :  * Mask a generic page before performing consistency checks on it.
                                542                 :  */
                                543                 : void
 2251 rhaas                     544 UIC           0 : generic_mask(char *page, BlockNumber blkno)
                                545                 : {
 2025                           546               0 :     mask_page_lsn_and_checksum(page);
                                547                 : 
 2251                           548               0 :     mask_unused_space(page);
 2251 rhaas                     549 UBC           0 : }
        

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