diff options
Diffstat (limited to 'src/backend/utils/resowner/resowner.c')
-rw-r--r-- | src/backend/utils/resowner/resowner.c | 103 |
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); +} |