Tom Lane wrote:
> Alvaro Herrera <[EMAIL PROTECTED]> writes:
> > Tom Lane wrote:
> >> But the patch changes things so that *everyone* excludes the vacuum from
> >> their xmin. Or at least I thought that was the plan.
>
> > We shouldn't do that, because that Xmin is also used to truncate
> > SUBTRANS.
>
> Yeah, but you were going to change that, no? Truncating SUBTRANS will
> need to include the vacuum xact's xmin, but we don't need it for any
> other purpose.
That's correct.
> > but it means
> > lazy vacuum will never be able to use subtransactions.
>
> This patch already depends on the assumption that lazy vacuum will never
> do any transactional updates, so I don't see what it would need
> subtransactions for.
Here is a patch pursuant to there ideas. The main change is that in
GetSnapshotData, a backend is skipped entirely if inVacuum is found to
be true.
I've been trying to update my SSH CVS several times today but I can't
reach the server. Maybe it's the DoS attach that it's been under, I
don't know.
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Index: src/backend/access/transam/twophase.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/access/transam/twophase.c,v
retrieving revision 1.21
diff -c -p -r1.21 twophase.c
*** src/backend/access/transam/twophase.c 14 Jul 2006 14:52:17 -0000
1.21
--- src/backend/access/transam/twophase.c 28 Jul 2006 21:59:42 -0000
*************** MarkAsPreparing(TransactionId xid, const
*** 279,284 ****
--- 279,285 ----
gxact->proc.pid = 0;
gxact->proc.databaseId = databaseid;
gxact->proc.roleId = owner;
+ gxact->proc.inVacuum = false;
gxact->proc.lwWaiting = false;
gxact->proc.lwExclusive = false;
gxact->proc.lwWaitLink = NULL;
Index: src/backend/access/transam/xact.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/access/transam/xact.c,v
retrieving revision 1.224
diff -c -p -r1.224 xact.c
*** src/backend/access/transam/xact.c 24 Jul 2006 16:32:44 -0000 1.224
--- src/backend/access/transam/xact.c 28 Jul 2006 21:59:42 -0000
*************** CommitTransaction(void)
*** 1529,1534 ****
--- 1529,1535 ----
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+ MyProc->inVacuum = false; /* must be cleared with
xid/xmin */
/* Clear the subtransaction-XID cache too while holding the
lock */
MyProc->subxids.nxids = 0;
*************** PrepareTransaction(void)
*** 1764,1769 ****
--- 1765,1771 ----
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+ MyProc->inVacuum = false; /* must be cleared with xid/xmin */
/* Clear the subtransaction-XID cache too while holding the lock */
MyProc->subxids.nxids = 0;
*************** AbortTransaction(void)
*** 1927,1932 ****
--- 1929,1935 ----
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+ MyProc->inVacuum = false; /* must be cleared with
xid/xmin */
/* Clear the subtransaction-XID cache too while holding the
lock */
MyProc->subxids.nxids = 0;
Index: src/backend/access/transam/xlog.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/access/transam/xlog.c,v
retrieving revision 1.244
diff -c -p -r1.244 xlog.c
*** src/backend/access/transam/xlog.c 14 Jul 2006 14:52:17 -0000 1.244
--- src/backend/access/transam/xlog.c 28 Jul 2006 21:59:42 -0000
*************** CreateCheckPoint(bool shutdown, bool for
*** 5413,5419 ****
* StartupSUBTRANS hasn't been called yet.
*/
if (!InRecovery)
! TruncateSUBTRANS(GetOldestXmin(true));
if (!shutdown)
ereport(DEBUG2,
--- 5413,5419 ----
* StartupSUBTRANS hasn't been called yet.
*/
if (!InRecovery)
! TruncateSUBTRANS(GetOldestXmin(true, false));
if (!shutdown)
ereport(DEBUG2,
Index: src/backend/catalog/index.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/index.c,v
retrieving revision 1.269
diff -c -p -r1.269 index.c
*** src/backend/catalog/index.c 13 Jul 2006 16:49:13 -0000 1.269
--- src/backend/catalog/index.c 28 Jul 2006 21:59:42 -0000
*************** IndexBuildHeapScan(Relation heapRelation
*** 1367,1373 ****
else
{
snapshot = SnapshotAny;
! OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared);
}
scan = heap_beginscan(heapRelation, /* relation */
--- 1367,1374 ----
else
{
snapshot = SnapshotAny;
! /* okay to ignore lazy VACUUMs here */
! OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared,
true);
}
scan = heap_beginscan(heapRelation, /* relation */
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.335
diff -c -p -r1.335 vacuum.c
*** src/backend/commands/vacuum.c 14 Jul 2006 14:52:18 -0000 1.335
--- src/backend/commands/vacuum.c 28 Jul 2006 21:59:42 -0000
***************
*** 37,42 ****
--- 37,43 ----
#include "postmaster/autovacuum.h"
#include "storage/freespace.h"
#include "storage/pmsignal.h"
+ #include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/acl.h"
#include "utils/builtins.h"
*************** vacuum_set_xid_limits(VacuumStmt *vacstm
*** 589,595 ****
{
TransactionId limit;
! *oldestXmin = GetOldestXmin(sharedRel);
Assert(TransactionIdIsNormal(*oldestXmin));
--- 590,605 ----
{
TransactionId limit;
! /*
! * We can always ignore processes running lazy vacuum. This is because
we
! * use these values only for deciding which tuples we must keep in the
! * tables. Since lazy vacuum doesn't write its xid to the table, it's
! * safe to ignore it. In theory it could be problematic to ignore lazy
! * vacuums on a full vacuum, but keep in mind that only one vacuum
process
! * can be working on a particular table at any time, and that each
vacuum
! * is always an independent transaction.
! */
! *oldestXmin = GetOldestXmin(sharedRel, true);
Assert(TransactionIdIsNormal(*oldestXmin));
*************** vacuum_set_xid_limits(VacuumStmt *vacstm
*** 645,650 ****
--- 655,665 ----
* pg_class would've been obsoleted. Of course, this only works
for
* fixed-size never-null columns, but these are.
*
+ * Another reason for doing it this way is that when we are in a
lazy
+ * VACUUM and have inVacuum set, we mustn't do any updates ---
somebody
+ * vacuuming pg_class might think they could delete a tuple marked
with
+ * xmin = our xid.
+ *
* This routine is shared by full VACUUM, lazy VACUUM, and
stand-alone
* ANALYZE.
*/
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 996,1003 ****
/* Begin a transaction for vacuuming this relation */
StartTransactionCommand();
! /* functions in indexes may want a snapshot set */
! ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
/*
* Tell the cache replacement strategy that vacuum is causing all
--- 1011,1045 ----
/* Begin a transaction for vacuuming this relation */
StartTransactionCommand();
!
! if (vacstmt->full)
! {
! /* functions in indexes may want a snapshot set */
! ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
! }
! else
! {
! /*
! * During a lazy VACUUM we do not run any user-supplied
functions,
! * and so it should be safe to not create a transaction
snapshot.
! *
! * We can furthermore set the inVacuum flag, which lets other
! * concurrent VACUUMs know that they can ignore this one while
! * determining their OldestXmin. (The reason we don't set
inVacuum
! * during a full VACUUM is exactly that we may have to run user-
! * defined functions for functional indexes, and we want to make
! * sure that if they use the snapshot set above, any tuples it
! * requires can't get removed from other tables. An index
function
! * that depends on the contents of other tables is arguably
broken,
! * but we won't break it here by violating transaction
semantics.)
! *
! * Note: the inVacuum flag remains set until CommitTransaction
or
! * AbortTransaction. We don't want to clear it until we reset
! * MyProc->xid/xmin, else OldestXmin might appear to go
backwards,
! * which is probably Not Good.
! */
! MyProc->inVacuum = true;
! }
/*
* Tell the cache replacement strategy that vacuum is causing all
Index: src/backend/storage/ipc/procarray.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/ipc/procarray.c,v
retrieving revision 1.14
diff -c -p -r1.14 procarray.c
*** src/backend/storage/ipc/procarray.c 14 Jul 2006 14:52:22 -0000 1.14
--- src/backend/storage/ipc/procarray.c 28 Jul 2006 21:59:42 -0000
*************** TransactionIdIsActive(TransactionId xid)
*** 388,407 ****
* If allDbs is TRUE then all backends are considered; if allDbs is FALSE
* then only backends running in my own database are considered.
*
* This is used by VACUUM to decide which deleted tuples must be preserved
* in a table. allDbs = TRUE is needed for shared relations, but
allDbs =
* FALSE is sufficient for non-shared relations, since only backends in my
! * own database could ever see the tuples in them.
*
* This is also used to determine where to truncate pg_subtrans. allDbs
! * must be TRUE for that case.
*
* Note: we include the 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.
*/
TransactionId
! GetOldestXmin(bool allDbs)
{
ProcArrayStruct *arrayP = procArray;
TransactionId result;
--- 388,411 ----
* If allDbs is TRUE then all backends are considered; if allDbs is FALSE
* then only backends running in my own database are considered.
*
+ * If ignoreVacuum is TRUE then backends with inVacuum set are ignored.
+ *
* This is used by VACUUM to decide which deleted tuples must be preserved
* in a table. allDbs = TRUE is needed for shared relations, but
allDbs =
* FALSE is sufficient for non-shared relations, since only backends in my
! * own database could ever see the tuples in them. Also, we can ignore
! * concurrently running lazy VACUUMs because (a) they must be working on other
! * tables, and (b) they don't need to do snapshot-based lookups.
*
* 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.
* 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.
*/
TransactionId
! GetOldestXmin(bool allDbs, bool ignoreVacuum)
{
ProcArrayStruct *arrayP = procArray;
TransactionId result;
*************** GetOldestXmin(bool allDbs)
*** 425,430 ****
--- 429,437 ----
{
PGPROC *proc = arrayP->procs[index];
+ if (ignoreVacuum && proc->inVacuum)
+ continue;
+
if (allDbs || proc->databaseId == MyDatabaseId)
{
/* Fetch xid just once - see GetNewTransactionId */
*************** GetOldestXmin(bool allDbs)
*** 432,439 ****
--- 439,456 ----
if (TransactionIdIsNormal(xid))
{
+ /* First consider the transaction own's Xid */
if (TransactionIdPrecedes(xid, result))
result = xid;
+
+ /*
+ * Also consider the transaction's Xmin, if set.
+ *
+ * Note that this Xmin may seem to be
guaranteed to be always
+ * lower than the transaction's Xid, but this
is not so because
+ * there is a time window on which the Xid is
already assigned
+ * but the Xmin has not being calculated yet.
+ */
xid = proc->xmin;
if (TransactionIdIsNormal(xid))
if (TransactionIdPrecedes(xid, result))
*************** GetOldestXmin(bool allDbs)
*** 471,478 ****
* RecentXmin: the xmin computed for the most recent snapshot.
XIDs
* older than this are known not running any more.
* RecentGlobalXmin: the global xmin (oldest TransactionXmin
across all
! * running transactions). This is the same computation
done by
! * GetOldestXmin(TRUE).
*----------
*/
Snapshot
--- 488,495 ----
* RecentXmin: the xmin computed for the most recent snapshot.
XIDs
* older than this are known not running any more.
* RecentGlobalXmin: the global xmin (oldest TransactionXmin
across all
! * running transactions, except those running LAZY
VACUUM). This is
! * the same computation done by GetOldestXmin(true, false).
*----------
*/
Snapshot
*************** GetSnapshotData(Snapshot snapshot, bool
*** 561,575 ****
/*
* Ignore my own proc (dealt with my xid above), procs not
running a
! * transaction, and xacts started since we read the next
transaction
! * ID. 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))
continue;
if (TransactionIdPrecedes(xid, xmin))
--- 578,594 ----
/*
* 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)
continue;
if (TransactionIdPrecedes(xid, xmin))
Index: src/backend/storage/lmgr/proc.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/lmgr/proc.c,v
retrieving revision 1.178
diff -c -p -r1.178 proc.c
*** src/backend/storage/lmgr/proc.c 23 Jul 2006 23:08:46 -0000 1.178
--- src/backend/storage/lmgr/proc.c 28 Jul 2006 21:59:42 -0000
*************** InitProcess(void)
*** 257,262 ****
--- 257,263 ----
/* databaseId and roleId will be filled in later */
MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
+ MyProc->inVacuum = false;
MyProc->lwWaiting = false;
MyProc->lwExclusive = false;
MyProc->lwWaitLink = NULL;
*************** InitDummyProcess(void)
*** 388,393 ****
--- 389,395 ----
MyProc->xmin = InvalidTransactionId;
MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
+ MyProc->inVacuum = false;
MyProc->lwWaiting = false;
MyProc->lwExclusive = false;
MyProc->lwWaitLink = NULL;
Index: src/include/storage/proc.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/storage/proc.h,v
retrieving revision 1.89
diff -c -p -r1.89 proc.h
*** src/include/storage/proc.h 13 Jul 2006 16:49:20 -0000 1.89
--- src/include/storage/proc.h 28 Jul 2006 21:59:42 -0000
*************** struct PGPROC
*** 66,78 ****
* this proc */
TransactionId xmin; /* minimal running XID as it
was when we were
! * starting our
xact: vacuum must not remove
! * tuples
deleted by xid >= xmin ! */
int pid; /* This backend's
process id, or 0 */
Oid databaseId; /* OID of database this
backend is using */
Oid roleId; /* OID of role using
this backend */
/* Info about LWLock the process is currently waiting for, if any. */
bool lwWaiting; /* true if waiting for an LW
lock */
bool lwExclusive; /* true if waiting for exclusive access
*/
--- 66,81 ----
* this proc */
TransactionId xmin; /* minimal running XID as it
was when we were
! * starting our
xact, excluding LAZY VACUUM:
! * vacuum must
not remove tuples deleted by
! * xid >= xmin
! */
int pid; /* This backend's
process id, or 0 */
Oid databaseId; /* OID of database this
backend is using */
Oid roleId; /* OID of role using
this backend */
+ bool inVacuum; /* true if current xact is a
LAZY VACUUM */
+
/* Info about LWLock the process is currently waiting for, if any. */
bool lwWaiting; /* true if waiting for an LW
lock */
bool lwExclusive; /* true if waiting for exclusive access
*/
Index: src/include/storage/procarray.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/storage/procarray.h,v
retrieving revision 1.9
diff -c -p -r1.9 procarray.h
*** src/include/storage/procarray.h 19 Jun 2006 01:51:22 -0000 1.9
--- src/include/storage/procarray.h 28 Jul 2006 21:59:42 -0000
*************** extern void ProcArrayRemove(PGPROC *proc
*** 24,30 ****
extern bool TransactionIdIsInProgress(TransactionId xid);
extern bool TransactionIdIsActive(TransactionId xid);
! extern TransactionId GetOldestXmin(bool allDbs);
extern PGPROC *BackendPidGetProc(int pid);
extern int BackendXidGetPid(TransactionId xid);
--- 24,30 ----
extern bool TransactionIdIsInProgress(TransactionId xid);
extern bool TransactionIdIsActive(TransactionId xid);
! extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum);
extern PGPROC *BackendPidGetProc(int pid);
extern int BackendXidGetPid(TransactionId xid);
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match