LCOV - differential code coverage report
Current view: top level - src/backend/access/transam - generic_xlog.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 93.6 % 156 146 10 146
Current Date: 2024-04-14 14:21:10 Functions: 90.0 % 10 9 1 9
Baseline: 16@8cea358b128 Branches: 79.5 % 88 70 18 70
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (180,240] days: 100.0 % 9 9 9
(240..) days: 93.2 % 147 137 10 137
Function coverage date bins:
(240..) days: 90.0 % 10 9 1 9
Branch coverage date bins:
(180,240] days: 100.0 % 2 2 2
(240..) days: 79.1 % 86 68 18 68

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

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