LCOV - code coverage report
Current view: top level - src/backend/access/transam - multixact.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 54.4 % 967 526
Test Date: 2026-01-26 10:56:24 Functions: 64.3 % 56 36
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 25.4 % 464 118

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * multixact.c
       4                 :             :  *              PostgreSQL multi-transaction-log manager
       5                 :             :  *
       6                 :             :  * The pg_multixact manager is a pg_xact-like manager that stores an array of
       7                 :             :  * MultiXactMember for each MultiXactId.  It is a fundamental part of the
       8                 :             :  * shared-row-lock implementation.  Each MultiXactMember is comprised of a
       9                 :             :  * TransactionId and a set of flag bits.  The name is a bit historical:
      10                 :             :  * originally, a MultiXactId consisted of more than one TransactionId (except
      11                 :             :  * in rare corner cases), hence "multi".  Nowadays, however, it's perfectly
      12                 :             :  * legitimate to have MultiXactIds that only include a single Xid.
      13                 :             :  *
      14                 :             :  * The meaning of the flag bits is opaque to this module, but they are mostly
      15                 :             :  * used in heapam.c to identify lock modes that each of the member transactions
      16                 :             :  * is holding on any given tuple.  This module just contains support to store
      17                 :             :  * and retrieve the arrays.
      18                 :             :  *
      19                 :             :  * We use two SLRU areas, one for storing the offsets at which the data
      20                 :             :  * starts for each MultiXactId in the other one.  This trick allows us to
      21                 :             :  * store variable length arrays of TransactionIds.  (We could alternatively
      22                 :             :  * use one area containing counts and TransactionIds, with valid MultiXactId
      23                 :             :  * values pointing at slots containing counts; but that way seems less robust
      24                 :             :  * since it would get completely confused if someone inquired about a bogus
      25                 :             :  * MultiXactId that pointed to an intermediate slot containing an XID.)
      26                 :             :  *
      27                 :             :  * XLOG interactions: this module generates a record whenever a new OFFSETs or
      28                 :             :  * MEMBERs page is initialized to zeroes, as well as an
      29                 :             :  * XLOG_MULTIXACT_CREATE_ID record whenever a new MultiXactId is defined.
      30                 :             :  * This module ignores the WAL rule "write xlog before data," because it
      31                 :             :  * suffices that actions recording a MultiXactId in a heap xmax do follow that
      32                 :             :  * rule.  The only way for the MXID to be referenced from any data page is for
      33                 :             :  * heap_lock_tuple() or heap_update() to have put it there, and each generates
      34                 :             :  * an XLOG record that must follow ours.  The normal LSN interlock between the
      35                 :             :  * data page and that XLOG record will ensure that our XLOG record reaches
      36                 :             :  * disk first.  If the SLRU members/offsets data reaches disk sooner than the
      37                 :             :  * XLOG records, we do not care; after recovery, no xmax will refer to it.  On
      38                 :             :  * the flip side, to ensure that all referenced entries _do_ reach disk, this
      39                 :             :  * module's XLOG records completely rebuild the data entered since the last
      40                 :             :  * checkpoint.  We flush and sync all dirty OFFSETs and MEMBERs pages to disk
      41                 :             :  * before each checkpoint is considered complete.
      42                 :             :  *
      43                 :             :  * Like clog.c, and unlike subtrans.c, we have to preserve state across
      44                 :             :  * crashes and ensure that MXID and offset numbering increases monotonically
      45                 :             :  * across a crash.  We do this in the same way as it's done for transaction
      46                 :             :  * IDs: the WAL record is guaranteed to contain evidence of every MXID we
      47                 :             :  * could need to worry about, and we just make sure that at the end of
      48                 :             :  * replay, the next-MXID and next-offset counters are at least as large as
      49                 :             :  * anything we saw during replay.
      50                 :             :  *
      51                 :             :  * We are able to remove segments no longer necessary by carefully tracking
      52                 :             :  * each table's used values: during vacuum, any multixact older than a certain
      53                 :             :  * value is removed; the cutoff value is stored in pg_class.  The minimum value
      54                 :             :  * across all tables in each database is stored in pg_database, and the global
      55                 :             :  * minimum across all databases is part of pg_control and is kept in shared
      56                 :             :  * memory.  Whenever that minimum is advanced, the SLRUs are truncated.
      57                 :             :  *
      58                 :             :  * When new multixactid values are to be created, care is taken that the
      59                 :             :  * counter does not fall within the wraparound horizon considering the global
      60                 :             :  * minimum value.
      61                 :             :  *
      62                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      63                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      64                 :             :  *
      65                 :             :  * src/backend/access/transam/multixact.c
      66                 :             :  *
      67                 :             :  *-------------------------------------------------------------------------
      68                 :             :  */
      69                 :             : #include "postgres.h"
      70                 :             : 
      71                 :             : #include "access/multixact.h"
      72                 :             : #include "access/multixact_internal.h"
      73                 :             : #include "access/slru.h"
      74                 :             : #include "access/twophase.h"
      75                 :             : #include "access/twophase_rmgr.h"
      76                 :             : #include "access/xlog.h"
      77                 :             : #include "access/xloginsert.h"
      78                 :             : #include "access/xlogutils.h"
      79                 :             : #include "miscadmin.h"
      80                 :             : #include "pg_trace.h"
      81                 :             : #include "pgstat.h"
      82                 :             : #include "postmaster/autovacuum.h"
      83                 :             : #include "storage/pmsignal.h"
      84                 :             : #include "storage/proc.h"
      85                 :             : #include "storage/procarray.h"
      86                 :             : #include "utils/guc_hooks.h"
      87                 :             : #include "utils/injection_point.h"
      88                 :             : #include "utils/lsyscache.h"
      89                 :             : #include "utils/memutils.h"
      90                 :             : 
      91                 :             : 
      92                 :             : /*
      93                 :             :  * Thresholds used to keep members disk usage in check when multixids have a
      94                 :             :  * lot of members.  When MULTIXACT_MEMBER_LOW_THRESHOLD is reached, vacuum
      95                 :             :  * starts freezing multixids more aggressively, even if the normal multixid
      96                 :             :  * age limits haven't been reached yet.
      97                 :             :  */
      98                 :             : #define MULTIXACT_MEMBER_LOW_THRESHOLD          UINT64CONST(2000000000)
      99                 :             : #define MULTIXACT_MEMBER_HIGH_THRESHOLD         UINT64CONST(4000000000)
     100                 :             : 
     101                 :             : static inline MultiXactId
     102                 :           6 : NextMultiXactId(MultiXactId multi)
     103                 :             : {
     104         [ +  - ]:           6 :         return multi == MaxMultiXactId ? FirstMultiXactId : multi + 1;
     105                 :             : }
     106                 :             : 
     107                 :             : static inline MultiXactId
     108                 :           0 : PreviousMultiXactId(MultiXactId multi)
     109                 :             : {
     110         [ #  # ]:           0 :         return multi == FirstMultiXactId ? MaxMultiXactId : multi - 1;
     111                 :             : }
     112                 :             : 
     113                 :             : /*
     114                 :             :  * Links to shared-memory data structures for MultiXact control
     115                 :             :  */
     116                 :             : static SlruCtlData MultiXactOffsetCtlData;
     117                 :             : static SlruCtlData MultiXactMemberCtlData;
     118                 :             : 
     119                 :             : #define MultiXactOffsetCtl      (&MultiXactOffsetCtlData)
     120                 :             : #define MultiXactMemberCtl      (&MultiXactMemberCtlData)
     121                 :             : 
     122                 :             : /*
     123                 :             :  * MultiXact state shared across all backends.  All this state is protected
     124                 :             :  * by MultiXactGenLock.  (We also use SLRU bank's lock of MultiXactOffset and
     125                 :             :  * MultiXactMember to guard accesses to the two sets of SLRU buffers.  For
     126                 :             :  * concurrency's sake, we avoid holding more than one of these locks at a
     127                 :             :  * time.)
     128                 :             :  */
     129                 :             : typedef struct MultiXactStateData
     130                 :             : {
     131                 :             :         /* next-to-be-assigned MultiXactId */
     132                 :             :         MultiXactId nextMXact;
     133                 :             : 
     134                 :             :         /* next-to-be-assigned offset */
     135                 :             :         MultiXactOffset nextOffset;
     136                 :             : 
     137                 :             :         /* Have we completed multixact startup? */
     138                 :             :         bool            finishedStartup;
     139                 :             : 
     140                 :             :         /*
     141                 :             :          * Oldest multixact that is still potentially referenced by a relation.
     142                 :             :          * Anything older than this should not be consulted.  These values are
     143                 :             :          * updated by vacuum.
     144                 :             :          */
     145                 :             :         MultiXactId oldestMultiXactId;
     146                 :             :         Oid                     oldestMultiXactDB;
     147                 :             : 
     148                 :             :         /*
     149                 :             :          * Oldest multixact offset that is potentially referenced by a multixact
     150                 :             :          * referenced by a relation.
     151                 :             :          */
     152                 :             :         MultiXactOffset oldestOffset;
     153                 :             : 
     154                 :             :         /* support for anti-wraparound measures */
     155                 :             :         MultiXactId multiVacLimit;
     156                 :             :         MultiXactId multiWarnLimit;
     157                 :             :         MultiXactId multiStopLimit;
     158                 :             :         MultiXactId multiWrapLimit;
     159                 :             : 
     160                 :             :         /*
     161                 :             :          * Per-backend data starts here.  We have two arrays stored in the area
     162                 :             :          * immediately following the MultiXactStateData struct. Each is indexed by
     163                 :             :          * ProcNumber.
     164                 :             :          *
     165                 :             :          * In both arrays, there's a slot for all normal backends
     166                 :             :          * (0..MaxBackends-1) followed by a slot for max_prepared_xacts prepared
     167                 :             :          * transactions.
     168                 :             :          *
     169                 :             :          * OldestMemberMXactId[k] is the oldest MultiXactId each backend's current
     170                 :             :          * transaction(s) could possibly be a member of, or InvalidMultiXactId
     171                 :             :          * when the backend has no live transaction that could possibly be a
     172                 :             :          * member of a MultiXact.  Each backend sets its entry to the current
     173                 :             :          * nextMXact counter just before first acquiring a shared lock in a given
     174                 :             :          * transaction, and clears it at transaction end. (This works because only
     175                 :             :          * during or after acquiring a shared lock could an XID possibly become a
     176                 :             :          * member of a MultiXact, and that MultiXact would have to be created
     177                 :             :          * during or after the lock acquisition.)
     178                 :             :          *
     179                 :             :          * OldestVisibleMXactId[k] is the oldest MultiXactId each backend's
     180                 :             :          * current transaction(s) think is potentially live, or InvalidMultiXactId
     181                 :             :          * when not in a transaction or not in a transaction that's paid any
     182                 :             :          * attention to MultiXacts yet.  This is computed when first needed in a
     183                 :             :          * given transaction, and cleared at transaction end.  We can compute it
     184                 :             :          * as the minimum of the valid OldestMemberMXactId[] entries at the time
     185                 :             :          * we compute it (using nextMXact if none are valid).  Each backend is
     186                 :             :          * required not to attempt to access any SLRU data for MultiXactIds older
     187                 :             :          * than its own OldestVisibleMXactId[] setting; this is necessary because
     188                 :             :          * the relevant SLRU data can be concurrently truncated away.
     189                 :             :          *
     190                 :             :          * The oldest valid value among all of the OldestMemberMXactId[] and
     191                 :             :          * OldestVisibleMXactId[] entries is considered by vacuum as the earliest
     192                 :             :          * possible value still having any live member transaction -- OldestMxact.
     193                 :             :          * Any value older than that is typically removed from tuple headers, or
     194                 :             :          * "frozen" via being replaced with a new xmax.  VACUUM can sometimes even
     195                 :             :          * remove an individual MultiXact xmax whose value is >= its OldestMxact
     196                 :             :          * cutoff, though typically only when no individual member XID is still
     197                 :             :          * running.  See FreezeMultiXactId for full details.
     198                 :             :          *
     199                 :             :          * Whenever VACUUM advances relminmxid, then either its OldestMxact cutoff
     200                 :             :          * or the oldest extant Multi remaining in the table is used as the new
     201                 :             :          * pg_class.relminmxid value (whichever is earlier).  The minimum of all
     202                 :             :          * relminmxid values in each database is stored in pg_database.datminmxid.
     203                 :             :          * In turn, the minimum of all of those values is stored in pg_control.
     204                 :             :          * This is used as the truncation point for pg_multixact when unneeded
     205                 :             :          * segments get removed by vac_truncate_clog() during vacuuming.
     206                 :             :          */
     207                 :             :         MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER];
     208                 :             : } MultiXactStateData;
     209                 :             : 
     210                 :             : /*
     211                 :             :  * Size of OldestMemberMXactId and OldestVisibleMXactId arrays.
     212                 :             :  */
     213                 :             : #define MaxOldestSlot   (MaxBackends + max_prepared_xacts)
     214                 :             : 
     215                 :             : /* Pointers to the state data in shared memory */
     216                 :             : static MultiXactStateData *MultiXactState;
     217                 :             : static MultiXactId *OldestMemberMXactId;
     218                 :             : static MultiXactId *OldestVisibleMXactId;
     219                 :             : 
     220                 :             : 
     221                 :             : /*
     222                 :             :  * Definitions for the backend-local MultiXactId cache.
     223                 :             :  *
     224                 :             :  * We use this cache to store known MultiXacts, so we don't need to go to
     225                 :             :  * SLRU areas every time.
     226                 :             :  *
     227                 :             :  * The cache lasts for the duration of a single transaction, the rationale
     228                 :             :  * for this being that most entries will contain our own TransactionId and
     229                 :             :  * so they will be uninteresting by the time our next transaction starts.
     230                 :             :  * (XXX not clear that this is correct --- other members of the MultiXact
     231                 :             :  * could hang around longer than we did.  However, it's not clear what a
     232                 :             :  * better policy for flushing old cache entries would be.)      FIXME actually
     233                 :             :  * this is plain wrong now that multixact's may contain update Xids.
     234                 :             :  *
     235                 :             :  * We allocate the cache entries in a memory context that is deleted at
     236                 :             :  * transaction end, so we don't need to do retail freeing of entries.
     237                 :             :  */
     238                 :             : typedef struct mXactCacheEnt
     239                 :             : {
     240                 :             :         MultiXactId multi;
     241                 :             :         int                     nmembers;
     242                 :             :         dlist_node      node;
     243                 :             :         MultiXactMember members[FLEXIBLE_ARRAY_MEMBER];
     244                 :             : } mXactCacheEnt;
     245                 :             : 
     246                 :             : #define MAX_CACHE_ENTRIES       256
     247                 :             : static dclist_head MXactCache = DCLIST_STATIC_INIT(MXactCache);
     248                 :             : static MemoryContext MXactContext = NULL;
     249                 :             : 
     250                 :             : #ifdef MULTIXACT_DEBUG
     251                 :             : #define debug_elog2(a,b) elog(a,b)
     252                 :             : #define debug_elog3(a,b,c) elog(a,b,c)
     253                 :             : #define debug_elog4(a,b,c,d) elog(a,b,c,d)
     254                 :             : #define debug_elog5(a,b,c,d,e) elog(a,b,c,d,e)
     255                 :             : #define debug_elog6(a,b,c,d,e,f) elog(a,b,c,d,e,f)
     256                 :             : #else
     257                 :             : #define debug_elog2(a,b)
     258                 :             : #define debug_elog3(a,b,c)
     259                 :             : #define debug_elog4(a,b,c,d)
     260                 :             : #define debug_elog5(a,b,c,d,e)
     261                 :             : #define debug_elog6(a,b,c,d,e,f)
     262                 :             : #endif
     263                 :             : 
     264                 :             : /* internal MultiXactId management */
     265                 :             : static void MultiXactIdSetOldestVisible(void);
     266                 :             : static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
     267                 :             :                                                            int nmembers, MultiXactMember *members);
     268                 :             : static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset);
     269                 :             : 
     270                 :             : /* MultiXact cache management */
     271                 :             : static int      mxactMemberComparator(const void *arg1, const void *arg2);
     272                 :             : static MultiXactId mXactCacheGetBySet(int nmembers, MultiXactMember *members);
     273                 :             : static int      mXactCacheGetById(MultiXactId multi, MultiXactMember **members);
     274                 :             : static void mXactCachePut(MultiXactId multi, int nmembers,
     275                 :             :                                                   MultiXactMember *members);
     276                 :             : 
     277                 :             : /* management of SLRU infrastructure */
     278                 :             : static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2);
     279                 :             : static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2);
     280                 :             : static void ExtendMultiXactOffset(MultiXactId multi);
     281                 :             : static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers);
     282                 :             : static void SetOldestOffset(void);
     283                 :             : static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result);
     284                 :             : static void WriteMTruncateXlogRec(Oid oldestMultiDB,
     285                 :             :                                                                   MultiXactId endTruncOff,
     286                 :             :                                                                   MultiXactOffset endTruncMemb);
     287                 :             : 
     288                 :             : 
     289                 :             : /*
     290                 :             :  * MultiXactIdCreate
     291                 :             :  *              Construct a MultiXactId representing two TransactionIds.
     292                 :             :  *
     293                 :             :  * The two XIDs must be different, or be requesting different statuses.
     294                 :             :  *
     295                 :             :  * NB - we don't worry about our local MultiXactId cache here, because that
     296                 :             :  * is handled by the lower-level routines.
     297                 :             :  */
     298                 :             : MultiXactId
     299                 :           1 : MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1,
     300                 :             :                                   TransactionId xid2, MultiXactStatus status2)
     301                 :             : {
     302                 :           1 :         MultiXactId newMulti;
     303                 :           1 :         MultiXactMember members[2];
     304                 :             : 
     305         [ +  - ]:           1 :         Assert(TransactionIdIsValid(xid1));
     306         [ +  - ]:           1 :         Assert(TransactionIdIsValid(xid2));
     307                 :             : 
     308   [ -  +  #  # ]:           1 :         Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));
     309                 :             : 
     310                 :             :         /* MultiXactIdSetOldestMember() must have been called already. */
     311         [ +  - ]:           1 :         Assert(MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber]));
     312                 :             : 
     313                 :             :         /*
     314                 :             :          * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
     315                 :             :          * are still running.  In typical usage, xid2 will be our own XID and the
     316                 :             :          * caller just did a check on xid1, so it'd be wasted effort.
     317                 :             :          */
     318                 :             : 
     319                 :           1 :         members[0].xid = xid1;
     320                 :           1 :         members[0].status = status1;
     321                 :           1 :         members[1].xid = xid2;
     322                 :           1 :         members[1].status = status2;
     323                 :             : 
     324                 :           1 :         newMulti = MultiXactIdCreateFromMembers(2, members);
     325                 :             : 
     326                 :             :         debug_elog3(DEBUG2, "Create: %s",
     327                 :             :                                 mxid_to_string(newMulti, 2, members));
     328                 :             : 
     329                 :           2 :         return newMulti;
     330                 :           1 : }
     331                 :             : 
     332                 :             : /*
     333                 :             :  * MultiXactIdExpand
     334                 :             :  *              Add a TransactionId to a pre-existing MultiXactId.
     335                 :             :  *
     336                 :             :  * If the TransactionId is already a member of the passed MultiXactId with the
     337                 :             :  * same status, just return it as-is.
     338                 :             :  *
     339                 :             :  * Note that we do NOT actually modify the membership of a pre-existing
     340                 :             :  * MultiXactId; instead we create a new one.  This is necessary to avoid
     341                 :             :  * a race condition against code trying to wait for one MultiXactId to finish;
     342                 :             :  * see notes in heapam.c.
     343                 :             :  *
     344                 :             :  * NB - we don't worry about our local MultiXactId cache here, because that
     345                 :             :  * is handled by the lower-level routines.
     346                 :             :  *
     347                 :             :  * Note: It is critical that MultiXactIds that come from an old cluster (i.e.
     348                 :             :  * one upgraded by pg_upgrade from a cluster older than this feature) are not
     349                 :             :  * passed in.
     350                 :             :  */
     351                 :             : MultiXactId
     352                 :           1 : MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
     353                 :             : {
     354                 :           1 :         MultiXactId newMulti;
     355                 :           1 :         MultiXactMember *members;
     356                 :           1 :         MultiXactMember *newMembers;
     357                 :           1 :         int                     nmembers;
     358                 :           1 :         int                     i;
     359                 :           1 :         int                     j;
     360                 :             : 
     361         [ +  - ]:           1 :         Assert(MultiXactIdIsValid(multi));
     362         [ +  - ]:           1 :         Assert(TransactionIdIsValid(xid));
     363                 :             : 
     364                 :             :         /* MultiXactIdSetOldestMember() must have been called already. */
     365         [ +  - ]:           1 :         Assert(MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber]));
     366                 :             : 
     367                 :             :         debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s",
     368                 :             :                                 multi, xid, mxstatus_to_string(status));
     369                 :             : 
     370                 :             :         /*
     371                 :             :          * Note: we don't allow for old multis here.  The reason is that the only
     372                 :             :          * caller of this function does a check that the multixact is no longer
     373                 :             :          * running.
     374                 :             :          */
     375                 :           1 :         nmembers = GetMultiXactIdMembers(multi, &members, false, false);
     376                 :             : 
     377         [ +  - ]:           1 :         if (nmembers < 0)
     378                 :             :         {
     379                 :           0 :                 MultiXactMember member;
     380                 :             : 
     381                 :             :                 /*
     382                 :             :                  * The MultiXactId is obsolete.  This can only happen if all the
     383                 :             :                  * MultiXactId members stop running between the caller checking and
     384                 :             :                  * passing it to us.  It would be better to return that fact to the
     385                 :             :                  * caller, but it would complicate the API and it's unlikely to happen
     386                 :             :                  * too often, so just deal with it by creating a singleton MultiXact.
     387                 :             :                  */
     388                 :           0 :                 member.xid = xid;
     389                 :           0 :                 member.status = status;
     390                 :           0 :                 newMulti = MultiXactIdCreateFromMembers(1, &member);
     391                 :             : 
     392                 :             :                 debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
     393                 :             :                                         multi, newMulti);
     394                 :           0 :                 return newMulti;
     395                 :           0 :         }
     396                 :             : 
     397                 :             :         /*
     398                 :             :          * If the TransactionId is already a member of the MultiXactId with the
     399                 :             :          * same status, just return the existing MultiXactId.
     400                 :             :          */
     401         [ +  + ]:           3 :         for (i = 0; i < nmembers; i++)
     402                 :             :         {
     403   [ -  +  #  # ]:           2 :                 if (TransactionIdEquals(members[i].xid, xid) &&
     404                 :           0 :                         (members[i].status == status))
     405                 :             :                 {
     406                 :             :                         debug_elog4(DEBUG2, "Expand: %u is already a member of %u",
     407                 :             :                                                 xid, multi);
     408                 :           0 :                         pfree(members);
     409                 :           0 :                         return multi;
     410                 :             :                 }
     411                 :           2 :         }
     412                 :             : 
     413                 :             :         /*
     414                 :             :          * Determine which of the members of the MultiXactId are still of
     415                 :             :          * interest. This is any running transaction, and also any transaction
     416                 :             :          * that grabbed something stronger than just a lock and was committed. (An
     417                 :             :          * update that aborted is of no interest here; and having more than one
     418                 :             :          * update Xid in a multixact would cause errors elsewhere.)
     419                 :             :          *
     420                 :             :          * Removing dead members is not just an optimization: freezing of tuples
     421                 :             :          * whose Xmax are multis depends on this behavior.
     422                 :             :          *
     423                 :             :          * Note we have the same race condition here as above: j could be 0 at the
     424                 :             :          * end of the loop.
     425                 :             :          */
     426                 :           1 :         newMembers = palloc_array(MultiXactMember, nmembers + 1);
     427                 :             : 
     428         [ +  + ]:           3 :         for (i = 0, j = 0; i < nmembers; i++)
     429                 :             :         {
     430   [ +  +  -  + ]:           3 :                 if (TransactionIdIsInProgress(members[i].xid) ||
     431         [ +  - ]:           1 :                         (ISUPDATE_from_mxstatus(members[i].status) &&
     432                 :           1 :                          TransactionIdDidCommit(members[i].xid)))
     433                 :             :                 {
     434                 :           1 :                         newMembers[j].xid = members[i].xid;
     435                 :           1 :                         newMembers[j++].status = members[i].status;
     436                 :           1 :                 }
     437                 :           2 :         }
     438                 :             : 
     439                 :           1 :         newMembers[j].xid = xid;
     440                 :           1 :         newMembers[j++].status = status;
     441                 :           1 :         newMulti = MultiXactIdCreateFromMembers(j, newMembers);
     442                 :             : 
     443                 :           1 :         pfree(members);
     444                 :           1 :         pfree(newMembers);
     445                 :             : 
     446                 :             :         debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);
     447                 :             : 
     448                 :           1 :         return newMulti;
     449                 :           1 : }
     450                 :             : 
     451                 :             : /*
     452                 :             :  * MultiXactIdIsRunning
     453                 :             :  *              Returns whether a MultiXactId is "running".
     454                 :             :  *
     455                 :             :  * We return true if at least one member of the given MultiXactId is still
     456                 :             :  * running.  Note that a "false" result is certain not to change,
     457                 :             :  * because it is not legal to add members to an existing MultiXactId.
     458                 :             :  *
     459                 :             :  * Caller is expected to have verified that the multixact does not come from
     460                 :             :  * a pg_upgraded share-locked tuple.
     461                 :             :  */
     462                 :             : bool
     463                 :           2 : MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
     464                 :             : {
     465                 :           2 :         MultiXactMember *members;
     466                 :           2 :         int                     nmembers;
     467                 :           2 :         int                     i;
     468                 :             : 
     469                 :             :         debug_elog3(DEBUG2, "IsRunning %u?", multi);
     470                 :             : 
     471                 :             :         /*
     472                 :             :          * "false" here means we assume our callers have checked that the given
     473                 :             :          * multi cannot possibly come from a pg_upgraded database.
     474                 :             :          */
     475                 :           2 :         nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
     476                 :             : 
     477         [ -  + ]:           2 :         if (nmembers <= 0)
     478                 :             :         {
     479                 :             :                 debug_elog2(DEBUG2, "IsRunning: no members");
     480                 :           0 :                 return false;
     481                 :             :         }
     482                 :             : 
     483                 :             :         /*
     484                 :             :          * Checking for myself is cheap compared to looking in shared memory;
     485                 :             :          * return true if any live subtransaction of the current top-level
     486                 :             :          * transaction is a member.
     487                 :             :          *
     488                 :             :          * This is not needed for correctness, it's just a fast path.
     489                 :             :          */
     490         [ +  - ]:           2 :         for (i = 0; i < nmembers; i++)
     491                 :             :         {
     492         [ +  - ]:           2 :                 if (TransactionIdIsCurrentTransactionId(members[i].xid))
     493                 :             :                 {
     494                 :             :                         debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i);
     495                 :           2 :                         pfree(members);
     496                 :           2 :                         return true;
     497                 :             :                 }
     498                 :           0 :         }
     499                 :             : 
     500                 :             :         /*
     501                 :             :          * This could be made faster by having another entry point in procarray.c,
     502                 :             :          * walking the PGPROC array only once for all the members.  But in most
     503                 :             :          * cases nmembers should be small enough that it doesn't much matter.
     504                 :             :          */
     505         [ #  # ]:           0 :         for (i = 0; i < nmembers; i++)
     506                 :             :         {
     507         [ #  # ]:           0 :                 if (TransactionIdIsInProgress(members[i].xid))
     508                 :             :                 {
     509                 :             :                         debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running",
     510                 :             :                                                 i, members[i].xid);
     511                 :           0 :                         pfree(members);
     512                 :           0 :                         return true;
     513                 :             :                 }
     514                 :           0 :         }
     515                 :             : 
     516                 :           0 :         pfree(members);
     517                 :             : 
     518                 :             :         debug_elog3(DEBUG2, "IsRunning: %u is not running", multi);
     519                 :             : 
     520                 :           0 :         return false;
     521                 :           2 : }
     522                 :             : 
     523                 :             : /*
     524                 :             :  * MultiXactIdSetOldestMember
     525                 :             :  *              Save the oldest MultiXactId this transaction could be a member of.
     526                 :             :  *
     527                 :             :  * We set the OldestMemberMXactId for a given transaction the first time it's
     528                 :             :  * going to do some operation that might require a MultiXactId (tuple lock,
     529                 :             :  * update or delete).  We need to do this even if we end up using a
     530                 :             :  * TransactionId instead of a MultiXactId, because there is a chance that
     531                 :             :  * another transaction would add our XID to a MultiXactId.
     532                 :             :  *
     533                 :             :  * The value to set is the next-to-be-assigned MultiXactId, so this is meant to
     534                 :             :  * be called just before doing any such possibly-MultiXactId-able operation.
     535                 :             :  */
     536                 :             : void
     537                 :      327894 : MultiXactIdSetOldestMember(void)
     538                 :             : {
     539         [ +  + ]:      327894 :         if (!MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber]))
     540                 :             :         {
     541                 :       11753 :                 MultiXactId nextMXact;
     542                 :             : 
     543                 :             :                 /*
     544                 :             :                  * You might think we don't need to acquire a lock here, since
     545                 :             :                  * fetching and storing of TransactionIds is probably atomic, but in
     546                 :             :                  * fact we do: suppose we pick up nextMXact and then lose the CPU for
     547                 :             :                  * a long time.  Someone else could advance nextMXact, and then
     548                 :             :                  * another someone else could compute an OldestVisibleMXactId that
     549                 :             :                  * would be after the value we are going to store when we get control
     550                 :             :                  * back.  Which would be wrong.
     551                 :             :                  *
     552                 :             :                  * Note that a shared lock is sufficient, because it's enough to stop
     553                 :             :                  * someone from advancing nextMXact; and nobody else could be trying
     554                 :             :                  * to write to our OldestMember entry, only reading (and we assume
     555                 :             :                  * storing it is atomic.)
     556                 :             :                  */
     557                 :       11753 :                 LWLockAcquire(MultiXactGenLock, LW_SHARED);
     558                 :             : 
     559                 :       11753 :                 nextMXact = MultiXactState->nextMXact;
     560                 :             : 
     561                 :       11753 :                 OldestMemberMXactId[MyProcNumber] = nextMXact;
     562                 :             : 
     563                 :       11753 :                 LWLockRelease(MultiXactGenLock);
     564                 :             : 
     565                 :             :                 debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
     566                 :             :                                         MyProcNumber, nextMXact);
     567                 :       11753 :         }
     568                 :      327894 : }
     569                 :             : 
     570                 :             : /*
     571                 :             :  * MultiXactIdSetOldestVisible
     572                 :             :  *              Save the oldest MultiXactId this transaction considers possibly live.
     573                 :             :  *
     574                 :             :  * We set the OldestVisibleMXactId for a given transaction the first time
     575                 :             :  * it's going to inspect any MultiXactId.  Once we have set this, we are
     576                 :             :  * guaranteed that SLRU data for MultiXactIds >= our own OldestVisibleMXactId
     577                 :             :  * won't be truncated away.
     578                 :             :  *
     579                 :             :  * The value to set is the oldest of nextMXact and all the valid per-backend
     580                 :             :  * OldestMemberMXactId[] entries.  Because of the locking we do, we can be
     581                 :             :  * certain that no subsequent call to MultiXactIdSetOldestMember can set
     582                 :             :  * an OldestMemberMXactId[] entry older than what we compute here.  Therefore
     583                 :             :  * there is no live transaction, now or later, that can be a member of any
     584                 :             :  * MultiXactId older than the OldestVisibleMXactId we compute here.
     585                 :             :  */
     586                 :             : static void
     587                 :           0 : MultiXactIdSetOldestVisible(void)
     588                 :             : {
     589         [ #  # ]:           0 :         if (!MultiXactIdIsValid(OldestVisibleMXactId[MyProcNumber]))
     590                 :             :         {
     591                 :           0 :                 MultiXactId oldestMXact;
     592                 :           0 :                 int                     i;
     593                 :             : 
     594                 :           0 :                 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
     595                 :             : 
     596                 :           0 :                 oldestMXact = MultiXactState->nextMXact;
     597         [ #  # ]:           0 :                 for (i = 0; i < MaxOldestSlot; i++)
     598                 :             :                 {
     599                 :           0 :                         MultiXactId thisoldest = OldestMemberMXactId[i];
     600                 :             : 
     601   [ #  #  #  # ]:           0 :                         if (MultiXactIdIsValid(thisoldest) &&
     602                 :           0 :                                 MultiXactIdPrecedes(thisoldest, oldestMXact))
     603                 :           0 :                                 oldestMXact = thisoldest;
     604                 :           0 :                 }
     605                 :             : 
     606                 :           0 :                 OldestVisibleMXactId[MyProcNumber] = oldestMXact;
     607                 :             : 
     608                 :           0 :                 LWLockRelease(MultiXactGenLock);
     609                 :             : 
     610                 :             :                 debug_elog4(DEBUG2, "MultiXact: setting OldestVisible[%d] = %u",
     611                 :             :                                         MyProcNumber, oldestMXact);
     612                 :           0 :         }
     613                 :           0 : }
     614                 :             : 
     615                 :             : /*
     616                 :             :  * ReadNextMultiXactId
     617                 :             :  *              Return the next MultiXactId to be assigned, but don't allocate it
     618                 :             :  */
     619                 :             : MultiXactId
     620                 :        1932 : ReadNextMultiXactId(void)
     621                 :             : {
     622                 :        1932 :         MultiXactId mxid;
     623                 :             : 
     624                 :             :         /* XXX we could presumably do this without a lock. */
     625                 :        1932 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
     626                 :        1932 :         mxid = MultiXactState->nextMXact;
     627                 :        1932 :         LWLockRelease(MultiXactGenLock);
     628                 :             : 
     629                 :        3864 :         return mxid;
     630                 :        1932 : }
     631                 :             : 
     632                 :             : /*
     633                 :             :  * ReadMultiXactIdRange
     634                 :             :  *              Get the range of IDs that may still be referenced by a relation.
     635                 :             :  */
     636                 :             : void
     637                 :           0 : ReadMultiXactIdRange(MultiXactId *oldest, MultiXactId *next)
     638                 :             : {
     639                 :           0 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
     640                 :           0 :         *oldest = MultiXactState->oldestMultiXactId;
     641                 :           0 :         *next = MultiXactState->nextMXact;
     642                 :           0 :         LWLockRelease(MultiXactGenLock);
     643                 :           0 : }
     644                 :             : 
     645                 :             : 
     646                 :             : /*
     647                 :             :  * MultiXactIdCreateFromMembers
     648                 :             :  *              Make a new MultiXactId from the specified set of members
     649                 :             :  *
     650                 :             :  * Make XLOG, SLRU and cache entries for a new MultiXactId, recording the
     651                 :             :  * given TransactionIds as members.  Returns the newly created MultiXactId.
     652                 :             :  *
     653                 :             :  * NB: the passed members[] array will be sorted in-place.
     654                 :             :  */
     655                 :             : MultiXactId
     656                 :           2 : MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
     657                 :             : {
     658                 :           2 :         MultiXactId multi;
     659                 :           2 :         MultiXactOffset offset;
     660                 :           2 :         xl_multixact_create xlrec;
     661                 :             : 
     662                 :             :         debug_elog3(DEBUG2, "Create: %s",
     663                 :             :                                 mxid_to_string(InvalidMultiXactId, nmembers, members));
     664                 :             : 
     665                 :             :         /*
     666                 :             :          * See if the same set of members already exists in our cache; if so, just
     667                 :             :          * re-use that MultiXactId.  (Note: it might seem that looking in our
     668                 :             :          * cache is insufficient, and we ought to search disk to see if a
     669                 :             :          * duplicate definition already exists.  But since we only ever create
     670                 :             :          * MultiXacts containing our own XID, in most cases any such MultiXacts
     671                 :             :          * were in fact created by us, and so will be in our cache.  There are
     672                 :             :          * corner cases where someone else added us to a MultiXact without our
     673                 :             :          * knowledge, but it's not worth checking for.)
     674                 :             :          */
     675                 :           2 :         multi = mXactCacheGetBySet(nmembers, members);
     676         [ -  + ]:           2 :         if (MultiXactIdIsValid(multi))
     677                 :             :         {
     678                 :             :                 debug_elog2(DEBUG2, "Create: in cache!");
     679                 :           0 :                 return multi;
     680                 :             :         }
     681                 :             : 
     682                 :             :         /* Verify that there is a single update Xid among the given members. */
     683                 :             :         {
     684                 :           2 :                 int                     i;
     685                 :           2 :                 bool            has_update = false;
     686                 :             : 
     687         [ +  + ]:           6 :                 for (i = 0; i < nmembers; i++)
     688                 :             :                 {
     689         [ +  + ]:           4 :                         if (ISUPDATE_from_mxstatus(members[i].status))
     690                 :             :                         {
     691         [ +  - ]:           1 :                                 if (has_update)
     692   [ #  #  #  # ]:           0 :                                         elog(ERROR, "new multixact has more than one updating member: %s",
     693                 :             :                                                  mxid_to_string(InvalidMultiXactId, nmembers, members));
     694                 :           1 :                                 has_update = true;
     695                 :           1 :                         }
     696                 :           4 :                 }
     697                 :           2 :         }
     698                 :             : 
     699                 :             :         /* Load the injection point before entering the critical section */
     700                 :             :         INJECTION_POINT_LOAD("multixact-create-from-members");
     701                 :             : 
     702                 :             :         /*
     703                 :             :          * Assign the MXID and offsets range to use, and make sure there is space
     704                 :             :          * in the OFFSETs and MEMBERs files.  NB: this routine does
     705                 :             :          * START_CRIT_SECTION().
     706                 :             :          *
     707                 :             :          * Note: unlike MultiXactIdCreate and MultiXactIdExpand, we do not check
     708                 :             :          * that we've called MultiXactIdSetOldestMember here.  This is because
     709                 :             :          * this routine is used in some places to create new MultiXactIds of which
     710                 :             :          * the current backend is not a member, notably during freezing of multis
     711                 :             :          * in vacuum.  During vacuum, in particular, it would be unacceptable to
     712                 :             :          * keep OldestMulti set, in case it runs for long.
     713                 :             :          */
     714                 :           2 :         multi = GetNewMultiXactId(nmembers, &offset);
     715                 :             : 
     716                 :             :         INJECTION_POINT_CACHED("multixact-create-from-members", NULL);
     717                 :             : 
     718                 :             :         /* Make an XLOG entry describing the new MXID. */
     719                 :           2 :         xlrec.mid = multi;
     720                 :           2 :         xlrec.moff = offset;
     721                 :           2 :         xlrec.nmembers = nmembers;
     722                 :             : 
     723                 :             :         /*
     724                 :             :          * XXX Note: there's a lot of padding space in MultiXactMember.  We could
     725                 :             :          * find a more compact representation of this Xlog record -- perhaps all
     726                 :             :          * the status flags in one XLogRecData, then all the xids in another one?
     727                 :             :          * Not clear that it's worth the trouble though.
     728                 :             :          */
     729                 :           2 :         XLogBeginInsert();
     730                 :           2 :         XLogRegisterData(&xlrec, SizeOfMultiXactCreate);
     731                 :           2 :         XLogRegisterData(members, nmembers * sizeof(MultiXactMember));
     732                 :             : 
     733                 :           2 :         (void) XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_CREATE_ID);
     734                 :             : 
     735                 :             :         /* Now enter the information into the OFFSETs and MEMBERs logs */
     736                 :           2 :         RecordNewMultiXact(multi, offset, nmembers, members);
     737                 :             : 
     738                 :             :         /* Done with critical section */
     739         [ +  - ]:           2 :         END_CRIT_SECTION();
     740                 :             : 
     741                 :             :         /* Store the new MultiXactId in the local cache, too */
     742                 :           2 :         mXactCachePut(multi, nmembers, members);
     743                 :             : 
     744                 :             :         debug_elog2(DEBUG2, "Create: all done");
     745                 :             : 
     746                 :           2 :         return multi;
     747                 :           2 : }
     748                 :             : 
     749                 :             : /*
     750                 :             :  * RecordNewMultiXact
     751                 :             :  *              Write info about a new multixact into the offsets and members files
     752                 :             :  *
     753                 :             :  * This is broken out of MultiXactIdCreateFromMembers so that xlog replay can
     754                 :             :  * use it.
     755                 :             :  */
     756                 :             : static void
     757                 :           2 : RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
     758                 :             :                                    int nmembers, MultiXactMember *members)
     759                 :             : {
     760                 :           2 :         int64           pageno;
     761                 :           2 :         int64           prev_pageno;
     762                 :           2 :         int                     entryno;
     763                 :           2 :         int                     slotno;
     764                 :           2 :         MultiXactOffset *offptr;
     765                 :           2 :         MultiXactId next;
     766                 :           2 :         int64           next_pageno;
     767                 :           2 :         int                     next_entryno;
     768                 :           2 :         MultiXactOffset *next_offptr;
     769                 :           2 :         MultiXactOffset next_offset;
     770                 :           2 :         LWLock     *lock;
     771                 :           2 :         LWLock     *prevlock = NULL;
     772                 :             : 
     773                 :             :         /* position of this multixid in the offsets SLRU area  */
     774                 :           2 :         pageno = MultiXactIdToOffsetPage(multi);
     775                 :           2 :         entryno = MultiXactIdToOffsetEntry(multi);
     776                 :             : 
     777                 :             :         /* position of the next multixid */
     778                 :           2 :         next = NextMultiXactId(multi);
     779                 :           2 :         next_pageno = MultiXactIdToOffsetPage(next);
     780                 :           2 :         next_entryno = MultiXactIdToOffsetEntry(next);
     781                 :             : 
     782                 :             :         /*
     783                 :             :          * Set the starting offset of this multixid's members.
     784                 :             :          *
     785                 :             :          * In the common case, it was already be set by the previous
     786                 :             :          * RecordNewMultiXact call, as this was the next multixid of the previous
     787                 :             :          * multixid.  But if multiple backends are generating multixids
     788                 :             :          * concurrently, we might race ahead and get called before the previous
     789                 :             :          * multixid.
     790                 :             :          */
     791                 :           2 :         lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
     792                 :           2 :         LWLockAcquire(lock, LW_EXCLUSIVE);
     793                 :             : 
     794                 :             :         /*
     795                 :             :          * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
     796                 :             :          * to complain about if there's any I/O error.  This is kinda bogus, but
     797                 :             :          * since the errors will always give the full pathname, it should be clear
     798                 :             :          * enough that a MultiXactId is really involved.  Perhaps someday we'll
     799                 :             :          * take the trouble to generalize the slru.c error reporting code.
     800                 :             :          */
     801                 :           2 :         slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
     802                 :           2 :         offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
     803                 :           2 :         offptr += entryno;
     804                 :             : 
     805         [ +  - ]:           2 :         if (*offptr != offset)
     806                 :             :         {
     807                 :             :                 /* should already be set to the correct value, or not at all */
     808         [ #  # ]:           0 :                 Assert(*offptr == 0);
     809                 :           0 :                 *offptr = offset;
     810                 :           0 :                 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
     811                 :           0 :         }
     812                 :             : 
     813                 :             :         /*
     814                 :             :          * Set the next multixid's offset to the end of this multixid's members.
     815                 :             :          */
     816         [ +  - ]:           2 :         if (next_pageno == pageno)
     817                 :             :         {
     818                 :           2 :                 next_offptr = offptr + 1;
     819                 :           2 :         }
     820                 :             :         else
     821                 :             :         {
     822                 :             :                 /* must be the first entry on the page */
     823   [ #  #  #  # ]:           0 :                 Assert(next_entryno == 0 || next == FirstMultiXactId);
     824                 :             : 
     825                 :             :                 /* Swap the lock for a lock on the next page */
     826                 :           0 :                 LWLockRelease(lock);
     827                 :           0 :                 lock = SimpleLruGetBankLock(MultiXactOffsetCtl, next_pageno);
     828                 :           0 :                 LWLockAcquire(lock, LW_EXCLUSIVE);
     829                 :             : 
     830                 :           0 :                 slotno = SimpleLruReadPage(MultiXactOffsetCtl, next_pageno, true, next);
     831                 :           0 :                 next_offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
     832                 :           0 :                 next_offptr += next_entryno;
     833                 :             :         }
     834                 :             : 
     835                 :             :         /* Like in GetNewMultiXactId(), skip over offset 0 */
     836                 :           2 :         next_offset = offset + nmembers;
     837         [ +  - ]:           2 :         if (next_offset == 0)
     838                 :           0 :                 next_offset = 1;
     839         [ -  + ]:           2 :         if (*next_offptr != next_offset)
     840                 :             :         {
     841                 :             :                 /* should already be set to the correct value, or not at all */
     842         [ +  - ]:           2 :                 Assert(*next_offptr == 0);
     843                 :           2 :                 *next_offptr = next_offset;
     844                 :           2 :                 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
     845                 :           2 :         }
     846                 :             : 
     847                 :             :         /* Release MultiXactOffset SLRU lock. */
     848                 :           2 :         LWLockRelease(lock);
     849                 :             : 
     850                 :           2 :         prev_pageno = -1;
     851                 :             : 
     852         [ +  + ]:           6 :         for (int i = 0; i < nmembers; i++, offset++)
     853                 :             :         {
     854                 :           4 :                 TransactionId *memberptr;
     855                 :           4 :                 uint32     *flagsptr;
     856                 :           4 :                 uint32          flagsval;
     857                 :           4 :                 int                     bshift;
     858                 :           4 :                 int                     flagsoff;
     859                 :           4 :                 int                     memberoff;
     860                 :             : 
     861         [ +  - ]:           4 :                 Assert(members[i].status <= MultiXactStatusUpdate);
     862                 :             : 
     863                 :           4 :                 pageno = MXOffsetToMemberPage(offset);
     864                 :           4 :                 memberoff = MXOffsetToMemberOffset(offset);
     865                 :           4 :                 flagsoff = MXOffsetToFlagsOffset(offset);
     866                 :           4 :                 bshift = MXOffsetToFlagsBitShift(offset);
     867                 :             : 
     868         [ +  + ]:           4 :                 if (pageno != prev_pageno)
     869                 :             :                 {
     870                 :             :                         /*
     871                 :             :                          * MultiXactMember SLRU page is changed so check if this new page
     872                 :             :                          * fall into the different SLRU bank then release the old bank's
     873                 :             :                          * lock and acquire lock on the new bank.
     874                 :             :                          */
     875                 :           2 :                         lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
     876         [ -  + ]:           2 :                         if (lock != prevlock)
     877                 :             :                         {
     878         [ +  - ]:           2 :                                 if (prevlock != NULL)
     879                 :           0 :                                         LWLockRelease(prevlock);
     880                 :             : 
     881                 :           2 :                                 LWLockAcquire(lock, LW_EXCLUSIVE);
     882                 :           2 :                                 prevlock = lock;
     883                 :           2 :                         }
     884                 :           2 :                         slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
     885                 :           2 :                         prev_pageno = pageno;
     886                 :           2 :                 }
     887                 :             : 
     888                 :           4 :                 memberptr = (TransactionId *)
     889                 :           4 :                         (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
     890                 :             : 
     891                 :           4 :                 *memberptr = members[i].xid;
     892                 :             : 
     893                 :           4 :                 flagsptr = (uint32 *)
     894                 :           4 :                         (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
     895                 :             : 
     896                 :           4 :                 flagsval = *flagsptr;
     897                 :           4 :                 flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
     898                 :           4 :                 flagsval |= (members[i].status << bshift);
     899                 :           4 :                 *flagsptr = flagsval;
     900                 :             : 
     901                 :           4 :                 MultiXactMemberCtl->shared->page_dirty[slotno] = true;
     902                 :           4 :         }
     903                 :             : 
     904         [ -  + ]:           2 :         if (prevlock != NULL)
     905                 :           2 :                 LWLockRelease(prevlock);
     906                 :           2 : }
     907                 :             : 
     908                 :             : /*
     909                 :             :  * GetNewMultiXactId
     910                 :             :  *              Get the next MultiXactId.
     911                 :             :  *
     912                 :             :  * Also, reserve the needed amount of space in the "members" area.  The
     913                 :             :  * starting offset of the reserved space is returned in *offset.
     914                 :             :  *
     915                 :             :  * This may generate XLOG records for expansion of the offsets and/or members
     916                 :             :  * files.  Unfortunately, we have to do that while holding MultiXactGenLock
     917                 :             :  * to avoid race conditions --- the XLOG record for zeroing a page must appear
     918                 :             :  * before any backend can possibly try to store data in that page!
     919                 :             :  *
     920                 :             :  * We start a critical section before advancing the shared counters.  The
     921                 :             :  * caller must end the critical section after writing SLRU data.
     922                 :             :  */
     923                 :             : static MultiXactId
     924                 :           2 : GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
     925                 :             : {
     926                 :           2 :         MultiXactId result;
     927                 :           2 :         MultiXactOffset nextOffset;
     928                 :             : 
     929                 :             :         debug_elog3(DEBUG2, "GetNew: for %d xids", nmembers);
     930                 :             : 
     931                 :             :         /* safety check, we should never get this far in a HS standby */
     932         [ +  - ]:           2 :         if (RecoveryInProgress())
     933   [ #  #  #  # ]:           0 :                 elog(ERROR, "cannot assign MultiXactIds during recovery");
     934                 :             : 
     935                 :           2 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
     936                 :             : 
     937                 :             :         /* Assign the MXID */
     938                 :           2 :         result = MultiXactState->nextMXact;
     939                 :             : 
     940                 :             :         /*----------
     941                 :             :          * Check to see if it's safe to assign another MultiXactId.  This protects
     942                 :             :          * against catastrophic data loss due to multixact wraparound.  The basic
     943                 :             :          * rules are:
     944                 :             :          *
     945                 :             :          * If we're past multiVacLimit or the safe threshold for member storage
     946                 :             :          * space, or we don't know what the safe threshold for member storage is,
     947                 :             :          * start trying to force autovacuum cycles.
     948                 :             :          * If we're past multiWarnLimit, start issuing warnings.
     949                 :             :          * If we're past multiStopLimit, refuse to create new MultiXactIds.
     950                 :             :          *
     951                 :             :          * Note these are pretty much the same protections in GetNewTransactionId.
     952                 :             :          *----------
     953                 :             :          */
     954         [ +  - ]:           2 :         if (!MultiXactIdPrecedes(result, MultiXactState->multiVacLimit))
     955                 :             :         {
     956                 :             :                 /*
     957                 :             :                  * For safety's sake, we release MultiXactGenLock while sending
     958                 :             :                  * signals, warnings, etc.  This is not so much because we care about
     959                 :             :                  * preserving concurrency in this situation, as to avoid any
     960                 :             :                  * possibility of deadlock while doing get_database_name(). First,
     961                 :             :                  * copy all the shared values we'll need in this path.
     962                 :             :                  */
     963                 :           0 :                 MultiXactId multiWarnLimit = MultiXactState->multiWarnLimit;
     964                 :           0 :                 MultiXactId multiStopLimit = MultiXactState->multiStopLimit;
     965                 :           0 :                 MultiXactId multiWrapLimit = MultiXactState->multiWrapLimit;
     966                 :           0 :                 Oid                     oldest_datoid = MultiXactState->oldestMultiXactDB;
     967                 :             : 
     968                 :           0 :                 LWLockRelease(MultiXactGenLock);
     969                 :             : 
     970   [ #  #  #  # ]:           0 :                 if (IsUnderPostmaster &&
     971                 :           0 :                         !MultiXactIdPrecedes(result, multiStopLimit))
     972                 :             :                 {
     973                 :           0 :                         char       *oldest_datname = get_database_name(oldest_datoid);
     974                 :             : 
     975                 :             :                         /*
     976                 :             :                          * Immediately kick autovacuum into action as we're already in
     977                 :             :                          * ERROR territory.
     978                 :             :                          */
     979                 :           0 :                         SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
     980                 :             : 
     981                 :             :                         /* complain even if that DB has disappeared */
     982         [ #  # ]:           0 :                         if (oldest_datname)
     983   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     984                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     985                 :             :                                                  errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database \"%s\"",
     986                 :             :                                                                 oldest_datname),
     987                 :             :                                                  errhint("Execute a database-wide VACUUM in that database.\n"
     988                 :             :                                                                  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
     989                 :             :                         else
     990   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     991                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     992                 :             :                                                  errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database with OID %u",
     993                 :             :                                                                 oldest_datoid),
     994                 :             :                                                  errhint("Execute a database-wide VACUUM in that database.\n"
     995                 :             :                                                                  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
     996                 :           0 :                 }
     997                 :             : 
     998                 :             :                 /*
     999                 :             :                  * To avoid swamping the postmaster with signals, we issue the autovac
    1000                 :             :                  * request only once per 64K multis generated.  This still gives
    1001                 :             :                  * plenty of chances before we get into real trouble.
    1002                 :             :                  */
    1003   [ #  #  #  #  :           0 :                 if (IsUnderPostmaster && ((result % 65536) == 0 || result == FirstMultiXactId))
                   #  # ]
    1004                 :           0 :                         SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
    1005                 :             : 
    1006         [ #  # ]:           0 :                 if (!MultiXactIdPrecedes(result, multiWarnLimit))
    1007                 :             :                 {
    1008                 :           0 :                         char       *oldest_datname = get_database_name(oldest_datoid);
    1009                 :             : 
    1010                 :             :                         /* complain even if that DB has disappeared */
    1011         [ #  # ]:           0 :                         if (oldest_datname)
    1012   [ #  #  #  # ]:           0 :                                 ereport(WARNING,
    1013                 :             :                                                 (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
    1014                 :             :                                                                            "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
    1015                 :             :                                                                            multiWrapLimit - result,
    1016                 :             :                                                                            oldest_datname,
    1017                 :             :                                                                            multiWrapLimit - result),
    1018                 :             :                                                  errhint("Execute a database-wide VACUUM in that database.\n"
    1019                 :             :                                                                  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
    1020                 :             :                         else
    1021   [ #  #  #  # ]:           0 :                                 ereport(WARNING,
    1022                 :             :                                                 (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
    1023                 :             :                                                                            "database with OID %u must be vacuumed before %u more MultiXactIds are used",
    1024                 :             :                                                                            multiWrapLimit - result,
    1025                 :             :                                                                            oldest_datoid,
    1026                 :             :                                                                            multiWrapLimit - result),
    1027                 :             :                                                  errhint("Execute a database-wide VACUUM in that database.\n"
    1028                 :             :                                                                  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
    1029                 :           0 :                 }
    1030                 :             : 
    1031                 :             :                 /* Re-acquire lock and start over */
    1032                 :           0 :                 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    1033                 :           0 :                 result = MultiXactState->nextMXact;
    1034                 :           0 :         }
    1035                 :             : 
    1036                 :             :         /*
    1037                 :             :          * Make sure there is room for the next MXID in the file.  Assigning this
    1038                 :             :          * MXID sets the next MXID's offset already.
    1039                 :             :          */
    1040                 :           2 :         ExtendMultiXactOffset(NextMultiXactId(result));
    1041                 :             : 
    1042                 :             :         /*
    1043                 :             :          * Reserve the members space, similarly to above.
    1044                 :             :          */
    1045                 :           2 :         nextOffset = MultiXactState->nextOffset;
    1046                 :             : 
    1047                 :             :         /*
    1048                 :             :          * Offsets are 64-bit integers and will never wrap around.  Firstly, it
    1049                 :             :          * would take an unrealistic amount of time and resources to consume 2^64
    1050                 :             :          * offsets.  Secondly, multixid creation is WAL-logged, so you would run
    1051                 :             :          * out of LSNs before reaching offset wraparound.  Nevertheless, check for
    1052                 :             :          * wraparound as a sanity check.
    1053                 :             :          */
    1054         [ +  - ]:           2 :         if (nextOffset + nmembers < nextOffset)
    1055   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1056                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1057                 :             :                                  errmsg("MultiXact members would wrap around")));
    1058                 :           2 :         *offset = nextOffset;
    1059                 :             : 
    1060                 :           2 :         ExtendMultiXactMember(nextOffset, nmembers);
    1061                 :             : 
    1062                 :             :         /*
    1063                 :             :          * Critical section from here until caller has written the data into the
    1064                 :             :          * just-reserved SLRU space; we don't want to error out with a partly
    1065                 :             :          * written MultiXact structure.  (In particular, failing to write our
    1066                 :             :          * start offset after advancing nextMXact would effectively corrupt the
    1067                 :             :          * previous MultiXact.)
    1068                 :             :          */
    1069                 :           2 :         START_CRIT_SECTION();
    1070                 :             : 
    1071                 :             :         /*
    1072                 :             :          * Advance counters.  As in GetNewTransactionId(), this must not happen
    1073                 :             :          * until after file extension has succeeded!
    1074                 :             :          */
    1075                 :           2 :         MultiXactState->nextMXact = NextMultiXactId(result);
    1076                 :           2 :         MultiXactState->nextOffset += nmembers;
    1077                 :             : 
    1078                 :           2 :         LWLockRelease(MultiXactGenLock);
    1079                 :             : 
    1080                 :             :         debug_elog4(DEBUG2, "GetNew: returning %u offset %" PRIu64,
    1081                 :             :                                 result, *offset);
    1082                 :           4 :         return result;
    1083                 :           2 : }
    1084                 :             : 
    1085                 :             : /*
    1086                 :             :  * GetMultiXactIdMembers
    1087                 :             :  *              Return the set of MultiXactMembers that make up a MultiXactId
    1088                 :             :  *
    1089                 :             :  * Return value is the number of members found, or -1 if there are none,
    1090                 :             :  * and *members is set to a newly palloc'ed array of members.  It's the
    1091                 :             :  * caller's responsibility to free it when done with it.
    1092                 :             :  *
    1093                 :             :  * from_pgupgrade must be passed as true if and only if only the multixact
    1094                 :             :  * corresponds to a value from a tuple that was locked in a 9.2-or-older
    1095                 :             :  * installation and later pg_upgrade'd (that is, the infomask is
    1096                 :             :  * HEAP_LOCKED_UPGRADED).  In this case, we know for certain that no members
    1097                 :             :  * can still be running, so we return -1 just like for an empty multixact
    1098                 :             :  * without any further checking.  It would be wrong to try to resolve such a
    1099                 :             :  * multixact: either the multixact is within the current valid multixact
    1100                 :             :  * range, in which case the returned result would be bogus, or outside that
    1101                 :             :  * range, in which case an error would be raised.
    1102                 :             :  *
    1103                 :             :  * In all other cases, the passed multixact must be within the known valid
    1104                 :             :  * range, that is, greater than or equal to oldestMultiXactId, and less than
    1105                 :             :  * nextMXact.  Otherwise, an error is raised.
    1106                 :             :  *
    1107                 :             :  * isLockOnly must be set to true if caller is certain that the given multi
    1108                 :             :  * is used only to lock tuples; can be false without loss of correctness,
    1109                 :             :  * but passing a true means we can return quickly without checking for
    1110                 :             :  * old updates.
    1111                 :             :  */
    1112                 :             : int
    1113                 :          11 : GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
    1114                 :             :                                           bool from_pgupgrade, bool isLockOnly)
    1115                 :             : {
    1116                 :          11 :         int64           pageno;
    1117                 :          11 :         int64           prev_pageno;
    1118                 :          11 :         int                     entryno;
    1119                 :          11 :         int                     slotno;
    1120                 :          11 :         MultiXactOffset *offptr;
    1121                 :          11 :         MultiXactOffset offset;
    1122                 :          11 :         MultiXactOffset nextMXOffset;
    1123                 :          11 :         int                     length;
    1124                 :          11 :         MultiXactId oldestMXact;
    1125                 :          11 :         MultiXactId nextMXact;
    1126                 :          11 :         MultiXactMember *ptr;
    1127                 :          11 :         LWLock     *lock;
    1128                 :             : 
    1129                 :             :         debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
    1130                 :             : 
    1131   [ +  -  -  + ]:          11 :         if (!MultiXactIdIsValid(multi) || from_pgupgrade)
    1132                 :             :         {
    1133                 :           0 :                 *members = NULL;
    1134                 :           0 :                 return -1;
    1135                 :             :         }
    1136                 :             : 
    1137                 :             :         /* See if the MultiXactId is in the local cache */
    1138                 :          11 :         length = mXactCacheGetById(multi, members);
    1139         [ +  - ]:          11 :         if (length >= 0)
    1140                 :             :         {
    1141                 :             :                 debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
    1142                 :             :                                         mxid_to_string(multi, length, *members));
    1143                 :          11 :                 return length;
    1144                 :             :         }
    1145                 :             : 
    1146                 :             :         /* Set our OldestVisibleMXactId[] entry if we didn't already */
    1147                 :           0 :         MultiXactIdSetOldestVisible();
    1148                 :             : 
    1149                 :             :         /*
    1150                 :             :          * If we know the multi is used only for locking and not for updates, then
    1151                 :             :          * we can skip checking if the value is older than our oldest visible
    1152                 :             :          * multi.  It cannot possibly still be running.
    1153                 :             :          */
    1154   [ #  #  #  # ]:           0 :         if (isLockOnly &&
    1155                 :           0 :                 MultiXactIdPrecedes(multi, OldestVisibleMXactId[MyProcNumber]))
    1156                 :             :         {
    1157                 :             :                 debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
    1158                 :           0 :                 *members = NULL;
    1159                 :           0 :                 return -1;
    1160                 :             :         }
    1161                 :             : 
    1162                 :             :         /*
    1163                 :             :          * We check known limits on MultiXact before resorting to the SLRU area.
    1164                 :             :          *
    1165                 :             :          * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
    1166                 :             :          * useful; it has already been removed, or will be removed shortly, by
    1167                 :             :          * truncation.  If one is passed, an error is raised.
    1168                 :             :          *
    1169                 :             :          * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
    1170                 :             :          * implies undetected ID wraparound has occurred.  This raises a hard
    1171                 :             :          * error.
    1172                 :             :          *
    1173                 :             :          * Shared lock is enough here since we aren't modifying any global state.
    1174                 :             :          * Acquire it just long enough to grab the current counter values.
    1175                 :             :          */
    1176                 :           0 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
    1177                 :             : 
    1178                 :           0 :         oldestMXact = MultiXactState->oldestMultiXactId;
    1179                 :           0 :         nextMXact = MultiXactState->nextMXact;
    1180                 :             : 
    1181                 :           0 :         LWLockRelease(MultiXactGenLock);
    1182                 :             : 
    1183         [ #  # ]:           0 :         if (MultiXactIdPrecedes(multi, oldestMXact))
    1184   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1185                 :             :                                 (errcode(ERRCODE_INTERNAL_ERROR),
    1186                 :             :                                  errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
    1187                 :             :                                                 multi)));
    1188                 :             : 
    1189         [ #  # ]:           0 :         if (!MultiXactIdPrecedes(multi, nextMXact))
    1190   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1191                 :             :                                 (errcode(ERRCODE_INTERNAL_ERROR),
    1192                 :             :                                  errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
    1193                 :             :                                                 multi)));
    1194                 :             : 
    1195                 :             :         /*
    1196                 :             :          * Find out the offset at which we need to start reading MultiXactMembers
    1197                 :             :          * and the number of members in the multixact.  We determine the latter as
    1198                 :             :          * the difference between this multixact's starting offset and the next
    1199                 :             :          * one's.
    1200                 :             :          */
    1201                 :           0 :         pageno = MultiXactIdToOffsetPage(multi);
    1202                 :           0 :         entryno = MultiXactIdToOffsetEntry(multi);
    1203                 :             : 
    1204                 :             :         /* Acquire the bank lock for the page we need. */
    1205                 :           0 :         lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
    1206                 :           0 :         LWLockAcquire(lock, LW_EXCLUSIVE);
    1207                 :             : 
    1208                 :             :         /* read this multi's offset */
    1209                 :           0 :         slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
    1210                 :           0 :         offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
    1211                 :           0 :         offptr += entryno;
    1212                 :           0 :         offset = *offptr;
    1213                 :             : 
    1214         [ #  # ]:           0 :         if (offset == 0)
    1215   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1216                 :             :                                 (errcode(ERRCODE_DATA_CORRUPTED),
    1217                 :             :                                  errmsg("MultiXact %u has invalid offset", multi)));
    1218                 :             : 
    1219                 :             :         /* read next multi's offset */
    1220                 :             :         {
    1221                 :           0 :                 MultiXactId tmpMXact;
    1222                 :             : 
    1223                 :             :                 /* handle wraparound if needed */
    1224                 :           0 :                 tmpMXact = NextMultiXactId(multi);
    1225                 :             : 
    1226                 :           0 :                 prev_pageno = pageno;
    1227                 :             : 
    1228                 :           0 :                 pageno = MultiXactIdToOffsetPage(tmpMXact);
    1229                 :           0 :                 entryno = MultiXactIdToOffsetEntry(tmpMXact);
    1230                 :             : 
    1231         [ #  # ]:           0 :                 if (pageno != prev_pageno)
    1232                 :             :                 {
    1233                 :           0 :                         LWLock     *newlock;
    1234                 :             : 
    1235                 :             :                         /*
    1236                 :             :                          * Since we're going to access a different SLRU page, if this page
    1237                 :             :                          * falls under a different bank, release the old bank's lock and
    1238                 :             :                          * acquire the lock of the new bank.
    1239                 :             :                          */
    1240                 :           0 :                         newlock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
    1241         [ #  # ]:           0 :                         if (newlock != lock)
    1242                 :             :                         {
    1243                 :           0 :                                 LWLockRelease(lock);
    1244                 :           0 :                                 LWLockAcquire(newlock, LW_EXCLUSIVE);
    1245                 :           0 :                                 lock = newlock;
    1246                 :           0 :                         }
    1247                 :           0 :                         slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
    1248                 :           0 :                 }
    1249                 :             : 
    1250                 :           0 :                 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
    1251                 :           0 :                 offptr += entryno;
    1252                 :           0 :                 nextMXOffset = *offptr;
    1253                 :           0 :         }
    1254                 :             : 
    1255                 :           0 :         LWLockRelease(lock);
    1256                 :           0 :         lock = NULL;
    1257                 :             : 
    1258                 :             :         /* Sanity check the next offset */
    1259         [ #  # ]:           0 :         if (nextMXOffset == 0)
    1260   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1261                 :             :                                 (errcode(ERRCODE_DATA_CORRUPTED),
    1262                 :             :                                  errmsg("MultiXact %u has invalid next offset", multi)));
    1263         [ #  # ]:           0 :         if (nextMXOffset == offset)
    1264   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1265                 :             :                                 (errcode(ERRCODE_DATA_CORRUPTED),
    1266                 :             :                                  errmsg("MultiXact %u with offset (%" PRIu64 ") has zero members",
    1267                 :             :                                                 multi, offset)));
    1268         [ #  # ]:           0 :         if (nextMXOffset < offset)
    1269   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1270                 :             :                                 (errcode(ERRCODE_DATA_CORRUPTED),
    1271                 :             :                                  errmsg("MultiXact %u has offset (%" PRIu64 ") greater than its next offset (%" PRIu64 ")",
    1272                 :             :                                                 multi, offset, nextMXOffset)));
    1273         [ #  # ]:           0 :         if (nextMXOffset - offset > INT32_MAX)
    1274   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1275                 :             :                                 (errcode(ERRCODE_DATA_CORRUPTED),
    1276                 :             :                                  errmsg("MultiXact %u has too many members (%" PRIu64 ")",
    1277                 :             :                                                 multi, nextMXOffset - offset)));
    1278                 :           0 :         length = nextMXOffset - offset;
    1279                 :             : 
    1280                 :             :         /* read the members */
    1281                 :           0 :         ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
    1282                 :           0 :         prev_pageno = -1;
    1283         [ #  # ]:           0 :         for (int i = 0; i < length; i++, offset++)
    1284                 :             :         {
    1285                 :           0 :                 TransactionId *xactptr;
    1286                 :           0 :                 uint32     *flagsptr;
    1287                 :           0 :                 int                     flagsoff;
    1288                 :           0 :                 int                     bshift;
    1289                 :           0 :                 int                     memberoff;
    1290                 :             : 
    1291                 :           0 :                 pageno = MXOffsetToMemberPage(offset);
    1292                 :           0 :                 memberoff = MXOffsetToMemberOffset(offset);
    1293                 :             : 
    1294         [ #  # ]:           0 :                 if (pageno != prev_pageno)
    1295                 :             :                 {
    1296                 :           0 :                         LWLock     *newlock;
    1297                 :             : 
    1298                 :             :                         /*
    1299                 :             :                          * Since we're going to access a different SLRU page, if this page
    1300                 :             :                          * falls under a different bank, release the old bank's lock and
    1301                 :             :                          * acquire the lock of the new bank.
    1302                 :             :                          */
    1303                 :           0 :                         newlock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
    1304         [ #  # ]:           0 :                         if (newlock != lock)
    1305                 :             :                         {
    1306         [ #  # ]:           0 :                                 if (lock)
    1307                 :           0 :                                         LWLockRelease(lock);
    1308                 :           0 :                                 LWLockAcquire(newlock, LW_EXCLUSIVE);
    1309                 :           0 :                                 lock = newlock;
    1310                 :           0 :                         }
    1311                 :             : 
    1312                 :           0 :                         slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
    1313                 :           0 :                         prev_pageno = pageno;
    1314                 :           0 :                 }
    1315                 :             : 
    1316                 :           0 :                 xactptr = (TransactionId *)
    1317                 :           0 :                         (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
    1318         [ #  # ]:           0 :                 Assert(TransactionIdIsValid(*xactptr));
    1319                 :             : 
    1320                 :           0 :                 flagsoff = MXOffsetToFlagsOffset(offset);
    1321                 :           0 :                 bshift = MXOffsetToFlagsBitShift(offset);
    1322                 :           0 :                 flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
    1323                 :             : 
    1324                 :           0 :                 ptr[i].xid = *xactptr;
    1325                 :           0 :                 ptr[i].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
    1326                 :           0 :         }
    1327                 :             : 
    1328                 :           0 :         LWLockRelease(lock);
    1329                 :             : 
    1330                 :             :         /*
    1331                 :             :          * Copy the result into the local cache.
    1332                 :             :          */
    1333                 :           0 :         mXactCachePut(multi, length, ptr);
    1334                 :             : 
    1335                 :             :         debug_elog3(DEBUG2, "GetMembers: no cache for %s",
    1336                 :             :                                 mxid_to_string(multi, length, ptr));
    1337                 :           0 :         *members = ptr;
    1338                 :           0 :         return length;
    1339                 :          11 : }
    1340                 :             : 
    1341                 :             : /*
    1342                 :             :  * mxactMemberComparator
    1343                 :             :  *              qsort comparison function for MultiXactMember
    1344                 :             :  *
    1345                 :             :  * We can't use wraparound comparison for XIDs because that does not respect
    1346                 :             :  * the triangle inequality!  Any old sort order will do.
    1347                 :             :  */
    1348                 :             : static int
    1349                 :           4 : mxactMemberComparator(const void *arg1, const void *arg2)
    1350                 :             : {
    1351                 :           4 :         MultiXactMember member1 = *(const MultiXactMember *) arg1;
    1352                 :           4 :         MultiXactMember member2 = *(const MultiXactMember *) arg2;
    1353                 :             : 
    1354         [ -  + ]:           4 :         if (member1.xid > member2.xid)
    1355                 :           0 :                 return 1;
    1356         [ +  - ]:           4 :         if (member1.xid < member2.xid)
    1357                 :           4 :                 return -1;
    1358         [ #  # ]:           0 :         if (member1.status > member2.status)
    1359                 :           0 :                 return 1;
    1360         [ #  # ]:           0 :         if (member1.status < member2.status)
    1361                 :           0 :                 return -1;
    1362                 :           0 :         return 0;
    1363                 :           4 : }
    1364                 :             : 
    1365                 :             : /*
    1366                 :             :  * mXactCacheGetBySet
    1367                 :             :  *              returns a MultiXactId from the cache based on the set of
    1368                 :             :  *              TransactionIds that compose it, or InvalidMultiXactId if
    1369                 :             :  *              none matches.
    1370                 :             :  *
    1371                 :             :  * This is helpful, for example, if two transactions want to lock a huge
    1372                 :             :  * table.  By using the cache, the second will use the same MultiXactId
    1373                 :             :  * for the majority of tuples, thus keeping MultiXactId usage low (saving
    1374                 :             :  * both I/O and wraparound issues).
    1375                 :             :  *
    1376                 :             :  * NB: the passed members array will be sorted in-place.
    1377                 :             :  */
    1378                 :             : static MultiXactId
    1379                 :           2 : mXactCacheGetBySet(int nmembers, MultiXactMember *members)
    1380                 :             : {
    1381                 :           2 :         dlist_iter      iter;
    1382                 :             : 
    1383                 :             :         debug_elog3(DEBUG2, "CacheGet: looking for %s",
    1384                 :             :                                 mxid_to_string(InvalidMultiXactId, nmembers, members));
    1385                 :             : 
    1386                 :             :         /* sort the array so comparison is easy */
    1387                 :           2 :         qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
    1388                 :             : 
    1389   [ +  -  +  + ]:           3 :         dclist_foreach(iter, &MXactCache)
    1390                 :             :         {
    1391                 :           1 :                 mXactCacheEnt *entry = dclist_container(mXactCacheEnt, node,
    1392                 :             :                                                                                                 iter.cur);
    1393                 :             : 
    1394         [ -  + ]:           1 :                 if (entry->nmembers != nmembers)
    1395                 :           0 :                         continue;
    1396                 :             : 
    1397                 :             :                 /*
    1398                 :             :                  * We assume the cache entries are sorted, and that the unused bits in
    1399                 :             :                  * "status" are zeroed.
    1400                 :             :                  */
    1401         [ +  - ]:           1 :                 if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
    1402                 :             :                 {
    1403                 :             :                         debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
    1404                 :           0 :                         dclist_move_head(&MXactCache, iter.cur);
    1405                 :           0 :                         return entry->multi;
    1406                 :             :                 }
    1407      [ -  -  + ]:           1 :         }
    1408                 :             : 
    1409                 :             :         debug_elog2(DEBUG2, "CacheGet: not found :-(");
    1410                 :           2 :         return InvalidMultiXactId;
    1411                 :           2 : }
    1412                 :             : 
    1413                 :             : /*
    1414                 :             :  * mXactCacheGetById
    1415                 :             :  *              returns the composing MultiXactMember set from the cache for a
    1416                 :             :  *              given MultiXactId, if present.
    1417                 :             :  *
    1418                 :             :  * If successful, *xids is set to the address of a palloc'd copy of the
    1419                 :             :  * MultiXactMember set.  Return value is number of members, or -1 on failure.
    1420                 :             :  */
    1421                 :             : static int
    1422                 :          11 : mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
    1423                 :             : {
    1424                 :          11 :         dlist_iter      iter;
    1425                 :             : 
    1426                 :             :         debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
    1427                 :             : 
    1428   [ +  -  +  - ]:          11 :         dclist_foreach(iter, &MXactCache)
    1429                 :             :         {
    1430                 :          11 :                 mXactCacheEnt *entry = dclist_container(mXactCacheEnt, node,
    1431                 :             :                                                                                                 iter.cur);
    1432                 :             : 
    1433         [ +  - ]:          11 :                 if (entry->multi == multi)
    1434                 :             :                 {
    1435                 :          11 :                         MultiXactMember *ptr;
    1436                 :          11 :                         Size            size;
    1437                 :             : 
    1438                 :          11 :                         size = sizeof(MultiXactMember) * entry->nmembers;
    1439                 :          11 :                         ptr = (MultiXactMember *) palloc(size);
    1440                 :             : 
    1441                 :          11 :                         memcpy(ptr, entry->members, size);
    1442                 :             : 
    1443                 :             :                         debug_elog3(DEBUG2, "CacheGet: found %s",
    1444                 :             :                                                 mxid_to_string(multi,
    1445                 :             :                                                                            entry->nmembers,
    1446                 :             :                                                                            entry->members));
    1447                 :             : 
    1448                 :             :                         /*
    1449                 :             :                          * Note we modify the list while not using a modifiable iterator.
    1450                 :             :                          * This is acceptable only because we exit the iteration
    1451                 :             :                          * immediately afterwards.
    1452                 :             :                          */
    1453                 :          11 :                         dclist_move_head(&MXactCache, iter.cur);
    1454                 :             : 
    1455                 :          11 :                         *members = ptr;
    1456                 :          11 :                         return entry->nmembers;
    1457                 :          11 :                 }
    1458         [ +  - ]:          11 :         }
    1459                 :             : 
    1460                 :             :         debug_elog2(DEBUG2, "CacheGet: not found");
    1461                 :           0 :         return -1;
    1462                 :          11 : }
    1463                 :             : 
    1464                 :             : /*
    1465                 :             :  * mXactCachePut
    1466                 :             :  *              Add a new MultiXactId and its composing set into the local cache.
    1467                 :             :  */
    1468                 :             : static void
    1469                 :           2 : mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
    1470                 :             : {
    1471                 :           2 :         mXactCacheEnt *entry;
    1472                 :             : 
    1473                 :             :         debug_elog3(DEBUG2, "CachePut: storing %s",
    1474                 :             :                                 mxid_to_string(multi, nmembers, members));
    1475                 :             : 
    1476         [ +  + ]:           2 :         if (MXactContext == NULL)
    1477                 :             :         {
    1478                 :             :                 /* The cache only lives as long as the current transaction */
    1479                 :             :                 debug_elog2(DEBUG2, "CachePut: initializing memory context");
    1480                 :           1 :                 MXactContext = AllocSetContextCreate(TopTransactionContext,
    1481                 :             :                                                                                          "MultiXact cache context",
    1482                 :             :                                                                                          ALLOCSET_SMALL_SIZES);
    1483                 :           1 :         }
    1484                 :             : 
    1485                 :           2 :         entry = (mXactCacheEnt *)
    1486                 :           4 :                 MemoryContextAlloc(MXactContext,
    1487                 :           2 :                                                    offsetof(mXactCacheEnt, members) +
    1488                 :           2 :                                                    nmembers * sizeof(MultiXactMember));
    1489                 :             : 
    1490                 :           2 :         entry->multi = multi;
    1491                 :           2 :         entry->nmembers = nmembers;
    1492                 :           2 :         memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
    1493                 :             : 
    1494                 :             :         /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
    1495                 :           2 :         qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
    1496                 :             : 
    1497                 :           2 :         dclist_push_head(&MXactCache, &entry->node);
    1498         [ +  - ]:           2 :         if (dclist_count(&MXactCache) > MAX_CACHE_ENTRIES)
    1499                 :             :         {
    1500                 :           0 :                 dlist_node *node;
    1501                 :             : 
    1502                 :           0 :                 node = dclist_tail_node(&MXactCache);
    1503                 :           0 :                 dclist_delete_from(&MXactCache, node);
    1504                 :             : 
    1505                 :           0 :                 entry = dclist_container(mXactCacheEnt, node, node);
    1506                 :             :                 debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
    1507                 :             :                                         entry->multi);
    1508                 :             : 
    1509                 :           0 :                 pfree(entry);
    1510                 :           0 :         }
    1511                 :           2 : }
    1512                 :             : 
    1513                 :             : char *
    1514                 :           0 : mxstatus_to_string(MultiXactStatus status)
    1515                 :             : {
    1516   [ #  #  #  #  :           0 :         switch (status)
                #  #  # ]
    1517                 :             :         {
    1518                 :             :                 case MultiXactStatusForKeyShare:
    1519                 :           0 :                         return "keysh";
    1520                 :             :                 case MultiXactStatusForShare:
    1521                 :           0 :                         return "sh";
    1522                 :             :                 case MultiXactStatusForNoKeyUpdate:
    1523                 :           0 :                         return "fornokeyupd";
    1524                 :             :                 case MultiXactStatusForUpdate:
    1525                 :           0 :                         return "forupd";
    1526                 :             :                 case MultiXactStatusNoKeyUpdate:
    1527                 :           0 :                         return "nokeyupd";
    1528                 :             :                 case MultiXactStatusUpdate:
    1529                 :           0 :                         return "upd";
    1530                 :             :                 default:
    1531   [ #  #  #  # ]:           0 :                         elog(ERROR, "unrecognized multixact status %d", status);
    1532                 :           0 :                         return "";
    1533                 :             :         }
    1534                 :           0 : }
    1535                 :             : 
    1536                 :             : char *
    1537                 :           0 : mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
    1538                 :             : {
    1539                 :             :         static char *str = NULL;
    1540                 :           0 :         StringInfoData buf;
    1541                 :           0 :         int                     i;
    1542                 :             : 
    1543         [ #  # ]:           0 :         if (str != NULL)
    1544                 :           0 :                 pfree(str);
    1545                 :             : 
    1546                 :           0 :         initStringInfo(&buf);
    1547                 :             : 
    1548                 :           0 :         appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
    1549                 :           0 :                                          mxstatus_to_string(members[0].status));
    1550                 :             : 
    1551         [ #  # ]:           0 :         for (i = 1; i < nmembers; i++)
    1552                 :           0 :                 appendStringInfo(&buf, ", %u (%s)", members[i].xid,
    1553                 :           0 :                                                  mxstatus_to_string(members[i].status));
    1554                 :             : 
    1555                 :           0 :         appendStringInfoChar(&buf, ']');
    1556                 :           0 :         str = MemoryContextStrdup(TopMemoryContext, buf.data);
    1557                 :           0 :         pfree(buf.data);
    1558                 :           0 :         return str;
    1559                 :           0 : }
    1560                 :             : 
    1561                 :             : /*
    1562                 :             :  * AtEOXact_MultiXact
    1563                 :             :  *              Handle transaction end for MultiXact
    1564                 :             :  *
    1565                 :             :  * This is called at top transaction commit or abort (we don't care which).
    1566                 :             :  */
    1567                 :             : void
    1568                 :       57917 : AtEOXact_MultiXact(void)
    1569                 :             : {
    1570                 :             :         /*
    1571                 :             :          * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
    1572                 :             :          * which should only be valid while within a transaction.
    1573                 :             :          *
    1574                 :             :          * We assume that storing a MultiXactId is atomic and so we need not take
    1575                 :             :          * MultiXactGenLock to do this.
    1576                 :             :          */
    1577                 :       57917 :         OldestMemberMXactId[MyProcNumber] = InvalidMultiXactId;
    1578                 :       57917 :         OldestVisibleMXactId[MyProcNumber] = InvalidMultiXactId;
    1579                 :             : 
    1580                 :             :         /*
    1581                 :             :          * Discard the local MultiXactId cache.  Since MXactContext was created as
    1582                 :             :          * a child of TopTransactionContext, we needn't delete it explicitly.
    1583                 :             :          */
    1584                 :       57917 :         MXactContext = NULL;
    1585                 :       57917 :         dclist_init(&MXactCache);
    1586                 :       57917 : }
    1587                 :             : 
    1588                 :             : /*
    1589                 :             :  * AtPrepare_MultiXact
    1590                 :             :  *              Save multixact state at 2PC transaction prepare
    1591                 :             :  *
    1592                 :             :  * In this phase, we only store our OldestMemberMXactId value in the two-phase
    1593                 :             :  * state file.
    1594                 :             :  */
    1595                 :             : void
    1596                 :           0 : AtPrepare_MultiXact(void)
    1597                 :             : {
    1598                 :           0 :         MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
    1599                 :             : 
    1600         [ #  # ]:           0 :         if (MultiXactIdIsValid(myOldestMember))
    1601                 :           0 :                 RegisterTwoPhaseRecord(TWOPHASE_RM_MULTIXACT_ID, 0,
    1602                 :             :                                                            &myOldestMember, sizeof(MultiXactId));
    1603                 :           0 : }
    1604                 :             : 
    1605                 :             : /*
    1606                 :             :  * PostPrepare_MultiXact
    1607                 :             :  *              Clean up after successful PREPARE TRANSACTION
    1608                 :             :  */
    1609                 :             : void
    1610                 :           0 : PostPrepare_MultiXact(FullTransactionId fxid)
    1611                 :             : {
    1612                 :           0 :         MultiXactId myOldestMember;
    1613                 :             : 
    1614                 :             :         /*
    1615                 :             :          * Transfer our OldestMemberMXactId value to the slot reserved for the
    1616                 :             :          * prepared transaction.
    1617                 :             :          */
    1618                 :           0 :         myOldestMember = OldestMemberMXactId[MyProcNumber];
    1619         [ #  # ]:           0 :         if (MultiXactIdIsValid(myOldestMember))
    1620                 :             :         {
    1621                 :           0 :                 ProcNumber      dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, false);
    1622                 :             : 
    1623                 :             :                 /*
    1624                 :             :                  * Even though storing MultiXactId is atomic, acquire lock to make
    1625                 :             :                  * sure others see both changes, not just the reset of the slot of the
    1626                 :             :                  * current backend. Using a volatile pointer might suffice, but this
    1627                 :             :                  * isn't a hot spot.
    1628                 :             :                  */
    1629                 :           0 :                 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    1630                 :             : 
    1631                 :           0 :                 OldestMemberMXactId[dummyProcNumber] = myOldestMember;
    1632                 :           0 :                 OldestMemberMXactId[MyProcNumber] = InvalidMultiXactId;
    1633                 :             : 
    1634                 :           0 :                 LWLockRelease(MultiXactGenLock);
    1635                 :           0 :         }
    1636                 :             : 
    1637                 :             :         /*
    1638                 :             :          * We don't need to transfer OldestVisibleMXactId value, because the
    1639                 :             :          * transaction is not going to be looking at any more multixacts once it's
    1640                 :             :          * prepared.
    1641                 :             :          *
    1642                 :             :          * We assume that storing a MultiXactId is atomic and so we need not take
    1643                 :             :          * MultiXactGenLock to do this.
    1644                 :             :          */
    1645                 :           0 :         OldestVisibleMXactId[MyProcNumber] = InvalidMultiXactId;
    1646                 :             : 
    1647                 :             :         /*
    1648                 :             :          * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
    1649                 :             :          */
    1650                 :           0 :         MXactContext = NULL;
    1651                 :           0 :         dclist_init(&MXactCache);
    1652                 :           0 : }
    1653                 :             : 
    1654                 :             : /*
    1655                 :             :  * multixact_twophase_recover
    1656                 :             :  *              Recover the state of a prepared transaction at startup
    1657                 :             :  */
    1658                 :             : void
    1659                 :           0 : multixact_twophase_recover(FullTransactionId fxid, uint16 info,
    1660                 :             :                                                    void *recdata, uint32 len)
    1661                 :             : {
    1662                 :           0 :         ProcNumber      dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, false);
    1663                 :           0 :         MultiXactId oldestMember;
    1664                 :             : 
    1665                 :             :         /*
    1666                 :             :          * Get the oldest member XID from the state file record, and set it in the
    1667                 :             :          * OldestMemberMXactId slot reserved for this prepared transaction.
    1668                 :             :          */
    1669         [ #  # ]:           0 :         Assert(len == sizeof(MultiXactId));
    1670                 :           0 :         oldestMember = *((MultiXactId *) recdata);
    1671                 :             : 
    1672                 :           0 :         OldestMemberMXactId[dummyProcNumber] = oldestMember;
    1673                 :           0 : }
    1674                 :             : 
    1675                 :             : /*
    1676                 :             :  * multixact_twophase_postcommit
    1677                 :             :  *              Similar to AtEOXact_MultiXact but for COMMIT PREPARED
    1678                 :             :  */
    1679                 :             : void
    1680                 :           0 : multixact_twophase_postcommit(FullTransactionId fxid, uint16 info,
    1681                 :             :                                                           void *recdata, uint32 len)
    1682                 :             : {
    1683                 :           0 :         ProcNumber      dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, true);
    1684                 :             : 
    1685         [ #  # ]:           0 :         Assert(len == sizeof(MultiXactId));
    1686                 :             : 
    1687                 :           0 :         OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
    1688                 :           0 : }
    1689                 :             : 
    1690                 :             : /*
    1691                 :             :  * multixact_twophase_postabort
    1692                 :             :  *              This is actually just the same as the COMMIT case.
    1693                 :             :  */
    1694                 :             : void
    1695                 :           0 : multixact_twophase_postabort(FullTransactionId fxid, uint16 info,
    1696                 :             :                                                          void *recdata, uint32 len)
    1697                 :             : {
    1698                 :           0 :         multixact_twophase_postcommit(fxid, info, recdata, len);
    1699                 :           0 : }
    1700                 :             : 
    1701                 :             : /*
    1702                 :             :  * Initialization of shared memory for MultiXact.  We use two SLRU areas,
    1703                 :             :  * thus double memory.  Also, reserve space for the shared MultiXactState
    1704                 :             :  * struct and the per-backend MultiXactId arrays (two of those, too).
    1705                 :             :  */
    1706                 :             : Size
    1707                 :           9 : MultiXactShmemSize(void)
    1708                 :             : {
    1709                 :           9 :         Size            size;
    1710                 :             : 
    1711                 :             :         /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
    1712                 :             : #define SHARED_MULTIXACT_STATE_SIZE \
    1713                 :             :         add_size(offsetof(MultiXactStateData, perBackendXactIds), \
    1714                 :             :                          mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
    1715                 :             : 
    1716                 :           9 :         size = SHARED_MULTIXACT_STATE_SIZE;
    1717                 :           9 :         size = add_size(size, SimpleLruShmemSize(multixact_offset_buffers, 0));
    1718                 :           9 :         size = add_size(size, SimpleLruShmemSize(multixact_member_buffers, 0));
    1719                 :             : 
    1720                 :          18 :         return size;
    1721                 :           9 : }
    1722                 :             : 
    1723                 :             : void
    1724                 :           6 : MultiXactShmemInit(void)
    1725                 :             : {
    1726                 :           6 :         bool            found;
    1727                 :             : 
    1728                 :             :         debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
    1729                 :             : 
    1730                 :           6 :         MultiXactOffsetCtl->PagePrecedes = MultiXactOffsetPagePrecedes;
    1731                 :           6 :         MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
    1732                 :             : 
    1733                 :           6 :         SimpleLruInit(MultiXactOffsetCtl,
    1734                 :           6 :                                   "multixact_offset", multixact_offset_buffers, 0,
    1735                 :             :                                   "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
    1736                 :             :                                   LWTRANCHE_MULTIXACTOFFSET_SLRU,
    1737                 :             :                                   SYNC_HANDLER_MULTIXACT_OFFSET,
    1738                 :             :                                   false);
    1739                 :           6 :         SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
    1740                 :           6 :         SimpleLruInit(MultiXactMemberCtl,
    1741                 :           6 :                                   "multixact_member", multixact_member_buffers, 0,
    1742                 :             :                                   "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
    1743                 :             :                                   LWTRANCHE_MULTIXACTMEMBER_SLRU,
    1744                 :             :                                   SYNC_HANDLER_MULTIXACT_MEMBER,
    1745                 :             :                                   true);
    1746                 :             :         /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
    1747                 :             : 
    1748                 :             :         /* Initialize our shared state struct */
    1749                 :           6 :         MultiXactState = ShmemInitStruct("Shared MultiXact State",
    1750                 :           6 :                                                                          SHARED_MULTIXACT_STATE_SIZE,
    1751                 :             :                                                                          &found);
    1752         [ +  - ]:           6 :         if (!IsUnderPostmaster)
    1753                 :             :         {
    1754         [ +  - ]:           6 :                 Assert(!found);
    1755                 :             : 
    1756                 :             :                 /* Make sure we zero out the per-backend state */
    1757   [ +  -  +  -  :           6 :                 MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
          +  -  +  -  #  
                      # ]
    1758                 :           6 :         }
    1759                 :             :         else
    1760         [ #  # ]:           0 :                 Assert(found);
    1761                 :             : 
    1762                 :             :         /*
    1763                 :             :          * Set up array pointers.
    1764                 :             :          */
    1765                 :           6 :         OldestMemberMXactId = MultiXactState->perBackendXactIds;
    1766                 :           6 :         OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot;
    1767                 :           6 : }
    1768                 :             : 
    1769                 :             : /*
    1770                 :             :  * GUC check_hook for multixact_offset_buffers
    1771                 :             :  */
    1772                 :             : bool
    1773                 :           6 : check_multixact_offset_buffers(int *newval, void **extra, GucSource source)
    1774                 :             : {
    1775                 :           6 :         return check_slru_buffers("multixact_offset_buffers", newval);
    1776                 :             : }
    1777                 :             : 
    1778                 :             : /*
    1779                 :             :  * GUC check_hook for multixact_member_buffers
    1780                 :             :  */
    1781                 :             : bool
    1782                 :           6 : check_multixact_member_buffers(int *newval, void **extra, GucSource source)
    1783                 :             : {
    1784                 :           6 :         return check_slru_buffers("multixact_member_buffers", newval);
    1785                 :             : }
    1786                 :             : 
    1787                 :             : /*
    1788                 :             :  * This func must be called ONCE on system install.  It creates the initial
    1789                 :             :  * MultiXact segments.  (The MultiXacts directories are assumed to have been
    1790                 :             :  * created by initdb, and MultiXactShmemInit must have been called already.)
    1791                 :             :  */
    1792                 :             : void
    1793                 :           1 : BootStrapMultiXact(void)
    1794                 :             : {
    1795                 :             :         /* Zero the initial pages and flush them to disk */
    1796                 :           1 :         SimpleLruZeroAndWritePage(MultiXactOffsetCtl, 0);
    1797                 :           1 :         SimpleLruZeroAndWritePage(MultiXactMemberCtl, 0);
    1798                 :           1 : }
    1799                 :             : 
    1800                 :             : /*
    1801                 :             :  * This must be called ONCE during postmaster or standalone-backend startup.
    1802                 :             :  *
    1803                 :             :  * StartupXLOG has already established nextMXact/nextOffset by calling
    1804                 :             :  * MultiXactSetNextMXact and/or MultiXactAdvanceNextMXact, and the oldestMulti
    1805                 :             :  * info from pg_control and/or MultiXactAdvanceOldest, but we haven't yet
    1806                 :             :  * replayed WAL.
    1807                 :             :  */
    1808                 :             : void
    1809                 :           4 : StartupMultiXact(void)
    1810                 :             : {
    1811                 :           4 :         MultiXactId multi = MultiXactState->nextMXact;
    1812                 :           4 :         MultiXactOffset offset = MultiXactState->nextOffset;
    1813                 :           4 :         int64           pageno;
    1814                 :             : 
    1815                 :             :         /*
    1816                 :             :          * Initialize offset's idea of the latest page number.
    1817                 :             :          */
    1818                 :           4 :         pageno = MultiXactIdToOffsetPage(multi);
    1819                 :           8 :         pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
    1820                 :           4 :                                                 pageno);
    1821                 :             : 
    1822                 :             :         /*
    1823                 :             :          * Initialize member's idea of the latest page number.
    1824                 :             :          */
    1825                 :           4 :         pageno = MXOffsetToMemberPage(offset);
    1826                 :           8 :         pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
    1827                 :           4 :                                                 pageno);
    1828                 :           4 : }
    1829                 :             : 
    1830                 :             : /*
    1831                 :             :  * This must be called ONCE at the end of startup/recovery.
    1832                 :             :  */
    1833                 :             : void
    1834                 :           4 : TrimMultiXact(void)
    1835                 :             : {
    1836                 :           4 :         MultiXactId nextMXact;
    1837                 :           4 :         MultiXactOffset offset;
    1838                 :           4 :         MultiXactId oldestMXact;
    1839                 :           4 :         Oid                     oldestMXactDB;
    1840                 :           4 :         int64           pageno;
    1841                 :           4 :         int                     entryno;
    1842                 :           4 :         int                     flagsoff;
    1843                 :             : 
    1844                 :           4 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
    1845                 :           4 :         nextMXact = MultiXactState->nextMXact;
    1846                 :           4 :         offset = MultiXactState->nextOffset;
    1847                 :           4 :         oldestMXact = MultiXactState->oldestMultiXactId;
    1848                 :           4 :         oldestMXactDB = MultiXactState->oldestMultiXactDB;
    1849                 :           4 :         LWLockRelease(MultiXactGenLock);
    1850                 :             : 
    1851                 :             :         /* Clean up offsets state */
    1852                 :             : 
    1853                 :             :         /*
    1854                 :             :          * (Re-)Initialize our idea of the latest page number for offsets.
    1855                 :             :          */
    1856                 :           4 :         pageno = MultiXactIdToOffsetPage(nextMXact);
    1857                 :           8 :         pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
    1858                 :           4 :                                                 pageno);
    1859                 :             : 
    1860                 :             :         /*
    1861                 :             :          * Set the offset of nextMXact on the offsets page.  This is normally done
    1862                 :             :          * in RecordNewMultiXact() of the previous multixact, but let's be sure
    1863                 :             :          * the next page exists, if the nextMXact was reset with pg_resetwal for
    1864                 :             :          * example.
    1865                 :             :          *
    1866                 :             :          * Zero out the remainder of the page.  See notes in TrimCLOG() for
    1867                 :             :          * background.  Unlike CLOG, some WAL record covers every pg_multixact
    1868                 :             :          * SLRU mutation.  Since, also unlike CLOG, we ignore the WAL rule "write
    1869                 :             :          * xlog before data," nextMXact successors may carry obsolete, nonzero
    1870                 :             :          * offset values.
    1871                 :             :          */
    1872                 :           4 :         entryno = MultiXactIdToOffsetEntry(nextMXact);
    1873                 :             :         {
    1874                 :           4 :                 int                     slotno;
    1875                 :           4 :                 MultiXactOffset *offptr;
    1876                 :           4 :                 LWLock     *lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
    1877                 :             : 
    1878                 :           4 :                 LWLockAcquire(lock, LW_EXCLUSIVE);
    1879   [ +  -  +  - ]:           4 :                 if (entryno == 0 || nextMXact == FirstMultiXactId)
    1880                 :           4 :                         slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
    1881                 :             :                 else
    1882                 :           0 :                         slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
    1883                 :           4 :                 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
    1884                 :           4 :                 offptr += entryno;
    1885                 :             : 
    1886                 :           4 :                 *offptr = offset;
    1887   [ +  -  -  + ]:           4 :                 if (entryno != 0 && (entryno + 1) * sizeof(MultiXactOffset) != BLCKSZ)
    1888   [ +  -  +  -  :           4 :                         MemSet(offptr + 1, 0, BLCKSZ - (entryno + 1) * sizeof(MultiXactOffset));
          +  -  +  -  #  
                      # ]
    1889                 :             : 
    1890                 :           4 :                 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
    1891                 :           4 :                 LWLockRelease(lock);
    1892                 :           4 :         }
    1893                 :             : 
    1894                 :             :         /*
    1895                 :             :          * And the same for members.
    1896                 :             :          *
    1897                 :             :          * (Re-)Initialize our idea of the latest page number for members.
    1898                 :             :          */
    1899                 :           4 :         pageno = MXOffsetToMemberPage(offset);
    1900                 :           8 :         pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
    1901                 :           4 :                                                 pageno);
    1902                 :             : 
    1903                 :             :         /*
    1904                 :             :          * Zero out the remainder of the current members page.  See notes in
    1905                 :             :          * TrimCLOG() for motivation.
    1906                 :             :          */
    1907                 :           4 :         flagsoff = MXOffsetToFlagsOffset(offset);
    1908         [ +  - ]:           4 :         if (flagsoff != 0)
    1909                 :             :         {
    1910                 :           0 :                 int                     slotno;
    1911                 :           0 :                 TransactionId *xidptr;
    1912                 :           0 :                 int                     memberoff;
    1913                 :           0 :                 LWLock     *lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
    1914                 :             : 
    1915                 :           0 :                 LWLockAcquire(lock, LW_EXCLUSIVE);
    1916                 :           0 :                 memberoff = MXOffsetToMemberOffset(offset);
    1917                 :           0 :                 slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
    1918                 :           0 :                 xidptr = (TransactionId *)
    1919                 :           0 :                         (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
    1920                 :             : 
    1921   [ #  #  #  #  :           0 :                 MemSet(xidptr, 0, BLCKSZ - memberoff);
          #  #  #  #  #  
                      # ]
    1922                 :             : 
    1923                 :             :                 /*
    1924                 :             :                  * Note: we don't need to zero out the flag bits in the remaining
    1925                 :             :                  * members of the current group, because they are always reset before
    1926                 :             :                  * writing.
    1927                 :             :                  */
    1928                 :             : 
    1929                 :           0 :                 MultiXactMemberCtl->shared->page_dirty[slotno] = true;
    1930                 :           0 :                 LWLockRelease(lock);
    1931                 :           0 :         }
    1932                 :             : 
    1933                 :             :         /* signal that we're officially up */
    1934                 :           4 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    1935                 :           4 :         MultiXactState->finishedStartup = true;
    1936                 :           4 :         LWLockRelease(MultiXactGenLock);
    1937                 :             : 
    1938                 :             :         /* Now compute how far away the next multixid wraparound is. */
    1939                 :           4 :         SetMultiXactIdLimit(oldestMXact, oldestMXactDB);
    1940                 :           4 : }
    1941                 :             : 
    1942                 :             : /*
    1943                 :             :  * Get the MultiXact data to save in a checkpoint record
    1944                 :             :  */
    1945                 :             : void
    1946                 :           7 : MultiXactGetCheckptMulti(bool is_shutdown,
    1947                 :             :                                                  MultiXactId *nextMulti,
    1948                 :             :                                                  MultiXactOffset *nextMultiOffset,
    1949                 :             :                                                  MultiXactId *oldestMulti,
    1950                 :             :                                                  Oid *oldestMultiDB)
    1951                 :             : {
    1952                 :           7 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
    1953                 :           7 :         *nextMulti = MultiXactState->nextMXact;
    1954                 :           7 :         *nextMultiOffset = MultiXactState->nextOffset;
    1955                 :           7 :         *oldestMulti = MultiXactState->oldestMultiXactId;
    1956                 :           7 :         *oldestMultiDB = MultiXactState->oldestMultiXactDB;
    1957                 :           7 :         LWLockRelease(MultiXactGenLock);
    1958                 :             : 
    1959                 :             :         debug_elog6(DEBUG2,
    1960                 :             :                                 "MultiXact: checkpoint is nextMulti %u, nextOffset %" PRIu64 ", oldestMulti %u in DB %u",
    1961                 :             :                                 *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
    1962                 :           7 : }
    1963                 :             : 
    1964                 :             : /*
    1965                 :             :  * Perform a checkpoint --- either during shutdown, or on-the-fly
    1966                 :             :  */
    1967                 :             : void
    1968                 :           7 : CheckPointMultiXact(void)
    1969                 :             : {
    1970                 :           7 :         TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
    1971                 :             : 
    1972                 :             :         /*
    1973                 :             :          * Write dirty MultiXact pages to disk.  This may result in sync requests
    1974                 :             :          * queued for later handling by ProcessSyncRequests(), as part of the
    1975                 :             :          * checkpoint.
    1976                 :             :          */
    1977                 :           7 :         SimpleLruWriteAll(MultiXactOffsetCtl, true);
    1978                 :           7 :         SimpleLruWriteAll(MultiXactMemberCtl, true);
    1979                 :             : 
    1980                 :           7 :         TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
    1981                 :           7 : }
    1982                 :             : 
    1983                 :             : /*
    1984                 :             :  * Set the next-to-be-assigned MultiXactId and offset
    1985                 :             :  *
    1986                 :             :  * This is used when we can determine the correct next ID/offset exactly
    1987                 :             :  * from a checkpoint record.  Although this is only called during bootstrap
    1988                 :             :  * and XLog replay, we take the lock in case any hot-standby backends are
    1989                 :             :  * examining the values.
    1990                 :             :  */
    1991                 :             : void
    1992                 :           5 : MultiXactSetNextMXact(MultiXactId nextMulti,
    1993                 :             :                                           MultiXactOffset nextMultiOffset)
    1994                 :             : {
    1995         [ +  - ]:           5 :         Assert(MultiXactIdIsValid(nextMulti));
    1996                 :             :         debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %" PRIu64,
    1997                 :             :                                 nextMulti, nextMultiOffset);
    1998                 :             : 
    1999                 :           5 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    2000                 :           5 :         MultiXactState->nextMXact = nextMulti;
    2001                 :           5 :         MultiXactState->nextOffset = nextMultiOffset;
    2002                 :           5 :         LWLockRelease(MultiXactGenLock);
    2003                 :           5 : }
    2004                 :             : 
    2005                 :             : /*
    2006                 :             :  * Determine the last safe MultiXactId to allocate given the currently oldest
    2007                 :             :  * datminmxid (ie, the oldest MultiXactId that might exist in any database
    2008                 :             :  * of our cluster), and the OID of the (or a) database with that value.
    2009                 :             :  *
    2010                 :             :  * This also updates MultiXactState->oldestOffset, by looking up the offset of
    2011                 :             :  * MultiXactState->oldestMultiXactId.
    2012                 :             :  */
    2013                 :             : void
    2014                 :          11 : SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
    2015                 :             : {
    2016                 :          11 :         MultiXactId multiVacLimit;
    2017                 :          11 :         MultiXactId multiWarnLimit;
    2018                 :          11 :         MultiXactId multiStopLimit;
    2019                 :          11 :         MultiXactId multiWrapLimit;
    2020                 :          11 :         MultiXactId curMulti;
    2021                 :             : 
    2022         [ +  - ]:          11 :         Assert(MultiXactIdIsValid(oldest_datminmxid));
    2023                 :             : 
    2024                 :             :         /*
    2025                 :             :          * We pretend that a wrap will happen halfway through the multixact ID
    2026                 :             :          * space, but that's not really true, because multixacts wrap differently
    2027                 :             :          * from transaction IDs.
    2028                 :             :          */
    2029                 :          11 :         multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
    2030         [ +  - ]:          11 :         if (multiWrapLimit < FirstMultiXactId)
    2031                 :           0 :                 multiWrapLimit += FirstMultiXactId;
    2032                 :             : 
    2033                 :             :         /*
    2034                 :             :          * We'll refuse to continue assigning MultiXactIds once we get within 3M
    2035                 :             :          * multi of data loss.  See SetTransactionIdLimit.
    2036                 :             :          */
    2037                 :          11 :         multiStopLimit = multiWrapLimit - 3000000;
    2038         [ +  - ]:          11 :         if (multiStopLimit < FirstMultiXactId)
    2039                 :           0 :                 multiStopLimit -= FirstMultiXactId;
    2040                 :             : 
    2041                 :             :         /*
    2042                 :             :          * We'll start complaining loudly when we get within 40M multis of data
    2043                 :             :          * loss.  This is kind of arbitrary, but if you let your gas gauge get
    2044                 :             :          * down to 2% of full, would you be looking for the next gas station?  We
    2045                 :             :          * need to be fairly liberal about this number because there are lots of
    2046                 :             :          * scenarios where most transactions are done by automatic clients that
    2047                 :             :          * won't pay attention to warnings.  (No, we're not gonna make this
    2048                 :             :          * configurable.  If you know enough to configure it, you know enough to
    2049                 :             :          * not get in this kind of trouble in the first place.)
    2050                 :             :          */
    2051                 :          11 :         multiWarnLimit = multiWrapLimit - 40000000;
    2052         [ +  - ]:          11 :         if (multiWarnLimit < FirstMultiXactId)
    2053                 :           0 :                 multiWarnLimit -= FirstMultiXactId;
    2054                 :             : 
    2055                 :             :         /*
    2056                 :             :          * We'll start trying to force autovacuums when oldest_datminmxid gets to
    2057                 :             :          * be more than autovacuum_multixact_freeze_max_age mxids old.
    2058                 :             :          *
    2059                 :             :          * Note: autovacuum_multixact_freeze_max_age is a PGC_POSTMASTER parameter
    2060                 :             :          * so that we don't have to worry about dealing with on-the-fly changes in
    2061                 :             :          * its value.  See SetTransactionIdLimit.
    2062                 :             :          */
    2063                 :          11 :         multiVacLimit = oldest_datminmxid + autovacuum_multixact_freeze_max_age;
    2064         [ +  - ]:          11 :         if (multiVacLimit < FirstMultiXactId)
    2065                 :           0 :                 multiVacLimit += FirstMultiXactId;
    2066                 :             : 
    2067                 :             :         /* Grab lock for just long enough to set the new limit values */
    2068                 :          11 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    2069                 :          11 :         MultiXactState->oldestMultiXactId = oldest_datminmxid;
    2070                 :          11 :         MultiXactState->oldestMultiXactDB = oldest_datoid;
    2071                 :          11 :         MultiXactState->multiVacLimit = multiVacLimit;
    2072                 :          11 :         MultiXactState->multiWarnLimit = multiWarnLimit;
    2073                 :          11 :         MultiXactState->multiStopLimit = multiStopLimit;
    2074                 :          11 :         MultiXactState->multiWrapLimit = multiWrapLimit;
    2075                 :          11 :         curMulti = MultiXactState->nextMXact;
    2076                 :          11 :         LWLockRelease(MultiXactGenLock);
    2077                 :             : 
    2078                 :             :         /* Log the info */
    2079   [ -  +  -  + ]:          11 :         ereport(DEBUG1,
    2080                 :             :                         (errmsg_internal("MultiXactId wrap limit is %u, limited by database with OID %u",
    2081                 :             :                                                          multiWrapLimit, oldest_datoid)));
    2082                 :             : 
    2083                 :             :         /*
    2084                 :             :          * Computing the actual limits is only possible once the data directory is
    2085                 :             :          * in a consistent state. There's no need to compute the limits while
    2086                 :             :          * still replaying WAL - no decisions about new multis are made even
    2087                 :             :          * though multixact creations might be replayed. So we'll only do further
    2088                 :             :          * checks after TrimMultiXact() has been called.
    2089                 :             :          */
    2090         [ +  + ]:          11 :         if (!MultiXactState->finishedStartup)
    2091                 :           5 :                 return;
    2092                 :             : 
    2093         [ +  - ]:           6 :         Assert(!InRecovery);
    2094                 :             : 
    2095                 :             :         /*
    2096                 :             :          * Offsets are 64-bits wide and never wrap around, so we don't need to
    2097                 :             :          * consider them for emergency autovacuum purposes.  But now that we're in
    2098                 :             :          * a consistent state, determine MultiXactState->oldestOffset.  It will be
    2099                 :             :          * used to adjust the freezing cutoff, to keep the offsets disk usage in
    2100                 :             :          * check.
    2101                 :             :          */
    2102                 :           6 :         SetOldestOffset();
    2103                 :             : 
    2104                 :             :         /*
    2105                 :             :          * If past the autovacuum force point, immediately signal an autovac
    2106                 :             :          * request.  The reason for this is that autovac only processes one
    2107                 :             :          * database per invocation.  Once it's finished cleaning up the oldest
    2108                 :             :          * database, it'll call here, and we'll signal the postmaster to start
    2109                 :             :          * another iteration immediately if there are still any old databases.
    2110                 :             :          */
    2111   [ -  +  #  # ]:           6 :         if (MultiXactIdPrecedes(multiVacLimit, curMulti) && IsUnderPostmaster)
    2112                 :           0 :                 SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
    2113                 :             : 
    2114                 :             :         /* Give an immediate warning if past the wrap warn point */
    2115         [ +  - ]:           6 :         if (MultiXactIdPrecedes(multiWarnLimit, curMulti))
    2116                 :             :         {
    2117                 :           0 :                 char       *oldest_datname;
    2118                 :             : 
    2119                 :             :                 /*
    2120                 :             :                  * We can be called when not inside a transaction, for example during
    2121                 :             :                  * StartupXLOG().  In such a case we cannot do database access, so we
    2122                 :             :                  * must just report the oldest DB's OID.
    2123                 :             :                  *
    2124                 :             :                  * Note: it's also possible that get_database_name fails and returns
    2125                 :             :                  * NULL, for example because the database just got dropped.  We'll
    2126                 :             :                  * still warn, even though the warning might now be unnecessary.
    2127                 :             :                  */
    2128         [ #  # ]:           0 :                 if (IsTransactionState())
    2129                 :           0 :                         oldest_datname = get_database_name(oldest_datoid);
    2130                 :             :                 else
    2131                 :           0 :                         oldest_datname = NULL;
    2132                 :             : 
    2133         [ #  # ]:           0 :                 if (oldest_datname)
    2134   [ #  #  #  # ]:           0 :                         ereport(WARNING,
    2135                 :             :                                         (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
    2136                 :             :                                                                    "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
    2137                 :             :                                                                    multiWrapLimit - curMulti,
    2138                 :             :                                                                    oldest_datname,
    2139                 :             :                                                                    multiWrapLimit - curMulti),
    2140                 :             :                                          errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
    2141                 :             :                                                          "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
    2142                 :             :                 else
    2143   [ #  #  #  # ]:           0 :                         ereport(WARNING,
    2144                 :             :                                         (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
    2145                 :             :                                                                    "database with OID %u must be vacuumed before %u more MultiXactIds are used",
    2146                 :             :                                                                    multiWrapLimit - curMulti,
    2147                 :             :                                                                    oldest_datoid,
    2148                 :             :                                                                    multiWrapLimit - curMulti),
    2149                 :             :                                          errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
    2150                 :             :                                                          "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
    2151                 :           0 :         }
    2152         [ -  + ]:          11 : }
    2153                 :             : 
    2154                 :             : /*
    2155                 :             :  * Ensure the next-to-be-assigned MultiXactId is at least minMulti,
    2156                 :             :  * and similarly nextOffset is at least minMultiOffset.
    2157                 :             :  *
    2158                 :             :  * This is used when we can determine minimum safe values from an XLog
    2159                 :             :  * record (either an on-line checkpoint or an mxact creation log entry).
    2160                 :             :  * Although this is only called during XLog replay, we take the lock in case
    2161                 :             :  * any hot-standby backends are examining the values.
    2162                 :             :  */
    2163                 :             : void
    2164                 :           0 : MultiXactAdvanceNextMXact(MultiXactId minMulti,
    2165                 :             :                                                   MultiXactOffset minMultiOffset)
    2166                 :             : {
    2167         [ #  # ]:           0 :         Assert(MultiXactIdIsValid(minMulti));
    2168                 :             : 
    2169                 :           0 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    2170         [ #  # ]:           0 :         if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti))
    2171                 :             :         {
    2172                 :             :                 debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
    2173                 :           0 :                 MultiXactState->nextMXact = minMulti;
    2174                 :           0 :         }
    2175         [ #  # ]:           0 :         if (MultiXactState->nextOffset < minMultiOffset)
    2176                 :             :         {
    2177                 :             :                 debug_elog3(DEBUG2, "MultiXact: setting next offset to %" PRIu64,
    2178                 :             :                                         minMultiOffset);
    2179                 :           0 :                 MultiXactState->nextOffset = minMultiOffset;
    2180                 :           0 :         }
    2181                 :           0 :         LWLockRelease(MultiXactGenLock);
    2182                 :           0 : }
    2183                 :             : 
    2184                 :             : /*
    2185                 :             :  * Update our oldestMultiXactId value, but only if it's more recent than what
    2186                 :             :  * we had.
    2187                 :             :  *
    2188                 :             :  * This may only be called during WAL replay.
    2189                 :             :  */
    2190                 :             : void
    2191                 :           0 : MultiXactAdvanceOldest(MultiXactId oldestMulti, Oid oldestMultiDB)
    2192                 :             : {
    2193         [ #  # ]:           0 :         Assert(InRecovery);
    2194                 :             : 
    2195         [ #  # ]:           0 :         if (MultiXactIdPrecedes(MultiXactState->oldestMultiXactId, oldestMulti))
    2196                 :           0 :                 SetMultiXactIdLimit(oldestMulti, oldestMultiDB);
    2197                 :           0 : }
    2198                 :             : 
    2199                 :             : /*
    2200                 :             :  * Make sure that MultiXactOffset has room for a newly-allocated MultiXactId.
    2201                 :             :  *
    2202                 :             :  * NB: this is called while holding MultiXactGenLock.  We want it to be very
    2203                 :             :  * fast most of the time; even when it's not so fast, no actual I/O need
    2204                 :             :  * happen unless we're forced to write out a dirty log or xlog page to make
    2205                 :             :  * room in shared memory.
    2206                 :             :  */
    2207                 :             : static void
    2208                 :           2 : ExtendMultiXactOffset(MultiXactId multi)
    2209                 :             : {
    2210                 :           2 :         int64           pageno;
    2211                 :           2 :         LWLock     *lock;
    2212                 :             : 
    2213                 :             :         /*
    2214                 :             :          * No work except at first MultiXactId of a page.  But beware: just after
    2215                 :             :          * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
    2216                 :             :          */
    2217   [ +  -  -  + ]:           2 :         if (MultiXactIdToOffsetEntry(multi) != 0 &&
    2218                 :           2 :                 multi != FirstMultiXactId)
    2219                 :           2 :                 return;
    2220                 :             : 
    2221                 :           0 :         pageno = MultiXactIdToOffsetPage(multi);
    2222                 :           0 :         lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
    2223                 :             : 
    2224                 :           0 :         LWLockAcquire(lock, LW_EXCLUSIVE);
    2225                 :             : 
    2226                 :             :         /* Zero the page and make a WAL entry about it */
    2227                 :           0 :         SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
    2228                 :           0 :         XLogSimpleInsertInt64(RM_MULTIXACT_ID, XLOG_MULTIXACT_ZERO_OFF_PAGE,
    2229                 :           0 :                                                   pageno);
    2230                 :             : 
    2231                 :           0 :         LWLockRelease(lock);
    2232         [ -  + ]:           2 : }
    2233                 :             : 
    2234                 :             : /*
    2235                 :             :  * Make sure that MultiXactMember has room for the members of a newly-
    2236                 :             :  * allocated MultiXactId.
    2237                 :             :  *
    2238                 :             :  * Like the above routine, this is called while holding MultiXactGenLock;
    2239                 :             :  * same comments apply.
    2240                 :             :  */
    2241                 :             : static void
    2242                 :           2 : ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
    2243                 :             : {
    2244                 :             :         /*
    2245                 :             :          * It's possible that the members span more than one page of the members
    2246                 :             :          * file, so we loop to ensure we consider each page.  The coding is not
    2247                 :             :          * optimal if the members span several pages, but that seems unusual
    2248                 :             :          * enough to not worry much about.
    2249                 :             :          */
    2250         [ +  + ]:           4 :         while (nmembers > 0)
    2251                 :             :         {
    2252                 :           2 :                 int                     flagsoff;
    2253                 :           2 :                 int                     flagsbit;
    2254                 :           2 :                 uint32          difference;
    2255                 :             : 
    2256                 :             :                 /*
    2257                 :             :                  * Only zero when at first entry of a page.
    2258                 :             :                  */
    2259                 :           2 :                 flagsoff = MXOffsetToFlagsOffset(offset);
    2260                 :           2 :                 flagsbit = MXOffsetToFlagsBitShift(offset);
    2261   [ +  -  +  - ]:           2 :                 if (flagsoff == 0 && flagsbit == 0)
    2262                 :             :                 {
    2263                 :           0 :                         int64           pageno;
    2264                 :           0 :                         LWLock     *lock;
    2265                 :             : 
    2266                 :           0 :                         pageno = MXOffsetToMemberPage(offset);
    2267                 :           0 :                         lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
    2268                 :             : 
    2269                 :           0 :                         LWLockAcquire(lock, LW_EXCLUSIVE);
    2270                 :             : 
    2271                 :             :                         /* Zero the page and make a WAL entry about it */
    2272                 :           0 :                         SimpleLruZeroPage(MultiXactMemberCtl, pageno);
    2273                 :           0 :                         XLogSimpleInsertInt64(RM_MULTIXACT_ID,
    2274                 :           0 :                                                                   XLOG_MULTIXACT_ZERO_MEM_PAGE, pageno);
    2275                 :             : 
    2276                 :           0 :                         LWLockRelease(lock);
    2277                 :           0 :                 }
    2278                 :             : 
    2279                 :             :                 /* Compute the number of items till end of current page. */
    2280                 :           2 :                 difference = MULTIXACT_MEMBERS_PER_PAGE - offset % MULTIXACT_MEMBERS_PER_PAGE;
    2281                 :             : 
    2282                 :             :                 /*
    2283                 :             :                  * Advance to next page.  OK if nmembers goes negative.
    2284                 :             :                  */
    2285                 :           2 :                 nmembers -= difference;
    2286                 :           2 :                 offset += difference;
    2287                 :           2 :         }
    2288                 :           2 : }
    2289                 :             : 
    2290                 :             : /*
    2291                 :             :  * GetOldestMultiXactId
    2292                 :             :  *
    2293                 :             :  * Return the oldest MultiXactId that's still possibly still seen as live by
    2294                 :             :  * any running transaction.  Older ones might still exist on disk, but they no
    2295                 :             :  * longer have any running member transaction.
    2296                 :             :  *
    2297                 :             :  * It's not safe to truncate MultiXact SLRU segments on the value returned by
    2298                 :             :  * this function; however, it can be set as the new relminmxid for any table
    2299                 :             :  * that VACUUM knows has no remaining MXIDs < the same value.  It is only safe
    2300                 :             :  * to truncate SLRUs when no table can possibly still have a referencing MXID.
    2301                 :             :  */
    2302                 :             : MultiXactId
    2303                 :        7324 : GetOldestMultiXactId(void)
    2304                 :             : {
    2305                 :        7324 :         MultiXactId oldestMXact;
    2306                 :        7324 :         int                     i;
    2307                 :             : 
    2308                 :             :         /*
    2309                 :             :          * This is the oldest valid value among all the OldestMemberMXactId[] and
    2310                 :             :          * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
    2311                 :             :          */
    2312                 :        7324 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
    2313                 :        7324 :         oldestMXact = MultiXactState->nextMXact;
    2314         [ +  + ]:      933442 :         for (i = 0; i < MaxOldestSlot; i++)
    2315                 :             :         {
    2316                 :      926118 :                 MultiXactId thisoldest;
    2317                 :             : 
    2318                 :      926118 :                 thisoldest = OldestMemberMXactId[i];
    2319   [ +  +  +  + ]:      926118 :                 if (MultiXactIdIsValid(thisoldest) &&
    2320                 :        6932 :                         MultiXactIdPrecedes(thisoldest, oldestMXact))
    2321                 :          40 :                         oldestMXact = thisoldest;
    2322                 :      926118 :                 thisoldest = OldestVisibleMXactId[i];
    2323   [ -  +  #  # ]:      926118 :                 if (MultiXactIdIsValid(thisoldest) &&
    2324                 :           0 :                         MultiXactIdPrecedes(thisoldest, oldestMXact))
    2325                 :           0 :                         oldestMXact = thisoldest;
    2326                 :      926118 :         }
    2327                 :             : 
    2328                 :        7324 :         LWLockRelease(MultiXactGenLock);
    2329                 :             : 
    2330                 :       14648 :         return oldestMXact;
    2331                 :        7324 : }
    2332                 :             : 
    2333                 :             : /*
    2334                 :             :  * Calculate the oldest member offset and install it in MultiXactState, where
    2335                 :             :  * it can be used to adjust multixid freezing cutoffs.
    2336                 :             :  */
    2337                 :             : static void
    2338                 :           6 : SetOldestOffset(void)
    2339                 :             : {
    2340                 :           6 :         MultiXactId oldestMultiXactId;
    2341                 :           6 :         MultiXactId nextMXact;
    2342                 :           6 :         MultiXactOffset oldestOffset = 0;       /* placate compiler */
    2343                 :           6 :         MultiXactOffset nextOffset;
    2344                 :           6 :         bool            oldestOffsetKnown = false;
    2345                 :             : 
    2346                 :             :         /*
    2347                 :             :          * NB: Have to prevent concurrent truncation, we might otherwise try to
    2348                 :             :          * lookup an oldestMulti that's concurrently getting truncated away.
    2349                 :             :          */
    2350                 :           6 :         LWLockAcquire(MultiXactTruncationLock, LW_SHARED);
    2351                 :             : 
    2352                 :             :         /* Read relevant fields from shared memory. */
    2353                 :           6 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
    2354                 :           6 :         oldestMultiXactId = MultiXactState->oldestMultiXactId;
    2355                 :           6 :         nextMXact = MultiXactState->nextMXact;
    2356                 :           6 :         nextOffset = MultiXactState->nextOffset;
    2357         [ +  - ]:           6 :         Assert(MultiXactState->finishedStartup);
    2358                 :           6 :         LWLockRelease(MultiXactGenLock);
    2359                 :             : 
    2360                 :             :         /*
    2361                 :             :          * Determine the offset of the oldest multixact.  Normally, we can read
    2362                 :             :          * the offset from the multixact itself, but there's an important special
    2363                 :             :          * case: if there are no multixacts in existence at all, oldestMXact
    2364                 :             :          * obviously can't point to one.  It will instead point to the multixact
    2365                 :             :          * ID that will be assigned the next time one is needed.
    2366                 :             :          */
    2367         [ +  - ]:           6 :         if (oldestMultiXactId == nextMXact)
    2368                 :             :         {
    2369                 :             :                 /*
    2370                 :             :                  * When the next multixact gets created, it will be stored at the next
    2371                 :             :                  * offset.
    2372                 :             :                  */
    2373                 :           6 :                 oldestOffset = nextOffset;
    2374                 :           6 :                 oldestOffsetKnown = true;
    2375                 :           6 :         }
    2376                 :             :         else
    2377                 :             :         {
    2378                 :             :                 /*
    2379                 :             :                  * Look up the offset at which the oldest existing multixact's members
    2380                 :             :                  * are stored.  If we cannot find it, be careful not to fail, and
    2381                 :             :                  * leave oldestOffset unchanged.  oldestOffset is initialized to zero
    2382                 :             :                  * at system startup, which prevents truncating members until a proper
    2383                 :             :                  * value is calculated.
    2384                 :             :                  *
    2385                 :             :                  * (We had bugs in early releases of PostgreSQL 9.3.X and 9.4.X where
    2386                 :             :                  * the supposedly-earliest multixact might not really exist.  Those
    2387                 :             :                  * should be long gone by now, so this should not fail, but let's
    2388                 :             :                  * still be defensive.)
    2389                 :             :                  */
    2390                 :           0 :                 oldestOffsetKnown =
    2391                 :           0 :                         find_multixact_start(oldestMultiXactId, &oldestOffset);
    2392                 :             : 
    2393         [ #  # ]:           0 :                 if (oldestOffsetKnown)
    2394   [ #  #  #  # ]:           0 :                         ereport(DEBUG1,
    2395                 :             :                                         (errmsg_internal("oldest MultiXactId member is at offset %" PRIu64,
    2396                 :             :                                                                          oldestOffset)));
    2397                 :             :                 else
    2398   [ #  #  #  # ]:           0 :                         ereport(LOG,
    2399                 :             :                                         (errmsg("MultiXact member truncation is disabled because oldest checkpointed MultiXact %u does not exist on disk",
    2400                 :             :                                                         oldestMultiXactId)));
    2401                 :             :         }
    2402                 :             : 
    2403                 :           6 :         LWLockRelease(MultiXactTruncationLock);
    2404                 :             : 
    2405                 :             :         /* Install the computed value */
    2406         [ -  + ]:           6 :         if (oldestOffsetKnown)
    2407                 :             :         {
    2408                 :           6 :                 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    2409                 :           6 :                 MultiXactState->oldestOffset = oldestOffset;
    2410                 :           6 :                 LWLockRelease(MultiXactGenLock);
    2411                 :           6 :         }
    2412                 :           6 : }
    2413                 :             : 
    2414                 :             : /*
    2415                 :             :  * Find the starting offset of the given MultiXactId.
    2416                 :             :  *
    2417                 :             :  * Returns false if the file containing the multi does not exist on disk.
    2418                 :             :  * Otherwise, returns true and sets *result to the starting member offset.
    2419                 :             :  *
    2420                 :             :  * This function does not prevent concurrent truncation, so if that's
    2421                 :             :  * required, the caller has to protect against that.
    2422                 :             :  */
    2423                 :             : static bool
    2424                 :           0 : find_multixact_start(MultiXactId multi, MultiXactOffset *result)
    2425                 :             : {
    2426                 :           0 :         MultiXactOffset offset;
    2427                 :           0 :         int64           pageno;
    2428                 :           0 :         int                     entryno;
    2429                 :           0 :         int                     slotno;
    2430                 :           0 :         MultiXactOffset *offptr;
    2431                 :             : 
    2432         [ #  # ]:           0 :         Assert(MultiXactState->finishedStartup);
    2433                 :             : 
    2434                 :           0 :         pageno = MultiXactIdToOffsetPage(multi);
    2435                 :           0 :         entryno = MultiXactIdToOffsetEntry(multi);
    2436                 :             : 
    2437                 :             :         /*
    2438                 :             :          * Write out dirty data, so PhysicalPageExists can work correctly.
    2439                 :             :          */
    2440                 :           0 :         SimpleLruWriteAll(MultiXactOffsetCtl, true);
    2441                 :           0 :         SimpleLruWriteAll(MultiXactMemberCtl, true);
    2442                 :             : 
    2443         [ #  # ]:           0 :         if (!SimpleLruDoesPhysicalPageExist(MultiXactOffsetCtl, pageno))
    2444                 :           0 :                 return false;
    2445                 :             : 
    2446                 :             :         /* lock is acquired by SimpleLruReadPage_ReadOnly */
    2447                 :           0 :         slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
    2448                 :           0 :         offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
    2449                 :           0 :         offptr += entryno;
    2450                 :           0 :         offset = *offptr;
    2451                 :           0 :         LWLockRelease(SimpleLruGetBankLock(MultiXactOffsetCtl, pageno));
    2452                 :             : 
    2453                 :           0 :         *result = offset;
    2454                 :           0 :         return true;
    2455                 :           0 : }
    2456                 :             : 
    2457                 :             : /*
    2458                 :             :  * GetMultiXactInfo
    2459                 :             :  *
    2460                 :             :  * Returns information about the current MultiXact state, as of:
    2461                 :             :  * multixacts: Number of MultiXacts (nextMultiXactId - oldestMultiXactId)
    2462                 :             :  * nextOffset: Next-to-be-assigned offset
    2463                 :             :  * oldestMultiXactId: Oldest MultiXact ID still in use
    2464                 :             :  * oldestOffset: Oldest offset still in use
    2465                 :             :  */
    2466                 :             : void
    2467                 :         703 : GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *nextOffset,
    2468                 :             :                                  MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
    2469                 :             : {
    2470                 :         703 :         MultiXactId nextMultiXactId;
    2471                 :             : 
    2472                 :         703 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
    2473                 :         703 :         *nextOffset = MultiXactState->nextOffset;
    2474                 :         703 :         *oldestMultiXactId = MultiXactState->oldestMultiXactId;
    2475                 :         703 :         nextMultiXactId = MultiXactState->nextMXact;
    2476                 :         703 :         *oldestOffset = MultiXactState->oldestOffset;
    2477                 :         703 :         LWLockRelease(MultiXactGenLock);
    2478                 :             : 
    2479                 :         703 :         *multixacts = nextMultiXactId - *oldestMultiXactId;
    2480                 :         703 : }
    2481                 :             : 
    2482                 :             : /*
    2483                 :             :  * Multixact members can be removed once the multixacts that refer to them
    2484                 :             :  * are older than every datminmxid.  autovacuum_multixact_freeze_max_age and
    2485                 :             :  * vacuum_multixact_freeze_table_age work together to make sure we never have
    2486                 :             :  * too many multixacts; we hope that, at least under normal circumstances,
    2487                 :             :  * this will also be sufficient to keep us from using too many offsets.
    2488                 :             :  * However, if the average multixact has many members, we might accumulate a
    2489                 :             :  * large amount of members, consuming disk space, while still using few enough
    2490                 :             :  * multixids that the multixid limits fail to trigger relminmxid advancement
    2491                 :             :  * by VACUUM.
    2492                 :             :  *
    2493                 :             :  * To prevent that, if the members space usage exceeds a threshold
    2494                 :             :  * (MULTIXACT_MEMBER_LOW_THRESHOLD), we effectively reduce
    2495                 :             :  * autovacuum_multixact_freeze_max_age to a value just less than the number of
    2496                 :             :  * multixacts in use.  We hope that this will quickly trigger autovacuuming on
    2497                 :             :  * the table or tables with the oldest relminmxid, thus allowing datminmxid
    2498                 :             :  * values to advance and removing some members.
    2499                 :             :  *
    2500                 :             :  * As the amount of the member space in use grows, we become more aggressive
    2501                 :             :  * in clamping this value.  That not only causes autovacuum to ramp up, but
    2502                 :             :  * also makes any manual vacuums the user issues more aggressive.  This
    2503                 :             :  * happens because vacuum_get_cutoffs() will clamp the freeze table and the
    2504                 :             :  * minimum freeze age cutoffs based on the effective
    2505                 :             :  * autovacuum_multixact_freeze_max_age this function returns.  At the extreme,
    2506                 :             :  * when the members usage reaches MULTIXACT_MEMBER_HIGH_THRESHOLD, we clamp
    2507                 :             :  * freeze_max_age to zero, and every vacuum of any table will freeze every
    2508                 :             :  * multixact.
    2509                 :             :  */
    2510                 :             : int
    2511                 :         700 : MultiXactMemberFreezeThreshold(void)
    2512                 :             : {
    2513                 :         700 :         uint32          multixacts;
    2514                 :         700 :         uint32          victim_multixacts;
    2515                 :         700 :         double          fraction;
    2516                 :         700 :         int                     result;
    2517                 :         700 :         MultiXactId oldestMultiXactId;
    2518                 :         700 :         MultiXactOffset oldestOffset;
    2519                 :         700 :         MultiXactOffset nextOffset;
    2520                 :         700 :         uint64          members;
    2521                 :             : 
    2522                 :             :         /* Read the current offsets and multixact usage. */
    2523                 :         700 :         GetMultiXactInfo(&multixacts, &nextOffset, &oldestMultiXactId, &oldestOffset);
    2524                 :         700 :         members = nextOffset - oldestOffset;
    2525                 :             : 
    2526                 :             :         /* If member space utilization is low, no special action is required. */
    2527         [ +  - ]:         700 :         if (members <= MULTIXACT_MEMBER_LOW_THRESHOLD)
    2528                 :         700 :                 return autovacuum_multixact_freeze_max_age;
    2529                 :             : 
    2530                 :             :         /*
    2531                 :             :          * Compute a target for relminmxid advancement.  The number of multixacts
    2532                 :             :          * we try to eliminate from the system is based on how far we are past
    2533                 :             :          * MULTIXACT_MEMBER_LOW_THRESHOLD.
    2534                 :             :          *
    2535                 :             :          * The way this formula works is that when members is exactly at the low
    2536                 :             :          * threshold, fraction = 0.0, and we set freeze_max_age equal to
    2537                 :             :          * mxid_age(oldestMultiXactId).  As members grows further, towards the
    2538                 :             :          * high threshold, fraction grows linearly from 0.0 to 1.0, and the result
    2539                 :             :          * shrinks from mxid_age(oldestMultiXactId) to 0.  Beyond the high
    2540                 :             :          * threshold, fraction > 1.0 and the result is clamped to 0.
    2541                 :             :          */
    2542                 :           0 :         fraction = (double) (members - MULTIXACT_MEMBER_LOW_THRESHOLD) /
    2543                 :             :                 (MULTIXACT_MEMBER_HIGH_THRESHOLD - MULTIXACT_MEMBER_LOW_THRESHOLD);
    2544                 :             : 
    2545                 :             :         /* fraction could be > 1.0, but lowest possible freeze age is zero */
    2546         [ #  # ]:           0 :         if (fraction >= 1.0)
    2547                 :           0 :                 return 0;
    2548                 :             : 
    2549                 :           0 :         victim_multixacts = multixacts * fraction;
    2550                 :           0 :         result = multixacts - victim_multixacts;
    2551                 :             : 
    2552                 :             :         /*
    2553                 :             :          * Clamp to autovacuum_multixact_freeze_max_age, so that we never make
    2554                 :             :          * autovacuum less aggressive than it would otherwise be.
    2555                 :             :          */
    2556         [ #  # ]:           0 :         return Min(result, autovacuum_multixact_freeze_max_age);
    2557                 :         700 : }
    2558                 :             : 
    2559                 :             : 
    2560                 :             : /*
    2561                 :             :  * Delete members segments older than newOldestOffset
    2562                 :             :  */
    2563                 :             : static void
    2564                 :           0 : PerformMembersTruncation(MultiXactOffset newOldestOffset)
    2565                 :             : {
    2566                 :           0 :         SimpleLruTruncate(MultiXactMemberCtl,
    2567                 :           0 :                                           MXOffsetToMemberPage(newOldestOffset));
    2568                 :           0 : }
    2569                 :             : 
    2570                 :             : /*
    2571                 :             :  * Delete offsets segments older than newOldestMulti
    2572                 :             :  */
    2573                 :             : static void
    2574                 :           0 : PerformOffsetsTruncation(MultiXactId newOldestMulti)
    2575                 :             : {
    2576                 :             :         /*
    2577                 :             :          * We step back one multixact to avoid passing a cutoff page that hasn't
    2578                 :             :          * been created yet in the rare case that oldestMulti would be the first
    2579                 :             :          * item on a page and oldestMulti == nextMulti.  In that case, if we
    2580                 :             :          * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
    2581                 :             :          * detection.
    2582                 :             :          */
    2583                 :           0 :         SimpleLruTruncate(MultiXactOffsetCtl,
    2584                 :           0 :                                           MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
    2585                 :           0 : }
    2586                 :             : 
    2587                 :             : /*
    2588                 :             :  * Remove all MultiXactOffset and MultiXactMember segments before the oldest
    2589                 :             :  * ones still of interest.
    2590                 :             :  *
    2591                 :             :  * This is only called on a primary as part of vacuum (via
    2592                 :             :  * vac_truncate_clog()). During recovery truncation is done by replaying
    2593                 :             :  * truncation WAL records logged here.
    2594                 :             :  *
    2595                 :             :  * newOldestMulti is the oldest currently required multixact, newOldestMultiDB
    2596                 :             :  * is one of the databases preventing newOldestMulti from increasing.
    2597                 :             :  */
    2598                 :             : void
    2599                 :           2 : TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
    2600                 :             : {
    2601                 :           2 :         MultiXactId oldestMulti;
    2602                 :           2 :         MultiXactId nextMulti;
    2603                 :           2 :         MultiXactOffset newOldestOffset;
    2604                 :           2 :         MultiXactOffset nextOffset;
    2605                 :             : 
    2606         [ +  - ]:           2 :         Assert(!RecoveryInProgress());
    2607         [ +  - ]:           2 :         Assert(MultiXactState->finishedStartup);
    2608         [ +  - ]:           2 :         Assert(MultiXactIdIsValid(newOldestMulti));
    2609                 :             : 
    2610                 :             :         /*
    2611                 :             :          * We can only allow one truncation to happen at once. Otherwise parts of
    2612                 :             :          * members might vanish while we're doing lookups or similar. There's no
    2613                 :             :          * need to have an interlock with creating new multis or such, since those
    2614                 :             :          * are constrained by the limits (which only grow, never shrink).
    2615                 :             :          */
    2616                 :           2 :         LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
    2617                 :             : 
    2618                 :           2 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
    2619                 :           2 :         nextMulti = MultiXactState->nextMXact;
    2620                 :           2 :         nextOffset = MultiXactState->nextOffset;
    2621                 :           2 :         oldestMulti = MultiXactState->oldestMultiXactId;
    2622                 :           2 :         LWLockRelease(MultiXactGenLock);
    2623                 :             : 
    2624                 :             :         /*
    2625                 :             :          * Make sure to only attempt truncation if there's values to truncate
    2626                 :             :          * away. In normal processing values shouldn't go backwards, but there's
    2627                 :             :          * some corner cases (due to bugs) where that's possible.
    2628                 :             :          */
    2629         [ +  - ]:           2 :         if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
    2630                 :             :         {
    2631                 :           2 :                 LWLockRelease(MultiXactTruncationLock);
    2632                 :           2 :                 return;
    2633                 :             :         }
    2634                 :             : 
    2635                 :             :         /*
    2636                 :             :          * Compute up to where to truncate MultiXactMember. Lookup the
    2637                 :             :          * corresponding member offset for newOldestMulti for that.
    2638                 :             :          */
    2639         [ #  # ]:           0 :         if (newOldestMulti == nextMulti)
    2640                 :             :         {
    2641                 :             :                 /* there are NO MultiXacts */
    2642                 :           0 :                 newOldestOffset = nextOffset;
    2643                 :           0 :         }
    2644         [ #  # ]:           0 :         else if (!find_multixact_start(newOldestMulti, &newOldestOffset))
    2645                 :             :         {
    2646   [ #  #  #  # ]:           0 :                 ereport(LOG,
    2647                 :             :                                 (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
    2648                 :             :                                                 newOldestMulti)));
    2649                 :           0 :                 LWLockRelease(MultiXactTruncationLock);
    2650                 :           0 :                 return;
    2651                 :             :         }
    2652                 :             : 
    2653                 :             :         /*
    2654                 :             :          * On crash, MultiXactIdCreateFromMembers() can leave behind multixids
    2655                 :             :          * that were not yet written out and hence have zero offset on disk. If
    2656                 :             :          * such a multixid becomes oldestMulti, we won't be able to look up its
    2657                 :             :          * offset. That should be rare, so we don't try to do anything smart about
    2658                 :             :          * it. Just skip the truncation, and hope that by the next truncation
    2659                 :             :          * attempt, oldestMulti has advanced to a valid multixid.
    2660                 :             :          */
    2661         [ #  # ]:           0 :         if (newOldestOffset == 0)
    2662                 :             :         {
    2663   [ #  #  #  # ]:           0 :                 ereport(LOG,
    2664                 :             :                                 (errmsg("cannot truncate up to MultiXact %u because it has invalid offset, skipping truncation",
    2665                 :             :                                                 newOldestMulti)));
    2666                 :           0 :                 LWLockRelease(MultiXactTruncationLock);
    2667                 :           0 :                 return;
    2668                 :             :         }
    2669                 :             : 
    2670   [ #  #  #  # ]:           0 :         elog(DEBUG1, "performing multixact truncation: "
    2671                 :             :                  "oldestMulti %u (offsets segment %" PRIx64 "), "
    2672                 :             :                  "oldestOffset %" PRIu64 " (members segment %" PRIx64 ")",
    2673                 :             :                  newOldestMulti,
    2674                 :             :                  MultiXactIdToOffsetSegment(newOldestMulti),
    2675                 :             :                  newOldestOffset,
    2676                 :             :                  MXOffsetToMemberSegment(newOldestOffset));
    2677                 :             : 
    2678                 :             :         /*
    2679                 :             :          * Do truncation, and the WAL logging of the truncation, in a critical
    2680                 :             :          * section. That way offsets/members cannot get out of sync anymore, i.e.
    2681                 :             :          * once consistent the newOldestMulti will always exist in members, even
    2682                 :             :          * if we crashed in the wrong moment.
    2683                 :             :          */
    2684                 :           0 :         START_CRIT_SECTION();
    2685                 :             : 
    2686                 :             :         /*
    2687                 :             :          * Prevent checkpoints from being scheduled concurrently. This is critical
    2688                 :             :          * because otherwise a truncation record might not be replayed after a
    2689                 :             :          * crash/basebackup, even though the state of the data directory would
    2690                 :             :          * require it.
    2691                 :             :          */
    2692         [ #  # ]:           0 :         Assert((MyProc->delayChkptFlags & DELAY_CHKPT_START) == 0);
    2693                 :           0 :         MyProc->delayChkptFlags |= DELAY_CHKPT_START;
    2694                 :             : 
    2695                 :             :         /* WAL log truncation */
    2696                 :           0 :         WriteMTruncateXlogRec(newOldestMultiDB, newOldestMulti, newOldestOffset);
    2697                 :             : 
    2698                 :             :         /*
    2699                 :             :          * Update in-memory limits before performing the truncation, while inside
    2700                 :             :          * the critical section: Have to do it before truncation, to prevent
    2701                 :             :          * concurrent lookups of those values. Has to be inside the critical
    2702                 :             :          * section as otherwise a future call to this function would error out,
    2703                 :             :          * while looking up the oldest member in offsets, if our caller crashes
    2704                 :             :          * before updating the limits.
    2705                 :             :          */
    2706                 :           0 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    2707                 :           0 :         MultiXactState->oldestMultiXactId = newOldestMulti;
    2708                 :           0 :         MultiXactState->oldestMultiXactDB = newOldestMultiDB;
    2709                 :           0 :         MultiXactState->oldestOffset = newOldestOffset;
    2710                 :           0 :         LWLockRelease(MultiXactGenLock);
    2711                 :             : 
    2712                 :             :         /* First truncate members */
    2713                 :           0 :         PerformMembersTruncation(newOldestOffset);
    2714                 :             : 
    2715                 :             :         /* Then offsets */
    2716                 :           0 :         PerformOffsetsTruncation(newOldestMulti);
    2717                 :             : 
    2718                 :           0 :         MyProc->delayChkptFlags &= ~DELAY_CHKPT_START;
    2719                 :             : 
    2720         [ #  # ]:           0 :         END_CRIT_SECTION();
    2721                 :           0 :         LWLockRelease(MultiXactTruncationLock);
    2722         [ -  + ]:           2 : }
    2723                 :             : 
    2724                 :             : /*
    2725                 :             :  * Decide whether a MultiXactOffset page number is "older" for truncation
    2726                 :             :  * purposes.  Analogous to CLOGPagePrecedes().
    2727                 :             :  *
    2728                 :             :  * Offsetting the values is optional, because MultiXactIdPrecedes() has
    2729                 :             :  * translational symmetry.
    2730                 :             :  */
    2731                 :             : static bool
    2732                 :         234 : MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
    2733                 :             : {
    2734                 :         234 :         MultiXactId multi1;
    2735                 :         234 :         MultiXactId multi2;
    2736                 :             : 
    2737                 :         234 :         multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
    2738                 :         234 :         multi1 += FirstMultiXactId + 1;
    2739                 :         234 :         multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
    2740                 :         234 :         multi2 += FirstMultiXactId + 1;
    2741                 :             : 
    2742         [ +  + ]:         390 :         return (MultiXactIdPrecedes(multi1, multi2) &&
    2743                 :         312 :                         MultiXactIdPrecedes(multi1,
    2744                 :         156 :                                                                 multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
    2745                 :         234 : }
    2746                 :             : 
    2747                 :             : /*
    2748                 :             :  * Decide whether a MultiXactMember page number is "older" for truncation
    2749                 :             :  * purposes.  There is no "invalid offset number" and members never wrap
    2750                 :             :  * around, so use the numbers verbatim.
    2751                 :             :  */
    2752                 :             : static bool
    2753                 :           0 : MultiXactMemberPagePrecedes(int64 page1, int64 page2)
    2754                 :             : {
    2755                 :           0 :         return page1 < page2;
    2756                 :             : }
    2757                 :             : 
    2758                 :             : /*
    2759                 :             :  * Decide which of two MultiXactIds is earlier.
    2760                 :             :  *
    2761                 :             :  * XXX do we need to do something special for InvalidMultiXactId?
    2762                 :             :  * (Doesn't look like it.)
    2763                 :             :  */
    2764                 :             : bool
    2765                 :      135762 : MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
    2766                 :             : {
    2767                 :      135762 :         int32           diff = (int32) (multi1 - multi2);
    2768                 :             : 
    2769                 :      271524 :         return (diff < 0);
    2770                 :      135762 : }
    2771                 :             : 
    2772                 :             : /*
    2773                 :             :  * MultiXactIdPrecedesOrEquals -- is multi1 logically <= multi2?
    2774                 :             :  *
    2775                 :             :  * XXX do we need to do something special for InvalidMultiXactId?
    2776                 :             :  * (Doesn't look like it.)
    2777                 :             :  */
    2778                 :             : bool
    2779                 :         523 : MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
    2780                 :             : {
    2781                 :         523 :         int32           diff = (int32) (multi1 - multi2);
    2782                 :             : 
    2783                 :        1046 :         return (diff <= 0);
    2784                 :         523 : }
    2785                 :             : 
    2786                 :             : 
    2787                 :             : /*
    2788                 :             :  * Write a TRUNCATE xlog record
    2789                 :             :  *
    2790                 :             :  * We must flush the xlog record to disk before returning --- see notes in
    2791                 :             :  * TruncateCLOG().
    2792                 :             :  */
    2793                 :             : static void
    2794                 :           0 : WriteMTruncateXlogRec(Oid oldestMultiDB,
    2795                 :             :                                           MultiXactId oldestMulti,
    2796                 :             :                                           MultiXactOffset oldestOffset)
    2797                 :             : {
    2798                 :           0 :         XLogRecPtr      recptr;
    2799                 :           0 :         xl_multixact_truncate xlrec;
    2800                 :             : 
    2801                 :           0 :         xlrec.oldestMultiDB = oldestMultiDB;
    2802                 :           0 :         xlrec.oldestMulti = oldestMulti;
    2803                 :           0 :         xlrec.oldestOffset = oldestOffset;
    2804                 :             : 
    2805                 :           0 :         XLogBeginInsert();
    2806                 :           0 :         XLogRegisterData(&xlrec, SizeOfMultiXactTruncate);
    2807                 :           0 :         recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
    2808                 :           0 :         XLogFlush(recptr);
    2809                 :           0 : }
    2810                 :             : 
    2811                 :             : /*
    2812                 :             :  * MULTIXACT resource manager's routines
    2813                 :             :  */
    2814                 :             : void
    2815                 :           0 : multixact_redo(XLogReaderState *record)
    2816                 :             : {
    2817                 :           0 :         uint8           info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
    2818                 :             : 
    2819                 :             :         /* Backup blocks are not used in multixact records */
    2820         [ #  # ]:           0 :         Assert(!XLogRecHasAnyBlockRefs(record));
    2821                 :             : 
    2822         [ #  # ]:           0 :         if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
    2823                 :             :         {
    2824                 :           0 :                 int64           pageno;
    2825                 :             : 
    2826                 :           0 :                 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
    2827                 :           0 :                 SimpleLruZeroAndWritePage(MultiXactOffsetCtl, pageno);
    2828                 :           0 :         }
    2829         [ #  # ]:           0 :         else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
    2830                 :             :         {
    2831                 :           0 :                 int64           pageno;
    2832                 :             : 
    2833                 :           0 :                 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
    2834                 :           0 :                 SimpleLruZeroAndWritePage(MultiXactMemberCtl, pageno);
    2835                 :           0 :         }
    2836         [ #  # ]:           0 :         else if (info == XLOG_MULTIXACT_CREATE_ID)
    2837                 :             :         {
    2838                 :           0 :                 xl_multixact_create *xlrec =
    2839                 :           0 :                         (xl_multixact_create *) XLogRecGetData(record);
    2840                 :           0 :                 TransactionId max_xid;
    2841                 :           0 :                 int                     i;
    2842                 :             : 
    2843                 :             :                 /* Store the data back into the SLRU files */
    2844                 :           0 :                 RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
    2845                 :           0 :                                                    xlrec->members);
    2846                 :             : 
    2847                 :             :                 /* Make sure nextMXact/nextOffset are beyond what this record has */
    2848                 :           0 :                 MultiXactAdvanceNextMXact(NextMultiXactId(xlrec->mid),
    2849                 :           0 :                                                                   xlrec->moff + xlrec->nmembers);
    2850                 :             : 
    2851                 :             :                 /*
    2852                 :             :                  * Make sure nextXid is beyond any XID mentioned in the record. This
    2853                 :             :                  * should be unnecessary, since any XID found here ought to have other
    2854                 :             :                  * evidence in the XLOG, but let's be safe.
    2855                 :             :                  */
    2856                 :           0 :                 max_xid = XLogRecGetXid(record);
    2857         [ #  # ]:           0 :                 for (i = 0; i < xlrec->nmembers; i++)
    2858                 :             :                 {
    2859         [ #  # ]:           0 :                         if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
    2860                 :           0 :                                 max_xid = xlrec->members[i].xid;
    2861                 :           0 :                 }
    2862                 :             : 
    2863                 :           0 :                 AdvanceNextFullTransactionIdPastXid(max_xid);
    2864                 :           0 :         }
    2865         [ #  # ]:           0 :         else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
    2866                 :             :         {
    2867                 :           0 :                 xl_multixact_truncate xlrec;
    2868                 :           0 :                 int64           pageno;
    2869                 :             : 
    2870                 :           0 :                 memcpy(&xlrec, XLogRecGetData(record),
    2871                 :             :                            SizeOfMultiXactTruncate);
    2872                 :             : 
    2873   [ #  #  #  # ]:           0 :                 elog(DEBUG1, "replaying multixact truncation: "
    2874                 :             :                          "oldestMulti %u (offsets segment %" PRIx64 "), "
    2875                 :             :                          "oldestOffset %" PRIu64 " (members segment %" PRIx64 ")",
    2876                 :             :                          xlrec.oldestMulti,
    2877                 :             :                          MultiXactIdToOffsetSegment(xlrec.oldestMulti),
    2878                 :             :                          xlrec.oldestOffset,
    2879                 :             :                          MXOffsetToMemberSegment(xlrec.oldestOffset));
    2880                 :             : 
    2881                 :             :                 /* should not be required, but more than cheap enough */
    2882                 :           0 :                 LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
    2883                 :             : 
    2884                 :             :                 /*
    2885                 :             :                  * Advance the horizon values, so they're current at the end of
    2886                 :             :                  * recovery.
    2887                 :             :                  */
    2888                 :           0 :                 SetMultiXactIdLimit(xlrec.oldestMulti, xlrec.oldestMultiDB);
    2889                 :             : 
    2890                 :           0 :                 PerformMembersTruncation(xlrec.oldestOffset);
    2891                 :             : 
    2892                 :             :                 /*
    2893                 :             :                  * During XLOG replay, latest_page_number isn't necessarily set up
    2894                 :             :                  * yet; insert a suitable value to bypass the sanity test in
    2895                 :             :                  * SimpleLruTruncate.
    2896                 :             :                  */
    2897                 :           0 :                 pageno = MultiXactIdToOffsetPage(xlrec.oldestMulti);
    2898                 :           0 :                 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
    2899                 :           0 :                                                         pageno);
    2900                 :           0 :                 PerformOffsetsTruncation(xlrec.oldestMulti);
    2901                 :             : 
    2902                 :           0 :                 LWLockRelease(MultiXactTruncationLock);
    2903                 :           0 :         }
    2904                 :             :         else
    2905   [ #  #  #  # ]:           0 :                 elog(PANIC, "multixact_redo: unknown op code %u", info);
    2906                 :           0 : }
    2907                 :             : 
    2908                 :             : /*
    2909                 :             :  * Entrypoint for sync.c to sync offsets files.
    2910                 :             :  */
    2911                 :             : int
    2912                 :           0 : multixactoffsetssyncfiletag(const FileTag *ftag, char *path)
    2913                 :             : {
    2914                 :           0 :         return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
    2915                 :             : }
    2916                 :             : 
    2917                 :             : /*
    2918                 :             :  * Entrypoint for sync.c to sync members files.
    2919                 :             :  */
    2920                 :             : int
    2921                 :           0 : multixactmemberssyncfiletag(const FileTag *ftag, char *path)
    2922                 :             : {
    2923                 :           0 :         return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
    2924                 :             : }
        

Generated by: LCOV version 2.3.2-1