提交 4e655714 编写于 作者: H Heikki Linnakangas

Enable autovacuum, but only for 'template0'.

Autovacuum has been completely disabled so far. In the upstream, even if
you set autovacuum=off, it would still run, if necessary, to prevent XID
wraparound, but in GPDB we would not launch it even for that.

That is problematic for template0, and any other databases with
datallowconn=false. If you cannot connect to a database, you cannot
manually VACUUM it. Therefore, its datfrozenxid is never advanced. We had
hacked our way through that by letting XID wraparound to happen for
databases with datallowconn=false. The theory was that template0 - and
hopefully any other such database! - was fully frozen, so there is no harm
in letting XID counter to wrap around. However, you get trouble if you
create a new database, using template0 as the template, around the time
that XID wraparound for template0 is about to happen. The new database will
inherit the datfrozenxid value, and because it will have datallowconn=true,
the system will immediately shut down because now it looks like XID
wraparound happened.

To fix, re-enable autovacuum, in a very limited fashion. The autovacuum
launcher is now started, but it will only perform anti-wraparound vacuums,
and only on databases with datallowconn=false.

This includes fixes for some garden-variety bugs that have been introduced
to autovacuum, when merging with upstream, that have gone unnoticed because
the code has been unused.

Discussion: https://groups.google.com/a/greenplum.org/d/msg/gpdb-dev/gqordopb6Gg/-GHXSE4qBwAJ
上级 b3f300b9
...@@ -4040,11 +4040,6 @@ heap_inplace_update(Relation relation, HeapTuple tuple) ...@@ -4040,11 +4040,6 @@ heap_inplace_update(Relation relation, HeapTuple tuple)
* exclusive lock ensures no other backend is in process of checking the * exclusive lock ensures no other backend is in process of checking the
* tuple status. Also, getting exclusive lock makes it safe to adjust the * tuple status. Also, getting exclusive lock makes it safe to adjust the
* infomask bits. * infomask bits.
*
* In GPDB, the caller must ensure that the cutoff_xid covers any transactions
* that are no longer running locally, but are still visible to a distributed
* snapshot in the QD node. GetOldestXmin() will do that for you, and
* RecentGlobalXmin is fine, too.
*/ */
bool bool
heap_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid, heap_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
......
...@@ -103,14 +103,9 @@ GetNewTransactionId(bool isSubXact) ...@@ -103,14 +103,9 @@ GetNewTransactionId(bool isSubXact)
* request only once per 64K transaction starts. This still gives * request only once per 64K transaction starts. This still gives
* plenty of chances before we get into real trouble. * plenty of chances before we get into real trouble.
*/ */
/* MPP-19652: autovacuum disabled */
#if 0
if (IsUnderPostmaster && (xid % 65536) == 0) if (IsUnderPostmaster && (xid % 65536) == 0)
{ SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
elog(LOG, "GetNewTransactionId: requesting autovac (xid %u xidVacLimit %u)", xid, ShmemVariableCache->xidVacLimit);
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC);
}
#endif
if (IsUnderPostmaster && if (IsUnderPostmaster &&
TransactionIdFollowsOrEquals(xid, xidStopLimit)) TransactionIdFollowsOrEquals(xid, xidStopLimit))
{ {
...@@ -361,14 +356,9 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid) ...@@ -361,14 +356,9 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
* resulting in race conditions as well as crashes of those not connected * resulting in race conditions as well as crashes of those not connected
* to shared memory). Perhaps this can be improved someday. * to shared memory). Perhaps this can be improved someday.
*/ */
/* MPP-19652: autovacuum disabled */
#if 0
xidVacLimit = oldest_datfrozenxid + autovacuum_freeze_max_age; xidVacLimit = oldest_datfrozenxid + autovacuum_freeze_max_age;
if (xidVacLimit < FirstNormalTransactionId) if (xidVacLimit < FirstNormalTransactionId)
xidVacLimit += FirstNormalTransactionId; xidVacLimit += FirstNormalTransactionId;
#else
xidVacLimit = xidWarnLimit;
#endif
/* Grab lock for just long enough to set the new limit values */ /* Grab lock for just long enough to set the new limit values */
LWLockAcquire(XidGenLock, LW_EXCLUSIVE); LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
...@@ -393,12 +383,9 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid) ...@@ -393,12 +383,9 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
* database, it'll call here, and we'll signal the postmaster to start * database, it'll call here, and we'll signal the postmaster to start
* another iteration immediately if there are still any old databases. * another iteration immediately if there are still any old databases.
*/ */
/* MPP-19652: autovacuum disabled */
#if 0
if (TransactionIdFollowsOrEquals(curXid, xidVacLimit) && if (TransactionIdFollowsOrEquals(curXid, xidVacLimit) &&
IsUnderPostmaster) IsUnderPostmaster)
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER); SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
#endif
/* Give an immediate warning if past the wrap warn point */ /* Give an immediate warning if past the wrap warn point */
if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit)) if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit))
......
...@@ -8797,7 +8797,7 @@ CreateCheckPoint(int flags) ...@@ -8797,7 +8797,7 @@ CreateCheckPoint(int flags)
* StartupSUBTRANS hasn't been called yet. * StartupSUBTRANS hasn't been called yet.
*/ */
if (!RecoveryInProgress()) if (!RecoveryInProgress())
TruncateSUBTRANS(GetOldestXmin(true, false)); TruncateSUBTRANS(GetLocalOldestXmin(true, false));
/* All real work is done, but log before releasing lock. */ /* All real work is done, but log before releasing lock. */
if (log_checkpoints) if (log_checkpoints)
......
...@@ -2126,19 +2126,12 @@ vac_truncate_clog(TransactionId frozenXID) ...@@ -2126,19 +2126,12 @@ vac_truncate_clog(TransactionId frozenXID)
Assert(TransactionIdIsNormal(dbform->datfrozenxid)); Assert(TransactionIdIsNormal(dbform->datfrozenxid));
/* if (TransactionIdPrecedes(myXID, dbform->datfrozenxid))
* MPP-20053: Skip databases that cannot be connected to in computing frozenAlreadyWrapped = true;
* the oldest database. else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
*/
if (dbform->datallowconn)
{ {
if (TransactionIdPrecedes(myXID, dbform->datfrozenxid)) frozenXID = dbform->datfrozenxid;
frozenAlreadyWrapped = true; oldest_datoid = HeapTupleGetOid(tuple);
else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
{
frozenXID = dbform->datfrozenxid;
oldest_datoid = HeapTupleGetOid(tuple);
}
} }
} }
......
...@@ -117,7 +117,7 @@ int autovacuum_freeze_max_age; ...@@ -117,7 +117,7 @@ int autovacuum_freeze_max_age;
int autovacuum_vac_cost_delay; int autovacuum_vac_cost_delay;
int autovacuum_vac_cost_limit; int autovacuum_vac_cost_limit;
int Log_autovacuum_min_duration = -1; int Log_autovacuum_min_duration = 0;
/* how long to keep pgstat data in the launcher, in milliseconds */ /* how long to keep pgstat data in the launcher, in milliseconds */
#define STATS_READ_DELAY 1000 #define STATS_READ_DELAY 1000
...@@ -1017,7 +1017,7 @@ rebuild_database_list(Oid newdb) ...@@ -1017,7 +1017,7 @@ rebuild_database_list(Oid newdb)
current_time = GetCurrentTimestamp(); current_time = GetCurrentTimestamp();
/* /*
* move the elements from the array into the dllist, setting the * move the elements from the array into the dllist, setting the
* next_worker while walking the array * next_worker while walking the array
*/ */
for (i = 0; i < nelems; i++) for (i = 0; i < nelems; i++)
...@@ -1091,13 +1091,12 @@ do_start_worker(void) ...@@ -1091,13 +1091,12 @@ do_start_worker(void)
* Create and switch to a temporary context to avoid leaking the memory * Create and switch to a temporary context to avoid leaking the memory
* allocated for the database list. * allocated for the database list.
*/ */
tmpcxt = AllocSetContextCreate(CurrentMemoryContext, tmpcxt = AllocSetContextCreate(CurrentMemoryContext,
"Start worker tmp cxt", "Start worker tmp cxt",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(tmpcxt); oldcxt = MemoryContextSwitchTo(tmpcxt);
/* use fresh stats */ /* use fresh stats */
autovac_refresh_stats(); autovac_refresh_stats();
...@@ -1552,7 +1551,7 @@ AutoVacWorkerMain(int argc, char *argv[]) ...@@ -1552,7 +1551,7 @@ AutoVacWorkerMain(int argc, char *argv[])
MyWorkerInfo->wi_proc = MyProc; MyWorkerInfo->wi_proc = MyProc;
/* insert into the running list */ /* insert into the running list */
SHMQueueInsertBefore(&AutoVacuumShmem->av_runningWorkers, SHMQueueInsertBefore(&AutoVacuumShmem->av_runningWorkers,
&MyWorkerInfo->wi_links); &MyWorkerInfo->wi_links);
/* /*
* remove from the "starting" pointer, so that the launcher can start * remove from the "starting" pointer, so that the launcher can start
...@@ -1803,6 +1802,16 @@ get_database_list(void) ...@@ -1803,6 +1802,16 @@ get_database_list(void)
Form_pg_database pgdatabase = (Form_pg_database) GETSTRUCT(tup); Form_pg_database pgdatabase = (Form_pg_database) GETSTRUCT(tup);
avw_dbase *avdb; avw_dbase *avdb;
/*
* In GPDB, autovacuum is currently disabled, except for the
* anti-wraparound vacuum of template0 (and any other databases
* with !datallowconn). The administrator is expected to do all
* VACUUMing manually, except for template0, which you cannot
* VACUUM manually because you cannot connect to it.
*/
if (pgdatabase->datallowconn)
continue;
avdb = (avw_dbase *) palloc(sizeof(avw_dbase)); avdb = (avw_dbase *) palloc(sizeof(avw_dbase));
avdb->adw_datid = HeapTupleGetOid(tup); avdb->adw_datid = HeapTupleGetOid(tup);
......
...@@ -153,7 +153,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) ...@@ -153,7 +153,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
size = add_size(size, SInvalShmemSize()); size = add_size(size, SInvalShmemSize());
size = add_size(size, PMSignalShmemSize()); size = add_size(size, PMSignalShmemSize());
size = add_size(size, ProcSignalShmemSize()); size = add_size(size, ProcSignalShmemSize());
//size = add_size(size, AutoVacuumShmemSize()); size = add_size(size, AutoVacuumShmemSize());
size = add_size(size, FtsShmemSize()); size = add_size(size, FtsShmemSize());
size = add_size(size, tmShmemSize()); size = add_size(size, tmShmemSize());
size = add_size(size, SeqServerShmemSize()); size = add_size(size, SeqServerShmemSize());
...@@ -170,7 +170,6 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) ...@@ -170,7 +170,6 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
elog(DEBUG1, "Size not including the buffer pool %lu", elog(DEBUG1, "Size not including the buffer pool %lu",
(unsigned long) size); (unsigned long) size);
size = add_size(size, AutoVacuumShmemSize());
size = add_size(size, BTreeShmemSize()); size = add_size(size, BTreeShmemSize());
size = add_size(size, SyncScanShmemSize()); size = add_size(size, SyncScanShmemSize());
size = add_size(size, CheckpointerShmemSize()); size = add_size(size, CheckpointerShmemSize());
...@@ -307,7 +306,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) ...@@ -307,7 +306,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
CheckpointerShmemInit(); CheckpointerShmemInit();
WalSndShmemInit(); WalSndShmemInit();
WalRcvShmemInit(); WalRcvShmemInit();
//AutoVacuumShmemInit(); AutoVacuumShmemInit();
SeqServerShmemInit(); SeqServerShmemInit();
#ifdef FAULT_INJECTOR #ifdef FAULT_INJECTOR
......
...@@ -357,12 +357,12 @@ InitProcess(void) ...@@ -357,12 +357,12 @@ InitProcess(void)
* cleaning up. (XXX autovac launcher currently doesn't participate in * cleaning up. (XXX autovac launcher currently doesn't participate in
* this; it probably should.) * this; it probably should.)
* *
* Ideally, we should create functions similar to IsAutoVacuumWorkerProcess() * Ideally, we should create functions similar to IsAutoVacuumLauncherProcess()
* for ftsProber, SeqServer etc who call InitProcess(). * for ftsProber, SeqServer etc who call InitProcess().
* But MyPMChildSlot helps to get away with it. * But MyPMChildSlot helps to get away with it.
*/ */
if (IsUnderPostmaster && !IsAutoVacuumLauncherProcess() if (IsUnderPostmaster && !IsAutoVacuumLauncherProcess()
&& !IsAutoVacuumWorkerProcess() && MyPMChildSlot > 0) && MyPMChildSlot > 0)
MarkPostmasterChildActive(); MarkPostmasterChildActive();
/* /*
...@@ -838,7 +838,7 @@ ProcKill(int code, Datum arg) ...@@ -838,7 +838,7 @@ ProcKill(int code, Datum arg)
* (XXX autovac launcher should be included here someday) * (XXX autovac launcher should be included here someday)
*/ */
if (IsUnderPostmaster && !IsAutoVacuumLauncherProcess() if (IsUnderPostmaster && !IsAutoVacuumLauncherProcess()
&& !IsAutoVacuumWorkerProcess() && MyPMChildSlot > 0) && MyPMChildSlot > 0)
MarkPostmasterChildInactive(); MarkPostmasterChildInactive();
/* wake autovac launcher if needed -- see comments in FreeWorkerInfo */ /* wake autovac launcher if needed -- see comments in FreeWorkerInfo */
......
...@@ -957,7 +957,8 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, ...@@ -957,7 +957,8 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
* protect ourselves from normal clients who might be trying to connect to * protect ourselves from normal clients who might be trying to connect to
* the system while we startup. * the system while we startup.
*/ */
if ((Gp_role == GP_ROLE_UTILITY) && (Gp_session_role != GP_ROLE_UTILITY)) if ((Gp_role == GP_ROLE_UTILITY) && (Gp_session_role != GP_ROLE_UTILITY) &&
!IsAutoVacuumWorkerProcess())
{ {
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_CANNOT_CONNECT_NOW), (errcode(ERRCODE_CANNOT_CONNECT_NOW),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册