aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/relcache.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-12-17 20:15:39 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2012-12-17 20:15:39 -0500
commitfe2ef429a19b25903438b882ce16617a6e700d0f (patch)
treebed25c0944bd41575589fbd7573cc667d2196ac8 /src/backend/utils/cache/relcache.c
parentd93c01f16854e655dd69b614747d3432a39f0385 (diff)
downloadpostgresql-fe2ef429a19b25903438b882ce16617a6e700d0f.tar.gz
postgresql-fe2ef429a19b25903438b882ce16617a6e700d0f.zip
Fix failure to ignore leftover temp tables after a server crash.
During crash recovery, we remove disk files belonging to temporary tables, but the system catalog entries for such tables are intentionally not cleaned up right away. Instead, the first backend that uses a temp schema is expected to clean out any leftover objects therein. This approach requires that we be careful to ignore leftover temp tables (since any actual access attempt would fail), *even if their BackendId matches our session*, if we have not yet established use of the session's corresponding temp schema. That worked fine in the past, but was broken by commit debcec7dc31a992703911a9953e299c8d730c778 which incorrectly removed the rd_islocaltemp relcache flag. Put it back, and undo various changes that substituted tests like "rel->rd_backend == MyBackendId" for use of a state-aware flag. Per trouble report from Heikki Linnakangas. Back-patch to 9.1 where the erroneous change was made. In the back branches, be careful to add rd_islocaltemp in a spot in the struct that was alignment padding before, so as not to break existing add-on code.
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r--src/backend/utils/cache/relcache.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index a64d739cebc..bd7f567f1e9 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -852,20 +852,33 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
relation->rd_backend = InvalidBackendId;
+ relation->rd_islocaltemp = false;
break;
case RELPERSISTENCE_TEMP:
if (isTempOrToastNamespace(relation->rd_rel->relnamespace))
+ {
relation->rd_backend = MyBackendId;
+ relation->rd_islocaltemp = true;
+ }
else
{
/*
- * If it's a local temp table, but not one of ours, we have to
- * use the slow, grotty method to figure out the owning
- * backend.
+ * If it's a temp table, but not one of ours, we have to use
+ * the slow, grotty method to figure out the owning backend.
+ *
+ * Note: it's possible that rd_backend gets set to MyBackendId
+ * here, in case we are looking at a pg_class entry left over
+ * from a crashed backend that coincidentally had the same
+ * BackendId we're using. We should *not* consider such a
+ * table to be "ours"; this is why we need the separate
+ * rd_islocaltemp flag. The pg_class entry will get flushed
+ * if/when we clean out the corresponding temp table namespace
+ * in preparation for using it.
*/
relation->rd_backend =
GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
Assert(relation->rd_backend != InvalidBackendId);
+ relation->rd_islocaltemp = false;
}
break;
default:
@@ -1386,6 +1399,7 @@ formrdesc(const char *relationName, Oid relationReltype,
relation->rd_createSubid = InvalidSubTransactionId;
relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
relation->rd_backend = InvalidBackendId;
+ relation->rd_islocaltemp = false;
/*
* initialize relation tuple form
@@ -2535,16 +2549,19 @@ RelationBuildLocalRelation(const char *relname,
/* needed when bootstrapping: */
rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
- /* set up persistence; rd_backend is a function of persistence type */
+ /* set up persistence and relcache fields dependent on it */
rel->rd_rel->relpersistence = relpersistence;
switch (relpersistence)
{
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
rel->rd_backend = InvalidBackendId;
+ rel->rd_islocaltemp = false;
break;
case RELPERSISTENCE_TEMP:
+ Assert(isTempOrToastNamespace(relnamespace));
rel->rd_backend = MyBackendId;
+ rel->rd_islocaltemp = true;
break;
default:
elog(ERROR, "invalid relpersistence: %c", relpersistence);