Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Enumerations | Functions

multixact.h File Reference

#include "access/xlog.h"
Include dependency graph for multixact.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  MultiXactMember
struct  xl_multixact_create

Defines

#define InvalidMultiXactId   ((MultiXactId) 0)
#define FirstMultiXactId   ((MultiXactId) 1)
#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)
#define MultiXactIdIsValid(multi)   ((multi) != InvalidMultiXactId)
#define NUM_MXACTOFFSET_BUFFERS   8
#define NUM_MXACTMEMBER_BUFFERS   16
#define MaxMultiXactStatus   MultiXactStatusUpdate
#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00
#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10
#define XLOG_MULTIXACT_CREATE_ID   0x20
#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Typedefs

typedef struct MultiXactMember MultiXactMember
typedef struct xl_multixact_create xl_multixact_create

Enumerations

enum  MultiXactStatus {
  MultiXactStatusForKeyShare = 0x00, MultiXactStatusForShare = 0x01, MultiXactStatusForNoKeyUpdate = 0x02, MultiXactStatusForUpdate = 0x03,
  MultiXactStatusNoKeyUpdate = 0x04, MultiXactStatusUpdate = 0x05
}

Functions

MultiXactId MultiXactIdCreate (TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
MultiXactId MultiXactIdExpand (MultiXactId multi, TransactionId xid, MultiXactStatus status)
MultiXactId ReadNextMultiXactId (void)
bool MultiXactIdIsRunning (MultiXactId multi)
void MultiXactIdSetOldestMember (void)
int GetMultiXactIdMembers (MultiXactId multi, MultiXactMember **xids, bool allow_old)
bool MultiXactIdPrecedes (MultiXactId multi1, MultiXactId multi2)
void AtEOXact_MultiXact (void)
void AtPrepare_MultiXact (void)
void PostPrepare_MultiXact (TransactionId xid)
Size MultiXactShmemSize (void)
void MultiXactShmemInit (void)
void BootStrapMultiXact (void)
void StartupMultiXact (void)
void ShutdownMultiXact (void)
void SetMultiXactIdLimit (MultiXactId oldest_datminmxid, Oid oldest_datoid)
void MultiXactGetCheckptMulti (bool is_shutdown, MultiXactId *nextMulti, MultiXactOffset *nextMultiOffset, MultiXactId *oldestMulti, Oid *oldestMultiDB)
void CheckPointMultiXact (void)
MultiXactId GetOldestMultiXactId (void)
void TruncateMultiXact (MultiXactId cutoff_multi)
void MultiXactSetNextMXact (MultiXactId nextMulti, MultiXactOffset nextMultiOffset)
void MultiXactAdvanceNextMXact (MultiXactId minMulti, MultiXactOffset minMultiOffset)
void MultiXactAdvanceOldest (MultiXactId oldestMulti, Oid oldestMultiDB)
void multixact_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
void multixact_twophase_postcommit (TransactionId xid, uint16 info, void *recdata, uint32 len)
void multixact_twophase_postabort (TransactionId xid, uint16 info, void *recdata, uint32 len)
void multixact_redo (XLogRecPtr lsn, XLogRecord *record)
void multixact_desc (StringInfo buf, uint8 xl_info, char *rec)
char * mxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)

Define Documentation

#define FirstMultiXactId   ((MultiXactId) 1)
#define InvalidMultiXactId   ((MultiXactId) 0)
#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)

Definition at line 24 of file multixact.h.

Referenced by SetMultiXactIdLimit().

#define MaxMultiXactStatus   MultiXactStatusUpdate

Definition at line 49 of file multixact.h.

#define MultiXactIdIsValid (   multi  )     ((multi) != InvalidMultiXactId)
#define NUM_MXACTMEMBER_BUFFERS   16

Definition at line 30 of file multixact.h.

Referenced by MultiXactShmemInit(), and MultiXactShmemSize().

#define NUM_MXACTOFFSET_BUFFERS   8

Definition at line 29 of file multixact.h.

Referenced by MultiXactShmemInit(), MultiXactShmemSize(), and NumLWLocks().

#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Definition at line 76 of file multixact.h.

#define XLOG_MULTIXACT_CREATE_ID   0x20

Definition at line 66 of file multixact.h.

Referenced by CreateMultiXactId(), multixact_desc(), and multixact_redo().

#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10

Definition at line 65 of file multixact.h.

Referenced by multixact_desc(), multixact_redo(), and ZeroMultiXactMemberPage().

#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00

Definition at line 64 of file multixact.h.

Referenced by multixact_desc(), multixact_redo(), and ZeroMultiXactOffsetPage().


Typedef Documentation


Enumeration Type Documentation

Enumerator:
MultiXactStatusForKeyShare 
MultiXactStatusForShare 
MultiXactStatusForNoKeyUpdate 
MultiXactStatusForUpdate 
MultiXactStatusNoKeyUpdate 
MultiXactStatusUpdate 

Definition at line 37 of file multixact.h.

{
    MultiXactStatusForKeyShare = 0x00,
    MultiXactStatusForShare = 0x01,
    MultiXactStatusForNoKeyUpdate = 0x02,
    MultiXactStatusForUpdate = 0x03,
    /* an update that doesn't touch "key" columns */
    MultiXactStatusNoKeyUpdate = 0x04,
    /* other updates, and delete */
    MultiXactStatusUpdate = 0x05
} MultiXactStatus;


Function Documentation

void AtEOXact_MultiXact ( void   ) 

Definition at line 1455 of file multixact.c.

References MyBackendId, OldestMemberMXactId, and OldestVisibleMXactId.

Referenced by AbortTransaction(), and CommitTransaction().

{
    /*
     * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
     * which should only be valid while within a transaction.
     *
     * We assume that storing a MultiXactId is atomic and so we need not take
     * MultiXactGenLock to do this.
     */
    OldestMemberMXactId[MyBackendId] = InvalidMultiXactId;
    OldestVisibleMXactId[MyBackendId] = InvalidMultiXactId;

    /*
     * Discard the local MultiXactId cache.  Since MXactContext was created as
     * a child of TopTransactionContext, we needn't delete it explicitly.
     */
    MXactContext = NULL;
    MXactCache = NULL;
}

void AtPrepare_MultiXact ( void   ) 
void BootStrapMultiXact ( void   ) 

Definition at line 1654 of file multixact.c.

References Assert, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, SimpleLruWritePage(), ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

Referenced by BootStrapXLOG().

{
    int         slotno;

    LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);

    /* Create and zero the first page of the offsets log */
    slotno = ZeroMultiXactOffsetPage(0, false);

    /* Make sure it's written out */
    SimpleLruWritePage(MultiXactOffsetCtl, slotno);
    Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);

    LWLockRelease(MultiXactOffsetControlLock);

    LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);

    /* Create and zero the first page of the members log */
    slotno = ZeroMultiXactMemberPage(0, false);

    /* Make sure it's written out */
    SimpleLruWritePage(MultiXactMemberCtl, slotno);
    Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);

    LWLockRelease(MultiXactMemberControlLock);
}

void CheckPointMultiXact ( void   ) 

Definition at line 1847 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().

Referenced by CheckPointGuts().

{
    TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);

    /* Flush dirty MultiXact pages to disk */
    SimpleLruFlush(MultiXactOffsetCtl, true);
    SimpleLruFlush(MultiXactMemberCtl, true);

    TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
}

int GetMultiXactIdMembers ( MultiXactId  multi,
MultiXactMember **  xids,
bool  allow_old 
)

Definition at line 1030 of file multixact.c.

References Assert, DEBUG1, DEBUG2, debug_elog3, ereport, errcode(), errmsg(), ERROR, FirstMultiXactId, i, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactIdSetOldestVisible(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, MXACT_MEMBER_XACT_BITMASK, mXactCacheGetById(), mXactCachePut(), mxid_to_string(), MXOffsetToFlagsBitShift, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactId, palloc(), pg_usleep(), SimpleLruReadPage(), MultiXactMember::status, TransactionIdIsValid, and MultiXactMember::xid.

Referenced by Do_MultiXactIdWait(), GetMultiXactIdHintBits(), heap_lock_tuple(), MultiXactIdExpand(), MultiXactIdGetUpdateXid(), MultiXactIdIsRunning(), pg_get_multixact_members(), and pgrowlocks().

{
    int         pageno;
    int         prev_pageno;
    int         entryno;
    int         slotno;
    MultiXactOffset *offptr;
    MultiXactOffset offset;
    int         length;
    int         truelength;
    int         i;
    MultiXactId oldestMXact;
    MultiXactId nextMXact;
    MultiXactId tmpMXact;
    MultiXactOffset nextOffset;
    MultiXactMember *ptr;

    debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);

    Assert(MultiXactIdIsValid(multi));

    /* See if the MultiXactId is in the local cache */
    length = mXactCacheGetById(multi, members);
    if (length >= 0)
    {
        debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
                    mxid_to_string(multi, length, *members));
        return length;
    }

    /* Set our OldestVisibleMXactId[] entry if we didn't already */
    MultiXactIdSetOldestVisible();

    /*
     * We check known limits on MultiXact before resorting to the SLRU area.
     *
     * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
     * useful; it should have already been frozen by vacuum.  We've truncated
     * the on-disk structures anyway.  Returning the wrong values could lead to
     * an incorrect visibility result.  However, to support pg_upgrade we need
     * to allow an empty set to be returned regardless, if the caller is
     * willing to accept it; the caller is expected to check that it's an
     * allowed condition (such as ensuring that the infomask bits set on the
     * tuple are consistent with the pg_upgrade scenario).  If the caller is
     * expecting this to be called only on recently created multis, then we
     * raise an error.
     *
     * Conversely, an ID >= nextMXact shouldn't ever be seen here; if it is
     * seen, it implies undetected ID wraparound has occurred.  This raises
     * a hard error.
     *
     * Shared lock is enough here since we aren't modifying any global state.
     * Acquire it just long enough to grab the current counter values.  We may
     * need both nextMXact and nextOffset; see below.
     */
    LWLockAcquire(MultiXactGenLock, LW_SHARED);

    oldestMXact = MultiXactState->oldestMultiXactId;
    nextMXact = MultiXactState->nextMXact;
    nextOffset = MultiXactState->nextOffset;

    LWLockRelease(MultiXactGenLock);

    if (MultiXactIdPrecedes(multi, oldestMXact))
    {
        ereport(allow_old ? DEBUG1 : ERROR,
                (errcode(ERRCODE_INTERNAL_ERROR),
                 errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
                        multi)));
        return -1;
    }

    if (!MultiXactIdPrecedes(multi, nextMXact))
        ereport(ERROR,
                (errcode(ERRCODE_INTERNAL_ERROR),
                 errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
                        multi)));

    /*
     * Find out the offset at which we need to start reading MultiXactMembers
     * and the number of members in the multixact.  We determine the latter as
     * the difference between this multixact's starting offset and the next
     * one's.  However, there are some corner cases to worry about:
     *
     * 1. This multixact may be the latest one created, in which case there is
     * no next one to look at.  In this case the nextOffset value we just
     * saved is the correct endpoint.
     *
     * 2. The next multixact may still be in process of being filled in: that
     * is, another process may have done GetNewMultiXactId but not yet written
     * the offset entry for that ID.  In that scenario, it is guaranteed that
     * the offset entry for that multixact exists (because GetNewMultiXactId
     * won't release MultiXactGenLock until it does) but contains zero
     * (because we are careful to pre-zero offset pages). Because
     * GetNewMultiXactId will never return zero as the starting offset for a
     * multixact, when we read zero as the next multixact's offset, we know we
     * have this case.  We sleep for a bit and try again.
     *
     * 3. Because GetNewMultiXactId increments offset zero to offset one to
     * handle case #2, there is an ambiguity near the point of offset
     * wraparound.  If we see next multixact's offset is one, is that our
     * multixact's actual endpoint, or did it end at zero with a subsequent
     * increment?  We handle this using the knowledge that if the zero'th
     * member slot wasn't filled, it'll contain zero, and zero isn't a valid
     * transaction ID so it can't be a multixact member.  Therefore, if we
     * read a zero from the members array, just ignore it.
     *
     * This is all pretty messy, but the mess occurs only in infrequent corner
     * cases, so it seems better than holding the MultiXactGenLock for a long
     * time on every multixact creation.
     */
retry:
    LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);

    pageno = MultiXactIdToOffsetPage(multi);
    entryno = MultiXactIdToOffsetEntry(multi);

    slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
    offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
    offptr += entryno;
    offset = *offptr;

    Assert(offset != 0);

    /*
     * Use the same increment rule as GetNewMultiXactId(), that is, don't
     * handle wraparound explicitly until needed.
     */
    tmpMXact = multi + 1;

    if (nextMXact == tmpMXact)
    {
        /* Corner case 1: there is no next multixact */
        length = nextOffset - offset;
    }
    else
    {
        MultiXactOffset nextMXOffset;

        /* handle wraparound if needed */
        if (tmpMXact < FirstMultiXactId)
            tmpMXact = FirstMultiXactId;

        prev_pageno = pageno;

        pageno = MultiXactIdToOffsetPage(tmpMXact);
        entryno = MultiXactIdToOffsetEntry(tmpMXact);

        if (pageno != prev_pageno)
            slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);

        offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
        offptr += entryno;
        nextMXOffset = *offptr;

        if (nextMXOffset == 0)
        {
            /* Corner case 2: next multixact is still being filled in */
            LWLockRelease(MultiXactOffsetControlLock);
            pg_usleep(1000L);
            goto retry;
        }

        length = nextMXOffset - offset;
    }

    LWLockRelease(MultiXactOffsetControlLock);

    ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
    *members = ptr;

    /* Now get the members themselves. */
    LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);

    truelength = 0;
    prev_pageno = -1;
    for (i = 0; i < length; i++, offset++)
    {
        TransactionId *xactptr;
        uint32     *flagsptr;
        int         flagsoff;
        int         bshift;
        int         memberoff;

        pageno = MXOffsetToMemberPage(offset);
        memberoff = MXOffsetToMemberOffset(offset);

        if (pageno != prev_pageno)
        {
            slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
            prev_pageno = pageno;
        }

        xactptr = (TransactionId *)
            (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);

        if (!TransactionIdIsValid(*xactptr))
        {
            /* Corner case 3: we must be looking at unused slot zero */
            Assert(offset == 0);
            continue;
        }

        flagsoff = MXOffsetToFlagsOffset(offset);
        bshift = MXOffsetToFlagsBitShift(offset);
        flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);

        ptr[truelength].xid = *xactptr;
        ptr[truelength].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
        truelength++;
    }

    LWLockRelease(MultiXactMemberControlLock);

    /*
     * Copy the result into the local cache.
     */
    mXactCachePut(multi, truelength, ptr);

    debug_elog3(DEBUG2, "GetMembers: no cache for %s",
                mxid_to_string(multi, truelength, ptr));
    return truelength;
}

MultiXactId GetOldestMultiXactId ( void   ) 

Definition at line 2128 of file multixact.c.

References FirstMultiXactId, i, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactStateData::nextMXact, OldestMemberMXactId, and OldestVisibleMXactId.

Referenced by AddNewRelationTuple(), ExecuteTruncate(), vac_update_datfrozenxid(), and vacuum_set_xid_limits().

{
    MultiXactId     oldestMXact;
    MultiXactId     nextMXact;
    int             i;

    /*
     * This is the oldest valid value among all the OldestMemberMXactId[] and
     * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
     */
    LWLockAcquire(MultiXactGenLock, LW_SHARED);

    /*
     * We have to beware of the possibility that nextMXact is in the
     * wrapped-around state.  We don't fix the counter itself here, but we
     * must be sure to use a valid value in our calculation.
     */
    nextMXact = MultiXactState->nextMXact;
    if (nextMXact < FirstMultiXactId)
        nextMXact = FirstMultiXactId;

    oldestMXact = nextMXact;
    for (i = 1; i <= MaxOldestSlot; i++)
    {
        MultiXactId thisoldest;

        thisoldest = OldestMemberMXactId[i];
        if (MultiXactIdIsValid(thisoldest) &&
            MultiXactIdPrecedes(thisoldest, oldestMXact))
            oldestMXact = thisoldest;
        thisoldest = OldestVisibleMXactId[i];
        if (MultiXactIdIsValid(thisoldest) &&
            MultiXactIdPrecedes(thisoldest, oldestMXact))
            oldestMXact = thisoldest;
    }

    LWLockRelease(MultiXactGenLock);

    return oldestMXact;
}

void multixact_desc ( StringInfo  buf,
uint8  xl_info,
char *  rec 
)

Definition at line 50 of file mxactdesc.c.

References appendStringInfo(), i, xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, xl_multixact_create::nmembers, out_member(), XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, and XLOG_MULTIXACT_ZERO_OFF_PAGE.

{
    uint8       info = xl_info & ~XLR_INFO_MASK;

    if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
    {
        int         pageno;

        memcpy(&pageno, rec, sizeof(int));
        appendStringInfo(buf, "zero offsets page: %d", pageno);
    }
    else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
    {
        int         pageno;

        memcpy(&pageno, rec, sizeof(int));
        appendStringInfo(buf, "zero members page: %d", pageno);
    }
    else if (info == XLOG_MULTIXACT_CREATE_ID)
    {
        xl_multixact_create *xlrec = (xl_multixact_create *) rec;
        int         i;

        appendStringInfo(buf, "create mxid %u offset %u nmembers %d: ", xlrec->mid,
                         xlrec->moff, xlrec->nmembers);
        for (i = 0; i < xlrec->nmembers; i++)
            out_member(buf, &xlrec->members[i]);
    }
    else
        appendStringInfo(buf, "UNKNOWN");
}

void multixact_redo ( XLogRecPtr  lsn,
XLogRecord record 
)

Definition at line 2343 of file multixact.c.

References Assert, elog, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, MultiXactAdvanceNextMXact(), MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, VariableCacheData::nextXid, xl_multixact_create::nmembers, PANIC, RecordNewMultiXact(), ShmemVariableCache, SimpleLruWritePage(), TransactionIdAdvance, TransactionIdFollowsOrEquals(), TransactionIdPrecedes(), MultiXactMember::xid, XidGenLock, XLogRecord::xl_info, XLogRecord::xl_xid, XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, XLogRecGetData, XLR_BKP_BLOCK_MASK, ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

{
    uint8       info = record->xl_info & ~XLR_INFO_MASK;

    /* Backup blocks are not used in multixact records */
    Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));

    if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
    {
        int         pageno;
        int         slotno;

        memcpy(&pageno, XLogRecGetData(record), sizeof(int));

        LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);

        slotno = ZeroMultiXactOffsetPage(pageno, false);
        SimpleLruWritePage(MultiXactOffsetCtl, slotno);
        Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);

        LWLockRelease(MultiXactOffsetControlLock);
    }
    else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
    {
        int         pageno;
        int         slotno;

        memcpy(&pageno, XLogRecGetData(record), sizeof(int));

        LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);

        slotno = ZeroMultiXactMemberPage(pageno, false);
        SimpleLruWritePage(MultiXactMemberCtl, slotno);
        Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);

        LWLockRelease(MultiXactMemberControlLock);
    }
    else if (info == XLOG_MULTIXACT_CREATE_ID)
    {
        xl_multixact_create *xlrec =
            (xl_multixact_create *) XLogRecGetData(record);
        TransactionId max_xid;
        int         i;

        /* Store the data back into the SLRU files */
        RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
                           xlrec->members);

        /* Make sure nextMXact/nextOffset are beyond what this record has */
        MultiXactAdvanceNextMXact(xlrec->mid + 1,
                                  xlrec->moff + xlrec->nmembers);

        /*
         * Make sure nextXid is beyond any XID mentioned in the record. This
         * should be unnecessary, since any XID found here ought to have other
         * evidence in the XLOG, but let's be safe.
         */
        max_xid = record->xl_xid;
        for (i = 0; i < xlrec->nmembers; i++)
        {
            if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
                max_xid = xlrec->members[i].xid;
        }

        /*
         * We don't expect anyone else to modify nextXid, hence startup
         * process doesn't need to hold a lock while checking this. We still
         * acquire the lock to modify it, though.
         */
        if (TransactionIdFollowsOrEquals(max_xid,
                                         ShmemVariableCache->nextXid))
        {
            LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
            ShmemVariableCache->nextXid = max_xid;
            TransactionIdAdvance(ShmemVariableCache->nextXid);
            LWLockRelease(XidGenLock);
        }
    }
    else
        elog(PANIC, "multixact_redo: unknown op code %u", info);
}

void multixact_twophase_postabort ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1582 of file multixact.c.

References multixact_twophase_postcommit().

{
    multixact_twophase_postcommit(xid, info, recdata, len);
}

void multixact_twophase_postcommit ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1567 of file multixact.c.

References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

Referenced by multixact_twophase_postabort().

{
    BackendId   dummyBackendId = TwoPhaseGetDummyBackendId(xid);

    Assert(len == sizeof(MultiXactId));

    OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
}

void multixact_twophase_recover ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1546 of file multixact.c.

References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

{
    BackendId   dummyBackendId = TwoPhaseGetDummyBackendId(xid);
    MultiXactId oldestMember;

    /*
     * Get the oldest member XID from the state file record, and set it in the
     * OldestMemberMXactId slot reserved for this prepared transaction.
     */
    Assert(len == sizeof(MultiXactId));
    oldestMember = *((MultiXactId *) recdata);

    OldestMemberMXactId[dummyBackendId] = oldestMember;
}

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)
void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2031 of file multixact.c.

References MultiXactIdPrecedes(), MultiXactStateData::oldestMultiXactId, and SetMultiXactIdLimit().

Referenced by vac_truncate_clog(), and xlog_redo().

{
    if (MultiXactIdPrecedes(MultiXactState->oldestMultiXactId, oldestMulti))
        SetMultiXactIdLimit(oldestMulti, oldestMultiDB);
}

void MultiXactGetCheckptMulti ( bool  is_shutdown,
MultiXactId nextMulti,
MultiXactOffset nextMultiOffset,
MultiXactId oldestMulti,
Oid oldestMultiDB 
)

Definition at line 1825 of file multixact.c.

References DEBUG2, debug_elog6, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, and MultiXactStateData::oldestMultiXactId.

Referenced by CreateCheckPoint().

{
    LWLockAcquire(MultiXactGenLock, LW_SHARED);
    *nextMulti = MultiXactState->nextMXact;
    *nextMultiOffset = MultiXactState->nextOffset;
    *oldestMulti = MultiXactState->oldestMultiXactId;
    *oldestMultiDB = MultiXactState->oldestMultiXactDB;
    LWLockRelease(MultiXactGenLock);

    debug_elog6(DEBUG2,
                "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
                *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
}

MultiXactId MultiXactIdCreate ( TransactionId  xid1,
MultiXactStatus  status1,
TransactionId  xid2,
MultiXactStatus  status2 
)

Definition at line 324 of file multixact.c.

References Assert, AssertArg, CreateMultiXactId(), DEBUG2, debug_elog3, mXactCacheEnt::members, mxid_to_string(), MultiXactMember::status, TransactionIdEquals, TransactionIdIsValid, and MultiXactMember::xid.

Referenced by compute_new_xmax_infomask().

{
    MultiXactId newMulti;
    MultiXactMember members[2];

    AssertArg(TransactionIdIsValid(xid1));
    AssertArg(TransactionIdIsValid(xid2));

    Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));

    /*
     * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
     * are still running.  In typical usage, xid2 will be our own XID and the
     * caller just did a check on xid1, so it'd be wasted effort.
     */

    members[0].xid = xid1;
    members[0].status = status1;
    members[1].xid = xid2;
    members[1].status = status2;

    newMulti = CreateMultiXactId(2, members);

    debug_elog3(DEBUG2, "Create: %s",
                mxid_to_string(newMulti, 2, members));

    return newMulti;
}

MultiXactId MultiXactIdExpand ( MultiXactId  multi,
TransactionId  xid,
MultiXactStatus  status 
)

Definition at line 374 of file multixact.c.

References AssertArg, CreateMultiXactId(), DEBUG2, debug_elog3, debug_elog4, debug_elog5, GetMultiXactIdMembers(), i, mXactCacheEnt::members, MultiXactIdIsValid, mxstatus_to_string(), mXactCacheEnt::nmembers, palloc(), pfree(), MultiXactMember::status, TransactionIdDidCommit(), TransactionIdEquals, TransactionIdIsInProgress(), TransactionIdIsValid, and MultiXactMember::xid.

Referenced by compute_new_xmax_infomask().

{
    MultiXactId newMulti;
    MultiXactMember *members;
    MultiXactMember *newMembers;
    int         nmembers;
    int         i;
    int         j;

    AssertArg(MultiXactIdIsValid(multi));
    AssertArg(TransactionIdIsValid(xid));

    debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s",
                multi, xid, mxstatus_to_string(status));

    /*
     * Note: we don't allow for old multis here.  The reason is that the
     * only caller of this function does a check that the multixact is
     * no longer running.
     */
    nmembers = GetMultiXactIdMembers(multi, &members, false);

    if (nmembers < 0)
    {
        MultiXactMember     member;

        /*
         * The MultiXactId is obsolete.  This can only happen if all the
         * MultiXactId members stop running between the caller checking and
         * passing it to us.  It would be better to return that fact to the
         * caller, but it would complicate the API and it's unlikely to happen
         * too often, so just deal with it by creating a singleton MultiXact.
         */
        member.xid = xid;
        member.status = status;
        newMulti = CreateMultiXactId(1, &member);

        debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
                    multi, newMulti);
        return newMulti;
    }

    /*
     * If the TransactionId is already a member of the MultiXactId with the
     * same status, just return the existing MultiXactId.
     */
    for (i = 0; i < nmembers; i++)
    {
        if (TransactionIdEquals(members[i].xid, xid) &&
            (members[i].status == status))
        {
            debug_elog4(DEBUG2, "Expand: %u is already a member of %u",
                        xid, multi);
            pfree(members);
            return multi;
        }
    }

    /*
     * Determine which of the members of the MultiXactId are still of interest.
     * This is any running transaction, and also any transaction that grabbed
     * something stronger than just a lock and was committed.  (An update that
     * aborted is of no interest here.)
     *
     * (Removing dead members is just an optimization, but a useful one.
     * Note we have the same race condition here as above: j could be 0 at the
     * end of the loop.)
     */
    newMembers = (MultiXactMember *)
        palloc(sizeof(MultiXactMember) * (nmembers + 1));

    for (i = 0, j = 0; i < nmembers; i++)
    {
        if (TransactionIdIsInProgress(members[i].xid) ||
            ((members[i].status > MultiXactStatusForUpdate) &&
             TransactionIdDidCommit(members[i].xid)))
        {
            newMembers[j].xid = members[i].xid;
            newMembers[j++].status = members[i].status;
        }
    }

    newMembers[j].xid = xid;
    newMembers[j++].status = status;
    newMulti = CreateMultiXactId(j, newMembers);

    pfree(members);
    pfree(newMembers);

    debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);

    return newMulti;
}

bool MultiXactIdIsRunning ( MultiXactId  multi  ) 

Definition at line 480 of file multixact.c.

References DEBUG2, debug_elog2, debug_elog3, debug_elog4, GetMultiXactIdMembers(), i, mXactCacheEnt::members, mXactCacheEnt::nmembers, pfree(), TransactionIdIsCurrentTransactionId(), and TransactionIdIsInProgress().

Referenced by compute_new_xmax_infomask(), HeapTupleSatisfiesUpdate(), and HeapTupleSatisfiesVacuum().

{
    MultiXactMember *members;
    int         nmembers;
    int         i;

    debug_elog3(DEBUG2, "IsRunning %u?", multi);

    /*
     * "false" here means we assume our callers have checked that the given
     * multi cannot possibly come from a pg_upgraded database.
     */
    nmembers = GetMultiXactIdMembers(multi, &members, false);

    if (nmembers < 0)
    {
        debug_elog2(DEBUG2, "IsRunning: no members");
        return false;
    }

    /*
     * Checking for myself is cheap compared to looking in shared memory;
     * return true if any live subtransaction of the current top-level
     * transaction is a member.
     *
     * This is not needed for correctness, it's just a fast path.
     */
    for (i = 0; i < nmembers; i++)
    {
        if (TransactionIdIsCurrentTransactionId(members[i].xid))
        {
            debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i);
            pfree(members);
            return true;
        }
    }

    /*
     * This could be made faster by having another entry point in procarray.c,
     * walking the PGPROC array only once for all the members.  But in most
     * cases nmembers should be small enough that it doesn't much matter.
     */
    for (i = 0; i < nmembers; i++)
    {
        if (TransactionIdIsInProgress(members[i].xid))
        {
            debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running",
                        i, members[i].xid);
            pfree(members);
            return true;
        }
    }

    pfree(members);

    debug_elog3(DEBUG2, "IsRunning: %u is not running", multi);

    return false;
}

bool MultiXactIdPrecedes ( MultiXactId  multi1,
MultiXactId  multi2 
)
void MultiXactIdSetOldestMember ( void   ) 

Definition at line 554 of file multixact.c.

References DEBUG2, debug_elog4, FirstMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdIsValid, MyBackendId, MultiXactStateData::nextMXact, and OldestMemberMXactId.

Referenced by heap_delete(), heap_lock_tuple(), heap_lock_updated_tuple(), and heap_update().

{
    if (!MultiXactIdIsValid(OldestMemberMXactId[MyBackendId]))
    {
        MultiXactId nextMXact;

        /*
         * You might think we don't need to acquire a lock here, since
         * fetching and storing of TransactionIds is probably atomic, but in
         * fact we do: suppose we pick up nextMXact and then lose the CPU for
         * a long time.  Someone else could advance nextMXact, and then
         * another someone else could compute an OldestVisibleMXactId that
         * would be after the value we are going to store when we get control
         * back.  Which would be wrong.
         */
        LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);

        /*
         * We have to beware of the possibility that nextMXact is in the
         * wrapped-around state.  We don't fix the counter itself here, but we
         * must be sure to store a valid value in our array entry.
         */
        nextMXact = MultiXactState->nextMXact;
        if (nextMXact < FirstMultiXactId)
            nextMXact = FirstMultiXactId;

        OldestMemberMXactId[MyBackendId] = nextMXact;

        LWLockRelease(MultiXactGenLock);

        debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
                    MyBackendId, nextMXact);
    }
}

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 1867 of file multixact.c.

References DEBUG2, debug_elog4, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactStateData::nextMXact, and MultiXactStateData::nextOffset.

Referenced by BootStrapXLOG(), StartupXLOG(), and xlog_redo().

{
    debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
                nextMulti, nextMultiOffset);
    LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    MultiXactState->nextMXact = nextMulti;
    MultiXactState->nextOffset = nextMultiOffset;
    LWLockRelease(MultiXactGenLock);
}

void MultiXactShmemInit ( void   ) 

Definition at line 1610 of file multixact.c.

References Assert, DEBUG2, debug_elog2, IsUnderPostmaster, MemSet, MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, NUM_MXACTMEMBER_BUFFERS, NUM_MXACTOFFSET_BUFFERS, OldestMemberMXactId, OldestVisibleMXactId, MultiXactStateData::perBackendXactIds, SHARED_MULTIXACT_STATE_SIZE, ShmemInitStruct(), and SimpleLruInit().

Referenced by CreateSharedMemoryAndSemaphores().

{
    bool        found;

    debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");

    MultiXactOffsetCtl->PagePrecedes = MultiXactOffsetPagePrecedes;
    MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes;

    SimpleLruInit(MultiXactOffsetCtl,
                  "MultiXactOffset Ctl", NUM_MXACTOFFSET_BUFFERS, 0,
                  MultiXactOffsetControlLock, "pg_multixact/offsets");
    SimpleLruInit(MultiXactMemberCtl,
                  "MultiXactMember Ctl", NUM_MXACTMEMBER_BUFFERS, 0,
                  MultiXactMemberControlLock, "pg_multixact/members");

    /* Initialize our shared state struct */
    MultiXactState = ShmemInitStruct("Shared MultiXact State",
                                     SHARED_MULTIXACT_STATE_SIZE,
                                     &found);
    if (!IsUnderPostmaster)
    {
        Assert(!found);

        /* Make sure we zero out the per-backend state */
        MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE);
    }
    else
        Assert(found);

    /*
     * Set up array pointers.  Note that perBackendXactIds[0] is wasted space
     * since we only use indexes 1..MaxOldestSlot in each array.
     */
    OldestMemberMXactId = MultiXactState->perBackendXactIds;
    OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot;
}

Size MultiXactShmemSize ( void   ) 

Definition at line 1594 of file multixact.c.

References add_size(), NUM_MXACTMEMBER_BUFFERS, NUM_MXACTOFFSET_BUFFERS, and SimpleLruShmemSize().

Referenced by CreateSharedMemoryAndSemaphores().

{
    Size        size;

#define SHARED_MULTIXACT_STATE_SIZE \
    add_size(sizeof(MultiXactStateData), \
             mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))

    size = SHARED_MULTIXACT_STATE_SIZE;
    size = add_size(size, SimpleLruShmemSize(NUM_MXACTOFFSET_BUFFERS, 0));
    size = add_size(size, SimpleLruShmemSize(NUM_MXACTMEMBER_BUFFERS, 0));

    return size;
}

char* mxid_to_string ( MultiXactId  multi,
int  nmembers,
MultiXactMember members 
)

Definition at line 1424 of file multixact.c.

References appendStringInfo(), appendStringInfoChar(), buf, StringInfoData::data, i, initStringInfo(), MemoryContextStrdup(), mxstatus_to_string(), NULL, pfree(), status(), and TopMemoryContext.

Referenced by CreateMultiXactId(), GetMultiXactIdMembers(), MultiXactIdCreate(), mXactCacheGetById(), mXactCacheGetBySet(), and mXactCachePut().

{
    static char    *str = NULL;
    StringInfoData  buf;
    int         i;

    if (str != NULL)
        pfree(str);

    initStringInfo(&buf);

    appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
                     mxstatus_to_string(members[0].status));

    for (i = 1; i < nmembers; i++)
        appendStringInfo(&buf, ", %u (%s)", members[i].xid,
                         mxstatus_to_string(members[i].status));

    appendStringInfoChar(&buf, ']');
    str = MemoryContextStrdup(TopMemoryContext, buf.data);
    pfree(buf.data);
    return str;
}

void PostPrepare_MultiXact ( TransactionId  xid  ) 

Definition at line 1497 of file multixact.c.

References LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdIsValid, MyBackendId, OldestMemberMXactId, OldestVisibleMXactId, and TwoPhaseGetDummyBackendId().

Referenced by PrepareTransaction().

{
    MultiXactId myOldestMember;

    /*
     * Transfer our OldestMemberMXactId value to the slot reserved for the
     * prepared transaction.
     */
    myOldestMember = OldestMemberMXactId[MyBackendId];
    if (MultiXactIdIsValid(myOldestMember))
    {
        BackendId   dummyBackendId = TwoPhaseGetDummyBackendId(xid);

        /*
         * Even though storing MultiXactId is atomic, acquire lock to make
         * sure others see both changes, not just the reset of the slot of the
         * current backend. Using a volatile pointer might suffice, but this
         * isn't a hot spot.
         */
        LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);

        OldestMemberMXactId[dummyBackendId] = myOldestMember;
        OldestMemberMXactId[MyBackendId] = InvalidMultiXactId;

        LWLockRelease(MultiXactGenLock);
    }

    /*
     * We don't need to transfer OldestVisibleMXactId value, because the
     * transaction is not going to be looking at any more multixacts once it's
     * prepared.
     *
     * We assume that storing a MultiXactId is atomic and so we need not take
     * MultiXactGenLock to do this.
     */
    OldestVisibleMXactId[MyBackendId] = InvalidMultiXactId;

    /*
     * Discard the local MultiXactId cache like in AtEOX_MultiXact
     */
    MXactContext = NULL;
    MXactCache = NULL;
}

MultiXactId ReadNextMultiXactId ( void   ) 

Definition at line 647 of file multixact.c.

References FirstMultiXactId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, and MultiXactStateData::nextMXact.

Referenced by ATRewriteTables(), AutoVacWorkerMain(), do_start_worker(), and ExecRefreshMatView().

{
    MultiXactId     mxid;

    /* XXX we could presumably do this without a lock. */
    LWLockAcquire(MultiXactGenLock, LW_SHARED);
    mxid = MultiXactState->nextMXact;
    LWLockRelease(MultiXactGenLock);

    if (mxid < FirstMultiXactId)
        mxid = FirstMultiXactId;

    return mxid;
}

void SetMultiXactIdLimit ( MultiXactId  oldest_datminmxid,
Oid  oldest_datoid 
)

Definition at line 1884 of file multixact.c.

References Assert, DEBUG1, ereport, errhint(), errmsg(), FirstMultiXactId, get_database_name(), InRecovery, IsTransactionState(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxMultiXactId, MultiXactStateData::multiStopLimit, MultiXactStateData::multiVacLimit, MultiXactStateData::multiWarnLimit, MultiXactStateData::multiWrapLimit, MultiXactGenLock, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactStateData::nextMXact, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, PMSIGNAL_START_AUTOVAC_LAUNCHER, SendPostmasterSignal(), and WARNING.

Referenced by BootStrapXLOG(), MultiXactAdvanceOldest(), StartupXLOG(), and xlog_redo().

{
    MultiXactId multiVacLimit;
    MultiXactId multiWarnLimit;
    MultiXactId multiStopLimit;
    MultiXactId multiWrapLimit;
    MultiXactId curMulti;

    Assert(MultiXactIdIsValid(oldest_datminmxid));

    /*
     * The place where we actually get into deep trouble is halfway around
     * from the oldest potentially-existing XID/multi.  (This calculation is
     * probably off by one or two counts for Xids, because the special XIDs
     * reduce the size of the loop a little bit.  But we throw in plenty of
     * slop below, so it doesn't matter.)
     */
    multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
    if (multiWrapLimit < FirstMultiXactId)
        multiWrapLimit += FirstMultiXactId;

    /*
     * We'll refuse to continue assigning MultiXactIds once we get within 100
     * multi of data loss.
     */
    multiStopLimit = multiWrapLimit - 100;
    if (multiStopLimit < FirstMultiXactId)
        multiStopLimit -= FirstMultiXactId;

    /*
     * We'll start complaining loudly when we get within 10M multis of the stop
     * point.   This is kind of arbitrary, but if you let your gas gauge get
     * down to 1% of full, would you be looking for the next gas station?  We
     * need to be fairly liberal about this number because there are lots of
     * scenarios where most transactions are done by automatic clients that
     * won't pay attention to warnings. (No, we're not gonna make this
     * configurable.  If you know enough to configure it, you know enough to
     * not get in this kind of trouble in the first place.)
     */
    multiWarnLimit = multiStopLimit - 10000000;
    if (multiWarnLimit < FirstMultiXactId)
        multiWarnLimit -= FirstMultiXactId;

    /*
     * We'll start trying to force autovacuums when oldest_datminmxid gets
     * to be more than 200 million transactions old.
     */
    multiVacLimit = oldest_datminmxid + 200000000;
    if (multiVacLimit < FirstMultiXactId)
        multiVacLimit += FirstMultiXactId;

    /* Grab lock for just long enough to set the new limit values */
    LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
    MultiXactState->oldestMultiXactId = oldest_datminmxid;
    MultiXactState->oldestMultiXactDB = oldest_datoid;
    MultiXactState->multiVacLimit = multiVacLimit;
    MultiXactState->multiWarnLimit = multiWarnLimit;
    MultiXactState->multiStopLimit = multiStopLimit;
    MultiXactState->multiWrapLimit = multiWrapLimit;
    curMulti = MultiXactState->nextMXact;
    LWLockRelease(MultiXactGenLock);

    /* Log the info */
    ereport(DEBUG1,
            (errmsg("MultiXactId wrap limit is %u, limited by database with OID %u",
                    multiWrapLimit, oldest_datoid)));

    /*
     * If past the autovacuum force point, immediately signal an autovac
     * request.  The reason for this is that autovac only processes one
     * database per invocation.  Once it's finished cleaning up the oldest
     * database, it'll call here, and we'll signal the postmaster to start
     * another iteration immediately if there are still any old databases.
     */
    if (MultiXactIdPrecedes(multiVacLimit, curMulti) &&
        IsUnderPostmaster && !InRecovery)
        SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);

    /* Give an immediate warning if past the wrap warn point */
    if (MultiXactIdPrecedes(multiWarnLimit, curMulti) && !InRecovery)
    {
        char       *oldest_datname;

        /*
         * We can be called when not inside a transaction, for example during
         * StartupXLOG().  In such a case we cannot do database access, so we
         * must just report the oldest DB's OID.
         *
         * Note: it's also possible that get_database_name fails and returns
         * NULL, for example because the database just got dropped.  We'll
         * still warn, even though the warning might now be unnecessary.
         */
        if (IsTransactionState())
            oldest_datname = get_database_name(oldest_datoid);
        else
            oldest_datname = NULL;

        if (oldest_datname)
            ereport(WARNING,
                    (errmsg("database \"%s\" must be vacuumed before %u more MultiXactIds are used",
                            oldest_datname,
                            multiWrapLimit - curMulti),
                     errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
                             "You might also need to commit or roll back old prepared transactions.")));
        else
            ereport(WARNING,
                    (errmsg("database with OID %u must be vacuumed before %u more MultiXactIds are used",
                            oldest_datoid,
                            multiWrapLimit - curMulti),
                     errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
                             "You might also need to commit or roll back old prepared transactions.")));
    }
}

void ShutdownMultiXact ( void   ) 

Definition at line 1812 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().

Referenced by ShutdownXLOG().

{
    /* Flush dirty MultiXact pages to disk */
    TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(false);
    SimpleLruFlush(MultiXactOffsetCtl, false);
    SimpleLruFlush(MultiXactMemberCtl, false);
    TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(false);
}

void StartupMultiXact ( void   ) 

Definition at line 1731 of file multixact.c.

References LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MemSet, mXactCacheEnt::multi, MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, and SimpleLruReadPage().

Referenced by StartupXLOG().

{
    MultiXactId multi = MultiXactState->nextMXact;
    MultiXactOffset offset = MultiXactState->nextOffset;
    int         pageno;
    int         entryno;
    int         flagsoff;

    /* Clean up offsets state */
    LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);

    /*
     * Initialize our idea of the latest page number.
     */
    pageno = MultiXactIdToOffsetPage(multi);
    MultiXactOffsetCtl->shared->latest_page_number = pageno;

    /*
     * Zero out the remainder of the current offsets page.  See notes in
     * StartupCLOG() for motivation.
     */
    entryno = MultiXactIdToOffsetEntry(multi);
    if (entryno != 0)
    {
        int         slotno;
        MultiXactOffset *offptr;

        slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
        offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
        offptr += entryno;

        MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));

        MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
    }

    LWLockRelease(MultiXactOffsetControlLock);

    /* And the same for members */
    LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);

    /*
     * Initialize our idea of the latest page number.
     */
    pageno = MXOffsetToMemberPage(offset);
    MultiXactMemberCtl->shared->latest_page_number = pageno;

    /*
     * Zero out the remainder of the current members page.  See notes in
     * TrimCLOG() for motivation.
     */
    flagsoff = MXOffsetToFlagsOffset(offset);
    if (flagsoff != 0)
    {
        int         slotno;
        TransactionId *xidptr;
        int         memberoff;

        memberoff = MXOffsetToMemberOffset(offset);
        slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
        xidptr = (TransactionId *)
            (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);

        MemSet(xidptr, 0, BLCKSZ - memberoff);

        /*
         * Note: we don't need to zero out the flag bits in the remaining
         * members of the current group, because they are always reset before
         * writing.
         */

        MultiXactMemberCtl->shared->page_dirty[slotno] = true;
    }

    LWLockRelease(MultiXactMemberControlLock);
}

void TruncateMultiXact ( MultiXactId  cutoff_multi  ) 

Definition at line 2201 of file multixact.c.

References mxtruncinfo::earliestExistingPage, LWLockRelease(), MultiXactIdPrecedes(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, MXOffsetToMemberPage, SimpleLruReadPage_ReadOnly(), SimpleLruTruncate(), SlruScanDirCbFindEarliest(), and SlruScanDirectory().

Referenced by vac_truncate_clog().

{
    MultiXactOffset oldestOffset;
    mxtruncinfo     trunc;
    MultiXactId     earliest;

    /*
     * Note we can't just plow ahead with the truncation; it's possible that
     * there are no segments to truncate, which is a problem because we are
     * going to attempt to read the offsets page to determine where to truncate
     * the members SLRU.  So we first scan the directory to determine the
     * earliest offsets page number that we can read without error.
     */
    trunc.earliestExistingPage = -1;
    SlruScanDirectory(MultiXactOffsetCtl, SlruScanDirCbFindEarliest, &trunc);
    earliest = trunc.earliestExistingPage * MULTIXACT_OFFSETS_PER_PAGE;

    /* nothing to do */
    if (MultiXactIdPrecedes(oldestMXact, earliest))
        return;

    /*
     * First, compute the safe truncation point for MultiXactMember.
     * This is the starting offset of the multixact we were passed
     * as MultiXactOffset cutoff.
     */
    {
        int         pageno;
        int         slotno;
        int         entryno;
        MultiXactOffset *offptr;

        /* lock is acquired by SimpleLruReadPage_ReadOnly */

        pageno = MultiXactIdToOffsetPage(oldestMXact);
        entryno = MultiXactIdToOffsetEntry(oldestMXact);

        slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno,
                                            oldestMXact);
        offptr = (MultiXactOffset *)
            MultiXactOffsetCtl->shared->page_buffer[slotno];
        offptr += entryno;
        oldestOffset = *offptr;

        LWLockRelease(MultiXactOffsetControlLock);
    }

    /* truncate MultiXactOffset */
    SimpleLruTruncate(MultiXactOffsetCtl,
                      MultiXactIdToOffsetPage(oldestMXact));

    /* truncate MultiXactMembers and we're done */
    SimpleLruTruncate(MultiXactMemberCtl,
                      MXOffsetToMemberPage(oldestOffset));
}