Header And Logo

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

Data Structures | Functions | Variables

deadlock.c File Reference

#include "postgres.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "utils/memutils.h"
Include dependency graph for deadlock.c:

Go to the source code of this file.

Data Structures

struct  EDGE
struct  WAIT_ORDER
struct  DEADLOCK_INFO

Functions

static bool DeadLockCheckRecurse (PGPROC *proc)
static int TestConfiguration (PGPROC *startProc)
static bool FindLockCycle (PGPROC *checkProc, EDGE *softEdges, int *nSoftEdges)
static bool FindLockCycleRecurse (PGPROC *checkProc, int depth, EDGE *softEdges, int *nSoftEdges)
static bool ExpandConstraints (EDGE *constraints, int nConstraints)
static bool TopoSort (LOCK *lock, EDGE *constraints, int nConstraints, PGPROC **ordering)
void InitDeadLockChecking (void)
DeadLockState DeadLockCheck (PGPROC *proc)
PGPROCGetBlockingAutoVacuumPgproc (void)
void DeadLockReport (void)
void RememberSimpleDeadLock (PGPROC *proc1, LOCKMODE lockmode, LOCK *lock, PGPROC *proc2)

Variables

static PGPROC ** visitedProcs
static int nVisitedProcs
static PGPROC ** topoProcs
static int * beforeConstraints
static int * afterConstraints
static WAIT_ORDERwaitOrders
static int nWaitOrders
static PGPROC ** waitOrderProcs
static EDGEcurConstraints
static int nCurConstraints
static int maxCurConstraints
static EDGEpossibleConstraints
static int nPossibleConstraints
static int maxPossibleConstraints
static DEADLOCK_INFOdeadlockDetails
static int nDeadlockDetails
static PGPROCblocking_autovacuum_proc = NULL

Function Documentation

DeadLockState DeadLockCheck ( PGPROC proc  ) 

Definition at line 204 of file deadlock.c.

References Assert, DeadLockCheckRecurse(), elog, FATAL, FindLockCycle(), GetLocksMethodTable(), i, PGPROC::links, PROC_QUEUE::links, WAIT_ORDER::lock, nCurConstraints, nPossibleConstraints, WAIT_ORDER::nProcs, NULL, nWaitOrders, ProcLockWakeup(), ProcQueueInit(), WAIT_ORDER::procs, SHMQueueInsertBefore(), PROC_QUEUE::size, and LOCK::waitProcs.

Referenced by CheckDeadLock().

{
    int         i,
                j;

    /* Initialize to "no constraints" */
    nCurConstraints = 0;
    nPossibleConstraints = 0;
    nWaitOrders = 0;

    /* Initialize to not blocked by an autovacuum worker */
    blocking_autovacuum_proc = NULL;

    /* Search for deadlocks and possible fixes */
    if (DeadLockCheckRecurse(proc))
    {
        /*
         * Call FindLockCycle one more time, to record the correct
         * deadlockDetails[] for the basic state with no rearrangements.
         */
        int         nSoftEdges;

        TRACE_POSTGRESQL_DEADLOCK_FOUND();

        nWaitOrders = 0;
        if (!FindLockCycle(proc, possibleConstraints, &nSoftEdges))
            elog(FATAL, "deadlock seems to have disappeared");

        return DS_HARD_DEADLOCK;    /* cannot find a non-deadlocked state */
    }

    /* Apply any needed rearrangements of wait queues */
    for (i = 0; i < nWaitOrders; i++)
    {
        LOCK       *lock = waitOrders[i].lock;
        PGPROC    **procs = waitOrders[i].procs;
        int         nProcs = waitOrders[i].nProcs;
        PROC_QUEUE *waitQueue = &(lock->waitProcs);

        Assert(nProcs == waitQueue->size);

#ifdef DEBUG_DEADLOCK
        PrintLockQueue(lock, "DeadLockCheck:");
#endif

        /* Reset the queue and re-add procs in the desired order */
        ProcQueueInit(waitQueue);
        for (j = 0; j < nProcs; j++)
        {
            SHMQueueInsertBefore(&(waitQueue->links), &(procs[j]->links));
            waitQueue->size++;
        }

#ifdef DEBUG_DEADLOCK
        PrintLockQueue(lock, "rearranged to:");
#endif

        /* See if any waiters for the lock can be woken up now */
        ProcLockWakeup(GetLocksMethodTable(lock), lock);
    }

    /* Return code tells caller if we had to escape a deadlock or not */
    if (nWaitOrders > 0)
        return DS_SOFT_DEADLOCK;
    else if (blocking_autovacuum_proc != NULL)
        return DS_BLOCKED_BY_AUTOVACUUM;
    else
        return DS_NO_DEADLOCK;
}

static bool DeadLockCheckRecurse ( PGPROC proc  )  [static]

Definition at line 302 of file deadlock.c.

References elog, FATAL, i, MaxBackends, maxCurConstraints, maxPossibleConstraints, nCurConstraints, nPossibleConstraints, and TestConfiguration().

Referenced by DeadLockCheck().

{
    int         nEdges;
    int         oldPossibleConstraints;
    bool        savedList;
    int         i;

    nEdges = TestConfiguration(proc);
    if (nEdges < 0)
        return true;            /* hard deadlock --- no solution */
    if (nEdges == 0)
        return false;           /* good configuration found */
    if (nCurConstraints >= maxCurConstraints)
        return true;            /* out of room for active constraints? */
    oldPossibleConstraints = nPossibleConstraints;
    if (nPossibleConstraints + nEdges + MaxBackends <= maxPossibleConstraints)
    {
        /* We can save the edge list in possibleConstraints[] */
        nPossibleConstraints += nEdges;
        savedList = true;
    }
    else
    {
        /* Not room; will need to regenerate the edges on-the-fly */
        savedList = false;
    }

    /*
     * Try each available soft edge as an addition to the configuration.
     */
    for (i = 0; i < nEdges; i++)
    {
        if (!savedList && i > 0)
        {
            /* Regenerate the list of possible added constraints */
            if (nEdges != TestConfiguration(proc))
                elog(FATAL, "inconsistent results during deadlock check");
        }
        curConstraints[nCurConstraints] =
            possibleConstraints[oldPossibleConstraints + i];
        nCurConstraints++;
        if (!DeadLockCheckRecurse(proc))
            return false;       /* found a valid solution! */
        /* give up on that added constraint, try again */
        nCurConstraints--;
    }
    nPossibleConstraints = oldPossibleConstraints;
    return true;                /* no solution found */
}

void DeadLockReport ( void   ) 

Definition at line 893 of file deadlock.c.

References _, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), StringInfoData::data, DescribeLockTag(), ereport, errcode(), errdetail_internal(), errdetail_log(), errhint(), errmsg(), ERROR, GetLockmodeName(), initStringInfo(), DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, LOCKTAG::locktag_lockmethodid, nDeadlockDetails, pgstat_get_backend_current_activity(), pgstat_report_deadlock(), DEADLOCK_INFO::pid, and resetStringInfo().

Referenced by WaitOnLock().

{
    StringInfoData clientbuf;   /* errdetail for client */
    StringInfoData logbuf;      /* errdetail for server log */
    StringInfoData locktagbuf;
    int         i;

    initStringInfo(&clientbuf);
    initStringInfo(&logbuf);
    initStringInfo(&locktagbuf);

    /* Generate the "waits for" lines sent to the client */
    for (i = 0; i < nDeadlockDetails; i++)
    {
        DEADLOCK_INFO *info = &deadlockDetails[i];
        int         nextpid;

        /* The last proc waits for the first one... */
        if (i < nDeadlockDetails - 1)
            nextpid = info[1].pid;
        else
            nextpid = deadlockDetails[0].pid;

        /* reset locktagbuf to hold next object description */
        resetStringInfo(&locktagbuf);

        DescribeLockTag(&locktagbuf, &info->locktag);

        if (i > 0)
            appendStringInfoChar(&clientbuf, '\n');

        appendStringInfo(&clientbuf,
                  _("Process %d waits for %s on %s; blocked by process %d."),
                         info->pid,
                         GetLockmodeName(info->locktag.locktag_lockmethodid,
                                         info->lockmode),
                         locktagbuf.data,
                         nextpid);
    }

    /* Duplicate all the above for the server ... */
    appendStringInfoString(&logbuf, clientbuf.data);

    /* ... and add info about query strings */
    for (i = 0; i < nDeadlockDetails; i++)
    {
        DEADLOCK_INFO *info = &deadlockDetails[i];

        appendStringInfoChar(&logbuf, '\n');

        appendStringInfo(&logbuf,
                         _("Process %d: %s"),
                         info->pid,
                      pgstat_get_backend_current_activity(info->pid, false));
    }

    pgstat_report_deadlock();

    ereport(ERROR,
            (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
             errmsg("deadlock detected"),
             errdetail_internal("%s", clientbuf.data),
             errdetail_log("%s", logbuf.data),
             errhint("See server log for query details.")));
}

static bool ExpandConstraints ( EDGE constraints,
int  nConstraints 
) [static]

Definition at line 698 of file deadlock.c.

References Assert, i, WAIT_ORDER::lock, MaxBackends, WAIT_ORDER::nProcs, nWaitOrders, WAIT_ORDER::procs, PROC_QUEUE::size, TopoSort(), EDGE::waiter, PGPROC::waitLock, and LOCK::waitProcs.

Referenced by TestConfiguration().

{
    int         nWaitOrderProcs = 0;
    int         i,
                j;

    nWaitOrders = 0;

    /*
     * Scan constraint list backwards.  This is because the last-added
     * constraint is the only one that could fail, and so we want to test it
     * for inconsistency first.
     */
    for (i = nConstraints; --i >= 0;)
    {
        PGPROC     *proc = constraints[i].waiter;
        LOCK       *lock = proc->waitLock;

        /* Did we already make a list for this lock? */
        for (j = nWaitOrders; --j >= 0;)
        {
            if (waitOrders[j].lock == lock)
                break;
        }
        if (j >= 0)
            continue;
        /* No, so allocate a new list */
        waitOrders[nWaitOrders].lock = lock;
        waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
        waitOrders[nWaitOrders].nProcs = lock->waitProcs.size;
        nWaitOrderProcs += lock->waitProcs.size;
        Assert(nWaitOrderProcs <= MaxBackends);

        /*
         * Do the topo sort.  TopoSort need not examine constraints after this
         * one, since they must be for different locks.
         */
        if (!TopoSort(lock, constraints, i + 1,
                      waitOrders[nWaitOrders].procs))
            return false;
        nWaitOrders++;
    }
    return true;
}

static bool FindLockCycle ( PGPROC checkProc,
EDGE softEdges,
int *  nSoftEdges 
) [static]

Definition at line 436 of file deadlock.c.

References FindLockCycleRecurse(), nDeadlockDetails, and nVisitedProcs.

Referenced by DeadLockCheck(), and TestConfiguration().

{
    nVisitedProcs = 0;
    nDeadlockDetails = 0;
    *nSoftEdges = 0;
    return FindLockCycleRecurse(checkProc, 0, softEdges, nSoftEdges);
}

static bool FindLockCycleRecurse ( PGPROC checkProc,
int  depth,
EDGE softEdges,
int *  nSoftEdges 
) [static]

Definition at line 447 of file deadlock.c.

References PROC_HDR::allPgXact, Assert, EDGE::blocker, LockMethodData::conflictTab, GetLocksMethodTable(), PROCLOCK::holdMask, i, PROC_QUEUE::links, PGPROC::links, LOCKBIT_ON, PROCLOCK::lockLink, DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, MaxBackends, MyProc, PROCLOCKTAG::myProc, nDeadlockDetails, SHM_QUEUE::next, WAIT_ORDER::nProcs, NULL, LockMethodData::numLockModes, nVisitedProcs, nWaitOrders, offsetof, PGPROC::pgprocno, PGPROC::pid, DEADLOCK_INFO::pid, PROC_IS_AUTOVACUUM, ProcGlobal, LOCK::procLocks, WAIT_ORDER::procs, SHMQueueNext(), PROC_QUEUE::size, LOCK::tag, PROCLOCK::tag, PGXACT::vacuumFlags, EDGE::waiter, PGPROC::waitLock, PGPROC::waitLockMode, and LOCK::waitProcs.

Referenced by FindLockCycle().

{
    PGPROC     *proc;
    PGXACT     *pgxact;
    LOCK       *lock;
    PROCLOCK   *proclock;
    SHM_QUEUE  *procLocks;
    LockMethod  lockMethodTable;
    PROC_QUEUE *waitQueue;
    int         queue_size;
    int         conflictMask;
    int         i;
    int         numLockModes,
                lm;

    /*
     * Have we already seen this proc?
     */
    for (i = 0; i < nVisitedProcs; i++)
    {
        if (visitedProcs[i] == checkProc)
        {
            /* If we return to starting point, we have a deadlock cycle */
            if (i == 0)
            {
                /*
                 * record total length of cycle --- outer levels will now fill
                 * deadlockDetails[]
                 */
                Assert(depth <= MaxBackends);
                nDeadlockDetails = depth;

                return true;
            }

            /*
             * Otherwise, we have a cycle but it does not include the start
             * point, so say "no deadlock".
             */
            return false;
        }
    }
    /* Mark proc as seen */
    Assert(nVisitedProcs < MaxBackends);
    visitedProcs[nVisitedProcs++] = checkProc;

    /*
     * If the proc is not waiting, we have no outgoing waits-for edges.
     */
    if (checkProc->links.next == NULL)
        return false;
    lock = checkProc->waitLock;
    if (lock == NULL)
        return false;
    lockMethodTable = GetLocksMethodTable(lock);
    numLockModes = lockMethodTable->numLockModes;
    conflictMask = lockMethodTable->conflictTab[checkProc->waitLockMode];

    /*
     * Scan for procs that already hold conflicting locks.  These are "hard"
     * edges in the waits-for graph.
     */
    procLocks = &(lock->procLocks);

    proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
                                         offsetof(PROCLOCK, lockLink));

    while (proclock)
    {
        proc = proclock->tag.myProc;
        pgxact = &ProcGlobal->allPgXact[proc->pgprocno];

        /* A proc never blocks itself */
        if (proc != checkProc)
        {
            for (lm = 1; lm <= numLockModes; lm++)
            {
                if ((proclock->holdMask & LOCKBIT_ON(lm)) &&
                    (conflictMask & LOCKBIT_ON(lm)))
                {
                    /* This proc hard-blocks checkProc */
                    if (FindLockCycleRecurse(proc, depth + 1,
                                             softEdges, nSoftEdges))
                    {
                        /* fill deadlockDetails[] */
                        DEADLOCK_INFO *info = &deadlockDetails[depth];

                        info->locktag = lock->tag;
                        info->lockmode = checkProc->waitLockMode;
                        info->pid = checkProc->pid;

                        return true;
                    }

                    /*
                     * No deadlock here, but see if this proc is an autovacuum
                     * that is directly hard-blocking our own proc.  If so,
                     * report it so that the caller can send a cancel signal
                     * to it, if appropriate.  If there's more than one such
                     * proc, it's indeterminate which one will be reported.
                     *
                     * We don't touch autovacuums that are indirectly blocking
                     * us; it's up to the direct blockee to take action.  This
                     * rule simplifies understanding the behavior and ensures
                     * that an autovacuum won't be canceled with less than
                     * deadlock_timeout grace period.
                     *
                     * Note we read vacuumFlags without any locking.  This is
                     * OK only for checking the PROC_IS_AUTOVACUUM flag,
                     * because that flag is set at process start and never
                     * reset.  There is logic elsewhere to avoid canceling an
                     * autovacuum that is working to prevent XID wraparound
                     * problems (which needs to read a different vacuumFlag
                     * bit), but we don't do that here to avoid grabbing
                     * ProcArrayLock.
                     */
                    if (checkProc == MyProc &&
                        pgxact->vacuumFlags & PROC_IS_AUTOVACUUM)
                        blocking_autovacuum_proc = proc;

                    /* We're done looking at this proclock */
                    break;
                }
            }
        }

        proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
                                             offsetof(PROCLOCK, lockLink));
    }

    /*
     * Scan for procs that are ahead of this one in the lock's wait queue.
     * Those that have conflicting requests soft-block this one.  This must be
     * done after the hard-block search, since if another proc both hard- and
     * soft-blocks this one, we want to call it a hard edge.
     *
     * If there is a proposed re-ordering of the lock's wait order, use that
     * rather than the current wait order.
     */
    for (i = 0; i < nWaitOrders; i++)
    {
        if (waitOrders[i].lock == lock)
            break;
    }

    if (i < nWaitOrders)
    {
        /* Use the given hypothetical wait queue order */
        PGPROC    **procs = waitOrders[i].procs;

        queue_size = waitOrders[i].nProcs;

        for (i = 0; i < queue_size; i++)
        {
            proc = procs[i];

            /* Done when we reach the target proc */
            if (proc == checkProc)
                break;

            /* Is there a conflict with this guy's request? */
            if (((1 << proc->waitLockMode) & conflictMask) != 0)
            {
                /* This proc soft-blocks checkProc */
                if (FindLockCycleRecurse(proc, depth + 1,
                                         softEdges, nSoftEdges))
                {
                    /* fill deadlockDetails[] */
                    DEADLOCK_INFO *info = &deadlockDetails[depth];

                    info->locktag = lock->tag;
                    info->lockmode = checkProc->waitLockMode;
                    info->pid = checkProc->pid;

                    /*
                     * Add this edge to the list of soft edges in the cycle
                     */
                    Assert(*nSoftEdges < MaxBackends);
                    softEdges[*nSoftEdges].waiter = checkProc;
                    softEdges[*nSoftEdges].blocker = proc;
                    (*nSoftEdges)++;
                    return true;
                }
            }
        }
    }
    else
    {
        /* Use the true lock wait queue order */
        waitQueue = &(lock->waitProcs);
        queue_size = waitQueue->size;

        proc = (PGPROC *) waitQueue->links.next;

        while (queue_size-- > 0)
        {
            /* Done when we reach the target proc */
            if (proc == checkProc)
                break;

            /* Is there a conflict with this guy's request? */
            if (((1 << proc->waitLockMode) & conflictMask) != 0)
            {
                /* This proc soft-blocks checkProc */
                if (FindLockCycleRecurse(proc, depth + 1,
                                         softEdges, nSoftEdges))
                {
                    /* fill deadlockDetails[] */
                    DEADLOCK_INFO *info = &deadlockDetails[depth];

                    info->locktag = lock->tag;
                    info->lockmode = checkProc->waitLockMode;
                    info->pid = checkProc->pid;

                    /*
                     * Add this edge to the list of soft edges in the cycle
                     */
                    Assert(*nSoftEdges < MaxBackends);
                    softEdges[*nSoftEdges].waiter = checkProc;
                    softEdges[*nSoftEdges].blocker = proc;
                    (*nSoftEdges)++;
                    return true;
                }
            }

            proc = (PGPROC *) proc->links.next;
        }
    }

    /*
     * No conflict detected here.
     */
    return false;
}

PGPROC* GetBlockingAutoVacuumPgproc ( void   ) 

Definition at line 280 of file deadlock.c.

Referenced by ProcSleep().

{
    PGPROC     *ptr;

    ptr = blocking_autovacuum_proc;
    blocking_autovacuum_proc = NULL;

    return ptr;
}

void InitDeadLockChecking ( void   ) 

Definition at line 130 of file deadlock.c.

References afterConstraints, beforeConstraints, MaxBackends, maxCurConstraints, maxPossibleConstraints, MemoryContextSwitchTo(), palloc(), and TopMemoryContext.

Referenced by InitProcess().

{
    MemoryContext oldcxt;

    /* Make sure allocations are permanent */
    oldcxt = MemoryContextSwitchTo(TopMemoryContext);

    /*
     * FindLockCycle needs at most MaxBackends entries in visitedProcs[] and
     * deadlockDetails[].
     */
    visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
    deadlockDetails = (DEADLOCK_INFO *) palloc(MaxBackends * sizeof(DEADLOCK_INFO));

    /*
     * TopoSort needs to consider at most MaxBackends wait-queue entries, and
     * it needn't run concurrently with FindLockCycle.
     */
    topoProcs = visitedProcs;   /* re-use this space */
    beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));
    afterConstraints = (int *) palloc(MaxBackends * sizeof(int));

    /*
     * We need to consider rearranging at most MaxBackends/2 wait queues
     * (since it takes at least two waiters in a queue to create a soft edge),
     * and the expanded form of the wait queues can't involve more than
     * MaxBackends total waiters.
     */
    waitOrders = (WAIT_ORDER *)
        palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
    waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));

    /*
     * Allow at most MaxBackends distinct constraints in a configuration. (Is
     * this enough?  In practice it seems it should be, but I don't quite see
     * how to prove it.  If we run out, we might fail to find a workable wait
     * queue rearrangement even though one exists.)  NOTE that this number
     * limits the maximum recursion depth of DeadLockCheckRecurse. Making it
     * really big might potentially allow a stack-overflow problem.
     */
    maxCurConstraints = MaxBackends;
    curConstraints = (EDGE *) palloc(maxCurConstraints * sizeof(EDGE));

    /*
     * Allow up to 3*MaxBackends constraints to be saved without having to
     * re-run TestConfiguration.  (This is probably more than enough, but we
     * can survive if we run low on space by doing excess runs of
     * TestConfiguration to re-compute constraint lists each time needed.) The
     * last MaxBackends entries in possibleConstraints[] are reserved as
     * output workspace for FindLockCycle.
     */
    maxPossibleConstraints = MaxBackends * 4;
    possibleConstraints =
        (EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));

    MemoryContextSwitchTo(oldcxt);
}

void RememberSimpleDeadLock ( PGPROC proc1,
LOCKMODE  lockmode,
LOCK lock,
PGPROC proc2 
)

Definition at line 965 of file deadlock.c.

References DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, nDeadlockDetails, PGPROC::pid, DEADLOCK_INFO::pid, LOCK::tag, PGPROC::waitLock, and PGPROC::waitLockMode.

Referenced by ProcSleep().

{
    DEADLOCK_INFO *info = &deadlockDetails[0];

    info->locktag = lock->tag;
    info->lockmode = lockmode;
    info->pid = proc1->pid;
    info++;
    info->locktag = proc2->waitLock->tag;
    info->lockmode = proc2->waitLockMode;
    info->pid = proc2->pid;
    nDeadlockDetails = 2;
}

static int TestConfiguration ( PGPROC startProc  )  [static]

Definition at line 368 of file deadlock.c.

References ExpandConstraints(), FindLockCycle(), i, MaxBackends, maxPossibleConstraints, nCurConstraints, and nPossibleConstraints.

Referenced by DeadLockCheckRecurse().

{
    int         softFound = 0;
    EDGE       *softEdges = possibleConstraints + nPossibleConstraints;
    int         nSoftEdges;
    int         i;

    /*
     * Make sure we have room for FindLockCycle's output.
     */
    if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)
        return -1;

    /*
     * Expand current constraint set into wait orderings.  Fail if the
     * constraint set is not self-consistent.
     */
    if (!ExpandConstraints(curConstraints, nCurConstraints))
        return -1;

    /*
     * Check for cycles involving startProc or any of the procs mentioned in
     * constraints.  We check startProc last because if it has a soft cycle
     * still to be dealt with, we want to deal with that first.
     */
    for (i = 0; i < nCurConstraints; i++)
    {
        if (FindLockCycle(curConstraints[i].waiter, softEdges, &nSoftEdges))
        {
            if (nSoftEdges == 0)
                return -1;      /* hard deadlock detected */
            softFound = nSoftEdges;
        }
        if (FindLockCycle(curConstraints[i].blocker, softEdges, &nSoftEdges))
        {
            if (nSoftEdges == 0)
                return -1;      /* hard deadlock detected */
            softFound = nSoftEdges;
        }
    }
    if (FindLockCycle(startProc, softEdges, &nSoftEdges))
    {
        if (nSoftEdges == 0)
            return -1;          /* hard deadlock detected */
        softFound = nSoftEdges;
    }
    return softFound;
}

static bool TopoSort ( LOCK lock,
EDGE constraints,
int  nConstraints,
PGPROC **  ordering 
) [static]

Definition at line 771 of file deadlock.c.

References afterConstraints, Assert, beforeConstraints, EDGE::blocker, i, EDGE::link, PGPROC::links, PROC_QUEUE::links, MemSet, SHM_QUEUE::next, NULL, EDGE::pred, PROC_QUEUE::size, EDGE::waiter, PGPROC::waitLock, and LOCK::waitProcs.

Referenced by ExpandConstraints().

{
    PROC_QUEUE *waitQueue = &(lock->waitProcs);
    int         queue_size = waitQueue->size;
    PGPROC     *proc;
    int         i,
                j,
                k,
                last;

    /* First, fill topoProcs[] array with the procs in their current order */
    proc = (PGPROC *) waitQueue->links.next;
    for (i = 0; i < queue_size; i++)
    {
        topoProcs[i] = proc;
        proc = (PGPROC *) proc->links.next;
    }

    /*
     * Scan the constraints, and for each proc in the array, generate a count
     * of the number of constraints that say it must be before something else,
     * plus a list of the constraints that say it must be after something
     * else. The count for the j'th proc is stored in beforeConstraints[j],
     * and the head of its list in afterConstraints[j].  Each constraint
     * stores its list link in constraints[i].link (note any constraint will
     * be in just one list). The array index for the before-proc of the i'th
     * constraint is remembered in constraints[i].pred.
     */
    MemSet(beforeConstraints, 0, queue_size * sizeof(int));
    MemSet(afterConstraints, 0, queue_size * sizeof(int));
    for (i = 0; i < nConstraints; i++)
    {
        proc = constraints[i].waiter;
        /* Ignore constraint if not for this lock */
        if (proc->waitLock != lock)
            continue;
        /* Find the waiter proc in the array */
        for (j = queue_size; --j >= 0;)
        {
            if (topoProcs[j] == proc)
                break;
        }
        Assert(j >= 0);         /* should have found a match */
        /* Find the blocker proc in the array */
        proc = constraints[i].blocker;
        for (k = queue_size; --k >= 0;)
        {
            if (topoProcs[k] == proc)
                break;
        }
        Assert(k >= 0);         /* should have found a match */
        beforeConstraints[j]++; /* waiter must come before */
        /* add this constraint to list of after-constraints for blocker */
        constraints[i].pred = j;
        constraints[i].link = afterConstraints[k];
        afterConstraints[k] = i + 1;
    }
    /*--------------------
     * Now scan the topoProcs array backwards.  At each step, output the
     * last proc that has no remaining before-constraints, and decrease
     * the beforeConstraints count of each of the procs it was constrained
     * against.
     * i = index of ordering[] entry we want to output this time
     * j = search index for topoProcs[]
     * k = temp for scanning constraint list for proc j
     * last = last non-null index in topoProcs (avoid redundant searches)
     *--------------------
     */
    last = queue_size - 1;
    for (i = queue_size; --i >= 0;)
    {
        /* Find next candidate to output */
        while (topoProcs[last] == NULL)
            last--;
        for (j = last; j >= 0; j--)
        {
            if (topoProcs[j] != NULL && beforeConstraints[j] == 0)
                break;
        }
        /* If no available candidate, topological sort fails */
        if (j < 0)
            return false;
        /* Output candidate, and mark it done by zeroing topoProcs[] entry */
        ordering[i] = topoProcs[j];
        topoProcs[j] = NULL;
        /* Update beforeConstraints counts of its predecessors */
        for (k = afterConstraints[j]; k > 0; k = constraints[k - 1].link)
            beforeConstraints[constraints[k - 1].pred]--;
    }

    /* Done */
    return true;
}


Variable Documentation

int* afterConstraints [static]

Definition at line 95 of file deadlock.c.

Referenced by InitDeadLockChecking(), and TopoSort().

int* beforeConstraints [static]

Definition at line 94 of file deadlock.c.

Referenced by InitDeadLockChecking(), and TopoSort().

PGPROC* blocking_autovacuum_proc = NULL [static]

Definition at line 115 of file deadlock.c.

EDGE* curConstraints [static]

Definition at line 103 of file deadlock.c.

Definition at line 111 of file deadlock.c.

int maxCurConstraints [static]

Definition at line 105 of file deadlock.c.

Referenced by DeadLockCheckRecurse(), and InitDeadLockChecking().

int maxPossibleConstraints [static]

Definition at line 110 of file deadlock.c.

Referenced by DeadLockCheckRecurse(), InitDeadLockChecking(), and TestConfiguration().

int nCurConstraints [static]

Definition at line 104 of file deadlock.c.

Referenced by DeadLockCheck(), DeadLockCheckRecurse(), and TestConfiguration().

int nDeadlockDetails [static]
int nPossibleConstraints [static]

Definition at line 109 of file deadlock.c.

Referenced by DeadLockCheck(), DeadLockCheckRecurse(), and TestConfiguration().

int nVisitedProcs [static]

Definition at line 90 of file deadlock.c.

Referenced by FindLockCycle(), and FindLockCycleRecurse().

int nWaitOrders [static]

Definition at line 99 of file deadlock.c.

Referenced by DeadLockCheck(), ExpandConstraints(), and FindLockCycleRecurse().

Definition at line 108 of file deadlock.c.

PGPROC** topoProcs [static]

Definition at line 93 of file deadlock.c.

PGPROC** visitedProcs [static]

Definition at line 89 of file deadlock.c.

PGPROC** waitOrderProcs [static]

Definition at line 100 of file deadlock.c.

Definition at line 98 of file deadlock.c.