#include "utils/resowner_private.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
* its parent, each resource owner has a small cache of locks it owns. The
ResourceOwner nextchild; /* next child of same parent */
const char *name; /* name (just for debugging) */
- /* We have built-in support for remembering owned buffers */
- int nbuffers; /* number of owned buffer pins */
- Buffer *buffers; /* dynamically allocated array */
- int maxbuffers; /* currently allocated array size */
+ /* We have built-in support for remembering: */
+ ResourceArray bufferarr; /* owned buffers */
+ ResourceArray catrefarr; /* catcache references */
+ 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. */
int nlocks; /* number of owned locks */
LOCALLOCK *locks[MAX_RESOWNER_LOCKS]; /* list of owned locks */
-
- /* 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;
+} ResourceOwnerData;
/*****************************************************************************
/* 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,
ResourceReleasePhase phase,
bool isCommit,
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 *
*****************************************************************************/
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;
}
ResourceOwner child;
ResourceOwner save;
ResourceReleaseCallbackItem *item;
+ Datum foundres;
/* Recurse to handle descendants */
for (child = owner->firstchild; child != NULL; child = child->nextchild)
{
/*
* Release buffer pins. Note that ReleaseBuffer will remove the
- * buffer entry from my list, so I just have to iterate till there are
- * none.
+ * buffer entry from our array, so we just have to iterate till there
+ * are none.
*
* During a commit, there shouldn't be any remaining pins --- that
* would indicate failure to clean up the executor correctly --- so
* 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)
- PrintBufferLeakWarning(owner->buffers[owner->nbuffers - 1]);
- ReleaseBuffer(owner->buffers[owner->nbuffers - 1]);
+ PrintBufferLeakWarning(res);
+ ReleaseBuffer(res);
}
- /*
- * Release relcache references. Note that RelationClose will remove
- * 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)
+ /* Ditto for relcache references */
+ while (ResourceArrayGetAny(&(owner->relrefarr), &foundres))
{
+ Relation res = (Relation) DatumGetPointer(foundres);
+
if (isCommit)
- PrintRelCacheLeakWarning(owner->relrefs[owner->nrelrefs - 1]);
- RelationClose(owner->relrefs[owner->nrelrefs - 1]);
+ PrintRelCacheLeakWarning(res);
+ RelationClose(res);
}
- /*
- * Release dynamic shared memory segments. Note that dsm_detach()
- * 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)
+ /* Ditto for dynamic shared memory segments */
+ while (ResourceArrayGetAny(&(owner->dsmarr), &foundres))
{
+ dsm_segment *res = (dsm_segment *) DatumGetPointer(foundres);
+
if (isCommit)
- PrintDSMLeakWarning(owner->dsms[owner->ndsms - 1]);
- dsm_detach(owner->dsms[owner->ndsms - 1]);
+ PrintDSMLeakWarning(res);
+ dsm_detach(res);
}
}
else if (phase == RESOURCE_RELEASE_LOCKS)
{
/*
* Release catcache references. Note that ReleaseCatCache will remove
- * the catref entry from my list, so I just have to iterate till there
- * are none.
+ * the catref entry from our array, so we 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.
+ * As with buffer pins, warn if any are left at commit time.
*/
- while (owner->ncatrefs > 0)
+ while (ResourceArrayGetAny(&(owner->catrefarr), &foundres))
{
+ HeapTuple res = (HeapTuple) DatumGetPointer(foundres);
+
if (isCommit)
- PrintCatCacheLeakWarning(owner->catrefs[owner->ncatrefs - 1]);
- ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]);
+ PrintCatCacheLeakWarning(res);
+ ReleaseCatCache(res);
}
+
/* Ditto for catcache lists */
- while (owner->ncatlistrefs > 0)
+ while (ResourceArrayGetAny(&(owner->catlistrefarr), &foundres))
{
+ CatCList *res = (CatCList *) DatumGetPointer(foundres);
+
if (isCommit)
- PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]);
- ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);
+ PrintCatCacheListLeakWarning(res);
+ ReleaseCatCacheList(res);
}
+
/* Ditto for plancache references */
- while (owner->nplanrefs > 0)
+ while (ResourceArrayGetAny(&(owner->planrefarr), &foundres))
{
+ CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);
+
if (isCommit)
- PrintPlanCacheLeakWarning(owner->planrefs[owner->nplanrefs - 1]);
- ReleaseCachedPlan(owner->planrefs[owner->nplanrefs - 1], true);
+ PrintPlanCacheLeakWarning(res);
+ ReleaseCachedPlan(res, true);
}
+
/* Ditto for tupdesc references */
- while (owner->ntupdescs > 0)
+ while (ResourceArrayGetAny(&(owner->tupdescarr), &foundres))
{
+ TupleDesc res = (TupleDesc) DatumGetPointer(foundres);
+
if (isCommit)
- PrintTupleDescLeakWarning(owner->tupdescs[owner->ntupdescs - 1]);
- DecrTupleDescRefCount(owner->tupdescs[owner->ntupdescs - 1]);
+ PrintTupleDescLeakWarning(res);
+ DecrTupleDescRefCount(res);
}
+
/* Ditto for snapshot references */
- while (owner->nsnapshots > 0)
+ while (ResourceArrayGetAny(&(owner->snapshotarr), &foundres))
{
+ Snapshot res = (Snapshot) DatumGetPointer(foundres);
+
if (isCommit)
- PrintSnapshotLeakWarning(owner->snapshots[owner->nsnapshots - 1]);
- UnregisterSnapshot(owner->snapshots[owner->nsnapshots - 1]);
+ PrintSnapshotLeakWarning(res);
+ UnregisterSnapshot(res);
}
/* Ditto for temporary files */
- while (owner->nfiles > 0)
+ while (ResourceArrayGetAny(&(owner->filearr), &foundres))
{
+ File res = DatumGetFile(foundres);
+
if (isCommit)
- PrintFileLeakWarning(owner->files[owner->nfiles - 1]);
- FileClose(owner->files[owner->nfiles - 1]);
+ PrintFileLeakWarning(res);
+ FileClose(res);
}
/* Clean up index scans too */
Assert(owner != CurrentResourceOwner);
/* 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->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
ResourceOwnerNewParent(owner, NULL);
/* And free the object. */
- if (owner->buffers)
- pfree(owner->buffers);
- if (owner->catrefs)
- pfree(owner->catrefs);
- if (owner->catlistrefs)
- pfree(owner->catlistrefs);
- if (owner->relrefs)
- pfree(owner->relrefs);
- if (owner->planrefs)
- 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);
+ ResourceArrayFree(&(owner->bufferarr));
+ ResourceArrayFree(&(owner->catrefarr));
+ ResourceArrayFree(&(owner->catlistrefarr));
+ ResourceArrayFree(&(owner->relrefarr));
+ ResourceArrayFree(&(owner->planrefarr));
+ ResourceArrayFree(&(owner->tupdescarr));
+ ResourceArrayFree(&(owner->snapshotarr));
+ ResourceArrayFree(&(owner->filearr));
+ ResourceArrayFree(&(owner->dsmarr));
pfree(owner);
}
void
ResourceOwnerEnlargeBuffers(ResourceOwner owner)
{
- int newmax;
-
- if (owner == NULL ||
- 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;
- }
+ if (owner == NULL)
+ return;
+ ResourceArrayEnlarge(&(owner->bufferarr));
}
/*
void
ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
{
- if (owner != NULL)
- {
- Assert(owner->nbuffers < owner->maxbuffers);
- owner->buffers[owner->nbuffers] = buffer;
- owner->nbuffers++;
- }
+ if (owner == NULL)
+ return;
+ ResourceArrayAdd(&(owner->bufferarr), BufferGetDatum(buffer));
}
/*
void
ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
{
- if (owner != NULL)
- {
- Buffer *buffers = owner->buffers;
- 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;
- }
- }
+ if (owner == NULL)
+ return;
+ if (!ResourceArrayRemove(&(owner->bufferarr), BufferGetDatum(buffer)))
elog(ERROR, "buffer %d is not owned by resource owner %s",
buffer, owner->name);
- }
}
/*
void
ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
{
+ Assert(locallock != NULL);
+
if (owner->nlocks > MAX_RESOWNER_LOCKS)
return; /* we have already overflowed */
void
ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
{
- int newmax;
-
- 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;
- }
+ ResourceArrayEnlarge(&(owner->catrefarr));
}
/*
void
ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
{
- Assert(owner->ncatrefs < owner->maxcatrefs);
- owner->catrefs[owner->ncatrefs] = tuple;
- owner->ncatrefs++;
+ ResourceArrayAdd(&(owner->catrefarr), PointerGetDatum(tuple));
}
/*
void
ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
{
- HeapTuple *catrefs = owner->catrefs;
- int nc1 = owner->ncatrefs - 1;
- int i;
-
- 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);
+ if (!ResourceArrayRemove(&(owner->catrefarr), PointerGetDatum(tuple)))
+ elog(ERROR, "catcache reference %p is not owned by resource owner %s",
+ tuple, owner->name);
}
/*
void
ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
{
- int newmax;
-
- 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;
- }
+ ResourceArrayEnlarge(&(owner->catlistrefarr));
}
/*
void
ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
{
- Assert(owner->ncatlistrefs < owner->maxcatlistrefs);
- owner->catlistrefs[owner->ncatlistrefs] = list;
- owner->ncatlistrefs++;
+ ResourceArrayAdd(&(owner->catlistrefarr), PointerGetDatum(list));
}
/*
void
ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
{
- CatCList **catlistrefs = owner->catlistrefs;
- int nc1 = owner->ncatlistrefs - 1;
- int i;
-
- 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);
+ if (!ResourceArrayRemove(&(owner->catlistrefarr), PointerGetDatum(list)))
+ elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
+ list, owner->name);
}
/*
void
ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
{
- int newmax;
-
- 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;
- }
+ ResourceArrayEnlarge(&(owner->relrefarr));
}
/*
void
ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
{
- Assert(owner->nrelrefs < owner->maxrelrefs);
- owner->relrefs[owner->nrelrefs] = rel;
- owner->nrelrefs++;
+ ResourceArrayAdd(&(owner->relrefarr), PointerGetDatum(rel));
}
/*
void
ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
{
- Relation *relrefs = owner->relrefs;
- int nr1 = owner->nrelrefs - 1;
- int i;
-
- 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);
+ if (!ResourceArrayRemove(&(owner->relrefarr), PointerGetDatum(rel)))
+ elog(ERROR, "relcache reference %s is not owned by resource owner %s",
+ RelationGetRelationName(rel), owner->name);
}
/*
void
ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
{
- int newmax;
-
- 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;
- }
+ ResourceArrayEnlarge(&(owner->planrefarr));
}
/*
void
ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
{
- Assert(owner->nplanrefs < owner->maxplanrefs);
- owner->planrefs[owner->nplanrefs] = plan;
- owner->nplanrefs++;
+ ResourceArrayAdd(&(owner->planrefarr), PointerGetDatum(plan));
}
/*
void
ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
{
- CachedPlan **planrefs = owner->planrefs;
- int np1 = owner->nplanrefs - 1;
- int i;
-
- 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);
+ if (!ResourceArrayRemove(&(owner->planrefarr), PointerGetDatum(plan)))
+ elog(ERROR, "plancache reference %p is not owned by resource owner %s",
+ plan, owner->name);
}
/*
void
ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
{
- int newmax;
-
- 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;
- }
+ ResourceArrayEnlarge(&(owner->tupdescarr));
}
/*
void
ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
{
- Assert(owner->ntupdescs < owner->maxtupdescs);
- owner->tupdescs[owner->ntupdescs] = tupdesc;
- owner->ntupdescs++;
+ ResourceArrayAdd(&(owner->tupdescarr), PointerGetDatum(tupdesc));
}
/*
void
ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
{
- TupleDesc *tupdescs = owner->tupdescs;
- int nt1 = owner->ntupdescs - 1;
- int i;
-
- 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);
+ if (!ResourceArrayRemove(&(owner->tupdescarr), PointerGetDatum(tupdesc)))
+ elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
+ tupdesc, owner->name);
}
/*
void
ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
{
- int newmax;
-
- 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;
- }
+ ResourceArrayEnlarge(&(owner->snapshotarr));
}
/*
void
ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
{
- Assert(owner->nsnapshots < owner->maxsnapshots);
- owner->snapshots[owner->nsnapshots] = snapshot;
- owner->nsnapshots++;
+ ResourceArrayAdd(&(owner->snapshotarr), PointerGetDatum(snapshot));
}
/*
void
ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
{
- Snapshot *snapshots = owner->snapshots;
- int ns1 = owner->nsnapshots - 1;
- int i;
-
- 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);
+ if (!ResourceArrayRemove(&(owner->snapshotarr), PointerGetDatum(snapshot)))
+ elog(ERROR, "snapshot reference %p is not owned by resource owner %s",
+ snapshot, owner->name);
}
/*
static void
PrintSnapshotLeakWarning(Snapshot snapshot)
{
- elog(WARNING,
- "Snapshot reference leak: Snapshot %p still referenced",
+ elog(WARNING, "Snapshot reference leak: Snapshot %p still referenced",
snapshot);
}
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;
- }
+ ResourceArrayEnlarge(&(owner->filearr));
}
/*
void
ResourceOwnerRememberFile(ResourceOwner owner, File file)
{
- Assert(owner->nfiles < owner->maxfiles);
- owner->files[owner->nfiles] = file;
- owner->nfiles++;
+ ResourceArrayAdd(&(owner->filearr), FileGetDatum(file));
}
/*
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);
+ if (!ResourceArrayRemove(&(owner->filearr), FileGetDatum(file)))
+ elog(ERROR, "temporary 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",
+ elog(WARNING, "temporary file leak: File %d still referenced",
file);
}
void
ResourceOwnerEnlargeDSMs(ResourceOwner owner)
{
- int newmax;
-
- 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;
- }
+ ResourceArrayEnlarge(&(owner->dsmarr));
}
/*
void
ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
{
- Assert(owner->ndsms < owner->maxdsms);
- owner->dsms[owner->ndsms] = seg;
- owner->ndsms++;
+ ResourceArrayAdd(&(owner->dsmarr), PointerGetDatum(seg));
}
/*
void
ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg)
{
- dsm_segment **dsms = owner->dsms;
- int ns1 = owner->ndsms - 1;
- int i;
-
- 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);
+ if (!ResourceArrayRemove(&(owner->dsmarr), PointerGetDatum(seg)))
+ elog(ERROR, "dynamic shared memory segment %u is not owned by resource owner %s",
+ dsm_segment_handle(seg), owner->name);
}
-
/*
* Debugging subroutine
*/
static void
PrintDSMLeakWarning(dsm_segment *seg)
{
- elog(WARNING,
- "dynamic shared memory leak: segment %u still referenced",
+ elog(WARNING, "dynamic shared memory leak: segment %u still referenced",
dsm_segment_handle(seg));
}