Optimizing GetConflictingVirtualXIDs()
Optimize GetConflictingVirtualXIDs() in roughly the same manner we
optimize TransactionIdIsInProgress().
Views?
--
Simon Riggs www.2ndQuadrant.com
Attachments:
optimize_get_conflicts.patchtext/x-patch; charset=UTF-8; name=optimize_get_conflicts.patchDownload
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 12de877..7f9b10e 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -1686,12 +1686,21 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
* this array sufficiently often that we use malloc for the result.
*/
VirtualTransactionId *
-GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
+GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid, int *return_count)
{
static VirtualTransactionId *vxids;
ProcArrayStruct *arrayP = procArray;
int count = 0;
int index;
+ TransactionId globalxmin;
+
+ /*
+ * Don't bother checking a valid TransactionId older than RecentGlobalXmin;
+ * it could not possibly cause a conflict.
+ */
+ if (TransactionIdPrecedes(limitXmin, RecentGlobalXmin) &&
+ TransactionIdIsValid(limitXmin))
+ return NULL;
/*
* If not first time through, get workspace to remember main XIDs in. We
@@ -1717,19 +1726,28 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
if (!TransactionIdIsValid(limitXmin))
limitXmin = ShmemVariableCache->latestCompletedXid;
+ globalxmin = ShmemVariableCache->latestCompletedXid;
+
for (index = 0; index < arrayP->numProcs; index++)
{
volatile PGPROC *proc = arrayP->procs[index];
+ TransactionId pxmin;
/* Exclude prepared transactions */
if (proc->pid == 0)
continue;
+ /* Fetch xmin just once - can't change on us, but good coding */
+ pxmin = proc->xmin;
+
+ /* Update globalxmin to be the smallest valid xmin */
+ if (TransactionIdIsNormal(pxmin) &&
+ TransactionIdPrecedes(pxmin, globalxmin))
+ globalxmin = pxmin;
+
if (!OidIsValid(dbOid) ||
proc->databaseId == dbOid)
{
- /* Fetch xmin just once - can't change on us, but good coding */
- TransactionId pxmin = proc->xmin;
/*
* We ignore an invalid pxmin because this means that backend
@@ -1748,6 +1766,10 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
LWLockRelease(ProcArrayLock);
+ RecentGlobalXmin = globalxmin;
+
+ *return_count = count;
+
/* add the terminator */
vxids[count].backendId = InvalidBackendId;
vxids[count].localTransactionId = InvalidLocalTransactionId;
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index c8fde2f..ea9c2e3 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -244,11 +244,12 @@ void
ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode node)
{
VirtualTransactionId *backends;
+ int conflicts = 0;
backends = GetConflictingVirtualXIDs(latestRemovedXid,
- node.dbNode);
-
- ResolveRecoveryConflictWithVirtualXIDs(backends,
+ node.dbNode, &conflicts);
+ if (conflicts > 0)
+ ResolveRecoveryConflictWithVirtualXIDs(backends,
PROCSIG_RECOVERY_CONFLICT_SNAPSHOT);
}
@@ -256,6 +257,7 @@ void
ResolveRecoveryConflictWithTablespace(Oid tsid)
{
VirtualTransactionId *temp_file_users;
+ int conflicts = 0;
/*
* Standby users may be currently using this tablespace for
@@ -277,7 +279,7 @@ ResolveRecoveryConflictWithTablespace(Oid tsid)
* non-transactional.
*/
temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId,
- InvalidOid);
+ InvalidOid, &conflicts);
ResolveRecoveryConflictWithVirtualXIDs(temp_file_users,
PROCSIG_RECOVERY_CONFLICT_TABLESPACE);
}
@@ -333,8 +335,9 @@ ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid)
backends = GetLockConflicts(&locktag, AccessExclusiveLock);
else
{
+ int conflicts = 0;
backends = GetConflictingVirtualXIDs(InvalidTransactionId,
- InvalidOid);
+ InvalidOid, &conflicts);
report_memory_error = true;
}
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index 5a026e9..e01ad79 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -57,7 +57,8 @@ extern bool IsBackendPid(int pid);
extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin,
bool excludeXmin0, bool allDbs, int excludeVacuum,
int *nvxids);
-extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid);
+extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin,
+ Oid dbOid, int *return_count);
extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode);
extern int CountActiveBackends(void);
On Sun, Feb 14, 2010 at 2:59 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
Optimize GetConflictingVirtualXIDs() in roughly the same manner we
optimize TransactionIdIsInProgress().Views?
EINSUFFICIENTEXPLANATION :)
--
greg
On Sun, 2010-02-14 at 17:06 +0000, Greg Stark wrote:
On Sun, Feb 14, 2010 at 2:59 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
Optimize GetConflictingVirtualXIDs() in roughly the same manner we
optimize TransactionIdIsInProgress().Views?
EINSUFFICIENTEXPLANATION :)
...I like that error code.
The patch adds a calculation of RecentGlobalXmin each time it accesses
the proc array to derive conflicts. It then uses the derived value to
provide a fast-path out if a potential snapshot conflict arrives that we
already know will not conflict with any backends. The purpose of this is
to reduce the number of scans of the procarray and improve the
performance of the startup process.
The mechanism and purpose is the same as the first check in
TransactionIdIsInProgress().
--
Simon Riggs www.2ndQuadrant.com
Simon Riggs <simon@2ndQuadrant.com> writes:
On Sun, 2010-02-14 at 17:06 +0000, Greg Stark wrote:
EINSUFFICIENTEXPLANATION :)
...I like that error code.
I think more EINSUFFICIENTCOMMENTS. The patch should also add a comment
to the function, along the lines of "While we have the lock, also update
RecentGlobalXmin, so that we will have as up-to-date a value as possible
for next time". You've also failed to document the meaning or purpose
of the added output parameter.
regards, tom lane