On E, 2005-08-22 at 02:14 +0300, Hannu Krosing wrote:
> Probably nonInVacuumXmin needs more care, i.e. initialising and setting
> it outside GetSnapshotData, at trx start and/or end. I'm too sleepy now
> to investigate further (it's 2:10 am here).
The attached patch works now as advertized so that concurrent non-vacuum
transactions don't interfere with vacuums OldestXmin calculations.
I fixed also the "VACUUM FULL case it manages to invoke *both*
full_vacuum_rel and lazy_vacuum_rel " bug.
But I could not find the breakage (from your Aug 17 email) with
> > In my patch I specifically exclude TruncateSUBTRANS from using the
> > inVacuum flag
>
> You missed vac_truncate_clog, though.
Has somethoing changed in vac_truncate_clog or am I just too
lazy/stupid ?
--
Hannu Krosing <[EMAIL PROTECTED]>
Index: src/backend/access/transam/xact.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/xact.c,v
retrieving revision 1.214
diff -c -r1.214 xact.c
*** src/backend/access/transam/xact.c 20 Aug 2005 23:45:08 -0000 1.214
--- src/backend/access/transam/xact.c 22 Aug 2005 10:13:20 -0000
***************
*** 1402,1407 ****
--- 1402,1416 ----
AfterTriggerBeginXact();
/*
+ * mark the transaction as not VACUUM (vacuum_rel will set inVacuum
+ * to true directly after calling BeginTransactionCommand() )
+ *
+ * this can probably be moved to be done only once when establishing
+ * connection as this is now quaranteed to be reset to false in vacuum.c
+ */
+ MyProc->inVacuum = false;
+
+ /*
* done with start processing, set current transaction state to "in
* progress"
*/
***************
*** 1516,1521 ****
--- 1525,1531 ----
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+ MyProc->nonInVacuumXmin = InvalidTransactionId;
/* Clear the subtransaction-XID cache too while holding the lock */
MyProc->subxids.nxids = 0;
***************
*** 1752,1757 ****
--- 1762,1768 ----
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+ MyProc->nonInVacuumXmin = InvalidTransactionId;
/* Clear the subtransaction-XID cache too while holding the lock */
MyProc->subxids.nxids = 0;
***************
*** 1915,1920 ****
--- 1926,1932 ----
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+ MyProc->nonInVacuumXmin = InvalidTransactionId;
/* Clear the subtransaction-XID cache too while holding the lock */
MyProc->subxids.nxids = 0;
Index: src/backend/access/transam/xlog.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/xlog.c,v
retrieving revision 1.216
diff -c -r1.216 xlog.c
*** src/backend/access/transam/xlog.c 20 Aug 2005 23:26:10 -0000 1.216
--- src/backend/access/transam/xlog.c 22 Aug 2005 10:13:20 -0000
***************
*** 5214,5220 ****
* mustn't do this because StartupSUBTRANS hasn't been called yet.
*/
if (!InRecovery)
! TruncateSUBTRANS(GetOldestXmin(true));
if (!shutdown)
ereport(DEBUG2,
--- 5214,5220 ----
* mustn't do this because StartupSUBTRANS hasn't been called yet.
*/
if (!InRecovery)
! TruncateSUBTRANS(GetOldestXmin(true, false));
if (!shutdown)
ereport(DEBUG2,
Index: src/backend/catalog/index.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/index.c,v
retrieving revision 1.259
diff -c -r1.259 index.c
*** src/backend/catalog/index.c 12 Aug 2005 01:35:56 -0000 1.259
--- src/backend/catalog/index.c 22 Aug 2005 10:13:21 -0000
***************
*** 1433,1439 ****
else
{
snapshot = SnapshotAny;
! OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared);
}
scan = heap_beginscan(heapRelation, /* relation */
--- 1433,1439 ----
else
{
snapshot = SnapshotAny;
! OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared,true);
}
scan = heap_beginscan(heapRelation, /* relation */
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.313
diff -c -r1.313 vacuum.c
*** src/backend/commands/vacuum.c 20 Aug 2005 00:39:54 -0000 1.313
--- src/backend/commands/vacuum.c 22 Aug 2005 10:13:21 -0000
***************
*** 37,42 ****
--- 37,43 ----
#include "miscadmin.h"
#include "storage/freespace.h"
#include "storage/procarray.h"
+ #include "storage/proc.h"
#include "storage/smgr.h"
#include "tcop/pquery.h"
#include "utils/acl.h"
***************
*** 618,624 ****
{
TransactionId limit;
! *oldestXmin = GetOldestXmin(sharedRel);
Assert(TransactionIdIsNormal(*oldestXmin));
--- 619,625 ----
{
TransactionId limit;
! *oldestXmin = GetOldestXmin(sharedRel, true);
Assert(TransactionIdIsNormal(*oldestXmin));
***************
*** 951,956 ****
--- 952,961 ----
Oid toast_relid;
bool result;
+ BlockNumber stats_rel_pages=0;
+ double stats_rel_tuples=0;
+ bool stats_hasindex=false;
+
/* Begin a transaction for vacuuming this relation */
StartTransactionCommand();
/* functions in indexes may want a snapshot set */
***************
*** 1064,1087 ****
*/
toast_relid = onerel->rd_rel->reltoastrelid;
! /*
! * Do the actual work --- either FULL or "lazy" vacuum
! */
! if (vacstmt->full)
! full_vacuum_rel(onerel, vacstmt);
! else
! lazy_vacuum_rel(onerel, vacstmt);
! result = true; /* did the vacuum */
! /* all done with this class, but hold lock until commit */
! relation_close(onerel, NoLock);
! /*
! * Complete the transaction and free all temporary memory used.
! */
! StrategyHintVacuum(false);
! CommitTransactionCommand();
/*
* If the relation has a secondary toast rel, vacuum that too while we
--- 1069,1117 ----
*/
toast_relid = onerel->rd_rel->reltoastrelid;
! PG_TRY();
! {
! /*
! * Do the actual work --- either FULL or "lazy" vacuum
! */
! if (vacstmt->full)
! full_vacuum_rel(onerel, vacstmt);
! else {
! /* mark this transaction as being the cleanup-only part of lazy vacuum */
! MyProc->inVacuum = true;
! lazy_vacuum_rel(onerel, vacstmt, &stats_rel_pages, &stats_rel_tuples, &stats_hasindex);
! }
! result = true; /* did the vacuum */
! /* all done with this class, but hold lock until commit */
! relation_close(onerel, NoLock);
! /*
! * Complete the transaction and free all temporary memory used.
! */
! StrategyHintVacuum(false);
! CommitTransactionCommand();
! }
! PG_CATCH();
! {
! /* make sure in-vacuum flag is cleared is cleared */
! MyProc->inVacuum = false;
! PG_RE_THROW();
! }
! PG_END_TRY();
! MyProc->inVacuum = false;
! /* use yet another transaction for saving stats from lazy_vacuum_rel into pg_class */
! if (stats_rel_pages > 0) {
! StartTransactionCommand();
! ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); /* is this needed ? */
! /* Update statistics in pg_class */
! vac_update_relstats(RelationGetRelid(onerel),
! stats_rel_pages,
! stats_rel_tuples,
! stats_hasindex);
! CommitTransactionCommand();
! }
/*
* If the relation has a secondary toast rel, vacuum that too while we
Index: src/backend/commands/vacuumlazy.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v
retrieving revision 1.57
diff -c -r1.57 vacuumlazy.c
*** src/backend/commands/vacuumlazy.c 20 Aug 2005 23:26:13 -0000 1.57
--- src/backend/commands/vacuumlazy.c 22 Aug 2005 10:13:21 -0000
***************
*** 129,135 ****
* and locked the relation.
*/
void
! lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
{
LVRelStats *vacrelstats;
Relation *Irel;
--- 129,135 ----
* and locked the relation.
*/
void
! lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, BlockNumber *stats_rel_pages, double *stats_rel_tuples, bool *stats_hasindex)
{
LVRelStats *vacrelstats;
Relation *Irel;
***************
*** 176,185 ****
--- 176,191 ----
lazy_update_fsm(onerel, vacrelstats);
/* Update statistics in pg_class */
+ /* this is moved to out erfunction to be run in a separate transaction
vac_update_relstats(RelationGetRelid(onerel),
vacrelstats->rel_pages,
vacrelstats->rel_tuples,
hasindex);
+ */
+ /* return values for setting relstats in another transaction */
+ *stats_rel_pages = vacrelstats->rel_pages;
+ *stats_rel_tuples = vacrelstats->rel_tuples;
+ *stats_hasindex = hasindex;
/* report results to the stats collector, too */
pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared,
Index: src/backend/storage/ipc/procarray.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/storage/ipc/procarray.c,v
retrieving revision 1.6
diff -c -r1.6 procarray.c
*** src/backend/storage/ipc/procarray.c 20 Aug 2005 23:26:20 -0000 1.6
--- src/backend/storage/ipc/procarray.c 22 Aug 2005 10:13:21 -0000
***************
*** 404,410 ****
* when it does set the snapshot it cannot set xmin less than what we compute.
*/
TransactionId
! GetOldestXmin(bool allDbs)
{
ProcArrayStruct *arrayP = procArray;
TransactionId result;
--- 404,410 ----
* when it does set the snapshot it cannot set xmin less than what we compute.
*/
TransactionId
! GetOldestXmin(bool allDbs, bool nonInVacuumTrxOnly)
{
ProcArrayStruct *arrayP = procArray;
TransactionId result;
***************
*** 428,434 ****
{
PGPROC *proc = arrayP->procs[index];
! if (allDbs || proc->databaseId == MyDatabaseId)
{
/* Fetch xid just once - see GetNewTransactionId */
TransactionId xid = proc->xid;
--- 428,437 ----
{
PGPROC *proc = arrayP->procs[index];
! /* if nonInVacuumTrxOnly==true then don't use xid of transactions
! * running lazy vacuum */
! if ( (nonInVacuumTrxOnly && (proc->inVacuum == false))
! && (allDbs || proc->databaseId == MyDatabaseId))
{
/* Fetch xid just once - see GetNewTransactionId */
TransactionId xid = proc->xid;
***************
*** 437,443 ****
{
if (TransactionIdPrecedes(xid, result))
result = xid;
! xid = proc->xmin;
if (TransactionIdIsNormal(xid))
if (TransactionIdPrecedes(xid, result))
result = xid;
--- 440,449 ----
{
if (TransactionIdPrecedes(xid, result))
result = xid;
! if (nonInVacuumTrxOnly)
! xid = proc->nonInVacuumXmin;
! else
! xid = proc->xmin;
if (TransactionIdIsNormal(xid))
if (TransactionIdPrecedes(xid, result))
result = xid;
***************
*** 485,490 ****
--- 491,497 ----
TransactionId xmin;
TransactionId xmax;
TransactionId globalxmin;
+ TransactionId noninvacuumxmin;
int index;
int count = 0;
***************
*** 518,524 ****
errmsg("out of memory")));
}
! globalxmin = xmin = GetTopTransactionId();
/*
* If we are going to set MyProc->xmin then we'd better get exclusive
--- 525,531 ----
errmsg("out of memory")));
}
! globalxmin = xmin = noninvacuumxmin = GetTopTransactionId();
/*
* If we are going to set MyProc->xmin then we'd better get exclusive
***************
*** 576,583 ****
TransactionIdFollowsOrEquals(xid, xmax))
continue;
! if (TransactionIdPrecedes(xid, xmin))
xmin = xid;
snapshot->xip[count] = xid;
count++;
--- 583,593 ----
TransactionIdFollowsOrEquals(xid, xmax))
continue;
! if (TransactionIdPrecedes(xid, xmin)){
xmin = xid;
+ if (proc->inVacuum==false)
+ noninvacuumxmin = xid;
+ }
snapshot->xip[count] = xid;
count++;
***************
*** 588,595 ****
globalxmin = xid;
}
! if (serializable)
MyProc->xmin = TransactionXmin = xmin;
LWLockRelease(ProcArrayLock);
--- 598,607 ----
globalxmin = xid;
}
! if (serializable) {
MyProc->xmin = TransactionXmin = xmin;
+ MyProc->nonInVacuumXmin = noninvacuumxmin;
+ }
LWLockRelease(ProcArrayLock);
Index: src/backend/storage/lmgr/proc.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v
retrieving revision 1.163
diff -c -r1.163 proc.c
*** src/backend/storage/lmgr/proc.c 20 Aug 2005 23:26:24 -0000 1.163
--- src/backend/storage/lmgr/proc.c 22 Aug 2005 10:13:24 -0000
***************
*** 256,261 ****
--- 256,263 ----
MyProc->waitStatus = STATUS_OK;
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+ MyProc->inVacuum = false;
+ MyProc->nonInVacuumXmin = InvalidTransactionId;
MyProc->pid = MyProcPid;
MyProc->databaseId = MyDatabaseId;
/* Will be set properly after the session role id is determined */
***************
*** 337,342 ****
--- 339,346 ----
MyProc->waitStatus = STATUS_OK;
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+ MyProc->inVacuum = false;
+ MyProc->nonInVacuumXmin = InvalidTransactionId;
MyProc->databaseId = MyDatabaseId;
MyProc->roleId = InvalidOid;
MyProc->lwWaiting = false;
Index: src/include/commands/vacuum.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/vacuum.h,v
retrieving revision 1.60
diff -c -r1.60 vacuum.h
*** src/include/commands/vacuum.h 14 Jul 2005 05:13:43 -0000 1.60
--- src/include/commands/vacuum.h 22 Aug 2005 10:13:24 -0000
***************
*** 142,148 ****
extern void vacuum_delay_point(void);
/* in commands/vacuumlazy.c */
! extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
/* in commands/analyze.c */
extern void analyze_rel(Oid relid, VacuumStmt *vacstmt);
--- 142,151 ----
extern void vacuum_delay_point(void);
/* in commands/vacuumlazy.c */
! extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
! BlockNumber *stats_rel_pages,
! double *stats_rel_tuples,
! bool *stats_hasindex);
/* in commands/analyze.c */
extern void analyze_rel(Oid relid, VacuumStmt *vacstmt);
Index: src/include/storage/proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/storage/proc.h,v
retrieving revision 1.81
diff -c -r1.81 proc.h
*** src/include/storage/proc.h 20 Aug 2005 23:26:34 -0000 1.81
--- src/include/storage/proc.h 22 Aug 2005 10:13:25 -0000
***************
*** 69,74 ****
--- 69,83 ----
* were starting our xact: vacuum must not
* remove tuples deleted by xid >= xmin ! */
+ bool inVacuum; /* true if current command is vacuum.
+ * used by other vacuum commands
+ * as xid or xmin of this cmd need not be used
+ * when finding global xmin for removing
+ * tuples */
+
+ TransactionId nonInVacuumXmin; /* same as xmin with transactions where
+ * (proc->inVacuum == true) excluded */
+
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 */
Index: src/include/storage/procarray.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/storage/procarray.h,v
retrieving revision 1.5
diff -c -r1.5 procarray.h
*** src/include/storage/procarray.h 20 Aug 2005 23:26:34 -0000 1.5
--- src/include/storage/procarray.h 22 Aug 2005 10:13:25 -0000
***************
*** 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 nonInVacuumTrxOnly);
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