mirror of
https://github.com/postgres/postgres.git
synced 2025-08-31 17:02:12 +03:00
pgindent run for 9.0
This commit is contained in:
@@ -37,7 +37,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.59 2010/01/23 16:37:12 sriggs Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.60 2010/02/26 02:01:00 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -56,7 +56,7 @@
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/snapmgr.h"
|
||||
|
||||
static RunningTransactionsData CurrentRunningXactsData;
|
||||
static RunningTransactionsData CurrentRunningXactsData;
|
||||
|
||||
/* Our shared memory area */
|
||||
typedef struct ProcArrayStruct
|
||||
@@ -64,13 +64,16 @@ typedef struct ProcArrayStruct
|
||||
int numProcs; /* number of valid procs entries */
|
||||
int maxProcs; /* allocated size of procs array */
|
||||
|
||||
int numKnownAssignedXids; /* current number of known assigned xids */
|
||||
int maxKnownAssignedXids; /* allocated size of known assigned xids */
|
||||
int numKnownAssignedXids; /* current number of known assigned
|
||||
* xids */
|
||||
int maxKnownAssignedXids; /* allocated size of known assigned
|
||||
* xids */
|
||||
|
||||
/*
|
||||
* Highest subxid that overflowed KnownAssignedXids array. Similar to
|
||||
* overflowing cached subxids in PGPROC entries.
|
||||
*/
|
||||
TransactionId lastOverflowedXid;
|
||||
TransactionId lastOverflowedXid;
|
||||
|
||||
/*
|
||||
* We declare procs[] as 1 entry because C wants a fixed-size array, but
|
||||
@@ -85,7 +88,7 @@ static ProcArrayStruct *procArray;
|
||||
* Bookkeeping for tracking emulated transactions in recovery
|
||||
*/
|
||||
static HTAB *KnownAssignedXidsHash;
|
||||
static TransactionId latestObservedXid = InvalidTransactionId;
|
||||
static TransactionId latestObservedXid = InvalidTransactionId;
|
||||
|
||||
/*
|
||||
* If we're in STANDBY_SNAPSHOT_PENDING state, standbySnapshotPendingXmin is
|
||||
@@ -135,9 +138,9 @@ static void DisplayXidCache(void);
|
||||
#endif /* XIDCACHE_DEBUG */
|
||||
|
||||
/* Primitives for KnownAssignedXids array handling for standby */
|
||||
static int KnownAssignedXidsGet(TransactionId *xarray, TransactionId xmax);
|
||||
static int KnownAssignedXidsGetAndSetXmin(TransactionId *xarray, TransactionId *xmin,
|
||||
TransactionId xmax);
|
||||
static int KnownAssignedXidsGet(TransactionId *xarray, TransactionId xmax);
|
||||
static int KnownAssignedXidsGetAndSetXmin(TransactionId *xarray, TransactionId *xmin,
|
||||
TransactionId xmax);
|
||||
static bool KnownAssignedXidsExist(TransactionId xid);
|
||||
static void KnownAssignedXidsAdd(TransactionId *xids, int nxids);
|
||||
static void KnownAssignedXidsRemove(TransactionId xid);
|
||||
@@ -436,9 +439,9 @@ ProcArrayInitRecoveryInfo(TransactionId oldestActiveXid)
|
||||
void
|
||||
ProcArrayApplyRecoveryInfo(RunningTransactions running)
|
||||
{
|
||||
int xid_index; /* main loop */
|
||||
TransactionId *xids;
|
||||
int nxids;
|
||||
int xid_index; /* main loop */
|
||||
TransactionId *xids;
|
||||
int nxids;
|
||||
|
||||
Assert(standbyState >= STANDBY_INITIALIZED);
|
||||
|
||||
@@ -455,14 +458,14 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If our initial RunningXactData had an overflowed snapshot then we
|
||||
* knew we were missing some subxids from our snapshot. We can use
|
||||
* this data as an initial snapshot, but we cannot yet mark it valid.
|
||||
* We know that the missing subxids are equal to or earlier than
|
||||
* nextXid. After we initialise we continue to apply changes during
|
||||
* recovery, so once the oldestRunningXid is later than the nextXid
|
||||
* from the initial snapshot we know that we no longer have missing
|
||||
* information and can mark the snapshot as valid.
|
||||
* If our initial RunningXactData had an overflowed snapshot then we knew
|
||||
* we were missing some subxids from our snapshot. We can use this data as
|
||||
* an initial snapshot, but we cannot yet mark it valid. We know that the
|
||||
* missing subxids are equal to or earlier than nextXid. After we
|
||||
* initialise we continue to apply changes during recovery, so once the
|
||||
* oldestRunningXid is later than the nextXid from the initial snapshot we
|
||||
* know that we no longer have missing information and can mark the
|
||||
* snapshot as valid.
|
||||
*/
|
||||
if (standbyState == STANDBY_SNAPSHOT_PENDING)
|
||||
{
|
||||
@@ -471,9 +474,9 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
|
||||
{
|
||||
standbyState = STANDBY_SNAPSHOT_READY;
|
||||
elog(trace_recovery(DEBUG2),
|
||||
"running xact data now proven complete");
|
||||
"running xact data now proven complete");
|
||||
elog(trace_recovery(DEBUG2),
|
||||
"recovery snapshots are now enabled");
|
||||
"recovery snapshots are now enabled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -485,9 +488,9 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
|
||||
TransactionIdRetreat(latestObservedXid);
|
||||
|
||||
/*
|
||||
* If the snapshot overflowed, then we still initialise with what we
|
||||
* know, but the recovery snapshot isn't fully valid yet because we
|
||||
* know there are some subxids missing (ergo we don't know which ones)
|
||||
* If the snapshot overflowed, then we still initialise with what we know,
|
||||
* but the recovery snapshot isn't fully valid yet because we know there
|
||||
* are some subxids missing (ergo we don't know which ones)
|
||||
*/
|
||||
if (!running->subxid_overflow)
|
||||
{
|
||||
@@ -508,12 +511,12 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
|
||||
KnownAssignedXidsDisplay(trace_recovery(DEBUG3));
|
||||
|
||||
/*
|
||||
* Scan through the incoming array of RunningXacts and collect xids.
|
||||
* We don't use SubtransSetParent because it doesn't matter yet. If
|
||||
* we aren't overflowed then all xids will fit in snapshot and so we
|
||||
* don't need subtrans. If we later overflow, an xid assignment record
|
||||
* will add xids to subtrans. If RunningXacts is overflowed then we
|
||||
* don't have enough information to correctly update subtrans anyway.
|
||||
* Scan through the incoming array of RunningXacts and collect xids. We
|
||||
* don't use SubtransSetParent because it doesn't matter yet. If we aren't
|
||||
* overflowed then all xids will fit in snapshot and so we don't need
|
||||
* subtrans. If we later overflow, an xid assignment record will add xids
|
||||
* to subtrans. If RunningXacts is overflowed then we don't have enough
|
||||
* information to correctly update subtrans anyway.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -563,10 +566,10 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
|
||||
ShmemVariableCache->nextXid = running->nextXid;
|
||||
|
||||
elog(trace_recovery(DEBUG2),
|
||||
"running transaction data initialized");
|
||||
"running transaction data initialized");
|
||||
if (standbyState == STANDBY_SNAPSHOT_READY)
|
||||
elog(trace_recovery(DEBUG2),
|
||||
"recovery snapshots are now enabled");
|
||||
"recovery snapshots are now enabled");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -574,7 +577,7 @@ ProcArrayApplyXidAssignment(TransactionId topxid,
|
||||
int nsubxids, TransactionId *subxids)
|
||||
{
|
||||
TransactionId max_xid;
|
||||
int i;
|
||||
int i;
|
||||
|
||||
if (standbyState < STANDBY_SNAPSHOT_PENDING)
|
||||
return;
|
||||
@@ -592,15 +595,15 @@ ProcArrayApplyXidAssignment(TransactionId topxid,
|
||||
RecordKnownAssignedTransactionIds(max_xid);
|
||||
|
||||
/*
|
||||
* Notice that we update pg_subtrans with the top-level xid, rather
|
||||
* than the parent xid. This is a difference between normal
|
||||
* processing and recovery, yet is still correct in all cases. The
|
||||
* reason is that subtransaction commit is not marked in clog until
|
||||
* commit processing, so all aborted subtransactions have already been
|
||||
* clearly marked in clog. As a result we are able to refer directly
|
||||
* to the top-level transaction's state rather than skipping through
|
||||
* all the intermediate states in the subtransaction tree. This
|
||||
* should be the first time we have attempted to SubTransSetParent().
|
||||
* Notice that we update pg_subtrans with the top-level xid, rather than
|
||||
* the parent xid. This is a difference between normal processing and
|
||||
* recovery, yet is still correct in all cases. The reason is that
|
||||
* subtransaction commit is not marked in clog until commit processing, so
|
||||
* all aborted subtransactions have already been clearly marked in clog.
|
||||
* As a result we are able to refer directly to the top-level
|
||||
* transaction's state rather than skipping through all the intermediate
|
||||
* states in the subtransaction tree. This should be the first time we
|
||||
* have attempted to SubTransSetParent().
|
||||
*/
|
||||
for (i = 0; i < nsubxids; i++)
|
||||
SubTransSetParent(subxids[i], topxid, false);
|
||||
@@ -697,12 +700,12 @@ TransactionIdIsInProgress(TransactionId xid)
|
||||
if (xids == NULL)
|
||||
{
|
||||
/*
|
||||
* In hot standby mode, reserve enough space to hold all xids in
|
||||
* the known-assigned list. If we later finish recovery, we no longer
|
||||
* need the bigger array, but we don't bother to shrink it.
|
||||
* In hot standby mode, reserve enough space to hold all xids in the
|
||||
* known-assigned list. If we later finish recovery, we no longer need
|
||||
* the bigger array, but we don't bother to shrink it.
|
||||
*/
|
||||
int maxxids = RecoveryInProgress() ?
|
||||
arrayP->maxProcs : TOTAL_MAX_CACHED_SUBXIDS;
|
||||
int maxxids = RecoveryInProgress() ?
|
||||
arrayP->maxProcs : TOTAL_MAX_CACHED_SUBXIDS;
|
||||
|
||||
xids = (TransactionId *) malloc(maxxids * sizeof(TransactionId));
|
||||
if (xids == NULL)
|
||||
@@ -799,10 +802,10 @@ TransactionIdIsInProgress(TransactionId xid)
|
||||
}
|
||||
|
||||
/*
|
||||
* If the KnownAssignedXids overflowed, we have to check
|
||||
* pg_subtrans too. Copy all xids from KnownAssignedXids that are
|
||||
* lower than xid, since if xid is a subtransaction its parent will
|
||||
* always have a lower value.
|
||||
* If the KnownAssignedXids overflowed, we have to check pg_subtrans
|
||||
* too. Copy all xids from KnownAssignedXids that are lower than xid,
|
||||
* since if xid is a subtransaction its parent will always have a
|
||||
* lower value.
|
||||
*/
|
||||
if (TransactionIdPrecedesOrEquals(xid, procArray->lastOverflowedXid))
|
||||
nxids = KnownAssignedXidsGet(xids, xid);
|
||||
@@ -1052,8 +1055,8 @@ GetSnapshotData(Snapshot snapshot)
|
||||
if (snapshot->xip == NULL)
|
||||
{
|
||||
/*
|
||||
* First call for this snapshot. Snapshot is same size whether
|
||||
* or not we are in recovery, see later comments.
|
||||
* First call for this snapshot. Snapshot is same size whether or not
|
||||
* we are in recovery, see later comments.
|
||||
*/
|
||||
snapshot->xip = (TransactionId *)
|
||||
malloc(arrayP->maxProcs * sizeof(TransactionId));
|
||||
@@ -1176,16 +1179,16 @@ GetSnapshotData(Snapshot snapshot)
|
||||
* In recovery we don't know which xids are top-level and which are
|
||||
* subxacts, a design choice that greatly simplifies xid processing.
|
||||
*
|
||||
* It seems like we would want to try to put xids into xip[] only,
|
||||
* but that is fairly small. We would either need to make that bigger
|
||||
* or to increase the rate at which we WAL-log xid assignment;
|
||||
* neither is an appealing choice.
|
||||
* It seems like we would want to try to put xids into xip[] only, but
|
||||
* that is fairly small. We would either need to make that bigger or
|
||||
* to increase the rate at which we WAL-log xid assignment; neither is
|
||||
* an appealing choice.
|
||||
*
|
||||
* We could try to store xids into xip[] first and then into subxip[]
|
||||
* if there are too many xids. That only works if the snapshot doesn't
|
||||
* overflow because we do not search subxip[] in that case. A simpler
|
||||
* way is to just store all xids in the subxact array because this
|
||||
* is by far the bigger array. We just leave the xip array empty.
|
||||
* way is to just store all xids in the subxact array because this is
|
||||
* by far the bigger array. We just leave the xip array empty.
|
||||
*
|
||||
* Either way we need to change the way XidInMVCCSnapshot() works
|
||||
* depending upon when the snapshot was taken, or change normal
|
||||
@@ -1269,8 +1272,8 @@ GetRunningTransactionData(void)
|
||||
* the lock, so we can't look at numProcs. Likewise, we allocate much
|
||||
* more subxip storage than is probably needed.
|
||||
*
|
||||
* Should only be allocated for bgwriter, since only ever executed
|
||||
* during checkpoints.
|
||||
* Should only be allocated for bgwriter, since only ever executed during
|
||||
* checkpoints.
|
||||
*/
|
||||
if (CurrentRunningXacts->xids == NULL)
|
||||
{
|
||||
@@ -1300,6 +1303,7 @@ GetRunningTransactionData(void)
|
||||
latestCompletedXid = ShmemVariableCache->latestCompletedXid;
|
||||
|
||||
oldestRunningXid = ShmemVariableCache->nextXid;
|
||||
|
||||
/*
|
||||
* Spin over procArray collecting all xids and subxids.
|
||||
*/
|
||||
@@ -1325,8 +1329,8 @@ GetRunningTransactionData(void)
|
||||
oldestRunningXid = xid;
|
||||
|
||||
/*
|
||||
* Save subtransaction XIDs. Other backends can't add or remove entries
|
||||
* while we're holding XidGenLock.
|
||||
* Save subtransaction XIDs. Other backends can't add or remove
|
||||
* entries while we're holding XidGenLock.
|
||||
*/
|
||||
nxids = proc->subxids.nxids;
|
||||
if (nxids > 0)
|
||||
@@ -1642,13 +1646,13 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
|
||||
*
|
||||
* By using exclusive lock we prevent new snapshots from being taken while
|
||||
* we work out which snapshots to conflict with. This protects those new
|
||||
* snapshots from also being included in our conflict list.
|
||||
* snapshots from also being included in our conflict list.
|
||||
*
|
||||
* After the lock is released, we allow snapshots again. It is possible
|
||||
* that we arrive at a snapshot that is identical to one that we just
|
||||
* decided we should conflict with. This a case of false positives, not an
|
||||
* actual problem.
|
||||
*
|
||||
*
|
||||
* There are two cases: (1) if we were correct in using latestCompletedXid
|
||||
* then that means that all xids in the snapshot lower than that are FATAL
|
||||
* errors, so not xids that ever commit. We can make no visibility errors
|
||||
@@ -1657,11 +1661,11 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
|
||||
* latestCompletedXid then we conflicted with a snapshot needlessly. Taking
|
||||
* another identical snapshot is OK, because the earlier conflicted
|
||||
* snapshot was a false positive.
|
||||
*
|
||||
*
|
||||
* In either case, a snapshot taken after conflict assessment will still be
|
||||
* valid and non-conflicting even if an identical snapshot that existed
|
||||
* before conflict assessment was assessed as conflicting.
|
||||
*
|
||||
*
|
||||
* If we allowed concurrent snapshots while we were deciding who to
|
||||
* conflict with we would need to include all concurrent snapshotters in
|
||||
* the conflict list as well. We'd have difficulty in working out exactly
|
||||
@@ -1669,7 +1673,7 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
|
||||
* lock. Notice that we only hold that lock for as long as it takes to
|
||||
* make the conflict list, not for the whole duration of the conflict
|
||||
* resolution.
|
||||
*
|
||||
*
|
||||
* It also means that users waiting for a snapshot is a good thing, since
|
||||
* it is more likely that they will live longer after having waited. So it
|
||||
* is a benefit, not an oversight that we use exclusive lock here.
|
||||
@@ -1695,8 +1699,8 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
|
||||
|
||||
/*
|
||||
* If not first time through, get workspace to remember main XIDs in. We
|
||||
* malloc it permanently to avoid repeated palloc/pfree overhead.
|
||||
* Allow result space, remembering room for a terminator.
|
||||
* malloc it permanently to avoid repeated palloc/pfree overhead. Allow
|
||||
* result space, remembering room for a terminator.
|
||||
*/
|
||||
if (vxids == NULL)
|
||||
{
|
||||
@@ -1711,8 +1715,8 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
|
||||
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
|
||||
|
||||
/*
|
||||
* If we don't know the TransactionId that created the conflict, set
|
||||
* it to latestCompletedXid which is the latest possible value.
|
||||
* If we don't know the TransactionId that created the conflict, set it to
|
||||
* latestCompletedXid which is the latest possible value.
|
||||
*/
|
||||
if (!TransactionIdIsValid(limitXmin))
|
||||
limitXmin = ShmemVariableCache->latestCompletedXid;
|
||||
@@ -1732,8 +1736,9 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
|
||||
TransactionId pxmin = proc->xmin;
|
||||
|
||||
/*
|
||||
* We ignore an invalid pxmin because this means that backend
|
||||
* has no snapshot and cannot get another one while we hold exclusive lock.
|
||||
* We ignore an invalid pxmin because this means that backend has
|
||||
* no snapshot and cannot get another one while we hold exclusive
|
||||
* lock.
|
||||
*/
|
||||
if (TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin))
|
||||
{
|
||||
@@ -1784,8 +1789,8 @@ CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode)
|
||||
if (pid != 0)
|
||||
{
|
||||
/*
|
||||
* Kill the pid if it's still here. If not, that's what we wanted
|
||||
* so ignore any errors.
|
||||
* Kill the pid if it's still here. If not, that's what we
|
||||
* wanted so ignore any errors.
|
||||
*/
|
||||
(void) SendProcSignal(pid, sigmode, vxid.backendId);
|
||||
}
|
||||
@@ -1905,8 +1910,8 @@ CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
|
||||
if (pid != 0)
|
||||
{
|
||||
/*
|
||||
* Kill the pid if it's still here. If not, that's what we wanted
|
||||
* so ignore any errors.
|
||||
* Kill the pid if it's still here. If not, that's what we
|
||||
* wanted so ignore any errors.
|
||||
*/
|
||||
(void) SendProcSignal(pid, sigmode, procvxid.backendId);
|
||||
}
|
||||
@@ -2133,11 +2138,10 @@ DisplayXidCache(void)
|
||||
xc_no_overflow,
|
||||
xc_slow_answer);
|
||||
}
|
||||
|
||||
#endif /* XIDCACHE_DEBUG */
|
||||
|
||||
/* ----------------------------------------------
|
||||
* KnownAssignedTransactions sub-module
|
||||
* KnownAssignedTransactions sub-module
|
||||
* ----------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -2199,48 +2203,49 @@ RecordKnownAssignedTransactionIds(TransactionId xid)
|
||||
return;
|
||||
|
||||
/*
|
||||
* We can see WAL records before the running-xacts snapshot that
|
||||
* contain XIDs that are not in the running-xacts snapshot, but that we
|
||||
* know to have finished before the running-xacts snapshot was taken.
|
||||
* Don't waste precious shared memory by keeping them in the hash table.
|
||||
* We can see WAL records before the running-xacts snapshot that contain
|
||||
* XIDs that are not in the running-xacts snapshot, but that we know to
|
||||
* have finished before the running-xacts snapshot was taken. Don't waste
|
||||
* precious shared memory by keeping them in the hash table.
|
||||
*
|
||||
* We can also see WAL records before the running-xacts snapshot that
|
||||
* contain XIDs that are not in the running-xacts snapshot for a different
|
||||
* reason: the transaction started *after* the running-xacts snapshot
|
||||
* was taken, but before it was written to WAL. We must be careful to
|
||||
* not ignore such XIDs. Because such a transaction started after the
|
||||
* running-xacts snapshot was taken, it must have an XID larger than
|
||||
* the oldest XID according to the running-xacts snapshot.
|
||||
* reason: the transaction started *after* the running-xacts snapshot was
|
||||
* taken, but before it was written to WAL. We must be careful to not
|
||||
* ignore such XIDs. Because such a transaction started after the
|
||||
* running-xacts snapshot was taken, it must have an XID larger than the
|
||||
* oldest XID according to the running-xacts snapshot.
|
||||
*/
|
||||
if (TransactionIdPrecedes(xid, snapshotOldestActiveXid))
|
||||
return;
|
||||
|
||||
ereport(trace_recovery(DEBUG4),
|
||||
(errmsg("record known xact %u latestObservedXid %u",
|
||||
xid, latestObservedXid)));
|
||||
(errmsg("record known xact %u latestObservedXid %u",
|
||||
xid, latestObservedXid)));
|
||||
|
||||
/*
|
||||
* When a newly observed xid arrives, it is frequently the case
|
||||
* that it is *not* the next xid in sequence. When this occurs, we
|
||||
* must treat the intervening xids as running also.
|
||||
* When a newly observed xid arrives, it is frequently the case that it is
|
||||
* *not* the next xid in sequence. When this occurs, we must treat the
|
||||
* intervening xids as running also.
|
||||
*/
|
||||
if (TransactionIdFollows(xid, latestObservedXid))
|
||||
{
|
||||
TransactionId next_expected_xid = latestObservedXid;
|
||||
TransactionId next_expected_xid = latestObservedXid;
|
||||
|
||||
TransactionIdAdvance(next_expected_xid);
|
||||
|
||||
/*
|
||||
* Locking requirement is currently higher than for xid assignment
|
||||
* in normal running. However, we only get called here for new
|
||||
* high xids - so on a multi-processor where it is common that xids
|
||||
* arrive out of order the average number of locks per assignment
|
||||
* will actually reduce. So not too worried about this locking.
|
||||
* Locking requirement is currently higher than for xid assignment in
|
||||
* normal running. However, we only get called here for new high xids
|
||||
* - so on a multi-processor where it is common that xids arrive out
|
||||
* of order the average number of locks per assignment will actually
|
||||
* reduce. So not too worried about this locking.
|
||||
*
|
||||
* XXX It does seem possible that we could add a whole range
|
||||
* of numbers atomically to KnownAssignedXids, if we use a sorted
|
||||
* list for KnownAssignedXids. But that design also increases the
|
||||
* length of time we hold lock when we process commits/aborts, so
|
||||
* on balance don't worry about this.
|
||||
* XXX It does seem possible that we could add a whole range of
|
||||
* numbers atomically to KnownAssignedXids, if we use a sorted list
|
||||
* for KnownAssignedXids. But that design also increases the length of
|
||||
* time we hold lock when we process commits/aborts, so on balance
|
||||
* don't worry about this.
|
||||
*/
|
||||
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
|
||||
|
||||
@@ -2248,8 +2253,8 @@ RecordKnownAssignedTransactionIds(TransactionId xid)
|
||||
{
|
||||
if (TransactionIdPrecedes(next_expected_xid, xid))
|
||||
ereport(trace_recovery(DEBUG4),
|
||||
(errmsg("recording unobserved xid %u (latestObservedXid %u)",
|
||||
next_expected_xid, latestObservedXid)));
|
||||
(errmsg("recording unobserved xid %u (latestObservedXid %u)",
|
||||
next_expected_xid, latestObservedXid)));
|
||||
KnownAssignedXidsAdd(&next_expected_xid, 1);
|
||||
|
||||
/*
|
||||
@@ -2327,9 +2332,9 @@ ExpireOldKnownAssignedTransactionIds(TransactionId xid)
|
||||
*
|
||||
* There are 3 main users of the KnownAssignedXids data structure:
|
||||
*
|
||||
* * backends taking snapshots
|
||||
* * startup process adding new knownassigned xids
|
||||
* * startup process removing xids as transactions end
|
||||
* * backends taking snapshots
|
||||
* * startup process adding new knownassigned xids
|
||||
* * startup process removing xids as transactions end
|
||||
*
|
||||
* If we make KnownAssignedXids a simple sorted array then the first two
|
||||
* operations are fast, but the last one is at least O(N). If we make
|
||||
@@ -2354,8 +2359,8 @@ static void
|
||||
KnownAssignedXidsAdd(TransactionId *xids, int nxids)
|
||||
{
|
||||
TransactionId *result;
|
||||
bool found;
|
||||
int i;
|
||||
bool found;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nxids; i++)
|
||||
{
|
||||
@@ -2369,19 +2374,19 @@ KnownAssignedXidsAdd(TransactionId *xids, int nxids)
|
||||
KnownAssignedXidsDisplay(LOG);
|
||||
LWLockRelease(ProcArrayLock);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("too many KnownAssignedXids")));
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("too many KnownAssignedXids")));
|
||||
}
|
||||
|
||||
result = (TransactionId *) hash_search(KnownAssignedXidsHash, &xids[i], HASH_ENTER,
|
||||
&found);
|
||||
&found);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LWLockRelease(ProcArrayLock);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of shared memory")));
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of shared memory")));
|
||||
}
|
||||
|
||||
if (found)
|
||||
@@ -2401,7 +2406,8 @@ KnownAssignedXidsAdd(TransactionId *xids, int nxids)
|
||||
static bool
|
||||
KnownAssignedXidsExist(TransactionId xid)
|
||||
{
|
||||
bool found;
|
||||
bool found;
|
||||
|
||||
(void) hash_search(KnownAssignedXidsHash, &xid, HASH_FIND, &found);
|
||||
return found;
|
||||
}
|
||||
@@ -2414,7 +2420,7 @@ KnownAssignedXidsExist(TransactionId xid)
|
||||
static void
|
||||
KnownAssignedXidsRemove(TransactionId xid)
|
||||
{
|
||||
bool found;
|
||||
bool found;
|
||||
|
||||
Assert(TransactionIdIsValid(xid));
|
||||
|
||||
@@ -2427,14 +2433,14 @@ KnownAssignedXidsRemove(TransactionId xid)
|
||||
Assert(procArray->numKnownAssignedXids >= 0);
|
||||
|
||||
/*
|
||||
* We can fail to find an xid if the xid came from a subtransaction
|
||||
* that aborts, though the xid hadn't yet been reported and no WAL records
|
||||
* have been written using the subxid. In that case the abort record will
|
||||
* We can fail to find an xid if the xid came from a subtransaction that
|
||||
* aborts, though the xid hadn't yet been reported and no WAL records have
|
||||
* been written using the subxid. In that case the abort record will
|
||||
* contain that subxid and we haven't seen it before.
|
||||
*
|
||||
* If we fail to find it for other reasons it might be a problem, but
|
||||
* it isn't much use to log that it happened, since we can't divine much
|
||||
* from just an isolated xid value.
|
||||
* If we fail to find it for other reasons it might be a problem, but it
|
||||
* isn't much use to log that it happened, since we can't divine much from
|
||||
* just an isolated xid value.
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -2460,7 +2466,7 @@ KnownAssignedXidsGet(TransactionId *xarray, TransactionId xmax)
|
||||
*/
|
||||
static int
|
||||
KnownAssignedXidsGetAndSetXmin(TransactionId *xarray, TransactionId *xmin,
|
||||
TransactionId xmax)
|
||||
TransactionId xmax)
|
||||
{
|
||||
HASH_SEQ_STATUS status;
|
||||
TransactionId *knownXid;
|
||||
@@ -2496,7 +2502,7 @@ KnownAssignedXidsGetAndSetXmin(TransactionId *xarray, TransactionId *xmin,
|
||||
static void
|
||||
KnownAssignedXidsRemoveMany(TransactionId xid, bool keepPreparedXacts)
|
||||
{
|
||||
TransactionId *knownXid;
|
||||
TransactionId *knownXid;
|
||||
HASH_SEQ_STATUS status;
|
||||
|
||||
if (TransactionIdIsValid(xid))
|
||||
@@ -2508,7 +2514,7 @@ KnownAssignedXidsRemoveMany(TransactionId xid, bool keepPreparedXacts)
|
||||
while ((knownXid = (TransactionId *) hash_seq_search(&status)) != NULL)
|
||||
{
|
||||
TransactionId removeXid = *knownXid;
|
||||
bool found;
|
||||
bool found;
|
||||
|
||||
if (!TransactionIdIsValid(xid) || TransactionIdPrecedes(removeXid, xid))
|
||||
{
|
||||
@@ -2537,9 +2543,9 @@ KnownAssignedXidsDisplay(int trace_level)
|
||||
HASH_SEQ_STATUS status;
|
||||
TransactionId *knownXid;
|
||||
StringInfoData buf;
|
||||
TransactionId *xids;
|
||||
int nxids;
|
||||
int i;
|
||||
TransactionId *xids;
|
||||
int nxids;
|
||||
int i;
|
||||
|
||||
xids = palloc(sizeof(TransactionId) * TOTAL_MAX_CACHED_SUBXIDS);
|
||||
nxids = 0;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/procsignal.c,v 1.5 2010/02/13 01:32:19 sriggs Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/procsignal.c,v 1.6 2010/02/26 02:01:00 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -36,12 +36,12 @@
|
||||
* reason is signaled more than once nearly simultaneously, the process may
|
||||
* observe it only once.)
|
||||
*
|
||||
* Each process that wants to receive signals registers its process ID
|
||||
* Each process that wants to receive signals registers its process ID
|
||||
* in the ProcSignalSlots array. The array is indexed by backend ID to make
|
||||
* slot allocation simple, and to avoid having to search the array when you
|
||||
* know the backend ID of the process you're signalling. (We do support
|
||||
* signalling without backend ID, but it's a bit less efficient.)
|
||||
*
|
||||
*
|
||||
* The flags are actually declared as "volatile sig_atomic_t" for maximum
|
||||
* portability. This should ensure that loads and stores of the flag
|
||||
* values are atomic, allowing us to dispense with any explicit locking.
|
||||
@@ -57,7 +57,7 @@ typedef struct
|
||||
* possible auxiliary process type. (This scheme assumes there is not
|
||||
* more than one of any auxiliary process type at a time.)
|
||||
*/
|
||||
#define NumProcSignalSlots (MaxBackends + NUM_AUXPROCTYPES)
|
||||
#define NumProcSignalSlots (MaxBackends + NUM_AUXPROCTYPES)
|
||||
|
||||
static ProcSignalSlot *ProcSignalSlots = NULL;
|
||||
static volatile ProcSignalSlot *MyProcSignalSlot = NULL;
|
||||
@@ -146,8 +146,8 @@ CleanupProcSignalState(int status, Datum arg)
|
||||
if (slot->pss_pid != MyProcPid)
|
||||
{
|
||||
/*
|
||||
* don't ERROR here. We're exiting anyway, and don't want to
|
||||
* get into infinite loop trying to exit
|
||||
* don't ERROR here. We're exiting anyway, and don't want to get into
|
||||
* infinite loop trying to exit
|
||||
*/
|
||||
elog(LOG, "process %d releasing ProcSignal slot %d, but it contains %d",
|
||||
MyProcPid, pss_idx, (int) slot->pss_pid);
|
||||
@@ -201,7 +201,7 @@ SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
|
||||
* InvalidBackendId means that the target is most likely an auxiliary
|
||||
* process, which will have a slot near the end of the array.
|
||||
*/
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = NumProcSignalSlots - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -252,7 +252,7 @@ CheckProcSignal(ProcSignalReason reason)
|
||||
void
|
||||
procsignal_sigusr1_handler(SIGNAL_ARGS)
|
||||
{
|
||||
int save_errno = errno;
|
||||
int save_errno = errno;
|
||||
|
||||
if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT))
|
||||
HandleCatchupInterrupt();
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.81 2010/01/02 16:57:51 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.82 2010/02/26 02:01:00 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -145,9 +145,10 @@ typedef struct ProcState
|
||||
bool signaled; /* backend has been sent catchup signal */
|
||||
|
||||
/*
|
||||
* Backend only sends invalidations, never receives them. This only makes sense
|
||||
* for Startup process during recovery because it doesn't maintain a relcache,
|
||||
* yet it fires inval messages to allow query backends to see schema changes.
|
||||
* Backend only sends invalidations, never receives them. This only makes
|
||||
* sense for Startup process during recovery because it doesn't maintain a
|
||||
* relcache, yet it fires inval messages to allow query backends to see
|
||||
* schema changes.
|
||||
*/
|
||||
bool sendOnly; /* backend only sends, never receives */
|
||||
|
||||
@@ -587,7 +588,7 @@ SICleanupQueue(bool callerHasWriteLock, int minFree)
|
||||
/*
|
||||
* Recompute minMsgNum = minimum of all backends' nextMsgNum, identify the
|
||||
* furthest-back backend that needs signaling (if any), and reset any
|
||||
* backends that are too far back. Note that because we ignore sendOnly
|
||||
* backends that are too far back. Note that because we ignore sendOnly
|
||||
* backends here it is possible for them to keep sending messages without
|
||||
* a problem even when they are the only active backend.
|
||||
*/
|
||||
|
@@ -3,15 +3,15 @@
|
||||
* standby.c
|
||||
* Misc functions used in Hot Standby mode.
|
||||
*
|
||||
* All functions for handling RM_STANDBY_ID, which relate to
|
||||
* AccessExclusiveLocks and starting snapshots for Hot Standby mode.
|
||||
* Plus conflict recovery processing.
|
||||
* All functions for handling RM_STANDBY_ID, which relate to
|
||||
* AccessExclusiveLocks and starting snapshots for Hot Standby mode.
|
||||
* Plus conflict recovery processing.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.13 2010/02/13 16:29:38 sriggs Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.14 2010/02/26 02:01:00 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "storage/standby.h"
|
||||
#include "utils/ps_status.h"
|
||||
|
||||
int vacuum_defer_cleanup_age;
|
||||
int vacuum_defer_cleanup_age;
|
||||
|
||||
static List *RecoveryLockList;
|
||||
|
||||
@@ -58,10 +58,10 @@ InitRecoveryTransactionEnvironment(void)
|
||||
VirtualTransactionId vxid;
|
||||
|
||||
/*
|
||||
* Initialise 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.
|
||||
* Initialise 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);
|
||||
|
||||
@@ -74,8 +74,8 @@ InitRecoveryTransactionEnvironment(void)
|
||||
* 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.
|
||||
* 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
|
||||
@@ -109,12 +109,12 @@ ShutdownRecoveryTransactionEnvironment(void)
|
||||
|
||||
/*
|
||||
* -----------------------------------------------------
|
||||
* Standby wait timers and backend cancel logic
|
||||
* Standby wait timers and backend cancel logic
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
#define STANDBY_INITIAL_WAIT_US 1000
|
||||
static int standbyWait_us = STANDBY_INITIAL_WAIT_US;
|
||||
static int standbyWait_us = STANDBY_INITIAL_WAIT_US;
|
||||
|
||||
/*
|
||||
* Standby wait logic for ResolveRecoveryConflictWithVirtualXIDs.
|
||||
@@ -124,8 +124,8 @@ static int standbyWait_us = STANDBY_INITIAL_WAIT_US;
|
||||
static bool
|
||||
WaitExceedsMaxStandbyDelay(void)
|
||||
{
|
||||
long delay_secs;
|
||||
int delay_usecs;
|
||||
long delay_secs;
|
||||
int delay_usecs;
|
||||
|
||||
if (MaxStandbyDelay == -1)
|
||||
return false;
|
||||
@@ -168,8 +168,8 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
|
||||
|
||||
while (VirtualTransactionIdIsValid(*waitlist))
|
||||
{
|
||||
long wait_s;
|
||||
int wait_us; /* wait in microseconds (us) */
|
||||
long wait_s;
|
||||
int wait_us; /* wait in microseconds (us) */
|
||||
TimestampTz waitStart;
|
||||
bool logged;
|
||||
|
||||
@@ -178,12 +178,13 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
|
||||
logged = false;
|
||||
|
||||
/* wait until the virtual xid is gone */
|
||||
while(!ConditionalVirtualXactLockTableWait(*waitlist))
|
||||
while (!ConditionalVirtualXactLockTableWait(*waitlist))
|
||||
{
|
||||
/*
|
||||
* Report if we have been waiting for a while now...
|
||||
*/
|
||||
TimestampTz now = GetCurrentTimestamp();
|
||||
|
||||
TimestampDifference(waitStart, now, &wait_s, &wait_us);
|
||||
if (!logged && (wait_s > 0 || wait_us > 500000))
|
||||
{
|
||||
@@ -211,7 +212,7 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
|
||||
/* Is it time to kill it? */
|
||||
if (WaitExceedsMaxStandbyDelay())
|
||||
{
|
||||
pid_t pid;
|
||||
pid_t pid;
|
||||
|
||||
/*
|
||||
* Now find out who to throw out of the balloon.
|
||||
@@ -237,7 +238,7 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
|
||||
|
||||
/* The virtual transaction is gone now, wait for the next one */
|
||||
waitlist++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -249,7 +250,7 @@ ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode
|
||||
node.dbNode);
|
||||
|
||||
ResolveRecoveryConflictWithVirtualXIDs(backends,
|
||||
PROCSIG_RECOVERY_CONFLICT_SNAPSHOT);
|
||||
PROCSIG_RECOVERY_CONFLICT_SNAPSHOT);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -258,43 +259,41 @@ ResolveRecoveryConflictWithTablespace(Oid tsid)
|
||||
VirtualTransactionId *temp_file_users;
|
||||
|
||||
/*
|
||||
* Standby users may be currently using this tablespace for
|
||||
* for their temporary files. We only care about current
|
||||
* users because temp_tablespace parameter will just ignore
|
||||
* tablespaces that no longer exist.
|
||||
* Standby users may be currently using this tablespace for 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.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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);
|
||||
PROCSIG_RECOVERY_CONFLICT_TABLESPACE);
|
||||
}
|
||||
|
||||
void
|
||||
ResolveRecoveryConflictWithDatabase(Oid dbid)
|
||||
{
|
||||
/*
|
||||
* We don't do ResolveRecoveryConflictWithVirutalXIDs() 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.
|
||||
* We don't do ResolveRecoveryConflictWithVirutalXIDs() 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.
|
||||
* 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)
|
||||
{
|
||||
@@ -312,20 +311,20 @@ static void
|
||||
ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid)
|
||||
{
|
||||
VirtualTransactionId *backends;
|
||||
bool report_memory_error = false;
|
||||
bool lock_acquired = false;
|
||||
int num_attempts = 0;
|
||||
LOCKTAG locktag;
|
||||
bool report_memory_error = false;
|
||||
bool lock_acquired = false;
|
||||
int num_attempts = 0;
|
||||
LOCKTAG locktag;
|
||||
|
||||
SET_LOCKTAG_RELATION(locktag, dbOid, relOid);
|
||||
|
||||
/*
|
||||
* If blowing away everybody with conflicting locks doesn't work,
|
||||
* after the first two attempts then we just start blowing everybody
|
||||
* away until it does work. We do this because its likely that we
|
||||
* either have too many locks and we just can't get one at all,
|
||||
* or that there are many people crowding for the same table.
|
||||
* Recovery must win; the end justifies the means.
|
||||
* If blowing away everybody with conflicting locks doesn't work, after
|
||||
* the first two attempts then we just start blowing everybody away until
|
||||
* it does work. We do this because its likely that we either have too
|
||||
* many locks and we just can't get one at all, or that there are many
|
||||
* people crowding for the same table. Recovery must win; the end
|
||||
* justifies the means.
|
||||
*/
|
||||
while (!lock_acquired)
|
||||
{
|
||||
@@ -339,10 +338,10 @@ ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid)
|
||||
}
|
||||
|
||||
ResolveRecoveryConflictWithVirtualXIDs(backends,
|
||||
PROCSIG_RECOVERY_CONFLICT_LOCK);
|
||||
PROCSIG_RECOVERY_CONFLICT_LOCK);
|
||||
|
||||
if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false)
|
||||
!= LOCKACQUIRE_NOT_AVAIL)
|
||||
!= LOCKACQUIRE_NOT_AVAIL)
|
||||
lock_acquired = true;
|
||||
}
|
||||
}
|
||||
@@ -372,14 +371,14 @@ ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid)
|
||||
void
|
||||
ResolveRecoveryConflictWithBufferPin(void)
|
||||
{
|
||||
bool sig_alarm_enabled = false;
|
||||
bool sig_alarm_enabled = false;
|
||||
|
||||
Assert(InHotStandby);
|
||||
|
||||
if (MaxStandbyDelay == 0)
|
||||
{
|
||||
/*
|
||||
* We don't want to wait, so just tell everybody holding the pin to
|
||||
* We don't want to wait, so just tell everybody holding the pin to
|
||||
* get out of town.
|
||||
*/
|
||||
SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
|
||||
@@ -387,17 +386,17 @@ ResolveRecoveryConflictWithBufferPin(void)
|
||||
else if (MaxStandbyDelay == -1)
|
||||
{
|
||||
/*
|
||||
* Send out a request to check for buffer pin deadlocks before we wait.
|
||||
* This is fairly cheap, so no need to wait for deadlock timeout before
|
||||
* trying to send it out.
|
||||
* Send out a request to check for buffer pin deadlocks before we
|
||||
* wait. This is fairly cheap, so no need to wait for deadlock timeout
|
||||
* before trying to send it out.
|
||||
*/
|
||||
SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
||||
}
|
||||
else
|
||||
{
|
||||
TimestampTz now;
|
||||
long standby_delay_secs; /* How far Startup process is lagging */
|
||||
int standby_delay_usecs;
|
||||
long standby_delay_secs; /* How far Startup process is lagging */
|
||||
int standby_delay_usecs;
|
||||
|
||||
now = GetCurrentTimestamp();
|
||||
|
||||
@@ -414,14 +413,15 @@ ResolveRecoveryConflictWithBufferPin(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
TimestampTz fin_time; /* Expected wake-up time by timer */
|
||||
long timer_delay_secs; /* Amount of time we set timer for */
|
||||
int timer_delay_usecs = 0;
|
||||
TimestampTz fin_time; /* Expected wake-up time by timer */
|
||||
long timer_delay_secs; /* Amount of time we set timer
|
||||
* for */
|
||||
int timer_delay_usecs = 0;
|
||||
|
||||
/*
|
||||
* Send out a request to check for buffer pin deadlocks before we wait.
|
||||
* This is fairly cheap, so no need to wait for deadlock timeout before
|
||||
* trying to send it out.
|
||||
* Send out a request to check for buffer pin deadlocks before we
|
||||
* wait. This is fairly cheap, so no need to wait for deadlock
|
||||
* timeout before trying to send it out.
|
||||
*/
|
||||
SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
||||
|
||||
@@ -446,8 +446,8 @@ ResolveRecoveryConflictWithBufferPin(void)
|
||||
* When is the finish time? We recheck this if we are woken early.
|
||||
*/
|
||||
fin_time = TimestampTzPlusMilliseconds(now,
|
||||
(timer_delay_secs * 1000) +
|
||||
(timer_delay_usecs / 1000));
|
||||
(timer_delay_secs * 1000) +
|
||||
(timer_delay_usecs / 1000));
|
||||
|
||||
if (enable_standby_sig_alarm(timer_delay_secs, timer_delay_usecs, fin_time))
|
||||
sig_alarm_enabled = true;
|
||||
@@ -473,10 +473,10 @@ SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
|
||||
reason == PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK);
|
||||
|
||||
/*
|
||||
* We send signal to all backends to ask them if they are holding
|
||||
* the buffer pin which is delaying the Startup process. We must
|
||||
* not set the conflict flag yet, since most backends will be innocent.
|
||||
* Let the SIGUSR1 handling in each backend decide their own fate.
|
||||
* We send signal to all backends to ask them if they are holding the
|
||||
* buffer pin which is delaying the Startup process. We must not set the
|
||||
* conflict flag yet, since most backends will be innocent. Let the
|
||||
* SIGUSR1 handling in each backend decide their own fate.
|
||||
*/
|
||||
CancelDBBackends(InvalidOid, reason, false);
|
||||
}
|
||||
@@ -503,15 +503,15 @@ CheckRecoveryConflictDeadlock(LWLockId partitionLock)
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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_QUERY_CANCELED),
|
||||
errmsg("canceling statement due to conflict with recovery"),
|
||||
errdetail("User transaction caused buffer deadlock with recovery.")));
|
||||
errdetail("User transaction caused buffer deadlock with recovery.")));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -543,8 +543,8 @@ CheckRecoveryConflictDeadlock(LWLockId partitionLock)
|
||||
void
|
||||
StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
|
||||
{
|
||||
xl_standby_lock *newlock;
|
||||
LOCKTAG locktag;
|
||||
xl_standby_lock *newlock;
|
||||
LOCKTAG locktag;
|
||||
|
||||
/* Already processed? */
|
||||
if (TransactionIdDidCommit(xid) || TransactionIdDidAbort(xid))
|
||||
@@ -568,7 +568,7 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
|
||||
SET_LOCKTAG_RELATION(locktag, newlock->dbOid, newlock->relOid);
|
||||
|
||||
if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false)
|
||||
== LOCKACQUIRE_NOT_AVAIL)
|
||||
== LOCKACQUIRE_NOT_AVAIL)
|
||||
ResolveRecoveryConflictWithLock(newlock->dbOid, newlock->relOid);
|
||||
}
|
||||
|
||||
@@ -586,6 +586,7 @@ StandbyReleaseLocks(TransactionId xid)
|
||||
for (cell = list_head(RecoveryLockList); cell; cell = next)
|
||||
{
|
||||
xl_standby_lock *lock = (xl_standby_lock *) lfirst(cell);
|
||||
|
||||
next = lnext(cell);
|
||||
|
||||
if (!TransactionIdIsValid(xid) || lock->xid == xid)
|
||||
@@ -619,7 +620,7 @@ StandbyReleaseLocks(TransactionId xid)
|
||||
void
|
||||
StandbyReleaseLockTree(TransactionId xid, int nsubxids, TransactionId *subxids)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
StandbyReleaseLocks(xid);
|
||||
|
||||
@@ -647,6 +648,7 @@ StandbyReleaseLocksMany(TransactionId removeXid, bool keepPreparedXacts)
|
||||
for (cell = list_head(RecoveryLockList); cell; cell = next)
|
||||
{
|
||||
xl_standby_lock *lock = (xl_standby_lock *) lfirst(cell);
|
||||
|
||||
next = lnext(cell);
|
||||
|
||||
if (!TransactionIdIsValid(removeXid) || TransactionIdPrecedes(lock->xid, removeXid))
|
||||
@@ -692,7 +694,7 @@ StandbyReleaseOldLocks(TransactionId removeXid)
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------
|
||||
* Recovery handling for Rmgr RM_STANDBY_ID
|
||||
* Recovery handling for Rmgr RM_STANDBY_ID
|
||||
*
|
||||
* These record types will only be created if XLogStandbyInfoActive()
|
||||
* --------------------------------------------------------------------
|
||||
@@ -710,7 +712,7 @@ standby_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
if (info == XLOG_STANDBY_LOCK)
|
||||
{
|
||||
xl_standby_locks *xlrec = (xl_standby_locks *) XLogRecGetData(record);
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < xlrec->nlocks; i++)
|
||||
StandbyAcquireAccessExclusiveLock(xlrec->locks[i].xid,
|
||||
@@ -761,7 +763,7 @@ standby_desc(StringInfo buf, uint8 xl_info, char *rec)
|
||||
if (info == XLOG_STANDBY_LOCK)
|
||||
{
|
||||
xl_standby_locks *xlrec = (xl_standby_locks *) rec;
|
||||
int i;
|
||||
int i;
|
||||
|
||||
appendStringInfo(buf, "AccessExclusive locks:");
|
||||
|
||||
@@ -790,7 +792,7 @@ LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid)
|
||||
{
|
||||
RunningTransactions running;
|
||||
xl_standby_lock *locks;
|
||||
int nlocks;
|
||||
int nlocks;
|
||||
|
||||
Assert(XLogStandbyInfoActive());
|
||||
|
||||
@@ -823,9 +825,9 @@ LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid)
|
||||
static void
|
||||
LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
|
||||
{
|
||||
xl_running_xacts xlrec;
|
||||
XLogRecData rdata[2];
|
||||
int lastrdata = 0;
|
||||
xl_running_xacts xlrec;
|
||||
XLogRecData rdata[2];
|
||||
int lastrdata = 0;
|
||||
XLogRecPtr recptr;
|
||||
|
||||
xlrec.xcnt = CurrRunningXacts->xcnt;
|
||||
@@ -876,8 +878,8 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
|
||||
static void
|
||||
LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
|
||||
{
|
||||
XLogRecData rdata[2];
|
||||
xl_standby_locks xlrec;
|
||||
XLogRecData rdata[2];
|
||||
xl_standby_locks xlrec;
|
||||
|
||||
xlrec.nlocks = nlocks;
|
||||
|
||||
@@ -900,22 +902,22 @@ LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
|
||||
void
|
||||
LogAccessExclusiveLock(Oid dbOid, Oid relOid)
|
||||
{
|
||||
xl_standby_lock xlrec;
|
||||
xl_standby_lock xlrec;
|
||||
|
||||
/*
|
||||
* Ensure that a TransactionId has been assigned to this transaction.
|
||||
* We don't actually need the xid yet but if we don't do this then
|
||||
* Ensure that a TransactionId has been assigned to this transaction. We
|
||||
* don't actually need the xid yet but if we don't do this then
|
||||
* RecordTransactionCommit() and RecordTransactionAbort() will 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.
|
||||
* release locks. It's a hack, but for a corner case not worth adding code
|
||||
* for into the main commit path.
|
||||
*/
|
||||
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
|
||||
* 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;
|
||||
|
Reference in New Issue
Block a user