1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-02 09:02:37 +03:00

Change SearchSysCache coding conventions so that a reference count is

maintained for each cache entry.  A cache entry will not be freed until
the matching ReleaseSysCache call has been executed.  This eliminates
worries about cache entries getting dropped while still in use.  See
my posting to pg-hackers of even date for more info.
This commit is contained in:
Tom Lane
2000-11-16 22:30:52 +00:00
parent cff23842a4
commit a933ee38bb
95 changed files with 2672 additions and 2314 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.56 2000/11/10 00:33:10 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.57 2000/11/16 22:30:33 tgl Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@ -343,7 +343,7 @@ static struct cachedesc cacheinfo[] = {
};
static CatCache *SysCache[lengthof(cacheinfo)];
static int32 SysCacheSize = lengthof(cacheinfo);
static int SysCacheSize = lengthof(cacheinfo);
static bool CacheInitialized = false;
@ -354,99 +354,68 @@ IsCacheInitialized(void)
}
/*
* zerocaches
*
* Make sure the SysCache structure is zero'd.
*/
void
zerocaches()
{
MemSet((char *) SysCache, 0, SysCacheSize * sizeof(CatCache *));
}
/*
* InitCatalogCache - initialize the caches
*
* Note that no database access is done here; we only allocate memory
* and initialize the cache structure. Interrogation of the database
* to complete initialization of a cache happens only upon first use
* of that cache.
*/
void
InitCatalogCache()
InitCatalogCache(void)
{
int cacheId; /* XXX type */
int cacheId;
if (!AMI_OVERRIDE)
Assert(!CacheInitialized);
MemSet((char *) SysCache, 0, sizeof(SysCache));
for (cacheId = 0; cacheId < SysCacheSize; cacheId++)
{
for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
{
Assert(!PointerIsValid(SysCache[cacheId]));
SysCache[cacheId] = InitSysCache(cacheId,
cacheinfo[cacheId].name,
cacheinfo[cacheId].indname,
cacheinfo[cacheId].nkeys,
cacheinfo[cacheId].key);
if (!PointerIsValid(SysCache[cacheId]))
{
elog(ERROR,
"InitCatalogCache: Can't init cache %s (%d)",
cacheinfo[cacheId].name,
cacheId);
}
}
SysCache[cacheId] = InitCatCache(cacheId,
cacheinfo[cacheId].name,
cacheinfo[cacheId].indname,
cacheinfo[cacheId].nkeys,
cacheinfo[cacheId].key);
if (!PointerIsValid(SysCache[cacheId]))
elog(ERROR, "InitCatalogCache: Can't init cache %s (%d)",
cacheinfo[cacheId].name, cacheId);
}
CacheInitialized = true;
}
/*
* SearchSysCacheTuple
* SearchSysCache
*
* A layer on top of SearchSysCache that does the initialization and
* A layer on top of SearchCatCache that does the initialization and
* key-setting for you.
*
* Returns the cache copy of the tuple if one is found, NULL if not.
* The tuple is the 'cache' copy.
* The tuple is the 'cache' copy and must NOT be modified!
*
* When the caller is done using the tuple, call ReleaseSysCache()
* to release the reference count grabbed by SearchSysCache(). If this
* is not done, the tuple will remain locked in cache until end of
* transaction, which is tolerable but not desirable.
*
* CAUTION: The tuple that is returned must NOT be freed by the caller!
*
* CAUTION: The returned tuple may be flushed from the cache during
* subsequent cache lookup operations, or by shared cache invalidation.
* Callers should not expect the pointer to remain valid for long.
*
* XXX we ought to have some kind of referencecount mechanism for
* cache entries, to ensure entries aren't deleted while in use.
*/
HeapTuple
SearchSysCacheTuple(int cacheId,/* cache selection code */
Datum key1,
Datum key2,
Datum key3,
Datum key4)
SearchSysCache(int cacheId,
Datum key1,
Datum key2,
Datum key3,
Datum key4)
{
HeapTuple tp;
if (cacheId < 0 || cacheId >= SysCacheSize)
{
elog(ERROR, "SearchSysCacheTuple: Bad cache id %d", cacheId);
elog(ERROR, "SearchSysCache: Bad cache id %d", cacheId);
return (HeapTuple) NULL;
}
Assert(AMI_OVERRIDE || PointerIsValid(SysCache[cacheId]));
if (!PointerIsValid(SysCache[cacheId]))
{
SysCache[cacheId] = InitSysCache(cacheId,
cacheinfo[cacheId].name,
cacheinfo[cacheId].indname,
cacheinfo[cacheId].nkeys,
cacheinfo[cacheId].key);
if (!PointerIsValid(SysCache[cacheId]))
elog(ERROR,
"InitCatalogCache: Can't init cache %s(%d)",
cacheinfo[cacheId].name,
cacheId);
}
Assert(PointerIsValid(SysCache[cacheId]));
/*
* If someone tries to look up a relname, translate temp relation
@ -464,51 +433,75 @@ SearchSysCacheTuple(int cacheId,/* cache selection code */
key1 = CStringGetDatum(nontemp_relname);
}
tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
if (!HeapTupleIsValid(tp))
{
#ifdef CACHEDEBUG
elog(DEBUG,
"SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
cacheinfo[cacheId].name,
cacheId, key1, key2, key3, key4);
#endif
return (HeapTuple) NULL;
}
return tp;
return SearchCatCache(SysCache[cacheId], key1, key2, key3, key4);
}
/*
* SearchSysCacheTupleCopy
*
* This is like SearchSysCacheTuple, except it returns a palloc'd copy of
* the tuple. The caller should heap_freetuple() the returned copy when
* done with it. This routine should be used when the caller intends to
* continue to access the tuple for more than a very short period of time.
* ReleaseSysCache
* Release previously grabbed reference count on a tuple
*/
HeapTuple
SearchSysCacheTupleCopy(int cacheId, /* cache selection code */
Datum key1,
Datum key2,
Datum key3,
Datum key4)
void
ReleaseSysCache(HeapTuple tuple)
{
HeapTuple cachetup;
cachetup = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
if (PointerIsValid(cachetup))
return heap_copytuple(cachetup);
else
return cachetup; /* NULL */
ReleaseCatCache(tuple);
}
/*
* SearchSysCacheCopy
*
* A convenience routine that does SearchSysCache and (if successful)
* returns a modifiable copy of the syscache entry. The original
* syscache entry is released before returning. The caller should
* heap_freetuple() the result when done with it.
*/
HeapTuple
SearchSysCacheCopy(int cacheId,
Datum key1,
Datum key2,
Datum key3,
Datum key4)
{
HeapTuple tuple,
newtuple;
tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
if (!HeapTupleIsValid(tuple))
return tuple;
newtuple = heap_copytuple(tuple);
ReleaseSysCache(tuple);
return newtuple;
}
/*
* GetSysCacheOid
*
* A convenience routine that does SearchSysCache and returns the OID
* of the found tuple, or InvalidOid if no tuple could be found.
* No lock is retained on the syscache entry.
*/
Oid
GetSysCacheOid(int cacheId,
Datum key1,
Datum key2,
Datum key3,
Datum key4)
{
HeapTuple tuple;
Oid result;
tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
if (!HeapTupleIsValid(tuple))
return InvalidOid;
result = tuple->t_data->t_oid;
ReleaseSysCache(tuple);
return result;
}
/*
* SysCacheGetAttr
*
* Given a tuple previously fetched by SearchSysCacheTuple() or
* SearchSysCacheTupleCopy(), extract a specific attribute.
* Given a tuple previously fetched by SearchSysCache(),
* extract a specific attribute.
*
* This is equivalent to using heap_getattr() on a tuple fetched
* from a non-cached relation. Usually, this is only used for attributes