LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - multixact_rewrite.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 77 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 3 0
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.3.2-1