Header And Logo

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

Data Structures | Defines | Typedefs | Functions | Variables

standby.h File Reference

#include "access/xlog.h"
#include "storage/lock.h"
#include "storage/procsignal.h"
#include "storage/relfilenode.h"
Include dependency graph for standby.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  xl_standby_locks
struct  xl_running_xacts
struct  RunningTransactionsData

Defines

#define XLOG_STANDBY_LOCK   0x00
#define XLOG_RUNNING_XACTS   0x10
#define MinSizeOfXactRunningXacts   offsetof(xl_running_xacts, xids)

Typedefs

typedef struct xl_standby_locks xl_standby_locks
typedef struct xl_running_xacts xl_running_xacts
typedef struct
RunningTransactionsData 
RunningTransactionsData
typedef RunningTransactionsDataRunningTransactions

Functions

void InitRecoveryTransactionEnvironment (void)
void ShutdownRecoveryTransactionEnvironment (void)
void ResolveRecoveryConflictWithSnapshot (TransactionId latestRemovedXid, RelFileNode node)
void ResolveRecoveryConflictWithTablespace (Oid tsid)
void ResolveRecoveryConflictWithDatabase (Oid dbid)
void ResolveRecoveryConflictWithBufferPin (void)
void CheckRecoveryConflictDeadlock (void)
void StandbyDeadLockHandler (void)
void StandbyTimeoutHandler (void)
void StandbyAcquireAccessExclusiveLock (TransactionId xid, Oid dbOid, Oid relOid)
void StandbyReleaseLockTree (TransactionId xid, int nsubxids, TransactionId *subxids)
void StandbyReleaseAllLocks (void)
void StandbyReleaseOldLocks (int nxids, TransactionId *xids)
void standby_redo (XLogRecPtr lsn, XLogRecord *record)
void standby_desc (StringInfo buf, uint8 xl_info, char *rec)
void LogAccessExclusiveLock (Oid dbOid, Oid relOid)
void LogAccessExclusiveLockPrepare (void)
void LogStandbySnapshot (void)

Variables

int vacuum_defer_cleanup_age
int max_standby_archive_delay
int max_standby_streaming_delay

Define Documentation

#define MinSizeOfXactRunningXacts   offsetof(xl_running_xacts, xids)

Definition at line 80 of file standby.h.

#define XLOG_RUNNING_XACTS   0x10

Definition at line 57 of file standby.h.

Referenced by LogCurrentRunningXacts(), standby_desc(), and standby_redo().

#define XLOG_STANDBY_LOCK   0x00

Definition at line 56 of file standby.h.

Referenced by LogAccessExclusiveLocks(), standby_desc(), and standby_redo().


Typedef Documentation

Definition at line 111 of file standby.h.


Function Documentation

void CheckRecoveryConflictDeadlock ( void   ) 

Definition at line 483 of file standby.c.

References Assert, ereport, errcode(), errdetail(), errmsg(), ERROR, HoldingBufferPinThatDelaysRecovery(), and InRecovery.

Referenced by ProcSleep().

{
    Assert(!InRecovery);        /* do not call in Startup process */

    if (!HoldingBufferPinThatDelaysRecovery())
        return;

    /*
     * Error message should match ProcessInterrupts() but we avoid calling
     * that because we aren't handling an interrupt at this point. Note that
     * we only cancel the current transaction here, so if we are in a
     * subtransaction and the pin is held by a parent, then the Startup
     * process will continue to wait even though we have avoided deadlock.
     */
    ereport(ERROR,
            (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
             errmsg("canceling statement due to conflict with recovery"),
       errdetail("User transaction caused buffer deadlock with recovery.")));
}

void InitRecoveryTransactionEnvironment ( void   ) 

Definition at line 62 of file standby.c.

References VirtualTransactionId::backendId, GetNextLocalTransactionId(), VirtualTransactionId::localTransactionId, MyBackendId, SharedInvalBackendInit(), standbyState, and VirtualXactLockTableInsert().

Referenced by StartupXLOG().

{
    VirtualTransactionId vxid;

    /*
     * Initialize shared invalidation management for Startup process, being
     * careful to register ourselves as a sendOnly process so we don't need to
     * read messages, nor will we get signalled when the queue starts filling
     * up.
     */
    SharedInvalBackendInit(true);

    /*
     * Lock a virtual transaction id for Startup process.
     *
     * We need to do GetNextLocalTransactionId() because
     * SharedInvalBackendInit() leaves localTransactionid invalid and the lock
     * manager doesn't like that at all.
     *
     * Note that we don't need to run XactLockTableInsert() because nobody
     * needs to wait on xids. That sounds a little strange, but table locks
     * are held by vxids and row level locks are held by xids. All queries
     * hold AccessShareLocks so never block while we write or lock new rows.
     */
    vxid.backendId = MyBackendId;
    vxid.localTransactionId = GetNextLocalTransactionId();
    VirtualXactLockTableInsert(vxid);

    standbyState = STANDBY_INITIALIZED;
}

void LogAccessExclusiveLock ( Oid  dbOid,
Oid  relOid 
)

Definition at line 978 of file standby.c.

References xl_standby_lock::dbOid, GetTopTransactionId(), LogAccessExclusiveLocks(), xl_standby_lock::relOid, and xl_standby_lock::xid.

Referenced by LockAcquireExtended().

{
    xl_standby_lock xlrec;

    xlrec.xid = GetTopTransactionId();

    /*
     * Decode the locktag back to the original values, to avoid sending lots
     * of empty bytes with every message.  See lock.h to check how a locktag
     * is defined for LOCKTAG_RELATION
     */
    xlrec.dbOid = dbOid;
    xlrec.relOid = relOid;

    LogAccessExclusiveLocks(1, &xlrec);
}

void LogAccessExclusiveLockPrepare ( void   ) 

Definition at line 999 of file standby.c.

References GetTopTransactionId().

Referenced by LockAcquireExtended().

{
    /*
     * Ensure that a TransactionId has been assigned to this transaction, for
     * two reasons, both related to lock release on the standby. First, we
     * must assign an xid so that RecordTransactionCommit() and
     * RecordTransactionAbort() do not optimise away the transaction
     * completion record which recovery relies upon to release locks. It's a
     * hack, but for a corner case not worth adding code for into the main
     * commit path. Second, we must assign an xid before the lock is recorded
     * in shared memory, otherwise a concurrently executing
     * GetRunningTransactionLocks() might see a lock associated with an
     * InvalidTransactionId which we later assert cannot happen.
     */
    (void) GetTopTransactionId();
}

void LogStandbySnapshot ( void   ) 

Definition at line 858 of file standby.c.

References Assert, GetRunningTransactionData(), GetRunningTransactionLocks(), LogAccessExclusiveLocks(), LogCurrentRunningXacts(), LWLockRelease(), XidGenLock, and XLogStandbyInfoActive.

Referenced by CreateCheckPoint().

{
    RunningTransactions running;
    xl_standby_lock *locks;
    int         nlocks;

    Assert(XLogStandbyInfoActive());

    /*
     * Get details of any AccessExclusiveLocks being held at the moment.
     *
     * XXX GetRunningTransactionLocks() currently holds a lock on all
     * partitions though it is possible to further optimise the locking. By
     * reference counting locks and storing the value on the ProcArray entry
     * for each backend we can easily tell if any locks need recording without
     * trying to acquire the partition locks and scanning the lock table.
     */
    locks = GetRunningTransactionLocks(&nlocks);
    if (nlocks > 0)
        LogAccessExclusiveLocks(nlocks, locks);

    /*
     * Log details of all in-progress transactions. This should be the last
     * record we write, because standby will open up when it sees this.
     */
    running = GetRunningTransactionData();
    LogCurrentRunningXacts(running);
    /* GetRunningTransactionData() acquired XidGenLock, we must release it */
    LWLockRelease(XidGenLock);
}

void ResolveRecoveryConflictWithBufferPin ( void   ) 

Definition at line 402 of file standby.c.

References Assert, DeadlockTimeout, EnableTimeoutParams::delay_ms, disable_all_timeouts(), enable_timeout_after(), enable_timeouts(), EnableTimeoutParams::fin_time, GetCurrentTimestamp(), GetStandbyLimitTime(), EnableTimeoutParams::id, InHotStandby, PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, ProcWaitForSignal(), SendRecoveryConflictWithBufferPin(), STANDBY_DEADLOCK_TIMEOUT, and EnableTimeoutParams::type.

Referenced by LockBufferForCleanup().

{
    TimestampTz ltime;

    Assert(InHotStandby);

    ltime = GetStandbyLimitTime();

    if (ltime == 0)
    {
        /*
         * We're willing to wait forever for conflicts, so set timeout for
         * deadlock check only
         */
        enable_timeout_after(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout);
    }
    else if (GetCurrentTimestamp() >= ltime)
    {
        /*
         * We're already behind, so clear a path as quickly as possible.
         */
        SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
    }
    else
    {
        /*
         * Wake up at ltime, and check for deadlocks as well if we will be
         * waiting longer than deadlock_timeout
         */
        EnableTimeoutParams timeouts[2];

        timeouts[0].id = STANDBY_TIMEOUT;
        timeouts[0].type = TMPARAM_AT;
        timeouts[0].fin_time = ltime;
        timeouts[1].id = STANDBY_DEADLOCK_TIMEOUT;
        timeouts[1].type = TMPARAM_AFTER;
        timeouts[1].delay_ms = DeadlockTimeout;
        enable_timeouts(timeouts, 2);
    }

    /* Wait to be signaled by UnpinBuffer() */
    ProcWaitForSignal();

    /*
     * Clear any timeout requests established above.  We assume here that
     * the Startup process doesn't have any other timeouts than what this
     * function uses.  If that stops being true, we could cancel the
     * timeouts individually, but that'd be slower.
     */
    disable_all_timeouts(false);
}

void ResolveRecoveryConflictWithDatabase ( Oid  dbid  ) 

Definition at line 314 of file standby.c.

References CancelDBBackends(), CountDBBackends(), pg_usleep(), and PROCSIG_RECOVERY_CONFLICT_DATABASE.

Referenced by dbase_redo().

{
    /*
     * We don't do ResolveRecoveryConflictWithVirtualXIDs() here since that
     * only waits for transactions and completely idle sessions would block
     * us. This is rare enough that we do this as simply as possible: no wait,
     * just force them off immediately.
     *
     * No locking is required here because we already acquired
     * AccessExclusiveLock. Anybody trying to connect while we do this will
     * block during InitPostgres() and then disconnect when they see the
     * database has been removed.
     */
    while (CountDBBackends(dbid) > 0)
    {
        CancelDBBackends(dbid, PROCSIG_RECOVERY_CONFLICT_DATABASE, true);

        /*
         * Wait awhile for them to die so that we avoid flooding an
         * unresponsive backend when system is heavily loaded.
         */
        pg_usleep(10000);
    }
}

void ResolveRecoveryConflictWithSnapshot ( TransactionId  latestRemovedXid,
RelFileNode  node 
)

Definition at line 264 of file standby.c.

References RelFileNode::dbNode, GetConflictingVirtualXIDs(), PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, ResolveRecoveryConflictWithVirtualXIDs(), and TransactionIdIsValid.

Referenced by btree_xlog_delete(), btree_xlog_reuse_page(), heap_xlog_clean(), heap_xlog_cleanup_info(), heap_xlog_freeze(), heap_xlog_visible(), and spgRedoVacuumRedirect().

{
    VirtualTransactionId *backends;

    /*
     * If we get passed InvalidTransactionId then we are a little surprised,
     * but it is theoretically possible in normal running. It also happens
     * when replaying already applied WAL records after a standby crash or
     * restart. If latestRemovedXid is invalid then there is no conflict. That
     * rule applies across all record types that suffer from this conflict.
     */
    if (!TransactionIdIsValid(latestRemovedXid))
        return;

    backends = GetConflictingVirtualXIDs(latestRemovedXid,
                                         node.dbNode);

    ResolveRecoveryConflictWithVirtualXIDs(backends,
                                         PROCSIG_RECOVERY_CONFLICT_SNAPSHOT);
}

void ResolveRecoveryConflictWithTablespace ( Oid  tsid  ) 

Definition at line 286 of file standby.c.

References GetConflictingVirtualXIDs(), InvalidOid, InvalidTransactionId, PROCSIG_RECOVERY_CONFLICT_TABLESPACE, and ResolveRecoveryConflictWithVirtualXIDs().

Referenced by tblspc_redo().

{
    VirtualTransactionId *temp_file_users;

    /*
     * Standby users may be currently using this tablespace for their
     * temporary files. We only care about current users because
     * temp_tablespace parameter will just ignore tablespaces that no longer
     * exist.
     *
     * Ask everybody to cancel their queries immediately so we can ensure no
     * temp files remain and we can remove the tablespace. Nuke the entire
     * site from orbit, it's the only way to be sure.
     *
     * XXX: We could work out the pids of active backends using this
     * tablespace by examining the temp filenames in the directory. We would
     * then convert the pids into VirtualXIDs before attempting to cancel
     * them.
     *
     * We don't wait for commit because drop tablespace is non-transactional.
     */
    temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId,
                                                InvalidOid);
    ResolveRecoveryConflictWithVirtualXIDs(temp_file_users,
                                       PROCSIG_RECOVERY_CONFLICT_TABLESPACE);
}

void ShutdownRecoveryTransactionEnvironment ( void   ) 

Definition at line 101 of file standby.c.

References ExpireAllKnownAssignedTransactionIds(), StandbyReleaseAllLocks(), and VirtualXactLockTableCleanup().

Referenced by StartupXLOG().

{
    /* Mark all tracked in-progress transactions as finished. */
    ExpireAllKnownAssignedTransactionIds();

    /* Release all locks the tracked transactions were holding */
    StandbyReleaseAllLocks();

    /* Cleanup our VirtualTransaction */
    VirtualXactLockTableCleanup();
}

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

Definition at line 40 of file standbydesc.c.

References appendStringInfo(), xl_standby_lock::dbOid, i, xl_standby_locks::locks, xl_standby_locks::nlocks, xl_standby_lock::relOid, standby_desc_running_xacts(), xl_standby_lock::xid, XLOG_RUNNING_XACTS, and XLOG_STANDBY_LOCK.

{
    uint8       info = xl_info & ~XLR_INFO_MASK;

    if (info == XLOG_STANDBY_LOCK)
    {
        xl_standby_locks *xlrec = (xl_standby_locks *) rec;
        int         i;

        appendStringInfo(buf, "AccessExclusive locks:");

        for (i = 0; i < xlrec->nlocks; i++)
            appendStringInfo(buf, " xid %u db %u rel %u",
                             xlrec->locks[i].xid, xlrec->locks[i].dbOid,
                             xlrec->locks[i].relOid);
    }
    else if (info == XLOG_RUNNING_XACTS)
    {
        xl_running_xacts *xlrec = (xl_running_xacts *) rec;

        appendStringInfo(buf, "running xacts:");
        standby_desc_running_xacts(buf, xlrec);
    }
    else
        appendStringInfo(buf, "UNKNOWN");
}

void standby_redo ( XLogRecPtr  lsn,
XLogRecord record 
)

Definition at line 761 of file standby.c.

References Assert, xl_standby_lock::dbOid, elog, i, xl_running_xacts::latestCompletedXid, RunningTransactionsData::latestCompletedXid, xl_standby_locks::locks, xl_running_xacts::nextXid, RunningTransactionsData::nextXid, xl_standby_locks::nlocks, xl_running_xacts::oldestRunningXid, RunningTransactionsData::oldestRunningXid, PANIC, ProcArrayApplyRecoveryInfo(), xl_standby_lock::relOid, STANDBY_DISABLED, StandbyAcquireAccessExclusiveLock(), standbyState, xl_running_xacts::subxcnt, RunningTransactionsData::subxcnt, xl_running_xacts::subxid_overflow, RunningTransactionsData::subxid_overflow, xl_running_xacts::xcnt, RunningTransactionsData::xcnt, xl_standby_lock::xid, xl_running_xacts::xids, RunningTransactionsData::xids, XLogRecord::xl_info, XLOG_RUNNING_XACTS, XLOG_STANDBY_LOCK, XLogRecGetData, and XLR_BKP_BLOCK_MASK.

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

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

    /* Do nothing if we're not in hot standby mode */
    if (standbyState == STANDBY_DISABLED)
        return;

    if (info == XLOG_STANDBY_LOCK)
    {
        xl_standby_locks *xlrec = (xl_standby_locks *) XLogRecGetData(record);
        int         i;

        for (i = 0; i < xlrec->nlocks; i++)
            StandbyAcquireAccessExclusiveLock(xlrec->locks[i].xid,
                                              xlrec->locks[i].dbOid,
                                              xlrec->locks[i].relOid);
    }
    else if (info == XLOG_RUNNING_XACTS)
    {
        xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record);
        RunningTransactionsData running;

        running.xcnt = xlrec->xcnt;
        running.subxcnt = xlrec->subxcnt;
        running.subxid_overflow = xlrec->subxid_overflow;
        running.nextXid = xlrec->nextXid;
        running.latestCompletedXid = xlrec->latestCompletedXid;
        running.oldestRunningXid = xlrec->oldestRunningXid;
        running.xids = xlrec->xids;

        ProcArrayApplyRecoveryInfo(&running);
    }
    else
        elog(PANIC, "standby_redo: unknown op code %u", info);
}

void StandbyAcquireAccessExclusiveLock ( TransactionId  xid,
Oid  dbOid,
Oid  relOid 
)

Definition at line 566 of file standby.c.

References AccessExclusiveLock, Assert, xl_standby_lock::dbOid, DEBUG4, elog, lappend(), LOCKACQUIRE_NOT_AVAIL, LockAcquireExtended(), OidIsValid, palloc(), xl_standby_lock::relOid, ResolveRecoveryConflictWithLock(), SET_LOCKTAG_RELATION, trace_recovery(), TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdIsValid, and xl_standby_lock::xid.

Referenced by lock_twophase_standby_recover(), and standby_redo().

{
    xl_standby_lock *newlock;
    LOCKTAG     locktag;

    /* Already processed? */
    if (!TransactionIdIsValid(xid) ||
        TransactionIdDidCommit(xid) ||
        TransactionIdDidAbort(xid))
        return;

    elog(trace_recovery(DEBUG4),
         "adding recovery lock: db %u rel %u", dbOid, relOid);

    /* dbOid is InvalidOid when we are locking a shared relation. */
    Assert(OidIsValid(relOid));

    newlock = palloc(sizeof(xl_standby_lock));
    newlock->xid = xid;
    newlock->dbOid = dbOid;
    newlock->relOid = relOid;
    RecoveryLockList = lappend(RecoveryLockList, newlock);

    /*
     * Attempt to acquire the lock as requested, if not resolve conflict
     */
    SET_LOCKTAG_RELATION(locktag, newlock->dbOid, newlock->relOid);

    if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false)
        == LOCKACQUIRE_NOT_AVAIL)
        ResolveRecoveryConflictWithLock(newlock->dbOid, newlock->relOid);
}

void StandbyDeadLockHandler ( void   ) 
void StandbyReleaseAllLocks ( void   ) 

Definition at line 659 of file standby.c.

References AccessExclusiveLock, xl_standby_lock::dbOid, DEBUG2, DEBUG4, elog, lfirst, list_delete_cell(), list_head(), lnext, LockRelease(), LOG, pfree(), xl_standby_lock::relOid, SET_LOCKTAG_RELATION, trace_recovery(), and xl_standby_lock::xid.

Referenced by ShutdownRecoveryTransactionEnvironment().

{
    ListCell   *cell,
               *prev,
               *next;
    LOCKTAG     locktag;

    elog(trace_recovery(DEBUG2), "release all standby locks");

    prev = NULL;
    for (cell = list_head(RecoveryLockList); cell; cell = next)
    {
        xl_standby_lock *lock = (xl_standby_lock *) lfirst(cell);

        next = lnext(cell);

        elog(trace_recovery(DEBUG4),
             "releasing recovery lock: xid %u db %u rel %u",
             lock->xid, lock->dbOid, lock->relOid);
        SET_LOCKTAG_RELATION(locktag, lock->dbOid, lock->relOid);
        if (!LockRelease(&locktag, AccessExclusiveLock, true))
            elog(LOG,
                 "RecoveryLockList contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
                 lock->xid, lock->dbOid, lock->relOid);
        RecoveryLockList = list_delete_cell(RecoveryLockList, cell, prev);
        pfree(lock);
    }
}

void StandbyReleaseLockTree ( TransactionId  xid,
int  nsubxids,
TransactionId subxids 
)

Definition at line 645 of file standby.c.

References i, and StandbyReleaseLocks().

Referenced by RecoverPreparedTransactions(), xact_redo_abort(), and xact_redo_commit_internal().

{
    int         i;

    StandbyReleaseLocks(xid);

    for (i = 0; i < nsubxids; i++)
        StandbyReleaseLocks(subxids[i]);
}

void StandbyReleaseOldLocks ( int  nxids,
TransactionId xids 
)

Definition at line 694 of file standby.c.

References AccessExclusiveLock, Assert, xl_standby_lock::dbOid, DEBUG4, elog, i, lfirst, list_delete_cell(), list_head(), lnext, LockRelease(), LOG, pfree(), xl_standby_lock::relOid, SET_LOCKTAG_RELATION, StandbyTransactionIdIsPrepared(), trace_recovery(), TransactionIdIsValid, and xl_standby_lock::xid.

Referenced by ProcArrayApplyRecoveryInfo().

{
    ListCell   *cell,
               *prev,
               *next;
    LOCKTAG     locktag;

    prev = NULL;
    for (cell = list_head(RecoveryLockList); cell; cell = next)
    {
        xl_standby_lock *lock = (xl_standby_lock *) lfirst(cell);
        bool        remove = false;

        next = lnext(cell);

        Assert(TransactionIdIsValid(lock->xid));

        if (StandbyTransactionIdIsPrepared(lock->xid))
            remove = false;
        else
        {
            int         i;
            bool        found = false;

            for (i = 0; i < nxids; i++)
            {
                if (lock->xid == xids[i])
                {
                    found = true;
                    break;
                }
            }

            /*
             * If its not a running transaction, remove it.
             */
            if (!found)
                remove = true;
        }

        if (remove)
        {
            elog(trace_recovery(DEBUG4),
                 "releasing recovery lock: xid %u db %u rel %u",
                 lock->xid, lock->dbOid, lock->relOid);
            SET_LOCKTAG_RELATION(locktag, lock->dbOid, lock->relOid);
            if (!LockRelease(&locktag, AccessExclusiveLock, true))
                elog(LOG,
                     "RecoveryLockList contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
                     lock->xid, lock->dbOid, lock->relOid);
            RecoveryLockList = list_delete_cell(RecoveryLockList, cell, prev);
            pfree(lock);
        }
        else
            prev = cell;
    }
}

void StandbyTimeoutHandler ( void   ) 

Variable Documentation

Definition at line 36 of file standby.c.

Referenced by GetStandbyLimitTime().

Definition at line 37 of file standby.c.

Referenced by GetStandbyLimitTime().

Definition at line 35 of file standby.c.

Referenced by GetOldestXmin(), and GetSnapshotData().