1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-16 15:02:33 +03:00

Implement lazy XID allocation: transactions that do not modify any database

rows will normally never obtain an XID at all.  We already did things this way
for subtransactions, but this patch extends the concept to top-level
transactions.  In applications where there are lots of short read-only
transactions, this should improve performance noticeably; not so much from
removal of the actual XID-assignments, as from reduction of overhead that's
driven by the rate of XID consumption.  We add a concept of a "virtual
transaction ID" so that active transactions can be uniquely identified even
if they don't have a regular XID.  This is a much lighter-weight concept:
uniqueness of VXIDs is only guaranteed over the short term, and no on-disk
record is made about them.

Florian Pflug, with some editorialization by Tom.
This commit is contained in:
Tom Lane
2007-09-05 18:10:48 +00:00
parent 2e74c53ec1
commit 295e63983d
34 changed files with 1002 additions and 754 deletions

View File

@@ -23,7 +23,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.28 2007/07/01 02:22:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.29 2007/09/05 18:10:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -404,7 +404,7 @@ TransactionIdIsActive(TransactionId xid)
* This is also used to determine where to truncate pg_subtrans. allDbs
* must be TRUE for that case, and ignoreVacuum FALSE.
*
* Note: we include the currently running xids in the set of considered xids.
* Note: we include all currently running xids in the set of considered xids.
* This ensures that if a just-started xact has not yet set its snapshot,
* when it does set the snapshot it cannot set xmin less than what we compute.
*/
@@ -416,15 +416,19 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
int index;
/*
* Normally we start the min() calculation with our own XID. But if
* called by checkpointer, we will not be inside a transaction, so use
* next XID as starting point for min() calculation. (Note that if there
* are no xacts running at all, that will be the subtrans truncation
* point!)
* We need to initialize the MIN() calculation with something.
* ReadNewTransactionId() is guaranteed to work, but is relatively
* expensive due to locking; so first we try a couple of shortcuts.
* If we have a valid xmin in our own PGPROC entry, that will do;
* or if we have assigned ourselves an XID, that will do.
*/
result = GetTopTransactionId();
result = MyProc ? MyProc->xmin : InvalidTransactionId;
if (!TransactionIdIsValid(result))
result = ReadNewTransactionId();
{
result = GetTopTransactionIdIfAny();
if (!TransactionIdIsValid(result))
result = ReadNewTransactionId();
}
LWLockAcquire(ProcArrayLock, LW_SHARED);
@@ -440,23 +444,22 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
/* Fetch xid just once - see GetNewTransactionId */
TransactionId xid = proc->xid;
if (TransactionIdIsNormal(xid))
{
/* First consider the transaction own's Xid */
if (TransactionIdPrecedes(xid, result))
result = xid;
/* First consider the transaction's own Xid, if any */
if (TransactionIdIsNormal(xid) &&
TransactionIdPrecedes(xid, result))
result = xid;
/*
* Also consider the transaction's Xmin, if set.
*
* We must check both Xid and Xmin because there is a window
* where an xact's Xid is set but Xmin isn't yet.
*/
xid = proc->xmin;
if (TransactionIdIsNormal(xid))
if (TransactionIdPrecedes(xid, result))
result = xid;
}
/*
* Also consider the transaction's Xmin, if set.
*
* We must check both Xid and Xmin because a transaction might
* have an Xmin but not (yet) an Xid; conversely, if it has
* an Xid, that could determine some not-yet-set Xmin.
*/
xid = proc->xmin; /* Fetch just once */
if (TransactionIdIsNormal(xid) &&
TransactionIdPrecedes(xid, result))
result = xid;
}
}
@@ -545,8 +548,6 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
errmsg("out of memory")));
}
globalxmin = xmin = GetTopTransactionId();
/*
* It is sufficient to get shared lock on ProcArrayLock, even if we are
* computing a serializable snapshot and therefore will be setting
@@ -557,6 +558,19 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
* discussion just below). So it doesn't matter whether another backend
* concurrently doing GetSnapshotData or GetOldestXmin sees our xmin as
* set or not; he'd compute the same xmin for himself either way.
* (We are assuming here that xmin can be set and read atomically,
* just like xid.)
*
* There is a corner case in which the above argument doesn't work: if
* there isn't any oldest xact, ie, all xids in the array are invalid.
* In that case we will compute xmin as the result of ReadNewTransactionId,
* and since GetNewTransactionId doesn't take the ProcArrayLock, it's not
* so obvious that two backends with overlapping shared locks will get
* the same answer. But GetNewTransactionId is required to store the XID
* it assigned into the ProcArray before releasing XidGenLock. Therefore
* the backend that did ReadNewTransactionId later will see that XID in
* the array, and will compute the same xmin as the earlier one that saw
* no XIDs in the array.
*/
LWLockAcquire(ProcArrayLock, LW_SHARED);
@@ -589,6 +603,9 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
xmax = ReadNewTransactionId();
/* initialize xmin calculation with xmax */
globalxmin = xmin = xmax;
/*
* Spin over procArray checking xid, xmin, and subxids. The goal is
* to gather all active xids, find the lowest xmin, and try to record
@@ -597,34 +614,40 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
for (index = 0; index < arrayP->numProcs; index++)
{
PGPROC *proc = arrayP->procs[index];
TransactionId xid;
/* Fetch xid just once - see GetNewTransactionId */
TransactionId xid = proc->xid;
/*
* Ignore my own proc (dealt with my xid above), procs not running a
* transaction, xacts started since we read the next transaction ID,
* and xacts executing LAZY VACUUM. There's no need to store XIDs
* above what we got from ReadNewTransactionId, since we'll treat them
* as running anyway. We also assume that such xacts can't compute an
* xmin older than ours, so they needn't be considered in computing
* globalxmin.
*/
if (proc == MyProc ||
!TransactionIdIsNormal(xid) ||
TransactionIdFollowsOrEquals(xid, xmax) ||
proc->inVacuum)
/* Ignore procs running LAZY VACUUM */
if (proc->inVacuum)
continue;
if (TransactionIdPrecedes(xid, xmin))
xmin = xid;
snapshot->xip[count++] = xid;
/* Update globalxmin to be the smallest valid xmin */
xid = proc->xmin;
xid = proc->xmin; /* fetch just once */
if (TransactionIdIsNormal(xid) &&
TransactionIdPrecedes(xid, globalxmin))
globalxmin = xid;
/* Fetch xid just once - see GetNewTransactionId */
xid = proc->xid;
/*
* If the transaction has been assigned an xid < xmax we add it to the
* snapshot, and update xmin if necessary. There's no need to store
* XIDs above what we got from ReadNewTransactionId, since we'll treat
* them as running anyway. We don't bother to examine their subxids
* either.
*
* We don't include our own XID (if any) in the snapshot, but we must
* include it into xmin.
*/
if (TransactionIdIsNormal(xid))
if (TransactionIdPrecedes(xid, globalxmin))
globalxmin = xid;
{
if (TransactionIdFollowsOrEquals(xid, xmax))
continue;
if (proc != MyProc)
snapshot->xip[count++] = xid;
if (TransactionIdPrecedes(xid, xmin))
xmin = xid;
}
/*
* Save subtransaction XIDs if possible (if we've already overflowed,
@@ -635,8 +658,10 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
* remove any. Hence it's important to fetch nxids just once. Should
* be safe to use memcpy, though. (We needn't worry about missing any
* xids added concurrently, because they must postdate xmax.)
*
* Again, our own XIDs are not included in the snapshot.
*/
if (subcount >= 0)
if (subcount >= 0 && proc != MyProc)
{
if (proc->subxids.overflowed)
subcount = -1; /* overflowed */
@@ -818,6 +843,9 @@ BackendPidGetProc(int pid)
*
* Only main transaction Ids are considered. This function is mainly
* useful for determining what backend owns a lock.
*
* Beware that not every xact has an XID assigned. However, as long as you
* only call this using an XID found on disk, you're safe.
*/
int
BackendXidGetPid(TransactionId xid)
@@ -856,6 +884,63 @@ IsBackendPid(int pid)
return (BackendPidGetProc(pid) != NULL);
}
/*
* GetCurrentVirtualXIDs -- returns an array of currently active VXIDs.
*
* The array is palloc'd and is terminated with an invalid VXID.
*
* If limitXmin is not InvalidTransactionId, we skip any backends
* with xmin >= limitXmin. Also, our own process is always skipped.
*/
VirtualTransactionId *
GetCurrentVirtualXIDs(TransactionId limitXmin)
{
VirtualTransactionId *vxids;
ProcArrayStruct *arrayP = procArray;
int count = 0;
int index;
/* allocate result space with room for a terminator */
vxids = (VirtualTransactionId *)
palloc(sizeof(VirtualTransactionId) * (arrayP->maxProcs + 1));
LWLockAcquire(ProcArrayLock, LW_SHARED);
for (index = 0; index < arrayP->numProcs; index++)
{
PGPROC *proc = arrayP->procs[index];
/* Fetch xmin just once - might change on us? */
TransactionId pxmin = proc->xmin;
if (proc == MyProc)
continue;
/*
* Note that InvalidTransactionId precedes all other XIDs, so a
* proc that hasn't set xmin yet will always be included.
*/
if (!TransactionIdIsValid(limitXmin) ||
TransactionIdPrecedes(pxmin, limitXmin))
{
VirtualTransactionId vxid;
GET_VXID_FROM_PGPROC(vxid, *proc);
if (VirtualTransactionIdIsValid(vxid))
vxids[count++] = vxid;
}
}
LWLockRelease(ProcArrayLock);
/* add the terminator */
vxids[count].backendId = InvalidBackendId;
vxids[count].localTransactionId = InvalidLocalTransactionId;
return vxids;
}
/*
* CountActiveBackends --- count backends (other than myself) that are in
* active transactions. This is used as a heuristic to decide if
@@ -885,7 +970,7 @@ CountActiveBackends(void)
if (proc->pid == 0)
continue; /* do not count prepared xacts */
if (proc->xid == InvalidTransactionId)
continue; /* do not count if not in a transaction */
continue; /* do not count if no XID assigned */
if (proc->waitLock != NULL)
continue; /* do not count if blocked on a lock */
count++;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.63 2007/01/05 22:19:38 momjian Exp $
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.64 2007/09/05 18:10:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,12 +19,15 @@
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/shmem.h"
#include "storage/sinvaladt.h"
SISeg *shmInvalBuffer;
static LocalTransactionId nextLocalTransactionId;
static void CleanupInvalidationState(int status, Datum arg);
static void SISetProcStateInvalid(SISeg *segP);
@@ -40,6 +43,8 @@ SInvalShmemSize(void)
size = offsetof(SISeg, procState);
size = add_size(size, mul_size(sizeof(ProcState), MaxBackends));
size = add_size(size, mul_size(sizeof(LocalTransactionId), MaxBackends));
return size;
}
@@ -51,15 +56,21 @@ void
SIBufferInit(void)
{
SISeg *segP;
Size size;
int i;
bool found;
/* Allocate space in shared memory */
size = offsetof(SISeg, procState);
size = add_size(size, mul_size(sizeof(ProcState), MaxBackends));
shmInvalBuffer = segP = (SISeg *)
ShmemInitStruct("shmInvalBuffer", SInvalShmemSize(), &found);
ShmemInitStruct("shmInvalBuffer", size, &found);
if (found)
return;
segP->nextLXID = ShmemAlloc(sizeof(LocalTransactionId) * MaxBackends);
/* Clear message counters, save size of procState array */
segP->minMsgNum = 0;
segP->maxMsgNum = 0;
@@ -69,11 +80,12 @@ SIBufferInit(void)
/* The buffer[] array is initially all unused, so we need not fill it */
/* Mark all backends inactive */
/* Mark all backends inactive, and initialize nextLXID */
for (i = 0; i < segP->maxBackends; i++)
{
segP->procState[i].nextMsgNum = -1; /* inactive */
segP->procState[i].resetState = false;
segP->nextLXID[i] = InvalidLocalTransactionId;
}
}
@@ -128,9 +140,15 @@ SIBackendInit(SISeg *segP)
elog(DEBUG2, "my backend id is %d", MyBackendId);
#endif /* INVALIDDEBUG */
/* Advertise assigned backend ID in MyProc */
MyProc->backendId = MyBackendId;
/* Reduce free slot count */
segP->freeBackends--;
/* Fetch next local transaction ID into local memory */
nextLocalTransactionId = segP->nextLXID[MyBackendId - 1];
/* mark myself active, with all extant messages already read */
stateP->nextMsgNum = segP->maxMsgNum;
stateP->resetState = false;
@@ -160,6 +178,9 @@ CleanupInvalidationState(int status, Datum arg)
LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
/* Update next local transaction ID for next holder of this backendID */
segP->nextLXID[MyBackendId - 1] = nextLocalTransactionId;
/* Mark myself inactive */
segP->procState[MyBackendId - 1].nextMsgNum = -1;
segP->procState[MyBackendId - 1].resetState = false;
@@ -352,3 +373,30 @@ SIDelExpiredDataEntries(SISeg *segP)
}
}
}
/*
* GetNextLocalTransactionId --- allocate a new LocalTransactionId
*
* We split VirtualTransactionIds into two parts so that it is possible
* to allocate a new one without any contention for shared memory, except
* for a bit of additional overhead during backend startup/shutdown.
* The high-order part of a VirtualTransactionId is a BackendId, and the
* low-order part is a LocalTransactionId, which we assign from a local
* counter. To avoid the risk of a VirtualTransactionId being reused
* within a short interval, successive procs occupying the same backend ID
* slot should use a consecutive sequence of local IDs, which is implemented
* by copying nextLocalTransactionId as seen above.
*/
LocalTransactionId
GetNextLocalTransactionId(void)
{
LocalTransactionId result;
/* loop to avoid returning InvalidLocalTransactionId at wraparound */
do {
result = nextLocalTransactionId++;
} while (!LocalTransactionIdIsValid(result));
return result;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.92 2007/07/25 22:16:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.93 2007/09/05 18:10:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -421,8 +421,8 @@ UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
* XactLockTableInsert
*
* Insert a lock showing that the given transaction ID is running ---
* this is done during xact startup. The lock can then be used to wait
* for the transaction to finish.
* this is done when an XID is acquired by a transaction or subtransaction.
* The lock can then be used to wait for the transaction to finish.
*/
void
XactLockTableInsert(TransactionId xid)
@@ -439,8 +439,7 @@ XactLockTableInsert(TransactionId xid)
*
* Delete the lock showing that the given transaction ID is running.
* (This is never used for main transaction IDs; those locks are only
* released implicitly at transaction end. But we do use it for subtrans
* IDs.)
* released implicitly at transaction end. But we do use it for subtrans IDs.)
*/
void
XactLockTableDelete(TransactionId xid)
@@ -472,7 +471,7 @@ XactLockTableWait(TransactionId xid)
for (;;)
{
Assert(TransactionIdIsValid(xid));
Assert(!TransactionIdEquals(xid, GetTopTransactionId()));
Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
SET_LOCKTAG_TRANSACTION(tag, xid);
@@ -500,7 +499,7 @@ ConditionalXactLockTableWait(TransactionId xid)
for (;;)
{
Assert(TransactionIdIsValid(xid));
Assert(!TransactionIdEquals(xid, GetTopTransactionId()));
Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
SET_LOCKTAG_TRANSACTION(tag, xid);
@@ -517,6 +516,70 @@ ConditionalXactLockTableWait(TransactionId xid)
return true;
}
/*
* VirtualXactLockTableInsert
*
* Insert a lock showing that the given virtual transaction ID is running ---
* this is done at main transaction start when its VXID is assigned.
* The lock can then be used to wait for the transaction to finish.
*/
void
VirtualXactLockTableInsert(VirtualTransactionId vxid)
{
LOCKTAG tag;
Assert(VirtualTransactionIdIsValid(vxid));
SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
(void) LockAcquire(&tag, ExclusiveLock, false, false);
}
/*
* VirtualXactLockTableWait
*
* Waits until the lock on the given VXID is released, which shows that
* the top-level transaction owning the VXID has ended.
*/
void
VirtualXactLockTableWait(VirtualTransactionId vxid)
{
LOCKTAG tag;
Assert(VirtualTransactionIdIsValid(vxid));
SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
(void) LockAcquire(&tag, ShareLock, false, false);
LockRelease(&tag, ShareLock, false);
}
/*
* ConditionalVirtualXactLockTableWait
*
* As above, but only lock if we can get the lock without blocking.
* Returns TRUE if the lock was acquired.
*/
bool
ConditionalVirtualXactLockTableWait(VirtualTransactionId vxid)
{
LOCKTAG tag;
Assert(VirtualTransactionIdIsValid(vxid));
SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
return false;
LockRelease(&tag, ShareLock, false);
return true;
}
/*
* LockDatabaseObject
*

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.177 2007/07/16 21:09:50 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.178 2007/09/05 18:10:47 tgl Exp $
*
* NOTES
* A lock table is a shared memory hash table. When
@@ -1681,20 +1681,24 @@ LockReassignCurrentOwner(void)
/*
* GetLockConflicts
* Get a list of TransactionIds of xacts currently holding locks
* Get an array of VirtualTransactionIds of xacts currently holding locks
* that would conflict with the specified lock/lockmode.
* xacts merely awaiting such a lock are NOT reported.
*
* The result array is palloc'd and is terminated with an invalid VXID.
*
* Of course, the result could be out of date by the time it's returned,
* so use of this function has to be thought about carefully.
*
* Only top-level XIDs are reported. Note we never include the current xact
* in the result list, since an xact never blocks itself.
* Note we never include the current xact's vxid in the result array,
* since an xact never blocks itself. Also, prepared transactions are
* ignored, which is a bit more debatable but is appropriate for current
* uses of the result.
*/
List *
VirtualTransactionId *
GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
{
List *result = NIL;
VirtualTransactionId *vxids;
LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
LockMethod lockMethodTable;
LOCK *lock;
@@ -1703,6 +1707,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
PROCLOCK *proclock;
uint32 hashcode;
LWLockId partitionLock;
int count = 0;
if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
@@ -1710,6 +1715,14 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
elog(ERROR, "unrecognized lock mode: %d", lockmode);
/*
* Allocate memory to store results, and fill with InvalidVXID. We
* only need enough space for MaxBackends + a terminator, since
* prepared xacts don't count.
*/
vxids = (VirtualTransactionId *)
palloc0(sizeof(VirtualTransactionId) * (MaxBackends + 1));
/*
* Look up the lock object matching the tag.
*/
@@ -1730,7 +1743,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
* on this lockable object.
*/
LWLockRelease(partitionLock);
return NIL;
return vxids;
}
/*
@@ -1752,18 +1765,17 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
/* A backend never blocks itself */
if (proc != MyProc)
{
/* Fetch xid just once - see GetNewTransactionId */
TransactionId xid = proc->xid;
VirtualTransactionId vxid;
GET_VXID_FROM_PGPROC(vxid, *proc);
/*
* Race condition: during xact commit/abort we zero out
* PGPROC's xid before we mark its locks released. If we see
* zero in the xid field, assume the xact is in process of
* shutting down and act as though the lock is already
* released.
* If we see an invalid VXID, then either the xact has already
* committed (or aborted), or it's a prepared xact. In
* either case we may ignore it.
*/
if (TransactionIdIsValid(xid))
result = lappend_xid(result, xid);
if (VirtualTransactionIdIsValid(vxid))
vxids[count++] = vxid;
}
}
@@ -1773,7 +1785,10 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
LWLockRelease(partitionLock);
return result;
if (count > MaxBackends) /* should never happen */
elog(PANIC, "too many conflicting locks found");
return vxids;
}
@@ -1782,7 +1797,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
* Do the preparatory work for a PREPARE: make 2PC state file records
* for all locks currently held.
*
* Non-transactional locks are ignored.
* Non-transactional locks are ignored, as are VXID locks.
*
* There are some special cases that we error out on: we can't be holding
* any session locks (should be OK since only VACUUM uses those) and we
@@ -1812,6 +1827,13 @@ AtPrepare_Locks(void)
if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
/*
* Ignore VXID locks. We don't want those to be held by prepared
* transactions, since they aren't meaningful after a restart.
*/
if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
continue;
/* Ignore it if we don't actually hold the lock */
if (locallock->nLocks <= 0)
continue;
@@ -1899,6 +1921,10 @@ PostPrepare_Locks(TransactionId xid)
if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
/* Ignore VXID locks */
if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
continue;
/* We already checked there are no session locks */
/* Mark the proclock to show we need to release this lockmode */
@@ -1944,6 +1970,10 @@ PostPrepare_Locks(TransactionId xid)
if (!LockMethods[LOCK_LOCKMETHOD(*lock)]->transactional)
goto next_item;
/* Ignore VXID locks */
if (lock->tag.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
goto next_item;
PROCLOCK_PRINT("PostPrepare_Locks", proclock);
LOCK_PRINT("PostPrepare_Locks", lock, 0);
Assert(lock->nRequested >= 0);

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.192 2007/08/28 03:23:44 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.193 2007/09/05 18:10:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -282,10 +282,12 @@ InitProcess(void)
*/
SHMQueueElemInit(&(MyProc->links));
MyProc->waitStatus = STATUS_OK;
MyProc->lxid = InvalidLocalTransactionId;
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
MyProc->pid = MyProcPid;
/* databaseId and roleId will be filled in later */
/* backendId, databaseId and roleId will be filled in later */
MyProc->backendId = InvalidBackendId;
MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
MyProc->inCommit = false;
@@ -359,7 +361,9 @@ InitProcessPhase2(void)
*
* Auxiliary processes are presently not expected to wait for real (lockmgr)
* locks, so we need not set up the deadlock checker. They are never added
* to the ProcArray or the sinval messaging mechanism, either.
* to the ProcArray or the sinval messaging mechanism, either. They also
* don't get a VXID assigned, since this is only useful when we actually
* hold lockmgr locks.
*/
void
InitAuxiliaryProcess(void)
@@ -418,8 +422,10 @@ InitAuxiliaryProcess(void)
*/
SHMQueueElemInit(&(MyProc->links));
MyProc->waitStatus = STATUS_OK;
MyProc->lxid = InvalidLocalTransactionId;
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
MyProc->backendId = InvalidBackendId;
MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
MyProc->inCommit = false;

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.105 2007/07/20 16:29:53 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.106 2007/09/05 18:10:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -347,9 +347,8 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
return;
/*
* Make a non-transactional XLOG entry showing the file creation. It's
* non-transactional because we should replay it whether the transaction
* commits or not; if not, the file will be dropped at abort time.
* Make an XLOG entry showing the file creation. If we abort, the file
* will be dropped at abort time.
*/
xlrec.rnode = reln->smgr_rnode;
@@ -358,7 +357,7 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
rdata.buffer = InvalidBuffer;
rdata.next = NULL;
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLOG_NO_TRAN, &rdata);
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
/* Add the relation to the list of stuff to delete at abort */
pending = (PendingRelDelete *)
@@ -554,10 +553,7 @@ smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
if (!isTemp)
{
/*
* Make a non-transactional XLOG entry showing the file truncation.
* It's non-transactional because we should replay it whether the
* transaction commits or not; the underlying file change is certainly
* not reversible.
* Make an XLOG entry showing the file truncation.
*/
XLogRecPtr lsn;
XLogRecData rdata;
@@ -571,8 +567,7 @@ smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
rdata.buffer = InvalidBuffer;
rdata.next = NULL;
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE | XLOG_NO_TRAN,
&rdata);
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata);
}
}
@@ -679,11 +674,14 @@ smgrDoPendingDeletes(bool isCommit)
* *ptr is set to point to a freshly-palloc'd array of RelFileNodes.
* If there are no relations to be deleted, *ptr is set to NULL.
*
* If haveNonTemp isn't NULL, the bool it points to gets set to true if
* there is any non-temp table pending to be deleted; false if not.
*
* Note that the list does not include anything scheduled for termination
* by upper-level transactions.
*/
int
smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr, bool *haveNonTemp)
{
int nestLevel = GetCurrentTransactionNestLevel();
int nrels;
@@ -691,6 +689,8 @@ smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
PendingRelDelete *pending;
nrels = 0;
if (haveNonTemp)
*haveNonTemp = false;
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
@@ -707,6 +707,8 @@ smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr)
{
if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
*rptr++ = pending->relnode;
if (haveNonTemp && !pending->isTemp)
*haveNonTemp = true;
}
return nrels;
}