aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/resowner/resowner.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2009-12-03 11:03:29 +0000
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2009-12-03 11:03:29 +0000
commitab3148b7128e1fe67d8badc9327fd958d2a14c90 (patch)
tree61e91e6cdedb6be7878b386b6a8da4ceef74b507 /src/backend/utils/resowner/resowner.c
parentdc588058a033ee9a6f9f84f30cef13b2aafee0bc (diff)
downloadpostgresql-ab3148b7128e1fe67d8badc9327fd958d2a14c90.tar.gz
postgresql-ab3148b7128e1fe67d8badc9327fd958d2a14c90.zip
Fix bug in temporary file management with subtransactions. A cursor opened
in a subtransaction stays open even if the subtransaction is aborted, so any temporary files related to it must stay alive as well. With the patch, we use ResourceOwners to track open temporary files and don't automatically close them at subtransaction end (though in the normal case temporary files are registered with the subtransaction resource owner and will therefore be closed). At end of top transaction, we still check that there's no temporary files marked as close-at-end-of-transaction open, but that's now just a debugging cross-check as the resource owner cleanup should've closed them already.
Diffstat (limited to 'src/backend/utils/resowner/resowner.c')
-rw-r--r--src/backend/utils/resowner/resowner.c103
1 files changed, 102 insertions, 1 deletions
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c
index 4ef47ca5601..1f8658d0104 100644
--- a/src/backend/utils/resowner/resowner.c
+++ b/src/backend/utils/resowner/resowner.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.32 2009/06/11 14:49:06 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.33 2009/12/03 11:03:29 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -72,6 +72,11 @@ typedef struct ResourceOwnerData
int nsnapshots; /* number of owned snapshot references */
Snapshot *snapshots; /* dynamically allocated array */
int maxsnapshots; /* currently allocated array size */
+
+ /* We have built-in support for remembering open temporary files */
+ int nfiles; /* number of owned temporary files */
+ File *files; /* dynamically allocated array */
+ int maxfiles; /* currently allocated array size */
} ResourceOwnerData;
@@ -105,6 +110,7 @@ static void PrintRelCacheLeakWarning(Relation rel);
static void PrintPlanCacheLeakWarning(CachedPlan *plan);
static void PrintTupleDescLeakWarning(TupleDesc tupdesc);
static void PrintSnapshotLeakWarning(Snapshot snapshot);
+static void PrintFileLeakWarning(File file);
/*****************************************************************************
@@ -316,6 +322,14 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
UnregisterSnapshot(owner->snapshots[owner->nsnapshots - 1]);
}
+ /* Ditto for temporary files */
+ while (owner->nfiles > 0)
+ {
+ if (isCommit)
+ PrintFileLeakWarning(owner->files[owner->nfiles - 1]);
+ FileClose(owner->files[owner->nfiles - 1]);
+ }
+
/* Clean up index scans too */
ReleaseResources_hash();
}
@@ -347,6 +361,7 @@ ResourceOwnerDelete(ResourceOwner owner)
Assert(owner->nplanrefs == 0);
Assert(owner->ntupdescs == 0);
Assert(owner->nsnapshots == 0);
+ Assert(owner->nfiles == 0);
/*
* Delete children. The recursive call will delink the child from me, so
@@ -377,6 +392,8 @@ ResourceOwnerDelete(ResourceOwner owner)
pfree(owner->tupdescs);
if (owner->snapshots)
pfree(owner->snapshots);
+ if (owner->files)
+ pfree(owner->files);
pfree(owner);
}
@@ -1035,3 +1052,87 @@ PrintSnapshotLeakWarning(Snapshot snapshot)
"Snapshot reference leak: Snapshot %p still referenced",
snapshot);
}
+
+
+/*
+ * Make sure there is room for at least one more entry in a ResourceOwner's
+ * files reference array.
+ *
+ * This is separate from actually inserting an entry because if we run out
+ * of memory, it's critical to do so *before* acquiring the resource.
+ */
+void
+ResourceOwnerEnlargeFiles(ResourceOwner owner)
+{
+ int newmax;
+
+ if (owner->nfiles < owner->maxfiles)
+ return; /* nothing to do */
+
+ if (owner->files == NULL)
+ {
+ newmax = 16;
+ owner->files = (File *)
+ MemoryContextAlloc(TopMemoryContext, newmax * sizeof(File));
+ owner->maxfiles = newmax;
+ }
+ else
+ {
+ newmax = owner->maxfiles * 2;
+ owner->files = (File *)
+ repalloc(owner->files, newmax * sizeof(File));
+ owner->maxfiles = newmax;
+ }
+}
+
+/*
+ * Remember that a temporary file is owned by a ResourceOwner
+ *
+ * Caller must have previously done ResourceOwnerEnlargeFiles()
+ */
+void
+ResourceOwnerRememberFile(ResourceOwner owner, File file)
+{
+ Assert(owner->nfiles < owner->maxfiles);
+ owner->files[owner->nfiles] = file;
+ owner->nfiles++;
+}
+
+/*
+ * Forget that a temporary file is owned by a ResourceOwner
+ */
+void
+ResourceOwnerForgetFile(ResourceOwner owner, File file)
+{
+ File *files = owner->files;
+ int ns1 = owner->nfiles - 1;
+ int i;
+
+ for (i = ns1; i >= 0; i--)
+ {
+ if (files[i] == file)
+ {
+ while (i < ns1)
+ {
+ files[i] = files[i + 1];
+ i++;
+ }
+ owner->nfiles = ns1;
+ return;
+ }
+ }
+ elog(ERROR, "temporery file %d is not owned by resource owner %s",
+ file, owner->name);
+}
+
+
+/*
+ * Debugging subroutine
+ */
+static void
+PrintFileLeakWarning(File file)
+{
+ elog(WARNING,
+ "temporary file leak: File %d still referenced",
+ file);
+}