1 /*-------------------------------------------------------------------------
4 * System catalog cache for tuples matching a key.
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.49 1999/09/18 19:07:55 tgl Exp $
12 *-------------------------------------------------------------------------
15 #include "access/genam.h"
16 #include "access/heapam.h"
17 #include "access/valid.h"
18 #include "catalog/pg_type.h"
19 #include "miscadmin.h"
20 #include "utils/builtins.h"
21 #include "utils/catcache.h"
23 static void CatCacheRemoveCTup(CatCache *cache, Dlelem *e);
24 static Index CatalogCacheComputeHashIndex(struct catcache * cacheInP);
25 static Index CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
26 Relation relation, HeapTuple tuple);
27 static void CatalogCacheInitializeCache(struct catcache * cache,
29 static long comphash(long l, char *v);
32 * variables, macros and other stuff
34 * note CCSIZE allocates 51 buckets .. one was already allocated in
35 * the catcache structure.
40 #define CACHE1_elog(a,b) elog(a,b)
41 #define CACHE2_elog(a,b,c) elog(a,b,c)
42 #define CACHE3_elog(a,b,c,d) elog(a,b,c,d)
43 #define CACHE4_elog(a,b,c,d,e) elog(a,b,c,d,e)
44 #define CACHE5_elog(a,b,c,d,e,f) elog(a,b,c,d,e,f)
45 #define CACHE6_elog(a,b,c,d,e,f,g) elog(a,b,c,d,e,f,g)
47 #define CACHE1_elog(a,b)
48 #define CACHE2_elog(a,b,c)
49 #define CACHE3_elog(a,b,c,d)
50 #define CACHE4_elog(a,b,c,d,e)
51 #define CACHE5_elog(a,b,c,d,e,f)
52 #define CACHE6_elog(a,b,c,d,e,f,g)
55 static CatCache *Caches = NULL; /* head of list of caches */
57 GlobalMemory CacheCxt; /* context in which caches are allocated */
58 /* CacheCxt is global because relcache uses it too. */
62 * EQPROC is used in CatalogCacheInitializeCache
63 * XXX this should be replaced by catalog lookups soon
66 static long eqproc[] = {
67 F_BOOLEQ, 0l, F_CHAREQ, F_NAMEEQ, 0l,
68 F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, 0l, F_TEXTEQ,
69 F_OIDEQ, 0l, 0l, 0l, F_OID8EQ
72 #define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-16]
74 /* ----------------------------------------------------------------
75 * internal support functions
76 * ----------------------------------------------------------------
78 /* --------------------------------
79 * CatalogCacheInitializeCache
80 * --------------------------------
83 #define CatalogCacheInitializeCache_DEBUG1 \
85 elog(DEBUG, "CatalogCacheInitializeCache: cache @%08lx", cache); \
87 elog(DEBUG, "CatalogCacheInitializeCache: called w/relation(inval)"); \
89 elog(DEBUG, "CatalogCacheInitializeCache: called w/relname %s", \
93 #define CatalogCacheInitializeCache_DEBUG2 \
95 if (cache->cc_key[i] > 0) { \
96 elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d, %d", \
97 i+1, cache->cc_nkeys, cache->cc_key[i], \
98 relation->rd_att->attrs[cache->cc_key[i] - 1]->attlen); \
100 elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d", \
101 i+1, cache->cc_nkeys, cache->cc_key[i]); \
106 #define CatalogCacheInitializeCache_DEBUG1
107 #define CatalogCacheInitializeCache_DEBUG2
111 CatalogCacheInitializeCache(struct catcache * cache,
114 MemoryContext oldcxt;
119 CatalogCacheInitializeCache_DEBUG1;
122 * first switch to the cache context so our allocations
123 * do not vanish at the end of a transaction
127 CacheCxt = CreateGlobalMemory("Cache");
128 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
131 * If no relation was passed we must open it to get access to
132 * its fields. If one of the other caches has already opened
133 * it we use heap_open() instead of heap_openr().
134 * XXX is that really worth the trouble of checking?
137 if (!RelationIsValid(relation))
142 * scan the caches to see if any other cache has opened the relation
145 for (cp = Caches; cp; cp = cp->cc_next)
147 if (strncmp(cp->cc_relname, cache->cc_relname, NAMEDATALEN) == 0)
149 if (cp->relationId != InvalidOid)
155 * open the relation by name or by id
159 relation = heap_open(cp->relationId, NoLock);
161 relation = heap_openr(cache->cc_relname, NoLock);
167 * initialize the cache's relation id
170 Assert(RelationIsValid(relation));
171 cache->relationId = RelationGetRelid(relation);
172 tupdesc = cache->cc_tupdesc = RelationGetDescr(relation);
174 CACHE3_elog(DEBUG, "CatalogCacheInitializeCache: relid %u, %d keys",
175 cache->relationId, cache->cc_nkeys);
178 * initialize cache's key information
181 for (i = 0; i < cache->cc_nkeys; ++i)
183 CatalogCacheInitializeCache_DEBUG2;
185 if (cache->cc_key[i] > 0)
189 * Yoiks. The implementation of the hashing code and the
190 * implementation of int28's are at loggerheads. The right
191 * thing to do is to throw out the implementation of int28's
192 * altogether; until that happens, we do the right thing here
193 * to guarantee that the hash key generator doesn't try to
194 * dereference an int2 by mistake.
197 if (tupdesc->attrs[cache->cc_key[i] - 1]->atttypid == INT28OID)
198 cache->cc_klen[i] = sizeof(short);
200 cache->cc_klen[i] = tupdesc->attrs[cache->cc_key[i] - 1]->attlen;
202 cache->cc_skey[i].sk_procedure = EQPROC(tupdesc->attrs[cache->cc_key[i] - 1]->atttypid);
204 fmgr_info(cache->cc_skey[i].sk_procedure,
205 &cache->cc_skey[i].sk_func);
206 cache->cc_skey[i].sk_nargs = cache->cc_skey[i].sk_func.fn_nargs;
208 CACHE5_elog(DEBUG, "CatalogCacheInit %s %d %d %x",
209 &relation->rd_rel->relname,
211 tupdesc->attrs[cache->cc_key[i] - 1]->attlen,
217 * close the relation if we opened it
221 heap_close(relation, NoLock);
224 * initialize index information for the cache. this
225 * should only be done once per cache.
228 if (cache->cc_indname != NULL && cache->indexId == InvalidOid)
230 if (RelationGetForm(relation)->relhasindex)
234 * If the index doesn't exist we are in trouble.
236 relation = index_openr(cache->cc_indname);
238 cache->indexId = RelationGetRelid(relation);
239 index_close(relation);
242 cache->cc_indname = NULL;
246 * return to the proper memory context
249 MemoryContextSwitchTo(oldcxt);
252 /* --------------------------------
255 * XXX temporary function
256 * --------------------------------
260 CatalogCacheSetId(CatCache *cacheInOutP, int id)
262 Assert(id == InvalidCatalogCacheId || id >= 0);
263 cacheInOutP->id = id;
270 * Compute a hash value, somehow.
272 * XXX explain algorithm here.
274 * l is length of the attribute value, v
275 * v is the attribute value ("Datum")
279 comphash(long l, char *v)
284 CACHE3_elog(DEBUG, "comphash (%d,%x)", l, v);
294 if (l == NAMEDATALEN)
298 * if it's a name, make sure that the values are null-padded.
300 * Note that this other fixed-length types can also have the same
301 * typelen so this may break them - XXX
315 /* --------------------------------
316 * CatalogCacheComputeHashIndex
317 * --------------------------------
320 CatalogCacheComputeHashIndex(struct catcache * cacheInP)
325 CACHE6_elog(DEBUG, "CatalogCacheComputeHashIndex %s %d %d %d %x",
326 cacheInP->cc_relname,
328 cacheInP->cc_klen[0],
329 cacheInP->cc_klen[1],
332 switch (cacheInP->cc_nkeys)
335 hashIndex ^= comphash(cacheInP->cc_klen[3],
336 (char *) cacheInP->cc_skey[3].sk_argument) << 9;
339 hashIndex ^= comphash(cacheInP->cc_klen[2],
340 (char *) cacheInP->cc_skey[2].sk_argument) << 6;
343 hashIndex ^= comphash(cacheInP->cc_klen[1],
344 (char *) cacheInP->cc_skey[1].sk_argument) << 3;
347 hashIndex ^= comphash(cacheInP->cc_klen[0],
348 (char *) cacheInP->cc_skey[0].sk_argument);
351 elog(FATAL, "CCComputeHashIndex: %d cc_nkeys", cacheInP->cc_nkeys);
354 hashIndex %= cacheInP->cc_size;
358 /* --------------------------------
359 * CatalogCacheComputeTupleHashIndex
360 * --------------------------------
363 CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
369 if (cacheInOutP->relationId == InvalidOid)
370 CatalogCacheInitializeCache(cacheInOutP, relation);
371 switch (cacheInOutP->cc_nkeys)
374 cacheInOutP->cc_skey[3].sk_argument =
375 (cacheInOutP->cc_key[3] == ObjectIdAttributeNumber)
376 ? (Datum) tuple->t_data->t_oid
378 cacheInOutP->cc_key[3],
379 RelationGetDescr(relation),
384 cacheInOutP->cc_skey[2].sk_argument =
385 (cacheInOutP->cc_key[2] == ObjectIdAttributeNumber)
386 ? (Datum) tuple->t_data->t_oid
388 cacheInOutP->cc_key[2],
389 RelationGetDescr(relation),
394 cacheInOutP->cc_skey[1].sk_argument =
395 (cacheInOutP->cc_key[1] == ObjectIdAttributeNumber)
396 ? (Datum) tuple->t_data->t_oid
398 cacheInOutP->cc_key[1],
399 RelationGetDescr(relation),
404 cacheInOutP->cc_skey[0].sk_argument =
405 (cacheInOutP->cc_key[0] == ObjectIdAttributeNumber)
406 ? (Datum) tuple->t_data->t_oid
408 cacheInOutP->cc_key[0],
409 RelationGetDescr(relation),
414 elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys",
415 cacheInOutP->cc_nkeys
420 return CatalogCacheComputeHashIndex(cacheInOutP);
423 /* --------------------------------
425 * --------------------------------
428 CatCacheRemoveCTup(CatCache *cache, Dlelem *elt)
435 ct = (CatCTup *) DLE_VAL(elt);
439 other_elt = ct->ct_node;
440 other_ct = (CatCTup *) DLE_VAL(other_elt);
442 DLFreeElem(other_elt);
450 /* --------------------------------
451 * CatalogCacheIdInvalidate()
453 * Invalidate a tuple given a cache id. In this case the id should always
454 * be found (whether the cache has opened its relation or not). Of course,
455 * if the cache has yet to open its relation, there will be no tuples so
457 * --------------------------------
460 CatalogCacheIdInvalidate(int cacheId, /* XXX */
467 MemoryContext oldcxt;
473 Assert(hashIndex < NCCBUCK);
474 Assert(ItemPointerIsValid(pointer));
475 CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
478 * switch to the cache context for our memory allocations
482 CacheCxt = CreateGlobalMemory("Cache");
483 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
486 * inspect every cache that could contain the tuple
489 for (ccp = Caches; ccp; ccp = ccp->cc_next)
491 if (cacheId != ccp->id)
494 * inspect the hash bucket until we find a match or exhaust
497 for (elt = DLGetHead(ccp->cc_cache[hashIndex]);
499 elt = DLGetSucc(elt))
501 ct = (CatCTup *) DLE_VAL(elt);
502 if (ItemPointerEquals(pointer, &ct->ct_tup->t_self))
507 * if we found a matching tuple, invalidate it.
513 CatCacheRemoveCTup(ccp, elt);
515 CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");
518 if (cacheId != InvalidCatalogCacheId)
523 * return to the proper memory context
526 MemoryContextSwitchTo(oldcxt);
527 /* sendpm('I', "Invalidated tuple"); */
530 /* ----------------------------------------------------------------
534 * InitIndexedSysCache
537 * RelationInvalidateCatalogCacheTuple
538 * ----------------------------------------------------------------
540 /* --------------------------------
542 * --------------------------------
547 MemoryContext oldcxt;
548 struct catcache *cache;
550 CACHE1_elog(DEBUG, "ResetSystemCache called");
553 * first switch to the cache context so our allocations
554 * do not vanish at the end of a transaction
558 CacheCxt = CreateGlobalMemory("Cache");
560 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
563 * here we purge the contents of all the caches
565 * for each system cache
566 * for each hash bucket
567 * for each tuple in hash bucket
571 for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
575 for (hash = 0; hash < NCCBUCK; hash += 1)
580 for (elt = DLGetHead(cache->cc_cache[hash]); elt; elt = nextelt)
582 nextelt = DLGetSucc(elt);
583 CatCacheRemoveCTup(cache, elt);
584 if (cache->cc_ntup < 0)
586 "ResetSystemCache: cc_ntup<0 (software error)");
589 cache->cc_ntup = 0; /* in case of WARN error above */
590 cache->busy = false; /* to recover from recursive-use error */
593 CACHE1_elog(DEBUG, "end of ResetSystemCache call");
596 * back to the old context before we return...
599 MemoryContextSwitchTo(oldcxt);
602 /* --------------------------------
603 * SystemCacheRelationFlushed
605 * This is called by RelationFlushRelation() to clear out cached information
606 * about a relation being dropped. (This could be a DROP TABLE command,
607 * or a temp table being dropped at end of transaction, or a table created
608 * during the current transaction that is being dropped because of abort.)
609 * Remove all cache entries relevant to the specified relation OID.
611 * A special case occurs when relId is itself one of the cacheable system
612 * tables --- although those'll never be dropped, they can get flushed from
613 * the relcache (VACUUM causes this, for example). In that case we need to
614 * force the next SearchSysCache() call to reinitialize the cache itself,
615 * because we have info (such as cc_tupdesc) that is pointing at the about-
616 * to-be-deleted relcache entry.
617 * --------------------------------
620 SystemCacheRelationFlushed(Oid relId)
622 struct catcache *cache;
625 * XXX Ideally we'd search the caches and just zap entries that actually
626 * refer to the indicated relation. For now, we take the brute-force
627 * approach: just flush the caches entirely.
632 * If relcache is dropping a system relation's cache entry, mark the
633 * associated cache structures invalid, so we can rebuild them from
634 * scratch (not just repopulate them) next time they are used.
636 for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
638 if (cache->relationId == relId)
639 cache->relationId = InvalidOid;
643 /* --------------------------------
644 * InitIndexedSysCache
646 * This allocates and initializes a cache for a system catalog relation.
647 * Actually, the cache is only partially initialized to avoid opening the
648 * relation. The relation will be opened and the rest of the cache
649 * structure initialized on the first access.
650 * --------------------------------
653 #define InitSysCache_DEBUG1 \
655 elog(DEBUG, "InitSysCache: rid=%u id=%d nkeys=%d size=%d\n", \
656 cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); \
657 for (i = 0; i < nkeys; i += 1) \
659 elog(DEBUG, "InitSysCache: key=%d len=%d skey=[%d %d %d %d]\n", \
660 cp->cc_key[i], cp->cc_klen[i], \
661 cp->cc_skey[i].sk_flags, \
662 cp->cc_skey[i].sk_attno, \
663 cp->cc_skey[i].sk_procedure, \
664 cp->cc_skey[i].sk_argument); \
669 #define InitSysCache_DEBUG1
673 InitSysCache(char *relname,
678 HeapTuple (*iScanfuncP) ())
682 MemoryContext oldcxt;
686 indname = (iname) ? iname : NULL;
689 * first switch to the cache context so our allocations
690 * do not vanish at the end of a transaction
694 CacheCxt = CreateGlobalMemory("Cache");
696 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
699 * allocate a new cache structure
702 cp = (CatCache *) palloc(sizeof(CatCache));
703 MemSet((char *) cp, 0, sizeof(CatCache));
706 * initialize the cache buckets (each bucket is a list header)
707 * and the LRU tuple list
713 * We can only do this optimization because the number of hash
714 * buckets never changes. Without it, we call malloc() too much.
715 * We could move this to dllist.c, but the way we do this is not
716 * dynamic/portabl, so why allow other routines to use it.
718 Dllist *cache_begin = malloc((NCCBUCK + 1) * sizeof(Dllist));
720 for (i = 0; i <= NCCBUCK; ++i)
722 cp->cc_cache[i] = &cache_begin[i];
723 cp->cc_cache[i]->dll_head = 0;
724 cp->cc_cache[i]->dll_tail = 0;
728 cp->cc_lrulist = DLNewList();
731 * Caches is the pointer to the head of the list of all the
732 * system caches. here we add the new cache to the top of the list.
735 cp->cc_next = Caches; /* list of caches (single link) */
739 * initialize the cache's relation information for the relation
740 * corresponding to this cache and initialize some of the the new
741 * cache's other internal fields.
744 cp->relationId = InvalidOid;
745 cp->indexId = InvalidOid;
746 cp->cc_relname = relname;
747 cp->cc_indname = indname;
748 cp->cc_tupdesc = (TupleDesc) NULL;
751 cp->cc_maxtup = MAXTUP;
752 cp->cc_size = NCCBUCK;
753 cp->cc_nkeys = nkeys;
754 cp->cc_iscanfunc = iScanfuncP;
757 * initialize the cache's key information
760 for (i = 0; i < nkeys; ++i)
762 cp->cc_key[i] = key[i];
764 elog(FATAL, "InitSysCache: called with 0 key[%d]", i);
767 if (key[i] != ObjectIdAttributeNumber)
768 elog(FATAL, "InitSysCache: called with %d key[%d]", key[i], i);
771 cp->cc_klen[i] = sizeof(Oid);
774 * ScanKeyEntryData and struct skey are equivalent. It
775 * looks like a move was made to obsolete struct skey, but
776 * it didn't reach this file. Someday we should clean up
777 * this code and consolidate to ScanKeyEntry - mer 10 Nov
780 ScanKeyEntryInitialize(&cp->cc_skey[i],
783 (RegProcedure) F_OIDEQ,
789 cp->cc_skey[i].sk_attno = key[i];
793 * all done. new cache is initialized. print some debugging
794 * information, if appropriate.
800 * back to the old context before we return...
803 MemoryContextSwitchTo(oldcxt);
808 /* --------------------------------
811 * This call searches a system cache for a tuple, opening the relation
812 * if necessary (the first access to a particular cache).
813 * --------------------------------
816 SearchSysCache(struct catcache * cache,
830 MemoryContext oldcxt;
836 if (cache->relationId == InvalidOid)
837 CatalogCacheInitializeCache(cache, NULL);
840 * initialize the search key information
843 cache->cc_skey[0].sk_argument = v1;
844 cache->cc_skey[1].sk_argument = v2;
845 cache->cc_skey[2].sk_argument = v3;
846 cache->cc_skey[3].sk_argument = v4;
849 * find the hash bucket in which to look for the tuple
852 hash = CatalogCacheComputeHashIndex(cache);
855 * scan the hash bucket until we find a match or exhaust our tuples
858 for (elt = DLGetHead(cache->cc_cache[hash]);
860 elt = DLGetSucc(elt))
864 ct = (CatCTup *) DLE_VAL(elt);
866 * see if the cached tuple matches our key.
867 * (should we be worried about time ranges? -cim 10/2/90)
870 HeapKeyTest(ct->ct_tup,
880 * if we found a tuple in the cache, move it to the top of the
881 * lru list, and return it. We also move it to the front of the
882 * list for its hashbucket, in order to speed subsequent searches.
883 * (The most frequently accessed elements in any hashbucket will
884 * tend to be near the front of the hashbucket's list.)
889 Dlelem *old_lru_elt = ((CatCTup *) DLE_VAL(elt))->ct_node;
891 DLMoveToFront(old_lru_elt);
895 relation = heap_open(cache->relationId, NoLock);
896 CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",
897 RelationGetRelationName(relation), hash);
898 heap_close(relation, NoLock);
899 #endif /* CACHEDEBUG */
905 * Tuple was not found in cache, so we have to try and
906 * retrieve it directly from the relation. If it's found,
907 * we add it to the cache.
909 * To guard against possible infinite recursion, we mark this cache
910 * "busy" while trying to load a new entry for it. It is OK to
911 * recursively invoke SearchSysCache for a different cache, but
912 * a recursive call for the same cache will error out. (We could
913 * store the specific key(s) being looked for, and consider only
914 * a recursive request for the same key to be an error, but this
915 * simple scheme is sufficient for now.)
921 elog(ERROR, "SearchSysCache: recursive use of cache %d", cache->id);
926 * open the relation associated with the cache
929 relation = heap_open(cache->relationId, AccessShareLock);
930 CACHE2_elog(DEBUG, "SearchSysCache(%s)",
931 RelationGetRelationName(relation));
934 * Switch to the cache memory context.
939 CacheCxt = CreateGlobalMemory("Cache");
941 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
944 * Scan the relation to find the tuple. If there's an index, and
945 * if this isn't bootstrap (initdb) time, use the index.
948 CACHE2_elog(DEBUG, "SearchSysCache: performing scan (override==%d)",
951 if ((RelationGetForm(relation))->relhasindex
952 && !IsBootstrapProcessingMode())
955 * Switch back to old memory context so memory not freed
956 * in the scan function will go away at transaction end.
960 MemoryContextSwitchTo(oldcxt);
961 Assert(cache->cc_iscanfunc);
962 switch (cache->cc_nkeys)
965 ntp = cache->cc_iscanfunc(relation, v1, v2, v3, v4);
968 ntp = cache->cc_iscanfunc(relation, v1, v2, v3);
971 ntp = cache->cc_iscanfunc(relation, v1, v2);
974 ntp = cache->cc_iscanfunc(relation, v1);
978 * Back to Cache context. If we got a tuple copy it
983 MemoryContextSwitchTo((MemoryContext) CacheCxt);
984 if (HeapTupleIsValid(ntp))
985 ntp = heap_copytuple(ntp);
992 * As above do the lookup in the callers memory
997 MemoryContextSwitchTo(oldcxt);
999 sd = heap_beginscan(relation, 0, SnapshotNow,
1000 cache->cc_nkeys, cache->cc_skey);
1002 ntp = heap_getnext(sd, 0);
1004 MemoryContextSwitchTo((MemoryContext) CacheCxt);
1006 if (HeapTupleIsValid(ntp))
1008 CACHE1_elog(DEBUG, "SearchSysCache: found tuple");
1009 ntp = heap_copytuple(ntp);
1012 MemoryContextSwitchTo(oldcxt);
1016 MemoryContextSwitchTo((MemoryContext) CacheCxt);
1019 cache->busy = false;
1022 * scan is complete. if tup is valid, we copy it and add the copy to
1026 if (HeapTupleIsValid(ntp))
1029 * allocate a new cache tuple holder, store the pointer
1030 * to the heap tuple there and initialize the list pointers.
1036 * this is a little cumbersome here because we want the Dlelem's
1037 * in both doubly linked lists to point to one another. That makes
1038 * it easier to remove something from both the cache bucket and
1039 * the lru list at the same time
1041 nct = (CatCTup *) malloc(sizeof(CatCTup));
1043 elt = DLNewElem(nct);
1044 nct2 = (CatCTup *) malloc(sizeof(CatCTup));
1046 lru_elt = DLNewElem(nct2);
1047 nct2->ct_node = elt;
1048 nct->ct_node = lru_elt;
1050 DLAddHead(cache->cc_lrulist, lru_elt);
1051 DLAddHead(cache->cc_cache[hash], elt);
1054 * If we've exceeded the desired size of this cache,
1055 * throw away the least recently used entry.
1058 if (++cache->cc_ntup > cache->cc_maxtup)
1062 elt = DLGetTail(cache->cc_lrulist);
1063 ct = (CatCTup *) DLE_VAL(elt);
1065 if (ct != nct) /* shouldn't be possible, but be safe... */
1067 CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",
1068 RelationGetRelationName(relation));
1070 CatCacheRemoveCTup(cache, elt);
1074 CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples",
1075 RelationGetRelationName(relation),
1076 cache->cc_ntup, cache->cc_maxtup);
1077 CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d",
1078 RelationGetRelationName(relation), hash);
1082 * close the relation, switch back to the original memory context
1083 * and return the tuple we found (or NULL)
1086 heap_close(relation, AccessShareLock);
1088 MemoryContextSwitchTo(oldcxt);
1092 /* --------------------------------
1093 * RelationInvalidateCatalogCacheTuple()
1095 * Invalidate a tuple from a specific relation. This call determines the
1096 * cache in question and calls CatalogCacheIdInvalidate(). It is -ok-
1097 * if the relation cannot be found, it simply means this backend has yet
1099 * --------------------------------
1102 RelationInvalidateCatalogCacheTuple(Relation relation,
1104 void (*function) (int, Index, ItemPointer))
1106 struct catcache *ccp;
1107 MemoryContext oldcxt;
1114 Assert(RelationIsValid(relation));
1115 Assert(HeapTupleIsValid(tuple));
1116 Assert(PointerIsValid(function));
1117 CACHE1_elog(DEBUG, "RelationInvalidateCatalogCacheTuple: called");
1120 * switch to the cache memory context
1124 CacheCxt = CreateGlobalMemory("Cache");
1125 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1129 * if the cache contains tuples from the specified relation
1130 * call the invalidation function on the tuples
1131 * in the proper hash bucket
1134 relationId = RelationGetRelid(relation);
1136 for (ccp = Caches; ccp; ccp = ccp->cc_next)
1138 if (relationId != ccp->relationId)
1142 /* OPT inline simplification of CatalogCacheIdInvalidate */
1143 if (!PointerIsValid(function))
1144 function = CatalogCacheIdInvalidate;
1147 (*function) (ccp->id,
1148 CatalogCacheComputeTupleHashIndex(ccp, relation, tuple),
1153 * return to the proper memory context
1156 MemoryContextSwitchTo(oldcxt);
1158 /* sendpm('I', "Invalidated tuple"); */