mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
Teach autovacuum how to determine whether a temp table belongs to a crashed
backend. If so, send a LOG message to the postmaster log, and if the table is beyond the vacuum-for-wraparound horizon, forcibly drop it. Per recent discussions. Perhaps we ought to back-patch this, but it probably needs to age a bit in HEAD first.
This commit is contained in:
parent
92d1cc8973
commit
5b965bf08b
@ -13,7 +13,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.106 2008/06/19 00:46:04 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.107 2008/07/01 02:09:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2209,6 +2209,32 @@ isOtherTempNamespace(Oid namespaceId)
|
|||||||
return isAnyTempNamespace(namespaceId);
|
return isAnyTempNamespace(namespaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetTempNamespaceBackendId - if the given namespace is a temporary-table
|
||||||
|
* namespace (either my own, or another backend's), return the BackendId
|
||||||
|
* that owns it. Temporary-toast-table namespaces are included, too.
|
||||||
|
* If it isn't a temp namespace, return -1.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
GetTempNamespaceBackendId(Oid namespaceId)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
char *nspname;
|
||||||
|
|
||||||
|
/* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
|
||||||
|
nspname = get_namespace_name(namespaceId);
|
||||||
|
if (!nspname)
|
||||||
|
return -1; /* no such namespace? */
|
||||||
|
if (strncmp(nspname, "pg_temp_", 8) == 0)
|
||||||
|
result = atoi(nspname + 8);
|
||||||
|
else if (strncmp(nspname, "pg_toast_temp_", 14) == 0)
|
||||||
|
result = atoi(nspname + 14);
|
||||||
|
else
|
||||||
|
result = -1;
|
||||||
|
pfree(nspname);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
|
* GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
|
||||||
* which must already be assigned. (This is only used when creating a toast
|
* which must already be assigned. (This is only used when creating a toast
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.79 2008/06/05 15:47:32 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.80 2008/07/01 02:09:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -71,6 +71,7 @@
|
|||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/transam.h"
|
#include "access/transam.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
|
#include "catalog/dependency.h"
|
||||||
#include "catalog/indexing.h"
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "catalog/pg_autovacuum.h"
|
#include "catalog/pg_autovacuum.h"
|
||||||
@ -90,7 +91,7 @@
|
|||||||
#include "storage/pmsignal.h"
|
#include "storage/pmsignal.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
#include "storage/sinval.h"
|
#include "storage/sinvaladt.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
#include "utils/flatfiles.h"
|
#include "utils/flatfiles.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
@ -275,10 +276,6 @@ static void autovac_balance_cost(void);
|
|||||||
static void do_autovacuum(void);
|
static void do_autovacuum(void);
|
||||||
static void FreeWorkerInfo(int code, Datum arg);
|
static void FreeWorkerInfo(int code, Datum arg);
|
||||||
|
|
||||||
static void relation_check_autovac(Oid relid, Form_pg_class classForm,
|
|
||||||
Form_pg_autovacuum avForm, PgStat_StatTabEntry *tabentry,
|
|
||||||
List **table_oids, List **table_toast_list,
|
|
||||||
List **toast_oids);
|
|
||||||
static autovac_table *table_recheck_autovac(Oid relid);
|
static autovac_table *table_recheck_autovac(Oid relid);
|
||||||
static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
|
static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
|
||||||
Form_pg_class classForm,
|
Form_pg_class classForm,
|
||||||
@ -1912,19 +1909,16 @@ do_autovacuum(void)
|
|||||||
PgStat_StatTabEntry *tabentry;
|
PgStat_StatTabEntry *tabentry;
|
||||||
HeapTuple avTup;
|
HeapTuple avTup;
|
||||||
Oid relid;
|
Oid relid;
|
||||||
|
bool dovacuum;
|
||||||
|
bool doanalyze;
|
||||||
|
bool wraparound;
|
||||||
|
int backendID;
|
||||||
|
|
||||||
/* Consider only regular and toast tables. */
|
/* Consider only regular and toast tables. */
|
||||||
if (classForm->relkind != RELKIND_RELATION &&
|
if (classForm->relkind != RELKIND_RELATION &&
|
||||||
classForm->relkind != RELKIND_TOASTVALUE)
|
classForm->relkind != RELKIND_TOASTVALUE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip temp tables (i.e. those in temp namespaces). We cannot safely
|
|
||||||
* process other backends' temp tables.
|
|
||||||
*/
|
|
||||||
if (isAnyTempNamespace(classForm->relnamespace))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
relid = HeapTupleGetOid(tuple);
|
relid = HeapTupleGetOid(tuple);
|
||||||
|
|
||||||
/* Fetch the pg_autovacuum tuple for the relation, if any */
|
/* Fetch the pg_autovacuum tuple for the relation, if any */
|
||||||
@ -1936,8 +1930,76 @@ do_autovacuum(void)
|
|||||||
tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
|
tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
|
||||||
shared, dbentry);
|
shared, dbentry);
|
||||||
|
|
||||||
relation_check_autovac(relid, classForm, avForm, tabentry,
|
/* Check if it needs vacuum or analyze */
|
||||||
&table_oids, &table_toast_list, &toast_oids);
|
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
|
||||||
|
&dovacuum, &doanalyze, &wraparound);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if it is a temp table (presumably, of some other backend's).
|
||||||
|
* We cannot safely process other backends' temp tables.
|
||||||
|
*/
|
||||||
|
backendID = GetTempNamespaceBackendId(classForm->relnamespace);
|
||||||
|
|
||||||
|
if (backendID > 0)
|
||||||
|
{
|
||||||
|
/* We just ignore it if the owning backend is still active */
|
||||||
|
if (backendID == MyBackendId || !BackendIdIsActive(backendID))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We found an orphan temp table (which was probably left
|
||||||
|
* behind by a crashed backend). If it's so old as to need
|
||||||
|
* vacuum for wraparound, forcibly drop it. Otherwise just
|
||||||
|
* log a complaint.
|
||||||
|
*/
|
||||||
|
if (wraparound && classForm->relkind == RELKIND_RELATION)
|
||||||
|
{
|
||||||
|
ObjectAddress object;
|
||||||
|
|
||||||
|
ereport(LOG,
|
||||||
|
(errmsg("autovacuum: dropping orphan temp table \"%s\".\"%s\" in database \"%s\"",
|
||||||
|
get_namespace_name(classForm->relnamespace),
|
||||||
|
NameStr(classForm->relname),
|
||||||
|
get_database_name(MyDatabaseId))));
|
||||||
|
object.classId = RelationRelationId;
|
||||||
|
object.objectId = relid;
|
||||||
|
object.objectSubId = 0;
|
||||||
|
performDeletion(&object, DROP_CASCADE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ereport(LOG,
|
||||||
|
(errmsg("autovacuum: found orphan temp table \"%s\".\"%s\" in database \"%s\"",
|
||||||
|
get_namespace_name(classForm->relnamespace),
|
||||||
|
NameStr(classForm->relname),
|
||||||
|
get_database_name(MyDatabaseId))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (classForm->relkind == RELKIND_RELATION)
|
||||||
|
{
|
||||||
|
/* Plain relations that need work are added to table_oids */
|
||||||
|
if (dovacuum || doanalyze)
|
||||||
|
table_oids = lappend_oid(table_oids, relid);
|
||||||
|
else if (OidIsValid(classForm->reltoastrelid))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If it doesn't appear to need vacuuming, but it has a toast
|
||||||
|
* table, remember the association to revisit below.
|
||||||
|
*/
|
||||||
|
av_relation *rel = palloc(sizeof(av_relation));
|
||||||
|
|
||||||
|
rel->ar_relid = relid;
|
||||||
|
rel->ar_toastrelid = classForm->reltoastrelid;
|
||||||
|
|
||||||
|
table_toast_list = lappend(table_toast_list, rel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TOAST relations that need vacuum are added to toast_oids */
|
||||||
|
if (dovacuum)
|
||||||
|
toast_oids = lappend_oid(toast_oids, relid);
|
||||||
|
}
|
||||||
|
|
||||||
if (HeapTupleIsValid(avTup))
|
if (HeapTupleIsValid(avTup))
|
||||||
heap_freetuple(avTup);
|
heap_freetuple(avTup);
|
||||||
@ -2231,56 +2293,6 @@ get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared,
|
|||||||
return tabentry;
|
return tabentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* relation_check_autovac
|
|
||||||
*
|
|
||||||
* For a given relation (either a plain table or TOAST table), check whether it
|
|
||||||
* needs vacuum or analyze.
|
|
||||||
*
|
|
||||||
* Plain tables that need either are added to the table_list. TOAST tables
|
|
||||||
* that need vacuum are added to toast_list. Plain tables that don't need
|
|
||||||
* either but which have a TOAST table are added, as a struct, to
|
|
||||||
* table_toast_list. The latter is to allow appending the OIDs of the plain
|
|
||||||
* tables whose TOAST table needs vacuuming into the plain tables list, which
|
|
||||||
* allows us to substantially reduce the number of "rechecks" that we need to
|
|
||||||
* do later on.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
relation_check_autovac(Oid relid, Form_pg_class classForm,
|
|
||||||
Form_pg_autovacuum avForm, PgStat_StatTabEntry *tabentry,
|
|
||||||
List **table_oids, List **table_toast_list,
|
|
||||||
List **toast_oids)
|
|
||||||
{
|
|
||||||
bool dovacuum;
|
|
||||||
bool doanalyze;
|
|
||||||
bool dummy;
|
|
||||||
|
|
||||||
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
|
|
||||||
&dovacuum, &doanalyze, &dummy);
|
|
||||||
|
|
||||||
if (classForm->relkind == RELKIND_TOASTVALUE)
|
|
||||||
{
|
|
||||||
if (dovacuum)
|
|
||||||
*toast_oids = lappend_oid(*toast_oids, relid);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert(classForm->relkind == RELKIND_RELATION);
|
|
||||||
|
|
||||||
if (dovacuum || doanalyze)
|
|
||||||
*table_oids = lappend_oid(*table_oids, relid);
|
|
||||||
else if (OidIsValid(classForm->reltoastrelid))
|
|
||||||
{
|
|
||||||
av_relation *rel = palloc(sizeof(av_relation));
|
|
||||||
|
|
||||||
rel->ar_relid = relid;
|
|
||||||
rel->ar_toastrelid = classForm->reltoastrelid;
|
|
||||||
|
|
||||||
*table_toast_list = lappend(*table_toast_list, rel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* table_recheck_autovac
|
* table_recheck_autovac
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.72 2008/06/20 00:24:53 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.73 2008/07/01 02:09:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -357,6 +357,33 @@ CleanupInvalidationState(int status, Datum arg)
|
|||||||
LWLockRelease(SInvalWriteLock);
|
LWLockRelease(SInvalWriteLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BackendIdIsActive
|
||||||
|
* Test if the given backend ID is currently assigned to a process.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
BackendIdIsActive(int backendID)
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
SISeg *segP = shmInvalBuffer;
|
||||||
|
|
||||||
|
/* Need to lock out additions/removals of backends */
|
||||||
|
LWLockAcquire(SInvalWriteLock, LW_SHARED);
|
||||||
|
|
||||||
|
if (backendID > 0 && backendID <= segP->lastBackend)
|
||||||
|
{
|
||||||
|
ProcState *stateP = &segP->procState[backendID - 1];
|
||||||
|
|
||||||
|
result = (stateP->procPid != 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = false;
|
||||||
|
|
||||||
|
LWLockRelease(SInvalWriteLock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIInsertDataEntries
|
* SIInsertDataEntries
|
||||||
* Add new invalidation message(s) to the buffer.
|
* Add new invalidation message(s) to the buffer.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.53 2008/01/01 19:45:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.54 2008/07/01 02:09:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -95,6 +95,7 @@ extern bool isTempToastNamespace(Oid namespaceId);
|
|||||||
extern bool isTempOrToastNamespace(Oid namespaceId);
|
extern bool isTempOrToastNamespace(Oid namespaceId);
|
||||||
extern bool isAnyTempNamespace(Oid namespaceId);
|
extern bool isAnyTempNamespace(Oid namespaceId);
|
||||||
extern bool isOtherTempNamespace(Oid namespaceId);
|
extern bool isOtherTempNamespace(Oid namespaceId);
|
||||||
|
extern int GetTempNamespaceBackendId(Oid namespaceId);
|
||||||
extern Oid GetTempToastNamespace(void);
|
extern Oid GetTempToastNamespace(void);
|
||||||
extern void ResetTempTableNamespace(void);
|
extern void ResetTempTableNamespace(void);
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/storage/sinvaladt.h,v 1.48 2008/06/19 21:32:56 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/storage/sinvaladt.h,v 1.49 2008/07/01 02:09:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -30,6 +30,7 @@
|
|||||||
extern Size SInvalShmemSize(void);
|
extern Size SInvalShmemSize(void);
|
||||||
extern void CreateSharedInvalidationState(void);
|
extern void CreateSharedInvalidationState(void);
|
||||||
extern void SharedInvalBackendInit(void);
|
extern void SharedInvalBackendInit(void);
|
||||||
|
extern bool BackendIdIsActive(int backendID);
|
||||||
|
|
||||||
extern void SIInsertDataEntries(const SharedInvalidationMessage *data, int n);
|
extern void SIInsertDataEntries(const SharedInvalidationMessage *data, int n);
|
||||||
extern int SIGetDataEntries(SharedInvalidationMessage *data, int datasize);
|
extern int SIGetDataEntries(SharedInvalidationMessage *data, int datasize);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user