aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-07-01 02:09:34 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-07-01 02:09:34 +0000
commit5b965bf08bfb4aa8928bafaed20e42b89de02a5c (patch)
tree5e8098d46cda226eb35aa38229d97a2258674b24
parent92d1cc89738e70a01e7c095f2315e80b9c4ef900 (diff)
downloadpostgresql-5b965bf08bfb4aa8928bafaed20e42b89de02a5c.tar.gz
postgresql-5b965bf08bfb4aa8928bafaed20e42b89de02a5c.zip
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.
-rw-r--r--src/backend/catalog/namespace.c28
-rw-r--r--src/backend/postmaster/autovacuum.c142
-rw-r--r--src/backend/storage/ipc/sinvaladt.c29
-rw-r--r--src/include/catalog/namespace.h3
-rw-r--r--src/include/storage/sinvaladt.h3
5 files changed, 136 insertions, 69 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 5bacb412a97..dfaea41cfe4 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -2210,6 +2210,32 @@ isOtherTempNamespace(Oid 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,
* which must already be assigned. (This is only used when creating a toast
* table for a temp table, so we must have already done InitTempTableNamespace)
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 7ac0bae1c58..9ed34eed6f8 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -55,7 +55,7 @@
*
*
* 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/transam.h"
#include "access/xact.h"
+#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_autovacuum.h"
@@ -90,7 +91,7 @@
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
-#include "storage/sinval.h"
+#include "storage/sinvaladt.h"
#include "tcop/tcopprot.h"
#include "utils/flatfiles.h"
#include "utils/fmgroids.h"
@@ -275,10 +276,6 @@ static void autovac_balance_cost(void);
static void do_autovacuum(void);
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 void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
Form_pg_class classForm,
@@ -1912,19 +1909,16 @@ do_autovacuum(void)
PgStat_StatTabEntry *tabentry;
HeapTuple avTup;
Oid relid;
+ bool dovacuum;
+ bool doanalyze;
+ bool wraparound;
+ int backendID;
/* Consider only regular and toast tables. */
if (classForm->relkind != RELKIND_RELATION &&
classForm->relkind != RELKIND_TOASTVALUE)
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);
/* 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,
shared, dbentry);
- relation_check_autovac(relid, classForm, avForm, tabentry,
- &table_oids, &table_toast_list, &toast_oids);
+ /* Check if it needs vacuum or analyze */
+ 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))
heap_freetuple(avTup);
@@ -2232,56 +2294,6 @@ get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared,
}
/*
- * 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
*
* Recheck whether a plain table still needs vacuum or analyze; be it because
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index e414e4a5071..8aa4ec836b5 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -358,6 +358,33 @@ CleanupInvalidationState(int status, Datum arg)
}
/*
+ * 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
* Add new invalidation message(s) to the buffer.
*/
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 7c9ad7c7359..b161b7108b6 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 isAnyTempNamespace(Oid namespaceId);
extern bool isOtherTempNamespace(Oid namespaceId);
+extern int GetTempNamespaceBackendId(Oid namespaceId);
extern Oid GetTempToastNamespace(void);
extern void ResetTempTableNamespace(void);
diff --git a/src/include/storage/sinvaladt.h b/src/include/storage/sinvaladt.h
index 1748f8821b4..abf243601c7 100644
--- a/src/include/storage/sinvaladt.h
+++ b/src/include/storage/sinvaladt.h
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 void CreateSharedInvalidationState(void);
extern void SharedInvalBackendInit(void);
+extern bool BackendIdIsActive(int backendID);
extern void SIInsertDataEntries(const SharedInvalidationMessage *data, int n);
extern int SIGetDataEntries(SharedInvalidationMessage *data, int datasize);