Ühel kenal päeval, K, 2005-12-21 kell 09:50, kirjutas Hannu Krosing: > Ühel kenal päeval, T, 2005-12-20 kell 17:18, kirjutas Tom Lane: > > =?ISO-8859-1?Q?Hans-J=FCrgen_Sch=F6nig?= <[EMAIL PROTECTED]> writes: > > > i was just wondering about the status of hannu's concurrent vacuum patch. > > > are there any plans to integrate this > > > > I still don't trust it (assuming that you're thinking of the same patch > > I am). > > What could I do to increase your trust in it ? > > Could you think of any specific case it could break ? Or any specific > tests to check for it ? > > I attach the version of the patch for 8.1.0 for anyone interested in > checking it.
It was pointed out to me that I did'nt. So here it is: --------------- Hannu
Index: src/backend/access/transam/twophase.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/twophase.c,v retrieving revision 1.16 diff -c -r1.16 twophase.c *** src/backend/access/transam/twophase.c 29 Oct 2005 00:31:50 -0000 1.16 --- src/backend/access/transam/twophase.c 21 Dec 2005 23:09:31 -0000 *************** *** 279,284 **** --- 279,286 ---- gxact->proc.pid = 0; gxact->proc.databaseId = databaseid; gxact->proc.roleId = owner; + gxact->proc.inVacuum = false; + gxact->proc.nonInVacuumXmin = InvalidTransactionId; gxact->proc.lwWaiting = false; gxact->proc.lwExclusive = false; gxact->proc.lwWaitLink = NULL; Index: src/backend/access/transam/xact.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/xact.c,v retrieving revision 1.215 diff -c -r1.215 xact.c *** src/backend/access/transam/xact.c 15 Oct 2005 02:49:09 -0000 1.215 --- src/backend/access/transam/xact.c 21 Dec 2005 23:09:32 -0000 *************** *** 1507,1512 **** --- 1507,1514 ---- LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); MyProc->xid = InvalidTransactionId; MyProc->xmin = InvalidTransactionId; + MyProc->inVacuum = false; /* must be cleared with xid/xmin */ + MyProc->nonInVacuumXmin = InvalidTransactionId; /* this too */ /* Clear the subtransaction-XID cache too while holding the lock */ MyProc->subxids.nxids = 0; *************** *** 1740,1745 **** --- 1742,1749 ---- LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); MyProc->xid = InvalidTransactionId; MyProc->xmin = InvalidTransactionId; + MyProc->inVacuum = false; /* must be cleared with xid/xmin */ + MyProc->nonInVacuumXmin = InvalidTransactionId; /* this too */ /* Clear the subtransaction-XID cache too while holding the lock */ MyProc->subxids.nxids = 0; *************** *** 1902,1907 **** --- 1906,1913 ---- LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); MyProc->xid = InvalidTransactionId; MyProc->xmin = InvalidTransactionId; + MyProc->inVacuum = false; /* must be cleared with xid/xmin */ + MyProc->nonInVacuumXmin = InvalidTransactionId; /* this too */ /* 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.222 diff -c -r1.222 xlog.c *** src/backend/access/transam/xlog.c 29 Oct 2005 00:31:50 -0000 1.222 --- src/backend/access/transam/xlog.c 21 Dec 2005 23:09:34 -0000 *************** *** 5294,5300 **** * StartupSUBTRANS hasn't been called yet. */ if (!InRecovery) ! TruncateSUBTRANS(GetOldestXmin(true)); if (!shutdown) ereport(DEBUG2, --- 5294,5300 ---- * 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.261 diff -c -r1.261 index.c *** src/backend/catalog/index.c 15 Oct 2005 02:49:12 -0000 1.261 --- src/backend/catalog/index.c 21 Dec 2005 23:09:34 -0000 *************** *** 1427,1433 **** else { snapshot = SnapshotAny; ! OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared); } scan = heap_beginscan(heapRelation, /* relation */ --- 1427,1434 ---- 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: /projects/cvsroot/pgsql/src/backend/commands/vacuum.c,v retrieving revision 1.317 diff -c -r1.317 vacuum.c *** src/backend/commands/vacuum.c 15 Oct 2005 02:49:16 -0000 1.317 --- src/backend/commands/vacuum.c 21 Dec 2005 23:09:35 -0000 *************** *** 36,41 **** --- 36,42 ---- #include "executor/executor.h" #include "miscadmin.h" #include "storage/freespace.h" + #include "storage/proc.h" #include "storage/procarray.h" #include "storage/smgr.h" #include "tcop/pquery.h" *************** *** 370,377 **** * cutoff with which we vacuum shared relations, it is not possible * for that database to have a cutoff newer than OLDXMIN recorded in * pg_database. */ ! vacuum_set_xid_limits(vacstmt, false, &initialOldestXmin, &initialFreezeLimit); } --- 371,381 ---- * cutoff with which we vacuum shared relations, it is not possible * for that database to have a cutoff newer than OLDXMIN recorded in * pg_database. + * + * We can't ignore concurrent lazy VACUUMs, because these values will + * be used to truncate clog below. */ ! vacuum_set_xid_limits(vacstmt, false,false, &initialOldestXmin, &initialFreezeLimit); } *************** *** 610,622 **** * vacuum_set_xid_limits() -- compute oldest-Xmin and freeze cutoff points */ void ! vacuum_set_xid_limits(VacuumStmt *vacstmt, bool sharedRel, TransactionId *oldestXmin, TransactionId *freezeLimit) { TransactionId limit; ! *oldestXmin = GetOldestXmin(sharedRel); Assert(TransactionIdIsNormal(*oldestXmin)); --- 614,627 ---- * vacuum_set_xid_limits() -- compute oldest-Xmin and freeze cutoff points */ void ! vacuum_set_xid_limits(VacuumStmt *vacstmt, ! bool sharedRel, bool ignoreVacuum, TransactionId *oldestXmin, TransactionId *freezeLimit) { TransactionId limit; ! *oldestXmin = GetOldestXmin(sharedRel, ignoreVacuum); Assert(TransactionIdIsNormal(*oldestXmin)); *************** *** 671,676 **** --- 676,686 ---- * 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. */ *************** *** 951,958 **** /* 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 --- 961,995 ---- /* 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 *************** *** 1129,1135 **** i; VRelStats *vacrelstats; ! vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared, &OldestXmin, &FreezeLimit); /* --- 1166,1172 ---- i; VRelStats *vacrelstats; ! vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared, true, &OldestXmin, &FreezeLimit); /* Index: src/backend/commands/vacuumlazy.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v retrieving revision 1.61 diff -c -r1.61 vacuumlazy.c *** src/backend/commands/vacuumlazy.c 15 Oct 2005 02:49:16 -0000 1.61 --- src/backend/commands/vacuumlazy.c 21 Dec 2005 23:09:36 -0000 *************** *** 140,146 **** else elevel = DEBUG2; ! vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared, &OldestXmin, &FreezeLimit); vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats)); --- 140,146 ---- else elevel = DEBUG2; ! vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared, true, &OldestXmin, &FreezeLimit); vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats)); Index: src/backend/storage/ipc/procarray.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/storage/ipc/procarray.c,v retrieving revision 1.7 diff -c -r1.7 procarray.c *** src/backend/storage/ipc/procarray.c 15 Oct 2005 02:49:25 -0000 1.7 --- src/backend/storage/ipc/procarray.c 21 Dec 2005 23:09:36 -0000 *************** *** 387,406 **** * 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; --- 387,410 ---- * 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; *************** *** 424,429 **** --- 428,436 ---- { PGPROC *proc = arrayP->procs[index]; + if (ignoreVacuum && proc->inVacuum) + continue; + if (allDbs || proc->databaseId == MyDatabaseId) { /* Fetch xid just once - see GetNewTransactionId */ *************** *** 433,439 **** { 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 (ignoreVacuum) ! xid = proc->nonInVacuumXmin; ! else ! xid = proc->xmin; if (TransactionIdIsNormal(xid)) if (TransactionIdPrecedes(xid, result)) result = xid; *************** *** 471,477 **** * 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 --- 481,487 ---- * 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,FALSE). *---------- */ Snapshot *************** *** 481,486 **** --- 491,497 ---- TransactionId xmin; TransactionId xmax; TransactionId globalxmin; + TransactionId noninvacuumxmin; int index; int count = 0; *************** *** 514,520 **** 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 *************** *** 571,578 **** TransactionIdFollowsOrEquals(xid, xmax)) continue; ! if (TransactionIdPrecedes(xid, xmin)) xmin = xid; snapshot->xip[count] = xid; count++; --- 582,592 ---- TransactionIdFollowsOrEquals(xid, xmax)) continue; ! if (TransactionIdPrecedes(xid, xmin)) { xmin = xid; + if (proc->inVacuum==false) + noninvacuumxmin = xid; + } snapshot->xip[count] = xid; count++; *************** *** 583,590 **** globalxmin = xid; } ! if (serializable) MyProc->xmin = TransactionXmin = xmin; LWLockRelease(ProcArrayLock); --- 597,606 ---- 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.167 diff -c -r1.167 proc.c *** src/backend/storage/lmgr/proc.c 15 Oct 2005 02:49:26 -0000 1.167 --- src/backend/storage/lmgr/proc.c 21 Dec 2005 23:09:37 -0000 *************** *** 259,264 **** --- 259,266 ---- MyProc->databaseId = MyDatabaseId; /* Will be set properly after the session role id is determined */ MyProc->roleId = InvalidOid; + MyProc->inVacuum = false; + MyProc->nonInVacuumXmin = InvalidTransactionId; MyProc->lwWaiting = false; MyProc->lwExclusive = false; MyProc->lwWaitLink = NULL; *************** *** 355,360 **** --- 357,364 ---- MyProc->xmin = InvalidTransactionId; MyProc->databaseId = MyDatabaseId; MyProc->roleId = InvalidOid; + MyProc->inVacuum = false; + MyProc->nonInVacuumXmin = InvalidTransactionId; MyProc->lwWaiting = false; MyProc->lwExclusive = false; MyProc->lwWaitLink = NULL; Index: src/include/commands/vacuum.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/commands/vacuum.h,v retrieving revision 1.62 diff -c -r1.62 vacuum.h *** src/include/commands/vacuum.h 15 Oct 2005 02:49:44 -0000 1.62 --- src/include/commands/vacuum.h 21 Dec 2005 23:09:37 -0000 *************** *** 118,124 **** BlockNumber num_pages, double num_tuples, bool hasindex); ! extern void vacuum_set_xid_limits(VacuumStmt *vacstmt, bool sharedRel, TransactionId *oldestXmin, TransactionId *freezeLimit); extern bool vac_is_partial_index(Relation indrel); --- 118,125 ---- BlockNumber num_pages, double num_tuples, bool hasindex); ! extern void vacuum_set_xid_limits(VacuumStmt *vacstmt, ! bool sharedRel, bool ignoreVacuum, TransactionId *oldestXmin, TransactionId *freezeLimit); extern bool vac_is_partial_index(Relation indrel); Index: src/include/storage/proc.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/storage/proc.h,v retrieving revision 1.84 diff -c -r1.84 proc.h *** src/include/storage/proc.h 15 Oct 2005 02:49:46 -0000 1.84 --- src/include/storage/proc.h 21 Dec 2005 23:09:37 -0000 *************** *** 73,78 **** --- 73,83 ---- 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 VACUUM */ + + TransactionId nonInVacuumXmin; /* same as xmin with transactions where + * (proc->inVacuum == true) excluded */ + /* 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: /projects/cvsroot/pgsql/src/include/storage/procarray.h,v retrieving revision 1.6 diff -c -r1.6 procarray.h *** src/include/storage/procarray.h 15 Oct 2005 02:49:46 -0000 1.6 --- src/include/storage/procarray.h 21 Dec 2005 23:09:37 -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 ignoreVacuum); extern PGPROC *BackendPidGetProc(int pid); extern int BackendXidGetPid(TransactionId xid);
---------------------------(end of broadcast)--------------------------- TIP 4: Have you searched our list archives? http://archives.postgresql.org