*** pgsql/src/backend/utils/resowner/resowner.c 2009/06/11 14:49:06 1.32 --- pgsql/src/backend/utils/resowner/resowner.c 2009/12/03 11:03:29 1.33 *************** *** 14,20 **** * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.31 2009/01/01 17:23:53 momjian Exp $ * *------------------------------------------------------------------------- */ --- 14,20 ---- * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.32 2009/06/11 14:49:06 momjian Exp $ * *------------------------------------------------------------------------- */ *************** typedef struct ResourceOwnerData *** 72,77 **** --- 72,82 ---- 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; *************** static void PrintRelCacheLeakWarning(Rel *** 105,110 **** --- 110,116 ---- static void PrintPlanCacheLeakWarning(CachedPlan *plan); static void PrintTupleDescLeakWarning(TupleDesc tupdesc); static void PrintSnapshotLeakWarning(Snapshot snapshot); + static void PrintFileLeakWarning(File file); /***************************************************************************** *************** ResourceOwnerReleaseInternal(ResourceOwn *** 316,321 **** --- 322,335 ---- 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(); } *************** ResourceOwnerDelete(ResourceOwner owner) *** 347,352 **** --- 361,367 ---- 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 *************** ResourceOwnerDelete(ResourceOwner owner) *** 377,382 **** --- 392,399 ---- pfree(owner->tupdescs); if (owner->snapshots) pfree(owner->snapshots); + if (owner->files) + pfree(owner->files); pfree(owner); } *************** PrintSnapshotLeakWarning(Snapshot snapsh *** 1035,1037 **** --- 1052,1138 ---- "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); + }