Commit cc988fbb authored by Tom Lane's avatar Tom Lane

Improve ResourceOwners' behavior for large numbers of owned objects.

The original coding was quite fast so long as objects were always
released in reverse order of addition; otherwise, it degenerated into
O(N^2) behavior due to searching for the array element to delete.
Improve matters by switching to hashed storage when the number of
objects of a given type exceeds 64.  (The cutover point is open to
discussion, of course, but some simple performance testing suggests
that hashing has enough overhead to be a loser below there.)

Also, refactor resowner.c so that we don't need N copies of the array
management code.  Since all the resource IDs the code currently needs
to deal with are either pointers or integers, it seems sufficient to
create a one-size-fits-all infrastructure in which everything is
converted to a Datum for storage.

Aleksander Alekseev, reviewed by Stas Kelvich, further fixes by me
parent 879d7139
...@@ -297,6 +297,9 @@ hashvarlena(PG_FUNCTION_ARGS) ...@@ -297,6 +297,9 @@ hashvarlena(PG_FUNCTION_ARGS)
* of 2. There is no need to do mod a prime (mod is sooo slow!). * of 2. There is no need to do mod a prime (mod is sooo slow!).
* If you need less than 32 bits, use a bitmask. * If you need less than 32 bits, use a bitmask.
* *
* This procedure must never throw elog(ERROR); the ResourceOwner code
* relies on this not to fail.
*
* Note: we could easily change this function to return a 64-bit hash value * Note: we could easily change this function to return a 64-bit hash value
* by using the final values of both b and c. b is perhaps a little less * by using the final values of both b and c. b is perhaps a little less
* well mixed than c, however. * well mixed than c, however.
......
...@@ -28,6 +28,64 @@ ...@@ -28,6 +28,64 @@
#include "utils/resowner_private.h" #include "utils/resowner_private.h"
#include "utils/snapmgr.h" #include "utils/snapmgr.h"
/*
* All resource IDs managed by this code are required to fit into a Datum,
* which is fine since they are generally pointers or integers.
*
* Provide Datum conversion macros for a couple of things that are really
* just "int".
*/
#define FileGetDatum(file) Int32GetDatum(file)
#define DatumGetFile(datum) ((File) DatumGetInt32(datum))
#define BufferGetDatum(buffer) Int32GetDatum(buffer)
#define DatumGetBuffer(datum) ((Buffer) DatumGetInt32(datum))
/*
* ResourceArray is a common structure for storing all types of resource IDs.
*
* We manage small sets of resource IDs by keeping them in a simple array:
* itemsarr[k] holds an ID, for 0 <= k < nitems <= maxitems = capacity.
*
* If a set grows large, we switch over to using open-addressing hashing.
* Then, itemsarr[] is a hash table of "capacity" slots, with each
* slot holding either an ID or "invalidval". nitems is the number of valid
* items present; if it would exceed maxitems, we enlarge the array and
* re-hash. In this mode, maxitems should be rather less than capacity so
* that we don't waste too much time searching for empty slots.
*
* In either mode, lastidx remembers the location of the last item inserted
* or returned by GetAny; this speeds up searches in ResourceArrayRemove.
*/
typedef struct ResourceArray
{
Datum *itemsarr; /* buffer for storing values */
Datum invalidval; /* value that is considered invalid */
uint32 capacity; /* allocated length of itemsarr[] */
uint32 nitems; /* how many items are stored in items array */
uint32 maxitems; /* current limit on nitems before enlarging */
uint32 lastidx; /* index of last item returned by GetAny */
} ResourceArray;
/*
* Initially allocated size of a ResourceArray. Must be power of two since
* we'll use (arraysize - 1) as mask for hashing.
*/
#define RESARRAY_INIT_SIZE 16
/*
* When to switch to hashing vs. simple array logic in a ResourceArray.
*/
#define RESARRAY_MAX_ARRAY 64
#define RESARRAY_IS_ARRAY(resarr) ((resarr)->capacity <= RESARRAY_MAX_ARRAY)
/*
* How many items may be stored in a resource array of given capacity.
* When this number is reached, we must resize.
*/
#define RESARRAY_MAX_ITEMS(capacity) \
((capacity) <= RESARRAY_MAX_ARRAY ? (capacity) : (capacity)/4 * 3)
/* /*
* To speed up bulk releasing or reassigning locks from a resource owner to * To speed up bulk releasing or reassigning locks from a resource owner to
* its parent, each resource owner has a small cache of locks it owns. The * its parent, each resource owner has a small cache of locks it owns. The
...@@ -56,54 +114,21 @@ typedef struct ResourceOwnerData ...@@ -56,54 +114,21 @@ typedef struct ResourceOwnerData
ResourceOwner nextchild; /* next child of same parent */ ResourceOwner nextchild; /* next child of same parent */
const char *name; /* name (just for debugging) */ const char *name; /* name (just for debugging) */
/* We have built-in support for remembering owned buffers */ /* We have built-in support for remembering: */
int nbuffers; /* number of owned buffer pins */ ResourceArray bufferarr; /* owned buffers */
Buffer *buffers; /* dynamically allocated array */ ResourceArray catrefarr; /* catcache references */
int maxbuffers; /* currently allocated array size */ ResourceArray catlistrefarr; /* catcache-list pins */
ResourceArray relrefarr; /* relcache references */
ResourceArray planrefarr; /* plancache references */
ResourceArray tupdescarr; /* tupdesc references */
ResourceArray snapshotarr; /* snapshot references */
ResourceArray filearr; /* open temporary files */
ResourceArray dsmarr; /* dynamic shmem segments */
/* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */ /* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */
int nlocks; /* number of owned locks */ int nlocks; /* number of owned locks */
LOCALLOCK *locks[MAX_RESOWNER_LOCKS]; /* list of owned locks */ LOCALLOCK *locks[MAX_RESOWNER_LOCKS]; /* list of owned locks */
} ResourceOwnerData;
/* We have built-in support for remembering catcache references */
int ncatrefs; /* number of owned catcache pins */
HeapTuple *catrefs; /* dynamically allocated array */
int maxcatrefs; /* currently allocated array size */
int ncatlistrefs; /* number of owned catcache-list pins */
CatCList **catlistrefs; /* dynamically allocated array */
int maxcatlistrefs; /* currently allocated array size */
/* We have built-in support for remembering relcache references */
int nrelrefs; /* number of owned relcache pins */
Relation *relrefs; /* dynamically allocated array */
int maxrelrefs; /* currently allocated array size */
/* We have built-in support for remembering plancache references */
int nplanrefs; /* number of owned plancache pins */
CachedPlan **planrefs; /* dynamically allocated array */
int maxplanrefs; /* currently allocated array size */
/* We have built-in support for remembering tupdesc references */
int ntupdescs; /* number of owned tupdesc references */
TupleDesc *tupdescs; /* dynamically allocated array */
int maxtupdescs; /* currently allocated array size */
/* We have built-in support for remembering snapshot references */
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 */
/* We have built-in support for remembering dynamic shmem segments */
int ndsms; /* number of owned shmem segments */
dsm_segment **dsms; /* dynamically allocated array */
int maxdsms; /* currently allocated array size */
} ResourceOwnerData;
/***************************************************************************** /*****************************************************************************
...@@ -128,6 +153,12 @@ static ResourceReleaseCallbackItem *ResourceRelease_callbacks = NULL; ...@@ -128,6 +153,12 @@ static ResourceReleaseCallbackItem *ResourceRelease_callbacks = NULL;
/* Internal routines */ /* Internal routines */
static void ResourceArrayInit(ResourceArray *resarr, Datum invalidval);
static void ResourceArrayEnlarge(ResourceArray *resarr);
static void ResourceArrayAdd(ResourceArray *resarr, Datum value);
static bool ResourceArrayRemove(ResourceArray *resarr, Datum value);
static bool ResourceArrayGetAny(ResourceArray *resarr, Datum *value);
static void ResourceArrayFree(ResourceArray *resarr);
static void ResourceOwnerReleaseInternal(ResourceOwner owner, static void ResourceOwnerReleaseInternal(ResourceOwner owner,
ResourceReleasePhase phase, ResourceReleasePhase phase,
bool isCommit, bool isCommit,
...@@ -140,6 +171,235 @@ static void PrintFileLeakWarning(File file); ...@@ -140,6 +171,235 @@ static void PrintFileLeakWarning(File file);
static void PrintDSMLeakWarning(dsm_segment *seg); static void PrintDSMLeakWarning(dsm_segment *seg);
/*****************************************************************************
* INTERNAL ROUTINES *
*****************************************************************************/
/*
* Initialize a ResourceArray
*/
static void
ResourceArrayInit(ResourceArray *resarr, Datum invalidval)
{
/* Assert it's empty */
Assert(resarr->itemsarr == NULL);
Assert(resarr->capacity == 0);
Assert(resarr->nitems == 0);
Assert(resarr->maxitems == 0);
/* Remember the appropriate "invalid" value */
resarr->invalidval = invalidval;
/* We don't allocate any storage until needed */
}
/*
* Make sure there is room for at least one more resource in an array.
*
* This is separate from actually inserting a resource because if we run out
* of memory, it's critical to do so *before* acquiring the resource.
*/
static void
ResourceArrayEnlarge(ResourceArray *resarr)
{
uint32 i,
oldcap,
newcap;
Datum *olditemsarr;
Datum *newitemsarr;
if (resarr->nitems < resarr->maxitems)
return; /* no work needed */
olditemsarr = resarr->itemsarr;
oldcap = resarr->capacity;
/* Double the capacity of the array (capacity must stay a power of 2!) */
newcap = (oldcap > 0) ? oldcap * 2 : RESARRAY_INIT_SIZE;
newitemsarr = (Datum *) MemoryContextAlloc(TopMemoryContext,
newcap * sizeof(Datum));
for (i = 0; i < newcap; i++)
newitemsarr[i] = resarr->invalidval;
/* We assume we can't fail below this point, so OK to scribble on resarr */
resarr->itemsarr = newitemsarr;
resarr->capacity = newcap;
resarr->maxitems = RESARRAY_MAX_ITEMS(newcap);
resarr->nitems = 0;
if (olditemsarr != NULL)
{
/*
* Transfer any pre-existing entries into the new array; they don't
* necessarily go where they were before, so this simple logic is the
* best way. Note that if we were managing the set as a simple array,
* the entries after nitems are garbage, but that shouldn't matter
* because we won't get here unless nitems was equal to oldcap.
*/
for (i = 0; i < oldcap; i++)
{
if (olditemsarr[i] != resarr->invalidval)
ResourceArrayAdd(resarr, olditemsarr[i]);
}
/* And release old array. */
pfree(olditemsarr);
}
Assert(resarr->nitems < resarr->maxitems);
}
/*
* Add a resource to ResourceArray
*
* Caller must have previously done ResourceArrayEnlarge()
*/
static void
ResourceArrayAdd(ResourceArray *resarr, Datum value)
{
uint32 idx;
Assert(value != resarr->invalidval);
Assert(resarr->nitems < resarr->maxitems);
if (RESARRAY_IS_ARRAY(resarr))
{
/* Append to linear array. */
idx = resarr->nitems;
}
else
{
/* Insert into first free slot at or after hash location. */
uint32 mask = resarr->capacity - 1;
idx = DatumGetUInt32(hash_any((void *) &value, sizeof(value))) & mask;
for (;;)
{
if (resarr->itemsarr[idx] == resarr->invalidval)
break;
idx = (idx + 1) & mask;
}
}
resarr->lastidx = idx;
resarr->itemsarr[idx] = value;
resarr->nitems++;
}
/*
* Remove a resource from ResourceArray
*
* Returns true on success, false if resource was not found.
*
* Note: if same resource ID appears more than once, one instance is removed.
*/
static bool
ResourceArrayRemove(ResourceArray *resarr, Datum value)
{
uint32 i,
idx,
lastidx = resarr->lastidx;
Assert(value != resarr->invalidval);
/* Search through all items, but try lastidx first. */
if (RESARRAY_IS_ARRAY(resarr))
{
if (lastidx < resarr->nitems &&
resarr->itemsarr[lastidx] == value)
{
resarr->itemsarr[lastidx] = resarr->itemsarr[resarr->nitems - 1];
resarr->nitems--;
/* Update lastidx to make reverse-order removals fast. */
resarr->lastidx = resarr->nitems - 1;
return true;
}
for (i = 0; i < resarr->nitems; i++)
{
if (resarr->itemsarr[i] == value)
{
resarr->itemsarr[i] = resarr->itemsarr[resarr->nitems - 1];
resarr->nitems--;
/* Update lastidx to make reverse-order removals fast. */
resarr->lastidx = resarr->nitems - 1;
return true;
}
}
}
else
{
uint32 mask = resarr->capacity - 1;
if (lastidx < resarr->capacity &&
resarr->itemsarr[lastidx] == value)
{
resarr->itemsarr[lastidx] = resarr->invalidval;
resarr->nitems--;
return true;
}
idx = DatumGetUInt32(hash_any((void *) &value, sizeof(value))) & mask;
for (i = 0; i < resarr->capacity; i++)
{
if (resarr->itemsarr[idx] == value)
{
resarr->itemsarr[idx] = resarr->invalidval;
resarr->nitems--;
return true;
}
idx = (idx + 1) & mask;
}
}
return false;
}
/*
* Get any convenient entry in a ResourceArray.
*
* "Convenient" is defined as "easy for ResourceArrayRemove to remove";
* we help that along by setting lastidx to match. This avoids O(N^2) cost
* when removing all ResourceArray items during ResourceOwner destruction.
*
* Returns true if we found an element, or false if the array is empty.
*/
static bool
ResourceArrayGetAny(ResourceArray *resarr, Datum *value)
{
if (resarr->nitems == 0)
return false;
if (RESARRAY_IS_ARRAY(resarr))
{
/* Linear array: just return the first element. */
resarr->lastidx = 0;
}
else
{
/* Hash: search forward from whereever we were last. */
uint32 mask = resarr->capacity - 1;
for (;;)
{
resarr->lastidx &= mask;
if (resarr->itemsarr[resarr->lastidx] != resarr->invalidval)
break;
resarr->lastidx++;
}
}
*value = resarr->itemsarr[resarr->lastidx];
return true;
}
/*
* Trash a ResourceArray (we don't care about its state after this)
*/
static void
ResourceArrayFree(ResourceArray *resarr)
{
if (resarr->itemsarr)
pfree(resarr->itemsarr);
}
/***************************************************************************** /*****************************************************************************
* EXPORTED ROUTINES * * EXPORTED ROUTINES *
*****************************************************************************/ *****************************************************************************/
...@@ -168,6 +428,16 @@ ResourceOwnerCreate(ResourceOwner parent, const char *name) ...@@ -168,6 +428,16 @@ ResourceOwnerCreate(ResourceOwner parent, const char *name)
parent->firstchild = owner; parent->firstchild = owner;
} }
ResourceArrayInit(&(owner->bufferarr), BufferGetDatum(InvalidBuffer));
ResourceArrayInit(&(owner->catrefarr), PointerGetDatum(NULL));
ResourceArrayInit(&(owner->catlistrefarr), PointerGetDatum(NULL));
ResourceArrayInit(&(owner->relrefarr), PointerGetDatum(NULL));
ResourceArrayInit(&(owner->planrefarr), PointerGetDatum(NULL));
ResourceArrayInit(&(owner->tupdescarr), PointerGetDatum(NULL));
ResourceArrayInit(&(owner->snapshotarr), PointerGetDatum(NULL));
ResourceArrayInit(&(owner->filearr), FileGetDatum(-1));
ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL));
return owner; return owner;
} }
...@@ -229,6 +499,7 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, ...@@ -229,6 +499,7 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
ResourceOwner child; ResourceOwner child;
ResourceOwner save; ResourceOwner save;
ResourceReleaseCallbackItem *item; ResourceReleaseCallbackItem *item;
Datum foundres;
/* Recurse to handle descendants */ /* Recurse to handle descendants */
for (child = owner->firstchild; child != NULL; child = child->nextchild) for (child = owner->firstchild; child != NULL; child = child->nextchild)
...@@ -246,51 +517,40 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, ...@@ -246,51 +517,40 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
{ {
/* /*
* Release buffer pins. Note that ReleaseBuffer will remove the * Release buffer pins. Note that ReleaseBuffer will remove the
* buffer entry from my list, so I just have to iterate till there are * buffer entry from our array, so we just have to iterate till there
* none. * are none.
* *
* During a commit, there shouldn't be any remaining pins --- that * During a commit, there shouldn't be any remaining pins --- that
* would indicate failure to clean up the executor correctly --- so * would indicate failure to clean up the executor correctly --- so
* issue warnings. In the abort case, just clean up quietly. * issue warnings. In the abort case, just clean up quietly.
*
* We are careful to do the releasing back-to-front, so as to avoid
* O(N^2) behavior in ResourceOwnerForgetBuffer().
*/ */
while (owner->nbuffers > 0) while (ResourceArrayGetAny(&(owner->bufferarr), &foundres))
{ {
Buffer res = DatumGetBuffer(foundres);
if (isCommit) if (isCommit)
PrintBufferLeakWarning(owner->buffers[owner->nbuffers - 1]); PrintBufferLeakWarning(res);
ReleaseBuffer(owner->buffers[owner->nbuffers - 1]); ReleaseBuffer(res);
} }
/* /* Ditto for relcache references */
* Release relcache references. Note that RelationClose will remove while (ResourceArrayGetAny(&(owner->relrefarr), &foundres))
* the relref entry from my list, so I just have to iterate till there
* are none.
*
* As with buffer pins, warn if any are left at commit time, and
* release back-to-front for speed.
*/
while (owner->nrelrefs > 0)
{ {
Relation res = (Relation) DatumGetPointer(foundres);
if (isCommit) if (isCommit)
PrintRelCacheLeakWarning(owner->relrefs[owner->nrelrefs - 1]); PrintRelCacheLeakWarning(res);
RelationClose(owner->relrefs[owner->nrelrefs - 1]); RelationClose(res);
} }
/* /* Ditto for dynamic shared memory segments */
* Release dynamic shared memory segments. Note that dsm_detach() while (ResourceArrayGetAny(&(owner->dsmarr), &foundres))
* will remove the segment from my list, so I just have to iterate
* until there are none.
*
* As in the preceding cases, warn if there are leftover at commit
* time.
*/
while (owner->ndsms > 0)
{ {
dsm_segment *res = (dsm_segment *) DatumGetPointer(foundres);
if (isCommit) if (isCommit)
PrintDSMLeakWarning(owner->dsms[owner->ndsms - 1]); PrintDSMLeakWarning(res);
dsm_detach(owner->dsms[owner->ndsms - 1]); dsm_detach(res);
} }
} }
else if (phase == RESOURCE_RELEASE_LOCKS) else if (phase == RESOURCE_RELEASE_LOCKS)
...@@ -345,53 +605,68 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, ...@@ -345,53 +605,68 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
{ {
/* /*
* Release catcache references. Note that ReleaseCatCache will remove * Release catcache references. Note that ReleaseCatCache will remove
* the catref entry from my list, so I just have to iterate till there * the catref entry from our array, so we just have to iterate till
* are none. * there are none.
* *
* As with buffer pins, warn if any are left at commit time, and * As with buffer pins, warn if any are left at commit time.
* release back-to-front for speed.
*/ */
while (owner->ncatrefs > 0) while (ResourceArrayGetAny(&(owner->catrefarr), &foundres))
{ {
HeapTuple res = (HeapTuple) DatumGetPointer(foundres);
if (isCommit) if (isCommit)
PrintCatCacheLeakWarning(owner->catrefs[owner->ncatrefs - 1]); PrintCatCacheLeakWarning(res);
ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]); ReleaseCatCache(res);
} }
/* Ditto for catcache lists */ /* Ditto for catcache lists */
while (owner->ncatlistrefs > 0) while (ResourceArrayGetAny(&(owner->catlistrefarr), &foundres))
{ {
CatCList *res = (CatCList *) DatumGetPointer(foundres);
if (isCommit) if (isCommit)
PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]); PrintCatCacheListLeakWarning(res);
ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]); ReleaseCatCacheList(res);
} }
/* Ditto for plancache references */ /* Ditto for plancache references */
while (owner->nplanrefs > 0) while (ResourceArrayGetAny(&(owner->planrefarr), &foundres))
{ {
CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);
if (isCommit) if (isCommit)
PrintPlanCacheLeakWarning(owner->planrefs[owner->nplanrefs - 1]); PrintPlanCacheLeakWarning(res);
ReleaseCachedPlan(owner->planrefs[owner->nplanrefs - 1], true); ReleaseCachedPlan(res, true);
} }
/* Ditto for tupdesc references */ /* Ditto for tupdesc references */
while (owner->ntupdescs > 0) while (ResourceArrayGetAny(&(owner->tupdescarr), &foundres))
{ {
TupleDesc res = (TupleDesc) DatumGetPointer(foundres);
if (isCommit) if (isCommit)
PrintTupleDescLeakWarning(owner->tupdescs[owner->ntupdescs - 1]); PrintTupleDescLeakWarning(res);
DecrTupleDescRefCount(owner->tupdescs[owner->ntupdescs - 1]); DecrTupleDescRefCount(res);
} }
/* Ditto for snapshot references */ /* Ditto for snapshot references */
while (owner->nsnapshots > 0) while (ResourceArrayGetAny(&(owner->snapshotarr), &foundres))
{ {
Snapshot res = (Snapshot) DatumGetPointer(foundres);
if (isCommit) if (isCommit)
PrintSnapshotLeakWarning(owner->snapshots[owner->nsnapshots - 1]); PrintSnapshotLeakWarning(res);
UnregisterSnapshot(owner->snapshots[owner->nsnapshots - 1]); UnregisterSnapshot(res);
} }
/* Ditto for temporary files */ /* Ditto for temporary files */
while (owner->nfiles > 0) while (ResourceArrayGetAny(&(owner->filearr), &foundres))
{ {
File res = DatumGetFile(foundres);
if (isCommit) if (isCommit)
PrintFileLeakWarning(owner->files[owner->nfiles - 1]); PrintFileLeakWarning(res);
FileClose(owner->files[owner->nfiles - 1]); FileClose(res);
} }
/* Clean up index scans too */ /* Clean up index scans too */
...@@ -418,16 +693,16 @@ ResourceOwnerDelete(ResourceOwner owner) ...@@ -418,16 +693,16 @@ ResourceOwnerDelete(ResourceOwner owner)
Assert(owner != CurrentResourceOwner); Assert(owner != CurrentResourceOwner);
/* And it better not own any resources, either */ /* And it better not own any resources, either */
Assert(owner->nbuffers == 0); Assert(owner->bufferarr.nitems == 0);
Assert(owner->catrefarr.nitems == 0);
Assert(owner->catlistrefarr.nitems == 0);
Assert(owner->relrefarr.nitems == 0);
Assert(owner->planrefarr.nitems == 0);
Assert(owner->tupdescarr.nitems == 0);
Assert(owner->snapshotarr.nitems == 0);
Assert(owner->filearr.nitems == 0);
Assert(owner->dsmarr.nitems == 0);
Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1); Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
Assert(owner->ncatrefs == 0);
Assert(owner->ncatlistrefs == 0);
Assert(owner->nrelrefs == 0);
Assert(owner->ndsms == 0);
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 * Delete children. The recursive call will delink the child from me, so
...@@ -444,24 +719,15 @@ ResourceOwnerDelete(ResourceOwner owner) ...@@ -444,24 +719,15 @@ ResourceOwnerDelete(ResourceOwner owner)
ResourceOwnerNewParent(owner, NULL); ResourceOwnerNewParent(owner, NULL);
/* And free the object. */ /* And free the object. */
if (owner->buffers) ResourceArrayFree(&(owner->bufferarr));
pfree(owner->buffers); ResourceArrayFree(&(owner->catrefarr));
if (owner->catrefs) ResourceArrayFree(&(owner->catlistrefarr));
pfree(owner->catrefs); ResourceArrayFree(&(owner->relrefarr));
if (owner->catlistrefs) ResourceArrayFree(&(owner->planrefarr));
pfree(owner->catlistrefs); ResourceArrayFree(&(owner->tupdescarr));
if (owner->relrefs) ResourceArrayFree(&(owner->snapshotarr));
pfree(owner->relrefs); ResourceArrayFree(&(owner->filearr));
if (owner->planrefs) ResourceArrayFree(&(owner->dsmarr));
pfree(owner->planrefs);
if (owner->tupdescs)
pfree(owner->tupdescs);
if (owner->snapshots)
pfree(owner->snapshots);
if (owner->files)
pfree(owner->files);
if (owner->dsms)
pfree(owner->dsms);
pfree(owner); pfree(owner);
} }
...@@ -575,26 +841,9 @@ UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg) ...@@ -575,26 +841,9 @@ UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
void void
ResourceOwnerEnlargeBuffers(ResourceOwner owner) ResourceOwnerEnlargeBuffers(ResourceOwner owner)
{ {
int newmax; if (owner == NULL)
return;
if (owner == NULL || ResourceArrayEnlarge(&(owner->bufferarr));
owner->nbuffers < owner->maxbuffers)
return; /* nothing to do */
if (owner->buffers == NULL)
{
newmax = 16;
owner->buffers = (Buffer *)
MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Buffer));
owner->maxbuffers = newmax;
}
else
{
newmax = owner->maxbuffers * 2;
owner->buffers = (Buffer *)
repalloc(owner->buffers, newmax * sizeof(Buffer));
owner->maxbuffers = newmax;
}
} }
/* /*
...@@ -608,12 +857,9 @@ ResourceOwnerEnlargeBuffers(ResourceOwner owner) ...@@ -608,12 +857,9 @@ ResourceOwnerEnlargeBuffers(ResourceOwner owner)
void void
ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer) ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
{ {
if (owner != NULL) if (owner == NULL)
{ return;
Assert(owner->nbuffers < owner->maxbuffers); ResourceArrayAdd(&(owner->bufferarr), BufferGetDatum(buffer));
owner->buffers[owner->nbuffers] = buffer;
owner->nbuffers++;
}
} }
/* /*
...@@ -625,33 +871,11 @@ ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer) ...@@ -625,33 +871,11 @@ ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
void void
ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer) ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
{ {
if (owner != NULL) if (owner == NULL)
{ return;
Buffer *buffers = owner->buffers; if (!ResourceArrayRemove(&(owner->bufferarr), BufferGetDatum(buffer)))
int nb1 = owner->nbuffers - 1;
int i;
/*
* Scan back-to-front because it's more likely we are releasing a
* recently pinned buffer. This isn't always the case of course, but
* it's the way to bet.
*/
for (i = nb1; i >= 0; i--)
{
if (buffers[i] == buffer)
{
while (i < nb1)
{
buffers[i] = buffers[i + 1];
i++;
}
owner->nbuffers = nb1;
return;
}
}
elog(ERROR, "buffer %d is not owned by resource owner %s", elog(ERROR, "buffer %d is not owned by resource owner %s",
buffer, owner->name); buffer, owner->name);
}
} }
/* /*
...@@ -667,6 +891,8 @@ ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer) ...@@ -667,6 +891,8 @@ ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
void void
ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock) ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
{ {
Assert(locallock != NULL);
if (owner->nlocks > MAX_RESOWNER_LOCKS) if (owner->nlocks > MAX_RESOWNER_LOCKS)
return; /* we have already overflowed */ return; /* we have already overflowed */
...@@ -714,25 +940,7 @@ ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock) ...@@ -714,25 +940,7 @@ ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
void void
ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner) ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
{ {
int newmax; ResourceArrayEnlarge(&(owner->catrefarr));
if (owner->ncatrefs < owner->maxcatrefs)
return; /* nothing to do */
if (owner->catrefs == NULL)
{
newmax = 16;
owner->catrefs = (HeapTuple *)
MemoryContextAlloc(TopMemoryContext, newmax * sizeof(HeapTuple));
owner->maxcatrefs = newmax;
}
else
{
newmax = owner->maxcatrefs * 2;
owner->catrefs = (HeapTuple *)
repalloc(owner->catrefs, newmax * sizeof(HeapTuple));
owner->maxcatrefs = newmax;
}
} }
/* /*
...@@ -743,9 +951,7 @@ ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner) ...@@ -743,9 +951,7 @@ ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
void void
ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple) ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
{ {
Assert(owner->ncatrefs < owner->maxcatrefs); ResourceArrayAdd(&(owner->catrefarr), PointerGetDatum(tuple));
owner->catrefs[owner->ncatrefs] = tuple;
owner->ncatrefs++;
} }
/* /*
...@@ -754,25 +960,9 @@ ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple) ...@@ -754,25 +960,9 @@ ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
void void
ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple) ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
{ {
HeapTuple *catrefs = owner->catrefs; if (!ResourceArrayRemove(&(owner->catrefarr), PointerGetDatum(tuple)))
int nc1 = owner->ncatrefs - 1; elog(ERROR, "catcache reference %p is not owned by resource owner %s",
int i; tuple, owner->name);
for (i = nc1; i >= 0; i--)
{
if (catrefs[i] == tuple)
{
while (i < nc1)
{
catrefs[i] = catrefs[i + 1];
i++;
}
owner->ncatrefs = nc1;
return;
}
}
elog(ERROR, "catcache reference %p is not owned by resource owner %s",
tuple, owner->name);
} }
/* /*
...@@ -785,25 +975,7 @@ ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple) ...@@ -785,25 +975,7 @@ ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
void void
ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner) ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
{ {
int newmax; ResourceArrayEnlarge(&(owner->catlistrefarr));
if (owner->ncatlistrefs < owner->maxcatlistrefs)
return; /* nothing to do */
if (owner->catlistrefs == NULL)
{
newmax = 16;
owner->catlistrefs = (CatCList **)
MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CatCList *));
owner->maxcatlistrefs = newmax;
}
else
{
newmax = owner->maxcatlistrefs * 2;
owner->catlistrefs = (CatCList **)
repalloc(owner->catlistrefs, newmax * sizeof(CatCList *));
owner->maxcatlistrefs = newmax;
}
} }
/* /*
...@@ -814,9 +986,7 @@ ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner) ...@@ -814,9 +986,7 @@ ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
void void
ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list) ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
{ {
Assert(owner->ncatlistrefs < owner->maxcatlistrefs); ResourceArrayAdd(&(owner->catlistrefarr), PointerGetDatum(list));
owner->catlistrefs[owner->ncatlistrefs] = list;
owner->ncatlistrefs++;
} }
/* /*
...@@ -825,25 +995,9 @@ ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list) ...@@ -825,25 +995,9 @@ ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
void void
ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list) ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
{ {
CatCList **catlistrefs = owner->catlistrefs; if (!ResourceArrayRemove(&(owner->catlistrefarr), PointerGetDatum(list)))
int nc1 = owner->ncatlistrefs - 1; elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
int i; list, owner->name);
for (i = nc1; i >= 0; i--)
{
if (catlistrefs[i] == list)
{
while (i < nc1)
{
catlistrefs[i] = catlistrefs[i + 1];
i++;
}
owner->ncatlistrefs = nc1;
return;
}
}
elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
list, owner->name);
} }
/* /*
...@@ -856,25 +1010,7 @@ ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list) ...@@ -856,25 +1010,7 @@ ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
void void
ResourceOwnerEnlargeRelationRefs(ResourceOwner owner) ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
{ {
int newmax; ResourceArrayEnlarge(&(owner->relrefarr));
if (owner->nrelrefs < owner->maxrelrefs)
return; /* nothing to do */
if (owner->relrefs == NULL)
{
newmax = 16;
owner->relrefs = (Relation *)
MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Relation));
owner->maxrelrefs = newmax;
}
else
{
newmax = owner->maxrelrefs * 2;
owner->relrefs = (Relation *)
repalloc(owner->relrefs, newmax * sizeof(Relation));
owner->maxrelrefs = newmax;
}
} }
/* /*
...@@ -885,9 +1021,7 @@ ResourceOwnerEnlargeRelationRefs(ResourceOwner owner) ...@@ -885,9 +1021,7 @@ ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
void void
ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel) ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
{ {
Assert(owner->nrelrefs < owner->maxrelrefs); ResourceArrayAdd(&(owner->relrefarr), PointerGetDatum(rel));
owner->relrefs[owner->nrelrefs] = rel;
owner->nrelrefs++;
} }
/* /*
...@@ -896,25 +1030,9 @@ ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel) ...@@ -896,25 +1030,9 @@ ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
void void
ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel) ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
{ {
Relation *relrefs = owner->relrefs; if (!ResourceArrayRemove(&(owner->relrefarr), PointerGetDatum(rel)))
int nr1 = owner->nrelrefs - 1; elog(ERROR, "relcache reference %s is not owned by resource owner %s",
int i; RelationGetRelationName(rel), owner->name);
for (i = nr1; i >= 0; i--)
{
if (relrefs[i] == rel)
{
while (i < nr1)
{
relrefs[i] = relrefs[i + 1];
i++;
}
owner->nrelrefs = nr1;
return;
}
}
elog(ERROR, "relcache reference %s is not owned by resource owner %s",
RelationGetRelationName(rel), owner->name);
} }
/* /*
...@@ -937,25 +1055,7 @@ PrintRelCacheLeakWarning(Relation rel) ...@@ -937,25 +1055,7 @@ PrintRelCacheLeakWarning(Relation rel)
void void
ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner) ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
{ {
int newmax; ResourceArrayEnlarge(&(owner->planrefarr));
if (owner->nplanrefs < owner->maxplanrefs)
return; /* nothing to do */
if (owner->planrefs == NULL)
{
newmax = 16;
owner->planrefs = (CachedPlan **)
MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CachedPlan *));
owner->maxplanrefs = newmax;
}
else
{
newmax = owner->maxplanrefs * 2;
owner->planrefs = (CachedPlan **)
repalloc(owner->planrefs, newmax * sizeof(CachedPlan *));
owner->maxplanrefs = newmax;
}
} }
/* /*
...@@ -966,9 +1066,7 @@ ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner) ...@@ -966,9 +1066,7 @@ ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
void void
ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan) ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
{ {
Assert(owner->nplanrefs < owner->maxplanrefs); ResourceArrayAdd(&(owner->planrefarr), PointerGetDatum(plan));
owner->planrefs[owner->nplanrefs] = plan;
owner->nplanrefs++;
} }
/* /*
...@@ -977,25 +1075,9 @@ ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan) ...@@ -977,25 +1075,9 @@ ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
void void
ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan) ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
{ {
CachedPlan **planrefs = owner->planrefs; if (!ResourceArrayRemove(&(owner->planrefarr), PointerGetDatum(plan)))
int np1 = owner->nplanrefs - 1; elog(ERROR, "plancache reference %p is not owned by resource owner %s",
int i; plan, owner->name);
for (i = np1; i >= 0; i--)
{
if (planrefs[i] == plan)
{
while (i < np1)
{
planrefs[i] = planrefs[i + 1];
i++;
}
owner->nplanrefs = np1;
return;
}
}
elog(ERROR, "plancache reference %p is not owned by resource owner %s",
plan, owner->name);
} }
/* /*
...@@ -1017,25 +1099,7 @@ PrintPlanCacheLeakWarning(CachedPlan *plan) ...@@ -1017,25 +1099,7 @@ PrintPlanCacheLeakWarning(CachedPlan *plan)
void void
ResourceOwnerEnlargeTupleDescs(ResourceOwner owner) ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
{ {
int newmax; ResourceArrayEnlarge(&(owner->tupdescarr));
if (owner->ntupdescs < owner->maxtupdescs)
return; /* nothing to do */
if (owner->tupdescs == NULL)
{
newmax = 16;
owner->tupdescs = (TupleDesc *)
MemoryContextAlloc(TopMemoryContext, newmax * sizeof(TupleDesc));
owner->maxtupdescs = newmax;
}
else
{
newmax = owner->maxtupdescs * 2;
owner->tupdescs = (TupleDesc *)
repalloc(owner->tupdescs, newmax * sizeof(TupleDesc));
owner->maxtupdescs = newmax;
}
} }
/* /*
...@@ -1046,9 +1110,7 @@ ResourceOwnerEnlargeTupleDescs(ResourceOwner owner) ...@@ -1046,9 +1110,7 @@ ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
void void
ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc) ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
{ {
Assert(owner->ntupdescs < owner->maxtupdescs); ResourceArrayAdd(&(owner->tupdescarr), PointerGetDatum(tupdesc));
owner->tupdescs[owner->ntupdescs] = tupdesc;
owner->ntupdescs++;
} }
/* /*
...@@ -1057,25 +1119,9 @@ ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc) ...@@ -1057,25 +1119,9 @@ ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
void void
ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc) ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
{ {
TupleDesc *tupdescs = owner->tupdescs; if (!ResourceArrayRemove(&(owner->tupdescarr), PointerGetDatum(tupdesc)))
int nt1 = owner->ntupdescs - 1; elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
int i; tupdesc, owner->name);
for (i = nt1; i >= 0; i--)
{
if (tupdescs[i] == tupdesc)
{
while (i < nt1)
{
tupdescs[i] = tupdescs[i + 1];
i++;
}
owner->ntupdescs = nt1;
return;
}
}
elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
tupdesc, owner->name);
} }
/* /*
...@@ -1099,25 +1145,7 @@ PrintTupleDescLeakWarning(TupleDesc tupdesc) ...@@ -1099,25 +1145,7 @@ PrintTupleDescLeakWarning(TupleDesc tupdesc)
void void
ResourceOwnerEnlargeSnapshots(ResourceOwner owner) ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
{ {
int newmax; ResourceArrayEnlarge(&(owner->snapshotarr));
if (owner->nsnapshots < owner->maxsnapshots)
return; /* nothing to do */
if (owner->snapshots == NULL)
{
newmax = 16;
owner->snapshots = (Snapshot *)
MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Snapshot));
owner->maxsnapshots = newmax;
}
else
{
newmax = owner->maxsnapshots * 2;
owner->snapshots = (Snapshot *)
repalloc(owner->snapshots, newmax * sizeof(Snapshot));
owner->maxsnapshots = newmax;
}
} }
/* /*
...@@ -1128,9 +1156,7 @@ ResourceOwnerEnlargeSnapshots(ResourceOwner owner) ...@@ -1128,9 +1156,7 @@ ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
void void
ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot) ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
{ {
Assert(owner->nsnapshots < owner->maxsnapshots); ResourceArrayAdd(&(owner->snapshotarr), PointerGetDatum(snapshot));
owner->snapshots[owner->nsnapshots] = snapshot;
owner->nsnapshots++;
} }
/* /*
...@@ -1139,25 +1165,9 @@ ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot) ...@@ -1139,25 +1165,9 @@ ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
void void
ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot) ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
{ {
Snapshot *snapshots = owner->snapshots; if (!ResourceArrayRemove(&(owner->snapshotarr), PointerGetDatum(snapshot)))
int ns1 = owner->nsnapshots - 1; elog(ERROR, "snapshot reference %p is not owned by resource owner %s",
int i; snapshot, owner->name);
for (i = ns1; i >= 0; i--)
{
if (snapshots[i] == snapshot)
{
while (i < ns1)
{
snapshots[i] = snapshots[i + 1];
i++;
}
owner->nsnapshots = ns1;
return;
}
}
elog(ERROR, "snapshot reference %p is not owned by resource owner %s",
snapshot, owner->name);
} }
/* /*
...@@ -1166,8 +1176,7 @@ ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot) ...@@ -1166,8 +1176,7 @@ ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
static void static void
PrintSnapshotLeakWarning(Snapshot snapshot) PrintSnapshotLeakWarning(Snapshot snapshot)
{ {
elog(WARNING, elog(WARNING, "Snapshot reference leak: Snapshot %p still referenced",
"Snapshot reference leak: Snapshot %p still referenced",
snapshot); snapshot);
} }
...@@ -1182,25 +1191,7 @@ PrintSnapshotLeakWarning(Snapshot snapshot) ...@@ -1182,25 +1191,7 @@ PrintSnapshotLeakWarning(Snapshot snapshot)
void void
ResourceOwnerEnlargeFiles(ResourceOwner owner) ResourceOwnerEnlargeFiles(ResourceOwner owner)
{ {
int newmax; ResourceArrayEnlarge(&(owner->filearr));
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;
}
} }
/* /*
...@@ -1211,9 +1202,7 @@ ResourceOwnerEnlargeFiles(ResourceOwner owner) ...@@ -1211,9 +1202,7 @@ ResourceOwnerEnlargeFiles(ResourceOwner owner)
void void
ResourceOwnerRememberFile(ResourceOwner owner, File file) ResourceOwnerRememberFile(ResourceOwner owner, File file)
{ {
Assert(owner->nfiles < owner->maxfiles); ResourceArrayAdd(&(owner->filearr), FileGetDatum(file));
owner->files[owner->nfiles] = file;
owner->nfiles++;
} }
/* /*
...@@ -1222,36 +1211,18 @@ ResourceOwnerRememberFile(ResourceOwner owner, File file) ...@@ -1222,36 +1211,18 @@ ResourceOwnerRememberFile(ResourceOwner owner, File file)
void void
ResourceOwnerForgetFile(ResourceOwner owner, File file) ResourceOwnerForgetFile(ResourceOwner owner, File file)
{ {
File *files = owner->files; if (!ResourceArrayRemove(&(owner->filearr), FileGetDatum(file)))
int ns1 = owner->nfiles - 1; elog(ERROR, "temporary file %d is not owned by resource owner %s",
int i; file, owner->name);
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 * Debugging subroutine
*/ */
static void static void
PrintFileLeakWarning(File file) PrintFileLeakWarning(File file)
{ {
elog(WARNING, elog(WARNING, "temporary file leak: File %d still referenced",
"temporary file leak: File %d still referenced",
file); file);
} }
...@@ -1265,26 +1236,7 @@ PrintFileLeakWarning(File file) ...@@ -1265,26 +1236,7 @@ PrintFileLeakWarning(File file)
void void
ResourceOwnerEnlargeDSMs(ResourceOwner owner) ResourceOwnerEnlargeDSMs(ResourceOwner owner)
{ {
int newmax; ResourceArrayEnlarge(&(owner->dsmarr));
if (owner->ndsms < owner->maxdsms)
return; /* nothing to do */
if (owner->dsms == NULL)
{
newmax = 16;
owner->dsms = (dsm_segment **)
MemoryContextAlloc(TopMemoryContext,
newmax * sizeof(dsm_segment *));
owner->maxdsms = newmax;
}
else
{
newmax = owner->maxdsms * 2;
owner->dsms = (dsm_segment **)
repalloc(owner->dsms, newmax * sizeof(dsm_segment *));
owner->maxdsms = newmax;
}
} }
/* /*
...@@ -1295,9 +1247,7 @@ ResourceOwnerEnlargeDSMs(ResourceOwner owner) ...@@ -1295,9 +1247,7 @@ ResourceOwnerEnlargeDSMs(ResourceOwner owner)
void void
ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg) ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
{ {
Assert(owner->ndsms < owner->maxdsms); ResourceArrayAdd(&(owner->dsmarr), PointerGetDatum(seg));
owner->dsms[owner->ndsms] = seg;
owner->ndsms++;
} }
/* /*
...@@ -1306,36 +1256,17 @@ ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg) ...@@ -1306,36 +1256,17 @@ ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
void void
ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg) ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg)
{ {
dsm_segment **dsms = owner->dsms; if (!ResourceArrayRemove(&(owner->dsmarr), PointerGetDatum(seg)))
int ns1 = owner->ndsms - 1; elog(ERROR, "dynamic shared memory segment %u is not owned by resource owner %s",
int i; dsm_segment_handle(seg), owner->name);
for (i = ns1; i >= 0; i--)
{
if (dsms[i] == seg)
{
while (i < ns1)
{
dsms[i] = dsms[i + 1];
i++;
}
owner->ndsms = ns1;
return;
}
}
elog(ERROR,
"dynamic shared memory segment %u is not owned by resource owner %s",
dsm_segment_handle(seg), owner->name);
} }
/* /*
* Debugging subroutine * Debugging subroutine
*/ */
static void static void
PrintDSMLeakWarning(dsm_segment *seg) PrintDSMLeakWarning(dsm_segment *seg)
{ {
elog(WARNING, elog(WARNING, "dynamic shared memory leak: segment %u still referenced",
"dynamic shared memory leak: segment %u still referenced",
dsm_segment_handle(seg)); dsm_segment_handle(seg));
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment