LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - multixact_rewrite.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 0.0 % 50 0
Test Date: 2026-07-16 11:17:59 Functions: 0.0 % 3 0
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 0.0 % 14 0

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * multixact_rewrite.c
       3                 :             :  *
       4                 :             :  * Functions to convert multixact SLRUs from the pre-v19 format to the current
       5                 :             :  * format with 64-bit MultiXactOffsets.
       6                 :             :  *
       7                 :             :  * Copyright (c) 2025-2026, PostgreSQL Global Development Group
       8                 :             :  * src/bin/pg_upgrade/multixact_rewrite.c
       9                 :             :  */
      10                 :             : 
      11                 :             : #include "postgres_fe.h"
      12                 :             : 
      13                 :             : #include "access/multixact_internal.h"
      14                 :             : #include "multixact_read_v18.h"
      15                 :             : #include "pg_upgrade.h"
      16                 :             : 
      17                 :             : static void RecordMultiXactOffset(SlruSegState *offsets_writer, MultiXactId multi,
      18                 :             :                                   MultiXactOffset offset);
      19                 :             : static void RecordMultiXactMembers(SlruSegState *members_writer,
      20                 :             :                                    MultiXactOffset offset,
      21                 :             :                                    int nmembers, MultiXactMember *members);
      22                 :             : 
      23                 :             : /*
      24                 :             :  * Convert pg_multixact/offset and /members from the old pre-v19 format with
      25                 :             :  * 32-bit offsets to the current format.
      26                 :             :  *
      27                 :             :  * Multixids in the range [from_multi, to_multi) are read from the old
      28                 :             :  * cluster, and written in the new format.
      29                 :             :  *
      30                 :             :  * Returns the new nextOffset value; the caller should set it in the new
      31                 :             :  * control file.  The new members always start from offset 1, regardless of
      32                 :             :  * the offset range used in the old cluster.
      33                 :             :  */
      34                 :             : MultiXactOffset
      35                 :           0 : rewrite_multixacts(MultiXactId from_multi, MultiXactId to_multi)
      36                 :             : {
      37                 :             :     MultiXactOffset next_offset;
      38                 :             :     SlruSegState *offsets_writer;
      39                 :             :     SlruSegState *members_writer;
      40                 :           0 :     char        dir[MAXPGPATH] = {0};
      41                 :           0 :     bool        prev_multixid_valid = false;
      42                 :             :     OldMultiXactReader *old_reader;
      43                 :             : 
      44                 :             :     /*
      45                 :             :      * The range of valid multi XIDs is unchanged by the conversion (they are
      46                 :             :      * referenced from the heap tables), but the members SLRU is rewritten to
      47                 :             :      * start from offset 1.
      48                 :             :      */
      49                 :           0 :     next_offset = 1;
      50                 :             : 
      51                 :             :     /* Prepare to write the new SLRU files */
      52                 :           0 :     pg_sprintf(dir, "%s/pg_multixact/offsets", new_cluster.pgdata);
      53                 :           0 :     offsets_writer = AllocSlruWrite(dir, false);
      54                 :           0 :     SlruWriteSwitchPage(offsets_writer, MultiXactIdToOffsetPage(from_multi));
      55                 :             : 
      56                 :           0 :     pg_sprintf(dir, "%s/pg_multixact/members", new_cluster.pgdata);
      57                 :           0 :     members_writer = AllocSlruWrite(dir, true /* use long segment names */ );
      58                 :           0 :     SlruWriteSwitchPage(members_writer, MXOffsetToMemberPage(next_offset));
      59                 :             : 
      60                 :             :     /*
      61                 :             :      * Convert old multixids, if needed, by reading them one-by-one from the
      62                 :             :      * old cluster.
      63                 :             :      */
      64                 :           0 :     old_reader = AllocOldMultiXactRead(old_cluster.pgdata,
      65                 :             :                                        old_cluster.controldata.chkpnt_nxtmulti,
      66                 :           0 :                                        old_cluster.controldata.chkpnt_nxtmxoff);
      67                 :             : 
      68         [ #  # ]:           0 :     for (MultiXactId multi = from_multi; multi != to_multi;)
      69                 :             :     {
      70                 :             :         MultiXactMember member;
      71                 :             :         bool        multixid_valid;
      72                 :             : 
      73                 :             :         /*
      74                 :             :          * Read this multixid's members.
      75                 :             :          *
      76                 :             :          * Locking-only XIDs that may be part of multi-xids don't matter after
      77                 :             :          * upgrade, as there can be no transactions running across upgrade. So
      78                 :             :          * as a small optimization, we only read one member from each
      79                 :             :          * multixid: the one updating one, or if there was no update,
      80                 :             :          * arbitrarily the first locking xid.
      81                 :             :          */
      82                 :           0 :         multixid_valid = GetOldMultiXactIdSingleMember(old_reader, multi, &member);
      83                 :             : 
      84                 :             :         /*
      85                 :             :          * Write the new offset to pg_multixact/offsets.
      86                 :             :          *
      87                 :             :          * Even if this multixid is invalid, we still need to write its offset
      88                 :             :          * if the *previous* multixid was valid.  That's because when reading
      89                 :             :          * a multixid, the number of members is calculated from the difference
      90                 :             :          * between the two offsets.
      91                 :             :          */
      92         [ #  # ]:           0 :         RecordMultiXactOffset(offsets_writer, multi,
      93         [ #  # ]:           0 :                               (multixid_valid || prev_multixid_valid) ? next_offset : 0);
      94                 :             : 
      95                 :             :         /* Write the members */
      96         [ #  # ]:           0 :         if (multixid_valid)
      97                 :             :         {
      98                 :           0 :             RecordMultiXactMembers(members_writer, next_offset, 1, &member);
      99                 :           0 :             next_offset += 1;
     100                 :             :         }
     101                 :             : 
     102                 :             :         /* Advance to next multixid, handling wraparound */
     103                 :           0 :         multi++;
     104         [ #  # ]:           0 :         if (multi < FirstMultiXactId)
     105                 :           0 :             multi = FirstMultiXactId;
     106                 :           0 :         prev_multixid_valid = multixid_valid;
     107                 :             :     }
     108                 :             : 
     109                 :           0 :     FreeOldMultiXactReader(old_reader);
     110                 :             : 
     111                 :             :     /* Write the final 'next' offset to the last SLRU page */
     112         [ #  # ]:           0 :     RecordMultiXactOffset(offsets_writer, to_multi,
     113                 :             :                           prev_multixid_valid ? next_offset : 0);
     114                 :             : 
     115                 :             :     /* Flush the last SLRU pages */
     116                 :           0 :     FreeSlruWrite(offsets_writer);
     117                 :           0 :     FreeSlruWrite(members_writer);
     118                 :             : 
     119                 :           0 :     return next_offset;
     120                 :             : }
     121                 :             : 
     122                 :             : 
     123                 :             : /*
     124                 :             :  * Write one offset to the offset SLRU
     125                 :             :  */
     126                 :             : static void
     127                 :           0 : RecordMultiXactOffset(SlruSegState *offsets_writer, MultiXactId multi,
     128                 :             :                       MultiXactOffset offset)
     129                 :             : {
     130                 :             :     int64       pageno;
     131                 :             :     int         entryno;
     132                 :             :     char       *buf;
     133                 :             :     MultiXactOffset *offptr;
     134                 :             : 
     135                 :           0 :     pageno = MultiXactIdToOffsetPage(multi);
     136                 :           0 :     entryno = MultiXactIdToOffsetEntry(multi);
     137                 :             : 
     138                 :           0 :     buf = SlruWriteSwitchPage(offsets_writer, pageno);
     139                 :           0 :     offptr = (MultiXactOffset *) buf;
     140                 :           0 :     offptr[entryno] = offset;
     141                 :           0 : }
     142                 :             : 
     143                 :             : /*
     144                 :             :  * Write the members for one multixid in the members SLRU
     145                 :             :  *
     146                 :             :  * (Currently, this is only ever called with nmembers == 1)
     147                 :             :  */
     148                 :             : static void
     149                 :           0 : RecordMultiXactMembers(SlruSegState *members_writer,
     150                 :             :                        MultiXactOffset offset,
     151                 :             :                        int nmembers, MultiXactMember *members)
     152                 :             : {
     153         [ #  # ]:           0 :     for (int i = 0; i < nmembers; i++, offset++)
     154                 :             :     {
     155                 :             :         int64       pageno;
     156                 :             :         char       *buf;
     157                 :             :         TransactionId *memberptr;
     158                 :             :         uint32     *flagsptr;
     159                 :             :         uint32      flagsval;
     160                 :             :         int         bshift;
     161                 :             :         int         flagsoff;
     162                 :             :         int         memberoff;
     163                 :             : 
     164                 :             :         Assert(members[i].status <= MultiXactStatusUpdate);
     165                 :             : 
     166                 :           0 :         pageno = MXOffsetToMemberPage(offset);
     167                 :           0 :         memberoff = MXOffsetToMemberOffset(offset);
     168                 :           0 :         flagsoff = MXOffsetToFlagsOffset(offset);
     169                 :           0 :         bshift = MXOffsetToFlagsBitShift(offset);
     170                 :             : 
     171                 :           0 :         buf = SlruWriteSwitchPage(members_writer, pageno);
     172                 :             : 
     173                 :           0 :         memberptr = (TransactionId *) (buf + memberoff);
     174                 :             : 
     175                 :           0 :         *memberptr = members[i].xid;
     176                 :             : 
     177                 :           0 :         flagsptr = (uint32 *) (buf + flagsoff);
     178                 :             : 
     179                 :           0 :         flagsval = *flagsptr;
     180                 :           0 :         flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
     181                 :           0 :         flagsval |= (members[i].status << bshift);
     182                 :           0 :         *flagsptr = flagsval;
     183                 :             :     }
     184                 :           0 : }
        

Generated by: LCOV version 2.0-1