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