]> granicus.if.org Git - postgresql/commitdiff
Teach autovacuum how to determine whether a temp table belongs to a crashed
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 1 Jul 2008 02:09:34 +0000 (02:09 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 1 Jul 2008 02:09:34 +0000 (02:09 +0000)
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.

src/backend/catalog/namespace.c
src/backend/postmaster/autovacuum.c
src/backend/storage/ipc/sinvaladt.c
src/include/catalog/namespace.h
src/include/storage/sinvaladt.h

index 5bacb412a971b1c2230e83d7f4f0a39938263fc8..dfaea41cfe4846e213d564d14bf14e84b0c0ce2c 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -2209,6 +2209,32 @@ isOtherTempNamespace(Oid 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,
  * which must already be assigned.     (This is only used when creating a toast
index 7ac0bae1c588975c93893fb703b16509d8a8d751..9ed34eed6f824e6012b3f77be9c7f0ae0cffe4cd 100644 (file)
@@ -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);
@@ -2231,56 +2293,6 @@ get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared,
        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
  *
index e414e4a507105aef95fdde4e830b915b60490aa9..8aa4ec836b5f1920ab4cbddca34f746b79bde1ff 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -357,6 +357,33 @@ CleanupInvalidationState(int status, Datum arg)
        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
  *             Add new invalidation message(s) to the buffer.
index 7c9ad7c73591e74188c59db4493a0edfcde5c7c6..b161b7108b6452f2566c5a61cb7cbb6337bf4fa4 100644 (file)
@@ -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);
 
index 1748f8821b42d64233eafd9c182af63ed4e35ba3..abf243601c7a57f7be73a00849106b1396d01f5b 100644 (file)
@@ -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);