LCOV - code coverage report
Current view: top level - src/backend/access/transam - multixact.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 78.5 % 724 568
Test Date: 2026-02-17 17:20:33 Functions: 83.9 % 56 47
Legend: Lines:     hit not hit

            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       107643 : NextMultiXactId(MultiXactId multi)
     103              : {
     104       107643 :     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         1100 : MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1,
     300              :                   TransactionId xid2, MultiXactStatus status2)
     301              : {
     302              :     MultiXactId newMulti;
     303              :     MultiXactMember members[2];
     304              : 
     305              :     Assert(TransactionIdIsValid(xid1));
     306              :     Assert(TransactionIdIsValid(xid2));
     307              : 
     308              :     Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));
     309              : 
     310              :     /* MultiXactIdSetOldestMember() must have been called already. */
     311              :     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         1100 :     members[0].xid = xid1;
     320         1100 :     members[0].status = status1;
     321         1100 :     members[1].xid = xid2;
     322         1100 :     members[1].status = status2;
     323              : 
     324         1100 :     newMulti = MultiXactIdCreateFromMembers(2, members);
     325              : 
     326              :     debug_elog3(DEBUG2, "Create: %s",
     327              :                 mxid_to_string(newMulti, 2, members));
     328              : 
     329         1100 :     return newMulti;
     330              : }
     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        75541 : MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
     353              : {
     354              :     MultiXactId newMulti;
     355              :     MultiXactMember *members;
     356              :     MultiXactMember *newMembers;
     357              :     int         nmembers;
     358              :     int         i;
     359              :     int         j;
     360              : 
     361              :     Assert(MultiXactIdIsValid(multi));
     362              :     Assert(TransactionIdIsValid(xid));
     363              : 
     364              :     /* MultiXactIdSetOldestMember() must have been called already. */
     365              :     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        75541 :     nmembers = GetMultiXactIdMembers(multi, &members, false, false);
     376              : 
     377        75541 :     if (nmembers < 0)
     378              :     {
     379              :         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              :     }
     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      1465952 :     for (i = 0; i < nmembers; i++)
     402              :     {
     403      1390411 :         if (TransactionIdEquals(members[i].xid, xid) &&
     404           54 :             (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              :     }
     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        75541 :     newMembers = palloc_array(MultiXactMember, nmembers + 1);
     427              : 
     428      1465952 :     for (i = 0, j = 0; i < nmembers; i++)
     429              :     {
     430      1390411 :         if (TransactionIdIsInProgress(members[i].xid) ||
     431        74685 :             (ISUPDATE_from_mxstatus(members[i].status) &&
     432           17 :              TransactionIdDidCommit(members[i].xid)))
     433              :         {
     434      1315743 :             newMembers[j].xid = members[i].xid;
     435      1315743 :             newMembers[j++].status = members[i].status;
     436              :         }
     437              :     }
     438              : 
     439        75541 :     newMembers[j].xid = xid;
     440        75541 :     newMembers[j++].status = status;
     441        75541 :     newMulti = MultiXactIdCreateFromMembers(j, newMembers);
     442              : 
     443        75541 :     pfree(members);
     444        75541 :     pfree(newMembers);
     445              : 
     446              :     debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);
     447              : 
     448        75541 :     return newMulti;
     449              : }
     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       149829 : MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
     464              : {
     465              :     MultiXactMember *members;
     466              :     int         nmembers;
     467              :     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       149829 :     nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
     476              : 
     477       149829 :     if (nmembers <= 0)
     478              :     {
     479              :         debug_elog2(DEBUG2, "IsRunning: no members");
     480          714 :         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      2891530 :     for (i = 0; i < nmembers; i++)
     491              :     {
     492      2742571 :         if (TransactionIdIsCurrentTransactionId(members[i].xid))
     493              :         {
     494              :             debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i);
     495          156 :             pfree(members);
     496          156 :             return true;
     497              :         }
     498              :     }
     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       296163 :     for (i = 0; i < nmembers; i++)
     506              :     {
     507       296116 :         if (TransactionIdIsInProgress(members[i].xid))
     508              :         {
     509              :             debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running",
     510              :                         i, members[i].xid);
     511       148912 :             pfree(members);
     512       148912 :             return true;
     513              :         }
     514              :     }
     515              : 
     516           47 :     pfree(members);
     517              : 
     518              :     debug_elog3(DEBUG2, "IsRunning: %u is not running", multi);
     519              : 
     520           47 :     return false;
     521              : }
     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      1984632 : MultiXactIdSetOldestMember(void)
     538              : {
     539      1984632 :     if (!MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber]))
     540              :     {
     541              :         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        75396 :         LWLockAcquire(MultiXactGenLock, LW_SHARED);
     558              : 
     559        75396 :         nextMXact = MultiXactState->nextMXact;
     560              : 
     561        75396 :         OldestMemberMXactId[MyProcNumber] = nextMXact;
     562              : 
     563        75396 :         LWLockRelease(MultiXactGenLock);
     564              : 
     565              :         debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
     566              :                     MyProcNumber, nextMXact);
     567              :     }
     568      1984632 : }
     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        92450 : MultiXactIdSetOldestVisible(void)
     588              : {
     589        92450 :     if (!MultiXactIdIsValid(OldestVisibleMXactId[MyProcNumber]))
     590              :     {
     591              :         MultiXactId oldestMXact;
     592              :         int         i;
     593              : 
     594         3194 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
     595              : 
     596         3194 :         oldestMXact = MultiXactState->nextMXact;
     597       407510 :         for (i = 0; i < MaxOldestSlot; i++)
     598              :         {
     599       404316 :             MultiXactId thisoldest = OldestMemberMXactId[i];
     600              : 
     601       460257 :             if (MultiXactIdIsValid(thisoldest) &&
     602        55941 :                 MultiXactIdPrecedes(thisoldest, oldestMXact))
     603         5685 :                 oldestMXact = thisoldest;
     604              :         }
     605              : 
     606         3194 :         OldestVisibleMXactId[MyProcNumber] = oldestMXact;
     607              : 
     608         3194 :         LWLockRelease(MultiXactGenLock);
     609              : 
     610              :         debug_elog4(DEBUG2, "MultiXact: setting OldestVisible[%d] = %u",
     611              :                     MyProcNumber, oldestMXact);
     612              :     }
     613        92450 : }
     614              : 
     615              : /*
     616              :  * ReadNextMultiXactId
     617              :  *      Return the next MultiXactId to be assigned, but don't allocate it
     618              :  */
     619              : MultiXactId
     620       220330 : ReadNextMultiXactId(void)
     621              : {
     622              :     MultiXactId mxid;
     623              : 
     624              :     /* XXX we could presumably do this without a lock. */
     625       220330 :     LWLockAcquire(MultiXactGenLock, LW_SHARED);
     626       220330 :     mxid = MultiXactState->nextMXact;
     627       220330 :     LWLockRelease(MultiXactGenLock);
     628              : 
     629       220330 :     return mxid;
     630              : }
     631              : 
     632              : /*
     633              :  * ReadMultiXactIdRange
     634              :  *      Get the range of IDs that may still be referenced by a relation.
     635              :  */
     636              : void
     637         1476 : ReadMultiXactIdRange(MultiXactId *oldest, MultiXactId *next)
     638              : {
     639         1476 :     LWLockAcquire(MultiXactGenLock, LW_SHARED);
     640         1476 :     *oldest = MultiXactState->oldestMultiXactId;
     641         1476 :     *next = MultiXactState->nextMXact;
     642         1476 :     LWLockRelease(MultiXactGenLock);
     643         1476 : }
     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        76642 : MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
     657              : {
     658              :     MultiXactId multi;
     659              :     MultiXactOffset offset;
     660              :     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        76642 :     multi = mXactCacheGetBySet(nmembers, members);
     676        76642 :     if (MultiXactIdIsValid(multi))
     677              :     {
     678              :         debug_elog2(DEBUG2, "Create: in cache!");
     679        71342 :         return multi;
     680              :     }
     681              : 
     682              :     /* Verify that there is a single update Xid among the given members. */
     683              :     {
     684              :         int         i;
     685         5300 :         bool        has_update = false;
     686              : 
     687       100028 :         for (i = 0; i < nmembers; i++)
     688              :         {
     689        94728 :             if (ISUPDATE_from_mxstatus(members[i].status))
     690              :             {
     691         2373 :                 if (has_update)
     692            0 :                     elog(ERROR, "new multixact has more than one updating member: %s",
     693              :                          mxid_to_string(InvalidMultiXactId, nmembers, members));
     694         2373 :                 has_update = true;
     695              :             }
     696              :         }
     697              :     }
     698              : 
     699              :     /* Load the injection point before entering the critical section */
     700         5300 :     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         5300 :     multi = GetNewMultiXactId(nmembers, &offset);
     715              : 
     716         5300 :     INJECTION_POINT_CACHED("multixact-create-from-members", NULL);
     717              : 
     718              :     /* Make an XLOG entry describing the new MXID. */
     719         5300 :     xlrec.mid = multi;
     720         5300 :     xlrec.moff = offset;
     721         5300 :     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         5300 :     XLogBeginInsert();
     730         5300 :     XLogRegisterData(&xlrec, SizeOfMultiXactCreate);
     731         5300 :     XLogRegisterData(members, nmembers * sizeof(MultiXactMember));
     732              : 
     733         5300 :     (void) XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_CREATE_ID);
     734              : 
     735              :     /* Now enter the information into the OFFSETs and MEMBERs logs */
     736         5300 :     RecordNewMultiXact(multi, offset, nmembers, members);
     737              : 
     738              :     /* Done with critical section */
     739         5300 :     END_CRIT_SECTION();
     740              : 
     741              :     /* Store the new MultiXactId in the local cache, too */
     742         5300 :     mXactCachePut(multi, nmembers, members);
     743              : 
     744              :     debug_elog2(DEBUG2, "Create: all done");
     745              : 
     746         5300 :     return multi;
     747              : }
     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         5304 : RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
     758              :                    int nmembers, MultiXactMember *members)
     759              : {
     760              :     int64       pageno;
     761              :     int64       prev_pageno;
     762              :     int         entryno;
     763              :     int         slotno;
     764              :     MultiXactOffset *offptr;
     765              :     MultiXactId next;
     766              :     int64       next_pageno;
     767              :     int         next_entryno;
     768              :     MultiXactOffset *next_offptr;
     769              :     MultiXactOffset next_offset;
     770              :     LWLock     *lock;
     771         5304 :     LWLock     *prevlock = NULL;
     772              : 
     773              :     /* position of this multixid in the offsets SLRU area  */
     774         5304 :     pageno = MultiXactIdToOffsetPage(multi);
     775         5304 :     entryno = MultiXactIdToOffsetEntry(multi);
     776              : 
     777              :     /* position of the next multixid */
     778         5304 :     next = NextMultiXactId(multi);
     779         5304 :     next_pageno = MultiXactIdToOffsetPage(next);
     780         5304 :     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         5304 :     lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
     792         5304 :     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         5304 :     slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
     802         5304 :     offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
     803         5304 :     offptr += entryno;
     804              : 
     805         5304 :     if (*offptr != offset)
     806              :     {
     807              :         /* should already be set to the correct value, or not at all */
     808              :         Assert(*offptr == 0);
     809            1 :         *offptr = offset;
     810            1 :         MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
     811              :     }
     812              : 
     813              :     /*
     814              :      * Set the next multixid's offset to the end of this multixid's members.
     815              :      */
     816         5304 :     if (next_pageno == pageno)
     817              :     {
     818         5299 :         next_offptr = offptr + 1;
     819              :     }
     820              :     else
     821              :     {
     822              :         /* must be the first entry on the page */
     823              :         Assert(next_entryno == 0 || next == FirstMultiXactId);
     824              : 
     825              :         /* Swap the lock for a lock on the next page */
     826            5 :         LWLockRelease(lock);
     827            5 :         lock = SimpleLruGetBankLock(MultiXactOffsetCtl, next_pageno);
     828            5 :         LWLockAcquire(lock, LW_EXCLUSIVE);
     829              : 
     830            5 :         slotno = SimpleLruReadPage(MultiXactOffsetCtl, next_pageno, true, next);
     831            5 :         next_offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
     832            5 :         next_offptr += next_entryno;
     833              :     }
     834              : 
     835              :     /* Like in GetNewMultiXactId(), skip over offset 0 */
     836         5304 :     next_offset = offset + nmembers;
     837         5304 :     if (next_offset == 0)
     838            0 :         next_offset = 1;
     839         5304 :     if (*next_offptr != next_offset)
     840              :     {
     841              :         /* should already be set to the correct value, or not at all */
     842              :         Assert(*next_offptr == 0);
     843         5304 :         *next_offptr = next_offset;
     844         5304 :         MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
     845              :     }
     846              : 
     847              :     /* Release MultiXactOffset SLRU lock. */
     848         5304 :     LWLockRelease(lock);
     849              : 
     850         5304 :     prev_pageno = -1;
     851              : 
     852       100040 :     for (int i = 0; i < nmembers; i++, offset++)
     853              :     {
     854              :         TransactionId *memberptr;
     855              :         uint32     *flagsptr;
     856              :         uint32      flagsval;
     857              :         int         bshift;
     858              :         int         flagsoff;
     859              :         int         memberoff;
     860              : 
     861              :         Assert(members[i].status <= MultiXactStatusUpdate);
     862              : 
     863        94736 :         pageno = MXOffsetToMemberPage(offset);
     864        94736 :         memberoff = MXOffsetToMemberOffset(offset);
     865        94736 :         flagsoff = MXOffsetToFlagsOffset(offset);
     866        94736 :         bshift = MXOffsetToFlagsBitShift(offset);
     867              : 
     868        94736 :         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         5358 :             lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
     876         5358 :             if (lock != prevlock)
     877              :             {
     878         5358 :                 if (prevlock != NULL)
     879           54 :                     LWLockRelease(prevlock);
     880              : 
     881         5358 :                 LWLockAcquire(lock, LW_EXCLUSIVE);
     882         5358 :                 prevlock = lock;
     883              :             }
     884         5358 :             slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
     885         5358 :             prev_pageno = pageno;
     886              :         }
     887              : 
     888        94736 :         memberptr = (TransactionId *)
     889        94736 :             (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
     890              : 
     891        94736 :         *memberptr = members[i].xid;
     892              : 
     893        94736 :         flagsptr = (uint32 *)
     894        94736 :             (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
     895              : 
     896        94736 :         flagsval = *flagsptr;
     897        94736 :         flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
     898        94736 :         flagsval |= (members[i].status << bshift);
     899        94736 :         *flagsptr = flagsval;
     900              : 
     901        94736 :         MultiXactMemberCtl->shared->page_dirty[slotno] = true;
     902              :     }
     903              : 
     904         5304 :     if (prevlock != NULL)
     905         5304 :         LWLockRelease(prevlock);
     906         5304 : }
     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         5300 : GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
     925              : {
     926              :     MultiXactId result;
     927              :     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         5300 :     if (RecoveryInProgress())
     933            0 :         elog(ERROR, "cannot assign MultiXactIds during recovery");
     934              : 
     935         5300 :     LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
     936              : 
     937              :     /* Assign the MXID */
     938         5300 :     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         5300 :     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              :         }
     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              :         }
    1030              : 
    1031              :         /* Re-acquire lock and start over */
    1032            0 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    1033            0 :         result = MultiXactState->nextMXact;
    1034              :     }
    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         5300 :     ExtendMultiXactOffset(NextMultiXactId(result));
    1041              : 
    1042              :     /*
    1043              :      * Reserve the members space, similarly to above.
    1044              :      */
    1045         5300 :     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         5300 :     if (nextOffset + nmembers < nextOffset)
    1055            0 :         ereport(ERROR,
    1056              :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1057              :                  errmsg("MultiXact members would wrap around")));
    1058         5300 :     *offset = nextOffset;
    1059              : 
    1060         5300 :     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         5300 :     START_CRIT_SECTION();
    1070              : 
    1071              :     /*
    1072              :      * Advance counters.  As in GetNewTransactionId(), this must not happen
    1073              :      * until after file extension has succeeded!
    1074              :      */
    1075         5300 :     MultiXactState->nextMXact = NextMultiXactId(result);
    1076         5300 :     MultiXactState->nextOffset += nmembers;
    1077              : 
    1078         5300 :     LWLockRelease(MultiXactGenLock);
    1079              : 
    1080              :     debug_elog4(DEBUG2, "GetNew: returning %u offset %" PRIu64,
    1081              :                 result, *offset);
    1082         5300 :     return result;
    1083              : }
    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       549888 : GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
    1114              :                       bool from_pgupgrade, bool isLockOnly)
    1115              : {
    1116              :     int64       pageno;
    1117              :     int64       prev_pageno;
    1118              :     int         entryno;
    1119              :     int         slotno;
    1120              :     MultiXactOffset *offptr;
    1121              :     MultiXactOffset offset;
    1122              :     MultiXactOffset nextMXOffset;
    1123              :     int         length;
    1124              :     MultiXactId oldestMXact;
    1125              :     MultiXactId nextMXact;
    1126              :     MultiXactMember *ptr;
    1127              :     LWLock     *lock;
    1128              : 
    1129              :     debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
    1130              : 
    1131       549888 :     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       549888 :     length = mXactCacheGetById(multi, members);
    1139       549888 :     if (length >= 0)
    1140              :     {
    1141              :         debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
    1142              :                     mxid_to_string(multi, length, *members));
    1143       457438 :         return length;
    1144              :     }
    1145              : 
    1146              :     /* Set our OldestVisibleMXactId[] entry if we didn't already */
    1147        92450 :     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        96144 :     if (isLockOnly &&
    1155         3694 :         MultiXactIdPrecedes(multi, OldestVisibleMXactId[MyProcNumber]))
    1156              :     {
    1157              :         debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
    1158          715 :         *members = NULL;
    1159          715 :         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        91735 :     LWLockAcquire(MultiXactGenLock, LW_SHARED);
    1177              : 
    1178        91735 :     oldestMXact = MultiXactState->oldestMultiXactId;
    1179        91735 :     nextMXact = MultiXactState->nextMXact;
    1180              : 
    1181        91735 :     LWLockRelease(MultiXactGenLock);
    1182              : 
    1183        91735 :     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        91735 :     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        91735 :     pageno = MultiXactIdToOffsetPage(multi);
    1202        91735 :     entryno = MultiXactIdToOffsetEntry(multi);
    1203              : 
    1204              :     /* Acquire the bank lock for the page we need. */
    1205        91735 :     lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
    1206        91735 :     LWLockAcquire(lock, LW_EXCLUSIVE);
    1207              : 
    1208              :     /* read this multi's offset */
    1209        91735 :     slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
    1210        91735 :     offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
    1211        91735 :     offptr += entryno;
    1212        91735 :     offset = *offptr;
    1213              : 
    1214        91735 :     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              :         MultiXactId tmpMXact;
    1222              : 
    1223              :         /* handle wraparound if needed */
    1224        91735 :         tmpMXact = NextMultiXactId(multi);
    1225              : 
    1226        91735 :         prev_pageno = pageno;
    1227              : 
    1228        91735 :         pageno = MultiXactIdToOffsetPage(tmpMXact);
    1229        91735 :         entryno = MultiXactIdToOffsetEntry(tmpMXact);
    1230              : 
    1231        91735 :         if (pageno != prev_pageno)
    1232              :         {
    1233              :             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           13 :             newlock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
    1241           13 :             if (newlock != lock)
    1242              :             {
    1243            0 :                 LWLockRelease(lock);
    1244            0 :                 LWLockAcquire(newlock, LW_EXCLUSIVE);
    1245            0 :                 lock = newlock;
    1246              :             }
    1247           13 :             slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
    1248              :         }
    1249              : 
    1250        91735 :         offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
    1251        91735 :         offptr += entryno;
    1252        91735 :         nextMXOffset = *offptr;
    1253              :     }
    1254              : 
    1255        91735 :     LWLockRelease(lock);
    1256        91735 :     lock = NULL;
    1257              : 
    1258              :     /* Sanity check the next offset */
    1259        91735 :     if (nextMXOffset == 0)
    1260            0 :         ereport(ERROR,
    1261              :                 (errcode(ERRCODE_DATA_CORRUPTED),
    1262              :                  errmsg("MultiXact %u has invalid next offset", multi)));
    1263        91735 :     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        91735 :     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        91735 :     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        91735 :     length = nextMXOffset - offset;
    1279              : 
    1280              :     /* read the members */
    1281        91735 :     ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
    1282        91735 :     prev_pageno = -1;
    1283      1827903 :     for (int i = 0; i < length; i++, offset++)
    1284              :     {
    1285              :         TransactionId *xactptr;
    1286              :         uint32     *flagsptr;
    1287              :         int         flagsoff;
    1288              :         int         bshift;
    1289              :         int         memberoff;
    1290              : 
    1291      1736168 :         pageno = MXOffsetToMemberPage(offset);
    1292      1736168 :         memberoff = MXOffsetToMemberOffset(offset);
    1293              : 
    1294      1736168 :         if (pageno != prev_pageno)
    1295              :         {
    1296              :             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        91897 :             newlock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
    1304        91897 :             if (newlock != lock)
    1305              :             {
    1306        91897 :                 if (lock)
    1307          162 :                     LWLockRelease(lock);
    1308        91897 :                 LWLockAcquire(newlock, LW_EXCLUSIVE);
    1309        91897 :                 lock = newlock;
    1310              :             }
    1311              : 
    1312        91897 :             slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
    1313        91897 :             prev_pageno = pageno;
    1314              :         }
    1315              : 
    1316      1736168 :         xactptr = (TransactionId *)
    1317      1736168 :             (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
    1318              :         Assert(TransactionIdIsValid(*xactptr));
    1319              : 
    1320      1736168 :         flagsoff = MXOffsetToFlagsOffset(offset);
    1321      1736168 :         bshift = MXOffsetToFlagsBitShift(offset);
    1322      1736168 :         flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
    1323              : 
    1324      1736168 :         ptr[i].xid = *xactptr;
    1325      1736168 :         ptr[i].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
    1326              :     }
    1327              : 
    1328        91735 :     LWLockRelease(lock);
    1329              : 
    1330              :     /*
    1331              :      * Copy the result into the local cache.
    1332              :      */
    1333        91735 :     mXactCachePut(multi, length, ptr);
    1334              : 
    1335              :     debug_elog3(DEBUG2, "GetMembers: no cache for %s",
    1336              :                 mxid_to_string(multi, length, ptr));
    1337        91735 :     *members = ptr;
    1338        91735 :     return length;
    1339              : }
    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      3050719 : mxactMemberComparator(const void *arg1, const void *arg2)
    1350              : {
    1351      3050719 :     MultiXactMember member1 = *(const MultiXactMember *) arg1;
    1352      3050719 :     MultiXactMember member2 = *(const MultiXactMember *) arg2;
    1353              : 
    1354      3050719 :     if (member1.xid > member2.xid)
    1355           31 :         return 1;
    1356      3050688 :     if (member1.xid < member2.xid)
    1357      3050477 :         return -1;
    1358          211 :     if (member1.status > member2.status)
    1359           16 :         return 1;
    1360          195 :     if (member1.status < member2.status)
    1361          195 :         return -1;
    1362            0 :     return 0;
    1363              : }
    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        76642 : mXactCacheGetBySet(int nmembers, MultiXactMember *members)
    1380              : {
    1381              :     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        76642 :     qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
    1388              : 
    1389       308331 :     dclist_foreach(iter, &MXactCache)
    1390              :     {
    1391       303031 :         mXactCacheEnt *entry = dclist_container(mXactCacheEnt, node,
    1392              :                                                 iter.cur);
    1393              : 
    1394       303031 :         if (entry->nmembers != nmembers)
    1395        85334 :             continue;
    1396              : 
    1397              :         /*
    1398              :          * We assume the cache entries are sorted, and that the unused bits in
    1399              :          * "status" are zeroed.
    1400              :          */
    1401       217697 :         if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
    1402              :         {
    1403              :             debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
    1404        71342 :             dclist_move_head(&MXactCache, iter.cur);
    1405        71342 :             return entry->multi;
    1406              :         }
    1407              :     }
    1408              : 
    1409              :     debug_elog2(DEBUG2, "CacheGet: not found :-(");
    1410         5300 :     return InvalidMultiXactId;
    1411              : }
    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       549888 : mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
    1423              : {
    1424              :     dlist_iter  iter;
    1425              : 
    1426              :     debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
    1427              : 
    1428      4905683 :     dclist_foreach(iter, &MXactCache)
    1429              :     {
    1430      4813233 :         mXactCacheEnt *entry = dclist_container(mXactCacheEnt, node,
    1431              :                                                 iter.cur);
    1432              : 
    1433      4813233 :         if (entry->multi == multi)
    1434              :         {
    1435              :             MultiXactMember *ptr;
    1436              :             Size        size;
    1437              : 
    1438       457438 :             size = sizeof(MultiXactMember) * entry->nmembers;
    1439       457438 :             ptr = (MultiXactMember *) palloc(size);
    1440              : 
    1441       457438 :             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       457438 :             dclist_move_head(&MXactCache, iter.cur);
    1454              : 
    1455       457438 :             *members = ptr;
    1456       457438 :             return entry->nmembers;
    1457              :         }
    1458              :     }
    1459              : 
    1460              :     debug_elog2(DEBUG2, "CacheGet: not found");
    1461        92450 :     return -1;
    1462              : }
    1463              : 
    1464              : /*
    1465              :  * mXactCachePut
    1466              :  *      Add a new MultiXactId and its composing set into the local cache.
    1467              :  */
    1468              : static void
    1469        97035 : mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
    1470              : {
    1471              :     mXactCacheEnt *entry;
    1472              : 
    1473              :     debug_elog3(DEBUG2, "CachePut: storing %s",
    1474              :                 mxid_to_string(multi, nmembers, members));
    1475              : 
    1476        97035 :     if (MXactContext == NULL)
    1477              :     {
    1478              :         /* The cache only lives as long as the current transaction */
    1479              :         debug_elog2(DEBUG2, "CachePut: initializing memory context");
    1480         3335 :         MXactContext = AllocSetContextCreate(TopTransactionContext,
    1481              :                                              "MultiXact cache context",
    1482              :                                              ALLOCSET_SMALL_SIZES);
    1483              :     }
    1484              : 
    1485              :     entry = (mXactCacheEnt *)
    1486        97035 :         MemoryContextAlloc(MXactContext,
    1487        97035 :                            offsetof(mXactCacheEnt, members) +
    1488              :                            nmembers * sizeof(MultiXactMember));
    1489              : 
    1490        97035 :     entry->multi = multi;
    1491        97035 :     entry->nmembers = nmembers;
    1492        97035 :     memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
    1493              : 
    1494              :     /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
    1495        97035 :     qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
    1496              : 
    1497        97035 :     dclist_push_head(&MXactCache, &entry->node);
    1498        97035 :     if (dclist_count(&MXactCache) > MAX_CACHE_ENTRIES)
    1499              :     {
    1500              :         dlist_node *node;
    1501              : 
    1502         9478 :         node = dclist_tail_node(&MXactCache);
    1503         9478 :         dclist_delete_from(&MXactCache, node);
    1504              : 
    1505         9478 :         entry = dclist_container(mXactCacheEnt, node, node);
    1506              :         debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
    1507              :                     entry->multi);
    1508              : 
    1509         9478 :         pfree(entry);
    1510              :     }
    1511        97035 : }
    1512              : 
    1513              : char *
    1514       188088 : mxstatus_to_string(MultiXactStatus status)
    1515              : {
    1516       188088 :     switch (status)
    1517              :     {
    1518       183634 :         case MultiXactStatusForKeyShare:
    1519       183634 :             return "keysh";
    1520            0 :         case MultiXactStatusForShare:
    1521            0 :             return "sh";
    1522            0 :         case MultiXactStatusForNoKeyUpdate:
    1523            0 :             return "fornokeyupd";
    1524            0 :         case MultiXactStatusForUpdate:
    1525            0 :             return "forupd";
    1526         4454 :         case MultiXactStatusNoKeyUpdate:
    1527         4454 :             return "nokeyupd";
    1528            0 :         case MultiXactStatusUpdate:
    1529            0 :             return "upd";
    1530            0 :         default:
    1531            0 :             elog(ERROR, "unrecognized multixact status %d", status);
    1532              :             return "";
    1533              :     }
    1534              : }
    1535              : 
    1536              : char *
    1537            0 : mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
    1538              : {
    1539              :     static char *str = NULL;
    1540              :     StringInfoData buf;
    1541              :     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              :                      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              : }
    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       550452 : 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       550452 :     OldestMemberMXactId[MyProcNumber] = InvalidMultiXactId;
    1578       550452 :     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       550452 :     MXactContext = NULL;
    1585       550452 :     dclist_init(&MXactCache);
    1586       550452 : }
    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          304 : AtPrepare_MultiXact(void)
    1597              : {
    1598          304 :     MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
    1599              : 
    1600          304 :     if (MultiXactIdIsValid(myOldestMember))
    1601           62 :         RegisterTwoPhaseRecord(TWOPHASE_RM_MULTIXACT_ID, 0,
    1602              :                                &myOldestMember, sizeof(MultiXactId));
    1603          304 : }
    1604              : 
    1605              : /*
    1606              :  * PostPrepare_MultiXact
    1607              :  *      Clean up after successful PREPARE TRANSACTION
    1608              :  */
    1609              : void
    1610          304 : PostPrepare_MultiXact(FullTransactionId fxid)
    1611              : {
    1612              :     MultiXactId myOldestMember;
    1613              : 
    1614              :     /*
    1615              :      * Transfer our OldestMemberMXactId value to the slot reserved for the
    1616              :      * prepared transaction.
    1617              :      */
    1618          304 :     myOldestMember = OldestMemberMXactId[MyProcNumber];
    1619          304 :     if (MultiXactIdIsValid(myOldestMember))
    1620              :     {
    1621           62 :         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           62 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    1630              : 
    1631           62 :         OldestMemberMXactId[dummyProcNumber] = myOldestMember;
    1632           62 :         OldestMemberMXactId[MyProcNumber] = InvalidMultiXactId;
    1633              : 
    1634           62 :         LWLockRelease(MultiXactGenLock);
    1635              :     }
    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          304 :     OldestVisibleMXactId[MyProcNumber] = InvalidMultiXactId;
    1646              : 
    1647              :     /*
    1648              :      * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
    1649              :      */
    1650          304 :     MXactContext = NULL;
    1651          304 :     dclist_init(&MXactCache);
    1652          304 : }
    1653              : 
    1654              : /*
    1655              :  * multixact_twophase_recover
    1656              :  *      Recover the state of a prepared transaction at startup
    1657              :  */
    1658              : void
    1659            8 : multixact_twophase_recover(FullTransactionId fxid, uint16 info,
    1660              :                            void *recdata, uint32 len)
    1661              : {
    1662            8 :     ProcNumber  dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, false);
    1663              :     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              :     Assert(len == sizeof(MultiXactId));
    1670            8 :     oldestMember = *((MultiXactId *) recdata);
    1671              : 
    1672            8 :     OldestMemberMXactId[dummyProcNumber] = oldestMember;
    1673            8 : }
    1674              : 
    1675              : /*
    1676              :  * multixact_twophase_postcommit
    1677              :  *      Similar to AtEOXact_MultiXact but for COMMIT PREPARED
    1678              :  */
    1679              : void
    1680           68 : multixact_twophase_postcommit(FullTransactionId fxid, uint16 info,
    1681              :                               void *recdata, uint32 len)
    1682              : {
    1683           68 :     ProcNumber  dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, true);
    1684              : 
    1685              :     Assert(len == sizeof(MultiXactId));
    1686              : 
    1687           68 :     OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
    1688           68 : }
    1689              : 
    1690              : /*
    1691              :  * multixact_twophase_postabort
    1692              :  *      This is actually just the same as the COMMIT case.
    1693              :  */
    1694              : void
    1695           26 : multixact_twophase_postabort(FullTransactionId fxid, uint16 info,
    1696              :                              void *recdata, uint32 len)
    1697              : {
    1698           26 :     multixact_twophase_postcommit(fxid, info, recdata, len);
    1699           26 : }
    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         2127 : MultiXactShmemSize(void)
    1708              : {
    1709              :     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         2127 :     size = SHARED_MULTIXACT_STATE_SIZE;
    1717         2127 :     size = add_size(size, SimpleLruShmemSize(multixact_offset_buffers, 0));
    1718         2127 :     size = add_size(size, SimpleLruShmemSize(multixact_member_buffers, 0));
    1719              : 
    1720         2127 :     return size;
    1721              : }
    1722              : 
    1723              : void
    1724         1140 : MultiXactShmemInit(void)
    1725              : {
    1726              :     bool        found;
    1727              : 
    1728              :     debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
    1729              : 
    1730         1140 :     MultiXactOffsetCtl->PagePrecedes = MultiXactOffsetPagePrecedes;
    1731         1140 :     MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;
    1732              : 
    1733         1140 :     SimpleLruInit(MultiXactOffsetCtl,
    1734              :                   "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              :     SlruPagePrecedesUnitTests(MultiXactOffsetCtl, MULTIXACT_OFFSETS_PER_PAGE);
    1740         1140 :     SimpleLruInit(MultiXactMemberCtl,
    1741              :                   "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         1140 :     MultiXactState = ShmemInitStruct("Shared MultiXact State",
    1750         1140 :                                      SHARED_MULTIXACT_STATE_SIZE,
    1751              :                                      &found);
    1752         1140 :     if (!IsUnderPostmaster)
    1753              :     {
    1754              :         Assert(!found);
    1755              : 
    1756              :         /* Make sure we zero out the per-backend state */
    1757        19519 :         MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
    1758              :     }
    1759              :     else
    1760              :         Assert(found);
    1761              : 
    1762              :     /*
    1763              :      * Set up array pointers.
    1764              :      */
    1765         1140 :     OldestMemberMXactId = MultiXactState->perBackendXactIds;
    1766         1140 :     OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot;
    1767         1140 : }
    1768              : 
    1769              : /*
    1770              :  * GUC check_hook for multixact_offset_buffers
    1771              :  */
    1772              : bool
    1773         1177 : check_multixact_offset_buffers(int *newval, void **extra, GucSource source)
    1774              : {
    1775         1177 :     return check_slru_buffers("multixact_offset_buffers", newval);
    1776              : }
    1777              : 
    1778              : /*
    1779              :  * GUC check_hook for multixact_member_buffers
    1780              :  */
    1781              : bool
    1782         1177 : check_multixact_member_buffers(int *newval, void **extra, GucSource source)
    1783              : {
    1784         1177 :     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           51 : BootStrapMultiXact(void)
    1794              : {
    1795              :     /* Zero the initial pages and flush them to disk */
    1796           51 :     SimpleLruZeroAndWritePage(MultiXactOffsetCtl, 0);
    1797           51 :     SimpleLruZeroAndWritePage(MultiXactMemberCtl, 0);
    1798           51 : }
    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          992 : StartupMultiXact(void)
    1810              : {
    1811          992 :     MultiXactId multi = MultiXactState->nextMXact;
    1812          992 :     MultiXactOffset offset = MultiXactState->nextOffset;
    1813              :     int64       pageno;
    1814              : 
    1815              :     /*
    1816              :      * Initialize offset's idea of the latest page number.
    1817              :      */
    1818          992 :     pageno = MultiXactIdToOffsetPage(multi);
    1819          992 :     pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
    1820              :                         pageno);
    1821              : 
    1822              :     /*
    1823              :      * Initialize member's idea of the latest page number.
    1824              :      */
    1825          992 :     pageno = MXOffsetToMemberPage(offset);
    1826          992 :     pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
    1827              :                         pageno);
    1828          992 : }
    1829              : 
    1830              : /*
    1831              :  * This must be called ONCE at the end of startup/recovery.
    1832              :  */
    1833              : void
    1834          931 : TrimMultiXact(void)
    1835              : {
    1836              :     MultiXactId nextMXact;
    1837              :     MultiXactOffset offset;
    1838              :     MultiXactId oldestMXact;
    1839              :     Oid         oldestMXactDB;
    1840              :     int64       pageno;
    1841              :     int         entryno;
    1842              :     int         flagsoff;
    1843              : 
    1844          931 :     LWLockAcquire(MultiXactGenLock, LW_SHARED);
    1845          931 :     nextMXact = MultiXactState->nextMXact;
    1846          931 :     offset = MultiXactState->nextOffset;
    1847          931 :     oldestMXact = MultiXactState->oldestMultiXactId;
    1848          931 :     oldestMXactDB = MultiXactState->oldestMultiXactDB;
    1849          931 :     LWLockRelease(MultiXactGenLock);
    1850              : 
    1851              :     /* Clean up offsets state */
    1852              : 
    1853              :     /*
    1854              :      * (Re-)Initialize our idea of the latest page number for offsets.
    1855              :      */
    1856          931 :     pageno = MultiXactIdToOffsetPage(nextMXact);
    1857          931 :     pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
    1858              :                         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          931 :     entryno = MultiXactIdToOffsetEntry(nextMXact);
    1873              :     {
    1874              :         int         slotno;
    1875              :         MultiXactOffset *offptr;
    1876          931 :         LWLock     *lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
    1877              : 
    1878          931 :         LWLockAcquire(lock, LW_EXCLUSIVE);
    1879          931 :         if (entryno == 0 || nextMXact == FirstMultiXactId)
    1880          913 :             slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
    1881              :         else
    1882           18 :             slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
    1883          931 :         offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
    1884          931 :         offptr += entryno;
    1885              : 
    1886          931 :         *offptr = offset;
    1887          931 :         if (entryno != 0 && (entryno + 1) * sizeof(MultiXactOffset) != BLCKSZ)
    1888         1552 :             MemSet(offptr + 1, 0, BLCKSZ - (entryno + 1) * sizeof(MultiXactOffset));
    1889              : 
    1890          931 :         MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
    1891          931 :         LWLockRelease(lock);
    1892              :     }
    1893              : 
    1894              :     /*
    1895              :      * And the same for members.
    1896              :      *
    1897              :      * (Re-)Initialize our idea of the latest page number for members.
    1898              :      */
    1899          931 :     pageno = MXOffsetToMemberPage(offset);
    1900          931 :     pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
    1901              :                         pageno);
    1902              : 
    1903              :     /*
    1904              :      * Zero out the remainder of the current members page.  See notes in
    1905              :      * TrimCLOG() for motivation.
    1906              :      */
    1907          931 :     flagsoff = MXOffsetToFlagsOffset(offset);
    1908          931 :     if (flagsoff != 0)
    1909              :     {
    1910              :         int         slotno;
    1911              :         TransactionId *xidptr;
    1912              :         int         memberoff;
    1913           17 :         LWLock     *lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
    1914              : 
    1915           17 :         LWLockAcquire(lock, LW_EXCLUSIVE);
    1916           17 :         memberoff = MXOffsetToMemberOffset(offset);
    1917           17 :         slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
    1918           17 :         xidptr = (TransactionId *)
    1919           17 :             (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
    1920              : 
    1921           17 :         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           17 :         MultiXactMemberCtl->shared->page_dirty[slotno] = true;
    1930           17 :         LWLockRelease(lock);
    1931              :     }
    1932              : 
    1933              :     /* signal that we're officially up */
    1934          931 :     LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    1935          931 :     MultiXactState->finishedStartup = true;
    1936          931 :     LWLockRelease(MultiXactGenLock);
    1937              : 
    1938              :     /* Now compute how far away the next multixid wraparound is. */
    1939          931 :     SetMultiXactIdLimit(oldestMXact, oldestMXactDB);
    1940          931 : }
    1941              : 
    1942              : /*
    1943              :  * Get the MultiXact data to save in a checkpoint record
    1944              :  */
    1945              : void
    1946         1586 : MultiXactGetCheckptMulti(bool is_shutdown,
    1947              :                          MultiXactId *nextMulti,
    1948              :                          MultiXactOffset *nextMultiOffset,
    1949              :                          MultiXactId *oldestMulti,
    1950              :                          Oid *oldestMultiDB)
    1951              : {
    1952         1586 :     LWLockAcquire(MultiXactGenLock, LW_SHARED);
    1953         1586 :     *nextMulti = MultiXactState->nextMXact;
    1954         1586 :     *nextMultiOffset = MultiXactState->nextOffset;
    1955         1586 :     *oldestMulti = MultiXactState->oldestMultiXactId;
    1956         1586 :     *oldestMultiDB = MultiXactState->oldestMultiXactDB;
    1957         1586 :     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         1586 : }
    1963              : 
    1964              : /*
    1965              :  * Perform a checkpoint --- either during shutdown, or on-the-fly
    1966              :  */
    1967              : void
    1968         1783 : CheckPointMultiXact(void)
    1969              : {
    1970              :     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         1783 :     SimpleLruWriteAll(MultiXactOffsetCtl, true);
    1978         1783 :     SimpleLruWriteAll(MultiXactMemberCtl, true);
    1979              : 
    1980              :     TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
    1981         1783 : }
    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         1084 : MultiXactSetNextMXact(MultiXactId nextMulti,
    1993              :                       MultiXactOffset nextMultiOffset)
    1994              : {
    1995              :     Assert(MultiXactIdIsValid(nextMulti));
    1996              :     debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %" PRIu64,
    1997              :                 nextMulti, nextMultiOffset);
    1998              : 
    1999         1084 :     LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    2000         1084 :     MultiXactState->nextMXact = nextMulti;
    2001         1084 :     MultiXactState->nextOffset = nextMultiOffset;
    2002         1084 :     LWLockRelease(MultiXactGenLock);
    2003         1084 : }
    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         3106 : SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
    2015              : {
    2016              :     MultiXactId multiVacLimit;
    2017              :     MultiXactId multiWarnLimit;
    2018              :     MultiXactId multiStopLimit;
    2019              :     MultiXactId multiWrapLimit;
    2020              :     MultiXactId curMulti;
    2021              : 
    2022              :     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         3106 :     multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
    2030         3106 :     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         3106 :     multiStopLimit = multiWrapLimit - 3000000;
    2038         3106 :     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         3106 :     multiWarnLimit = multiWrapLimit - 40000000;
    2052         3106 :     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         3106 :     multiVacLimit = oldest_datminmxid + autovacuum_multixact_freeze_max_age;
    2064         3106 :     if (multiVacLimit < FirstMultiXactId)
    2065            0 :         multiVacLimit += FirstMultiXactId;
    2066              : 
    2067              :     /* Grab lock for just long enough to set the new limit values */
    2068         3106 :     LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    2069         3106 :     MultiXactState->oldestMultiXactId = oldest_datminmxid;
    2070         3106 :     MultiXactState->oldestMultiXactDB = oldest_datoid;
    2071         3106 :     MultiXactState->multiVacLimit = multiVacLimit;
    2072         3106 :     MultiXactState->multiWarnLimit = multiWarnLimit;
    2073         3106 :     MultiXactState->multiStopLimit = multiStopLimit;
    2074         3106 :     MultiXactState->multiWrapLimit = multiWrapLimit;
    2075         3106 :     curMulti = MultiXactState->nextMXact;
    2076         3106 :     LWLockRelease(MultiXactGenLock);
    2077              : 
    2078              :     /* Log the info */
    2079         3106 :     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         3106 :     if (!MultiXactState->finishedStartup)
    2091         1045 :         return;
    2092              : 
    2093              :     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         2061 :     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         2061 :     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         2061 :     if (MultiXactIdPrecedes(multiWarnLimit, curMulti))
    2116              :     {
    2117              :         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              :     }
    2152              : }
    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          694 : MultiXactAdvanceNextMXact(MultiXactId minMulti,
    2165              :                           MultiXactOffset minMultiOffset)
    2166              : {
    2167              :     Assert(MultiXactIdIsValid(minMulti));
    2168              : 
    2169          694 :     LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    2170          694 :     if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti))
    2171              :     {
    2172              :         debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
    2173            4 :         MultiXactState->nextMXact = minMulti;
    2174              :     }
    2175          694 :     if (MultiXactState->nextOffset < minMultiOffset)
    2176              :     {
    2177              :         debug_elog3(DEBUG2, "MultiXact: setting next offset to %" PRIu64,
    2178              :                     minMultiOffset);
    2179            4 :         MultiXactState->nextOffset = minMultiOffset;
    2180              :     }
    2181          694 :     LWLockRelease(MultiXactGenLock);
    2182          694 : }
    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          729 : MultiXactAdvanceOldest(MultiXactId oldestMulti, Oid oldestMultiDB)
    2192              : {
    2193              :     Assert(InRecovery);
    2194              : 
    2195          729 :     if (MultiXactIdPrecedes(MultiXactState->oldestMultiXactId, oldestMulti))
    2196            0 :         SetMultiXactIdLimit(oldestMulti, oldestMultiDB);
    2197          729 : }
    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         5300 : ExtendMultiXactOffset(MultiXactId multi)
    2209              : {
    2210              :     int64       pageno;
    2211              :     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         5300 :     if (MultiXactIdToOffsetEntry(multi) != 0 &&
    2218              :         multi != FirstMultiXactId)
    2219         5295 :         return;
    2220              : 
    2221            5 :     pageno = MultiXactIdToOffsetPage(multi);
    2222            5 :     lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
    2223              : 
    2224            5 :     LWLockAcquire(lock, LW_EXCLUSIVE);
    2225              : 
    2226              :     /* Zero the page and make a WAL entry about it */
    2227            5 :     SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
    2228            5 :     XLogSimpleInsertInt64(RM_MULTIXACT_ID, XLOG_MULTIXACT_ZERO_OFF_PAGE,
    2229              :                           pageno);
    2230              : 
    2231            5 :     LWLockRelease(lock);
    2232              : }
    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         5300 : 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        10654 :     while (nmembers > 0)
    2251              :     {
    2252              :         int         flagsoff;
    2253              :         int         flagsbit;
    2254              :         uint32      difference;
    2255              : 
    2256              :         /*
    2257              :          * Only zero when at first entry of a page.
    2258              :          */
    2259         5354 :         flagsoff = MXOffsetToFlagsOffset(offset);
    2260         5354 :         flagsbit = MXOffsetToFlagsBitShift(offset);
    2261         5354 :         if (flagsoff == 0 && flagsbit == 0)
    2262              :         {
    2263              :             int64       pageno;
    2264              :             LWLock     *lock;
    2265              : 
    2266           57 :             pageno = MXOffsetToMemberPage(offset);
    2267           57 :             lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
    2268              : 
    2269           57 :             LWLockAcquire(lock, LW_EXCLUSIVE);
    2270              : 
    2271              :             /* Zero the page and make a WAL entry about it */
    2272           57 :             SimpleLruZeroPage(MultiXactMemberCtl, pageno);
    2273           57 :             XLogSimpleInsertInt64(RM_MULTIXACT_ID,
    2274              :                                   XLOG_MULTIXACT_ZERO_MEM_PAGE, pageno);
    2275              : 
    2276           57 :             LWLockRelease(lock);
    2277              :         }
    2278              : 
    2279              :         /* Compute the number of items till end of current page. */
    2280         5354 :         difference = MULTIXACT_MEMBERS_PER_PAGE - offset % MULTIXACT_MEMBERS_PER_PAGE;
    2281              : 
    2282              :         /*
    2283              :          * Advance to next page.  OK if nmembers goes negative.
    2284              :          */
    2285         5354 :         nmembers -= difference;
    2286         5354 :         offset += difference;
    2287              :     }
    2288         5300 : }
    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       153084 : GetOldestMultiXactId(void)
    2304              : {
    2305              :     MultiXactId oldestMXact;
    2306              :     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       153084 :     LWLockAcquire(MultiXactGenLock, LW_SHARED);
    2313       153084 :     oldestMXact = MultiXactState->nextMXact;
    2314     19083431 :     for (i = 0; i < MaxOldestSlot; i++)
    2315              :     {
    2316              :         MultiXactId thisoldest;
    2317              : 
    2318     18930347 :         thisoldest = OldestMemberMXactId[i];
    2319     18968750 :         if (MultiXactIdIsValid(thisoldest) &&
    2320        38403 :             MultiXactIdPrecedes(thisoldest, oldestMXact))
    2321           18 :             oldestMXact = thisoldest;
    2322     18930347 :         thisoldest = OldestVisibleMXactId[i];
    2323     18930440 :         if (MultiXactIdIsValid(thisoldest) &&
    2324           93 :             MultiXactIdPrecedes(thisoldest, oldestMXact))
    2325            2 :             oldestMXact = thisoldest;
    2326              :     }
    2327              : 
    2328       153084 :     LWLockRelease(MultiXactGenLock);
    2329              : 
    2330       153084 :     return oldestMXact;
    2331              : }
    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         2061 : SetOldestOffset(void)
    2339              : {
    2340              :     MultiXactId oldestMultiXactId;
    2341              :     MultiXactId nextMXact;
    2342         2061 :     MultiXactOffset oldestOffset = 0;   /* placate compiler */
    2343              :     MultiXactOffset nextOffset;
    2344         2061 :     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         2061 :     LWLockAcquire(MultiXactTruncationLock, LW_SHARED);
    2351              : 
    2352              :     /* Read relevant fields from shared memory. */
    2353         2061 :     LWLockAcquire(MultiXactGenLock, LW_SHARED);
    2354         2061 :     oldestMultiXactId = MultiXactState->oldestMultiXactId;
    2355         2061 :     nextMXact = MultiXactState->nextMXact;
    2356         2061 :     nextOffset = MultiXactState->nextOffset;
    2357              :     Assert(MultiXactState->finishedStartup);
    2358         2061 :     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         2061 :     if (oldestMultiXactId == nextMXact)
    2368              :     {
    2369              :         /*
    2370              :          * When the next multixact gets created, it will be stored at the next
    2371              :          * offset.
    2372              :          */
    2373         2041 :         oldestOffset = nextOffset;
    2374         2041 :         oldestOffsetKnown = true;
    2375              :     }
    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              :         oldestOffsetKnown =
    2391           20 :             find_multixact_start(oldestMultiXactId, &oldestOffset);
    2392              : 
    2393           20 :         if (oldestOffsetKnown)
    2394           20 :             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         2061 :     LWLockRelease(MultiXactTruncationLock);
    2404              : 
    2405              :     /* Install the computed value */
    2406         2061 :     if (oldestOffsetKnown)
    2407              :     {
    2408         2061 :         LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    2409         2061 :         MultiXactState->oldestOffset = oldestOffset;
    2410         2061 :         LWLockRelease(MultiXactGenLock);
    2411              :     }
    2412         2061 : }
    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           20 : find_multixact_start(MultiXactId multi, MultiXactOffset *result)
    2425              : {
    2426              :     MultiXactOffset offset;
    2427              :     int64       pageno;
    2428              :     int         entryno;
    2429              :     int         slotno;
    2430              :     MultiXactOffset *offptr;
    2431              : 
    2432              :     Assert(MultiXactState->finishedStartup);
    2433              : 
    2434           20 :     pageno = MultiXactIdToOffsetPage(multi);
    2435           20 :     entryno = MultiXactIdToOffsetEntry(multi);
    2436              : 
    2437              :     /*
    2438              :      * Write out dirty data, so PhysicalPageExists can work correctly.
    2439              :      */
    2440           20 :     SimpleLruWriteAll(MultiXactOffsetCtl, true);
    2441           20 :     SimpleLruWriteAll(MultiXactMemberCtl, true);
    2442              : 
    2443           20 :     if (!SimpleLruDoesPhysicalPageExist(MultiXactOffsetCtl, pageno))
    2444            0 :         return false;
    2445              : 
    2446              :     /* lock is acquired by SimpleLruReadPage_ReadOnly */
    2447           20 :     slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
    2448           20 :     offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
    2449           20 :     offptr += entryno;
    2450           20 :     offset = *offptr;
    2451           20 :     LWLockRelease(SimpleLruGetBankLock(MultiXactOffsetCtl, pageno));
    2452              : 
    2453           20 :     *result = offset;
    2454           20 :     return true;
    2455              : }
    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       119991 : GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *nextOffset,
    2468              :                  MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
    2469              : {
    2470              :     MultiXactId nextMultiXactId;
    2471              : 
    2472       119991 :     LWLockAcquire(MultiXactGenLock, LW_SHARED);
    2473       119991 :     *nextOffset = MultiXactState->nextOffset;
    2474       119991 :     *oldestMultiXactId = MultiXactState->oldestMultiXactId;
    2475       119991 :     nextMultiXactId = MultiXactState->nextMXact;
    2476       119991 :     *oldestOffset = MultiXactState->oldestOffset;
    2477       119991 :     LWLockRelease(MultiXactGenLock);
    2478              : 
    2479       119991 :     *multixacts = nextMultiXactId - *oldestMultiXactId;
    2480       119991 : }
    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       119979 : MultiXactMemberFreezeThreshold(void)
    2512              : {
    2513              :     uint32      multixacts;
    2514              :     uint32      victim_multixacts;
    2515              :     double      fraction;
    2516              :     int         result;
    2517              :     MultiXactId oldestMultiXactId;
    2518              :     MultiXactOffset oldestOffset;
    2519              :     MultiXactOffset nextOffset;
    2520              :     uint64      members;
    2521              : 
    2522              :     /* Read the current offsets and multixact usage. */
    2523       119979 :     GetMultiXactInfo(&multixacts, &nextOffset, &oldestMultiXactId, &oldestOffset);
    2524       119979 :     members = nextOffset - oldestOffset;
    2525              : 
    2526              :     /* If member space utilization is low, no special action is required. */
    2527       119979 :     if (members <= MULTIXACT_MEMBER_LOW_THRESHOLD)
    2528       119979 :         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              : }
    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              :                       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              :                       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         1130 : TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
    2600              : {
    2601              :     MultiXactId oldestMulti;
    2602              :     MultiXactId nextMulti;
    2603              :     MultiXactOffset newOldestOffset;
    2604              :     MultiXactOffset nextOffset;
    2605              : 
    2606              :     Assert(!RecoveryInProgress());
    2607              :     Assert(MultiXactState->finishedStartup);
    2608              :     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         1130 :     LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
    2617              : 
    2618         1130 :     LWLockAcquire(MultiXactGenLock, LW_SHARED);
    2619         1130 :     nextMulti = MultiXactState->nextMXact;
    2620         1130 :     nextOffset = MultiXactState->nextOffset;
    2621         1130 :     oldestMulti = MultiXactState->oldestMultiXactId;
    2622         1130 :     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         1130 :     if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
    2630              :     {
    2631         1130 :         LWLockRelease(MultiXactTruncationLock);
    2632         1130 :         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              :     }
    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              :     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              : }
    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            0 : MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
    2733              : {
    2734              :     MultiXactId multi1;
    2735              :     MultiXactId multi2;
    2736              : 
    2737            0 :     multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
    2738            0 :     multi1 += FirstMultiXactId + 1;
    2739            0 :     multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
    2740            0 :     multi2 += FirstMultiXactId + 1;
    2741              : 
    2742            0 :     return (MultiXactIdPrecedes(multi1, multi2) &&
    2743            0 :             MultiXactIdPrecedes(multi1,
    2744              :                                 multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
    2745              : }
    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      1544028 : MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
    2766              : {
    2767      1544028 :     int32       diff = (int32) (multi1 - multi2);
    2768              : 
    2769      1544028 :     return (diff < 0);
    2770              : }
    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         6934 : MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
    2780              : {
    2781         6934 :     int32       diff = (int32) (multi1 - multi2);
    2782              : 
    2783         6934 :     return (diff <= 0);
    2784              : }
    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              :     XLogRecPtr  recptr;
    2799              :     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            4 : multixact_redo(XLogReaderState *record)
    2816              : {
    2817            4 :     uint8       info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
    2818              : 
    2819              :     /* Backup blocks are not used in multixact records */
    2820              :     Assert(!XLogRecHasAnyBlockRefs(record));
    2821              : 
    2822            4 :     if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
    2823              :     {
    2824              :         int64       pageno;
    2825              : 
    2826            0 :         memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
    2827            0 :         SimpleLruZeroAndWritePage(MultiXactOffsetCtl, pageno);
    2828              :     }
    2829            4 :     else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
    2830              :     {
    2831              :         int64       pageno;
    2832              : 
    2833            0 :         memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
    2834            0 :         SimpleLruZeroAndWritePage(MultiXactMemberCtl, pageno);
    2835              :     }
    2836            4 :     else if (info == XLOG_MULTIXACT_CREATE_ID)
    2837              :     {
    2838            4 :         xl_multixact_create *xlrec =
    2839            4 :             (xl_multixact_create *) XLogRecGetData(record);
    2840              :         TransactionId max_xid;
    2841              :         int         i;
    2842              : 
    2843              :         /* Store the data back into the SLRU files */
    2844            4 :         RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
    2845            4 :                            xlrec->members);
    2846              : 
    2847              :         /* Make sure nextMXact/nextOffset are beyond what this record has */
    2848            4 :         MultiXactAdvanceNextMXact(NextMultiXactId(xlrec->mid),
    2849            4 :                                   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            4 :         max_xid = XLogRecGetXid(record);
    2857           12 :         for (i = 0; i < xlrec->nmembers; i++)
    2858              :         {
    2859            8 :             if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
    2860            0 :                 max_xid = xlrec->members[i].xid;
    2861              :         }
    2862              : 
    2863            4 :         AdvanceNextFullTransactionIdPastXid(max_xid);
    2864              :     }
    2865            0 :     else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
    2866              :     {
    2867              :         xl_multixact_truncate xlrec;
    2868              :         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              :                             pageno);
    2900            0 :         PerformOffsetsTruncation(xlrec.oldestMulti);
    2901              : 
    2902            0 :         LWLockRelease(MultiXactTruncationLock);
    2903              :     }
    2904              :     else
    2905            0 :         elog(PANIC, "multixact_redo: unknown op code %u", info);
    2906            4 : }
    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.0-1