Skip to content

Commit 5b965bf

Browse files
committed
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.
1 parent 92d1cc8 commit 5b965bf

File tree

5 files changed

+136
-69
lines changed

5 files changed

+136
-69
lines changed

src/backend/catalog/namespace.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.106 2008/06/19 00:46:04 alvherre Exp $
16+
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.107 2008/07/01 02:09:34 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -2209,6 +2209,32 @@ isOtherTempNamespace(Oid namespaceId)
22092209
return isAnyTempNamespace(namespaceId);
22102210
}
22112211

2212+
/*
2213+
* GetTempNamespaceBackendId - if the given namespace is a temporary-table
2214+
* namespace (either my own, or another backend's), return the BackendId
2215+
* that owns it. Temporary-toast-table namespaces are included, too.
2216+
* If it isn't a temp namespace, return -1.
2217+
*/
2218+
int
2219+
GetTempNamespaceBackendId(Oid namespaceId)
2220+
{
2221+
int result;
2222+
char *nspname;
2223+
2224+
/* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
2225+
nspname = get_namespace_name(namespaceId);
2226+
if (!nspname)
2227+
return -1; /* no such namespace? */
2228+
if (strncmp(nspname, "pg_temp_", 8) == 0)
2229+
result = atoi(nspname + 8);
2230+
else if (strncmp(nspname, "pg_toast_temp_", 14) == 0)
2231+
result = atoi(nspname + 14);
2232+
else
2233+
result = -1;
2234+
pfree(nspname);
2235+
return result;
2236+
}
2237+
22122238
/*
22132239
* GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
22142240
* which must already be assigned. (This is only used when creating a toast

src/backend/postmaster/autovacuum.c

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
*
5656
*
5757
* IDENTIFICATION
58-
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.79 2008/06/05 15:47:32 alvherre Exp $
58+
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.80 2008/07/01 02:09:34 tgl Exp $
5959
*
6060
*-------------------------------------------------------------------------
6161
*/
@@ -71,6 +71,7 @@
7171
#include "access/heapam.h"
7272
#include "access/transam.h"
7373
#include "access/xact.h"
74+
#include "catalog/dependency.h"
7475
#include "catalog/indexing.h"
7576
#include "catalog/namespace.h"
7677
#include "catalog/pg_autovacuum.h"
@@ -90,7 +91,7 @@
9091
#include "storage/pmsignal.h"
9192
#include "storage/proc.h"
9293
#include "storage/procarray.h"
93-
#include "storage/sinval.h"
94+
#include "storage/sinvaladt.h"
9495
#include "tcop/tcopprot.h"
9596
#include "utils/flatfiles.h"
9697
#include "utils/fmgroids.h"
@@ -275,10 +276,6 @@ static void autovac_balance_cost(void);
275276
static void do_autovacuum(void);
276277
static void FreeWorkerInfo(int code, Datum arg);
277278

278-
static void relation_check_autovac(Oid relid, Form_pg_class classForm,
279-
Form_pg_autovacuum avForm, PgStat_StatTabEntry *tabentry,
280-
List **table_oids, List **table_toast_list,
281-
List **toast_oids);
282279
static autovac_table *table_recheck_autovac(Oid relid);
283280
static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
284281
Form_pg_class classForm,
@@ -1912,19 +1909,16 @@ do_autovacuum(void)
19121909
PgStat_StatTabEntry *tabentry;
19131910
HeapTuple avTup;
19141911
Oid relid;
1912+
bool dovacuum;
1913+
bool doanalyze;
1914+
bool wraparound;
1915+
int backendID;
19151916

19161917
/* Consider only regular and toast tables. */
19171918
if (classForm->relkind != RELKIND_RELATION &&
19181919
classForm->relkind != RELKIND_TOASTVALUE)
19191920
continue;
19201921

1921-
/*
1922-
* Skip temp tables (i.e. those in temp namespaces). We cannot safely
1923-
* process other backends' temp tables.
1924-
*/
1925-
if (isAnyTempNamespace(classForm->relnamespace))
1926-
continue;
1927-
19281922
relid = HeapTupleGetOid(tuple);
19291923

19301924
/* Fetch the pg_autovacuum tuple for the relation, if any */
@@ -1936,8 +1930,76 @@ do_autovacuum(void)
19361930
tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
19371931
shared, dbentry);
19381932

1939-
relation_check_autovac(relid, classForm, avForm, tabentry,
1940-
&table_oids, &table_toast_list, &toast_oids);
1933+
/* Check if it needs vacuum or analyze */
1934+
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
1935+
&dovacuum, &doanalyze, &wraparound);
1936+
1937+
/*
1938+
* Check if it is a temp table (presumably, of some other backend's).
1939+
* We cannot safely process other backends' temp tables.
1940+
*/
1941+
backendID = GetTempNamespaceBackendId(classForm->relnamespace);
1942+
1943+
if (backendID > 0)
1944+
{
1945+
/* We just ignore it if the owning backend is still active */
1946+
if (backendID == MyBackendId || !BackendIdIsActive(backendID))
1947+
{
1948+
/*
1949+
* We found an orphan temp table (which was probably left
1950+
* behind by a crashed backend). If it's so old as to need
1951+
* vacuum for wraparound, forcibly drop it. Otherwise just
1952+
* log a complaint.
1953+
*/
1954+
if (wraparound && classForm->relkind == RELKIND_RELATION)
1955+
{
1956+
ObjectAddress object;
1957+
1958+
ereport(LOG,
1959+
(errmsg("autovacuum: dropping orphan temp table \"%s\".\"%s\" in database \"%s\"",
1960+
get_namespace_name(classForm->relnamespace),
1961+
NameStr(classForm->relname),
1962+
get_database_name(MyDatabaseId))));
1963+
object.classId = RelationRelationId;
1964+
object.objectId = relid;
1965+
object.objectSubId = 0;
1966+
performDeletion(&object, DROP_CASCADE);
1967+
}
1968+
else
1969+
{
1970+
ereport(LOG,
1971+
(errmsg("autovacuum: found orphan temp table \"%s\".\"%s\" in database \"%s\"",
1972+
get_namespace_name(classForm->relnamespace),
1973+
NameStr(classForm->relname),
1974+
get_database_name(MyDatabaseId))));
1975+
}
1976+
}
1977+
}
1978+
else if (classForm->relkind == RELKIND_RELATION)
1979+
{
1980+
/* Plain relations that need work are added to table_oids */
1981+
if (dovacuum || doanalyze)
1982+
table_oids = lappend_oid(table_oids, relid);
1983+
else if (OidIsValid(classForm->reltoastrelid))
1984+
{
1985+
/*
1986+
* If it doesn't appear to need vacuuming, but it has a toast
1987+
* table, remember the association to revisit below.
1988+
*/
1989+
av_relation *rel = palloc(sizeof(av_relation));
1990+
1991+
rel->ar_relid = relid;
1992+
rel->ar_toastrelid = classForm->reltoastrelid;
1993+
1994+
table_toast_list = lappend(table_toast_list, rel);
1995+
}
1996+
}
1997+
else
1998+
{
1999+
/* TOAST relations that need vacuum are added to toast_oids */
2000+
if (dovacuum)
2001+
toast_oids = lappend_oid(toast_oids, relid);
2002+
}
19412003

19422004
if (HeapTupleIsValid(avTup))
19432005
heap_freetuple(avTup);
@@ -2231,56 +2293,6 @@ get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared,
22312293
return tabentry;
22322294
}
22332295

2234-
/*
2235-
* relation_check_autovac
2236-
*
2237-
* For a given relation (either a plain table or TOAST table), check whether it
2238-
* needs vacuum or analyze.
2239-
*
2240-
* Plain tables that need either are added to the table_list. TOAST tables
2241-
* that need vacuum are added to toast_list. Plain tables that don't need
2242-
* either but which have a TOAST table are added, as a struct, to
2243-
* table_toast_list. The latter is to allow appending the OIDs of the plain
2244-
* tables whose TOAST table needs vacuuming into the plain tables list, which
2245-
* allows us to substantially reduce the number of "rechecks" that we need to
2246-
* do later on.
2247-
*/
2248-
static void
2249-
relation_check_autovac(Oid relid, Form_pg_class classForm,
2250-
Form_pg_autovacuum avForm, PgStat_StatTabEntry *tabentry,
2251-
List **table_oids, List **table_toast_list,
2252-
List **toast_oids)
2253-
{
2254-
bool dovacuum;
2255-
bool doanalyze;
2256-
bool dummy;
2257-
2258-
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
2259-
&dovacuum, &doanalyze, &dummy);
2260-
2261-
if (classForm->relkind == RELKIND_TOASTVALUE)
2262-
{
2263-
if (dovacuum)
2264-
*toast_oids = lappend_oid(*toast_oids, relid);
2265-
}
2266-
else
2267-
{
2268-
Assert(classForm->relkind == RELKIND_RELATION);
2269-
2270-
if (dovacuum || doanalyze)
2271-
*table_oids = lappend_oid(*table_oids, relid);
2272-
else if (OidIsValid(classForm->reltoastrelid))
2273-
{
2274-
av_relation *rel = palloc(sizeof(av_relation));
2275-
2276-
rel->ar_relid = relid;
2277-
rel->ar_toastrelid = classForm->reltoastrelid;
2278-
2279-
*table_toast_list = lappend(*table_toast_list, rel);
2280-
}
2281-
}
2282-
}
2283-
22842296
/*
22852297
* table_recheck_autovac
22862298
*

src/backend/storage/ipc/sinvaladt.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.72 2008/06/20 00:24:53 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.73 2008/07/01 02:09:34 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -357,6 +357,33 @@ CleanupInvalidationState(int status, Datum arg)
357357
LWLockRelease(SInvalWriteLock);
358358
}
359359

360+
/*
361+
* BackendIdIsActive
362+
* Test if the given backend ID is currently assigned to a process.
363+
*/
364+
bool
365+
BackendIdIsActive(int backendID)
366+
{
367+
bool result;
368+
SISeg *segP = shmInvalBuffer;
369+
370+
/* Need to lock out additions/removals of backends */
371+
LWLockAcquire(SInvalWriteLock, LW_SHARED);
372+
373+
if (backendID > 0 && backendID <= segP->lastBackend)
374+
{
375+
ProcState *stateP = &segP->procState[backendID - 1];
376+
377+
result = (stateP->procPid != 0);
378+
}
379+
else
380+
result = false;
381+
382+
LWLockRelease(SInvalWriteLock);
383+
384+
return result;
385+
}
386+
360387
/*
361388
* SIInsertDataEntries
362389
* Add new invalidation message(s) to the buffer.

src/include/catalog/namespace.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.53 2008/01/01 19:45:56 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.54 2008/07/01 02:09:34 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -95,6 +95,7 @@ extern bool isTempToastNamespace(Oid namespaceId);
9595
extern bool isTempOrToastNamespace(Oid namespaceId);
9696
extern bool isAnyTempNamespace(Oid namespaceId);
9797
extern bool isOtherTempNamespace(Oid namespaceId);
98+
extern int GetTempNamespaceBackendId(Oid namespaceId);
9899
extern Oid GetTempToastNamespace(void);
99100
extern void ResetTempTableNamespace(void);
100101

src/include/storage/sinvaladt.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
1616
* Portions Copyright (c) 1994, Regents of the University of California
1717
*
18-
* $PostgreSQL: pgsql/src/include/storage/sinvaladt.h,v 1.48 2008/06/19 21:32:56 tgl Exp $
18+
* $PostgreSQL: pgsql/src/include/storage/sinvaladt.h,v 1.49 2008/07/01 02:09:34 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -30,6 +30,7 @@
3030
extern Size SInvalShmemSize(void);
3131
extern void CreateSharedInvalidationState(void);
3232
extern void SharedInvalBackendInit(void);
33+
extern bool BackendIdIsActive(int backendID);
3334

3435
extern void SIInsertDataEntries(const SharedInvalidationMessage *data, int n);
3536
extern int SIGetDataEntries(SharedInvalidationMessage *data, int datasize);

0 commit comments

Comments
 (0)