1 /*-------------------------------------------------------------------------
4 * System catalog cache for tuples matching a key.
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.64 2000/05/28 17:56:06 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/hash.h"
19 #include "access/heapam.h"
20 #include "access/valid.h"
21 #include "catalog/pg_operator.h"
22 #include "catalog/pg_type.h"
23 #include "catalog/catname.h"
24 #include "catalog/indexing.h"
25 #include "miscadmin.h"
26 #include "utils/builtins.h"
27 #include "utils/fmgroids.h"
28 #include "utils/catcache.h"
29 #include "utils/syscache.h"
31 static void CatCacheRemoveCTup(CatCache *cache, Dlelem *e);
32 static Index CatalogCacheComputeHashIndex(struct catcache * cacheInP);
33 static Index CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
36 static void CatalogCacheInitializeCache(struct catcache * cache,
38 static uint32 cc_hashname(NameData *n);
41 * variables, macros and other stuff
46 #define CACHE1_elog(a,b) elog(a,b)
47 #define CACHE2_elog(a,b,c) elog(a,b,c)
48 #define CACHE3_elog(a,b,c,d) elog(a,b,c,d)
49 #define CACHE4_elog(a,b,c,d,e) elog(a,b,c,d,e)
50 #define CACHE5_elog(a,b,c,d,e,f) elog(a,b,c,d,e,f)
51 #define CACHE6_elog(a,b,c,d,e,f,g) elog(a,b,c,d,e,f,g)
53 #define CACHE1_elog(a,b)
54 #define CACHE2_elog(a,b,c)
55 #define CACHE3_elog(a,b,c,d)
56 #define CACHE4_elog(a,b,c,d,e)
57 #define CACHE5_elog(a,b,c,d,e,f)
58 #define CACHE6_elog(a,b,c,d,e,f,g)
61 static CatCache *Caches = NULL; /* head of list of caches */
63 GlobalMemory CacheCxt; /* context in which caches are allocated */
65 /* CacheCxt is global because relcache uses it too. */
69 * EQPROC is used in CatalogCacheInitializeCache to find the equality
70 * functions for system types that are used as cache key fields.
71 * See also GetCCHashFunc, which should support the same set of types.
73 * XXX this should be replaced by catalog lookups,
74 * but that seems to pose considerable risk of circularity...
77 static const Oid eqproc[] = {
78 F_BOOLEQ, InvalidOid, F_CHAREQ, F_NAMEEQ, InvalidOid,
79 F_INT2EQ, F_INT2VECTOREQ, F_INT4EQ, F_OIDEQ, F_TEXTEQ,
80 F_OIDEQ, InvalidOid, InvalidOid, InvalidOid, F_OIDVECTOREQ
83 #define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-BOOLOID]
85 /* ----------------------------------------------------------------
86 * internal support functions
87 * ----------------------------------------------------------------
91 GetCCHashFunc(Oid keytype)
97 return (CCHashFunc) hashchar;
99 return (CCHashFunc) cc_hashname;
101 return (CCHashFunc) hashint2;
103 return (CCHashFunc) hashint2vector;
105 return (CCHashFunc) hashint4;
107 return (CCHashFunc) hashtext;
110 return (CCHashFunc) hashoid;
112 return (CCHashFunc) hashoidvector;
114 elog(FATAL, "GetCCHashFunc: type %u unsupported as catcache key",
121 cc_hashname(NameData *n)
125 * We need our own variant of hashname because we want to accept
126 * null-terminated C strings as search values for name fields. So, we
127 * have to make sure the data is correctly padded before we compute
132 namestrcpy(&my_n, NameStr(*n));
134 return hashname(&my_n);
138 /* --------------------------------
139 * CatalogCacheInitializeCache
140 * --------------------------------
143 #define CatalogCacheInitializeCache_DEBUG1 \
145 elog(DEBUG, "CatalogCacheInitializeCache: cache @%08lx", cache); \
147 elog(DEBUG, "CatalogCacheInitializeCache: called w/relation(inval)"); \
149 elog(DEBUG, "CatalogCacheInitializeCache: called w/relname %s", \
153 #define CatalogCacheInitializeCache_DEBUG2 \
155 if (cache->cc_key[i] > 0) { \
156 elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d, %d", \
157 i+1, cache->cc_nkeys, cache->cc_key[i], \
158 relation->rd_att->attrs[cache->cc_key[i] - 1]->attlen); \
160 elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d", \
161 i+1, cache->cc_nkeys, cache->cc_key[i]); \
166 #define CatalogCacheInitializeCache_DEBUG1
167 #define CatalogCacheInitializeCache_DEBUG2
171 CatalogCacheInitializeCache(struct catcache * cache,
174 MemoryContext oldcxt;
179 CatalogCacheInitializeCache_DEBUG1;
182 * first switch to the cache context so our allocations
183 * do not vanish at the end of a transaction
187 CacheCxt = CreateGlobalMemory("Cache");
188 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
191 * If no relation was passed we must open it to get access to
192 * its fields. If one of the other caches has already opened
193 * it we use heap_open() instead of heap_openr().
194 * XXX is that really worth the trouble of checking?
197 if (!RelationIsValid(relation))
202 * scan the caches to see if any other cache has opened the relation
205 for (cp = Caches; cp; cp = cp->cc_next)
207 if (strncmp(cp->cc_relname, cache->cc_relname, NAMEDATALEN) == 0)
209 if (cp->relationId != InvalidOid)
215 * open the relation by name or by id
219 relation = heap_open(cp->relationId, NoLock);
221 relation = heap_openr(cache->cc_relname, NoLock);
227 * initialize the cache's relation id and tuple descriptor
230 Assert(RelationIsValid(relation));
231 cache->relationId = RelationGetRelid(relation);
232 tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(relation));
233 cache->cc_tupdesc = tupdesc;
235 CACHE3_elog(DEBUG, "CatalogCacheInitializeCache: relid %u, %d keys",
236 cache->relationId, cache->cc_nkeys);
239 * initialize cache's key information
242 for (i = 0; i < cache->cc_nkeys; ++i)
244 CatalogCacheInitializeCache_DEBUG2;
246 if (cache->cc_key[i] > 0)
248 Oid keytype = tupdesc->attrs[cache->cc_key[i] - 1]->atttypid;
250 cache->cc_hashfunc[i] = GetCCHashFunc(keytype);
253 * If GetCCHashFunc liked the type, safe to index into
256 cache->cc_skey[i].sk_procedure = EQPROC(keytype);
258 fmgr_info(cache->cc_skey[i].sk_procedure,
259 &cache->cc_skey[i].sk_func);
260 cache->cc_skey[i].sk_nargs = cache->cc_skey[i].sk_func.fn_nargs;
262 CACHE4_elog(DEBUG, "CatalogCacheInit %s %d %x",
263 RelationGetRelationName(relation),
270 * close the relation if we opened it
274 heap_close(relation, NoLock);
277 * initialize index information for the cache. this
278 * should only be done once per cache.
281 if (cache->cc_indname != NULL && cache->indexId == InvalidOid)
283 if (!IsIgnoringSystemIndexes() && RelationGetForm(relation)->relhasindex)
287 * If the index doesn't exist we are in trouble.
289 relation = index_openr(cache->cc_indname);
291 cache->indexId = RelationGetRelid(relation);
292 index_close(relation);
295 cache->cc_indname = NULL;
299 * return to the proper memory context
302 MemoryContextSwitchTo(oldcxt);
305 /* --------------------------------
306 * CatalogCacheComputeHashIndex
307 * --------------------------------
310 CatalogCacheComputeHashIndex(struct catcache * cacheInP)
312 uint32 hashIndex = 0;
314 CACHE4_elog(DEBUG, "CatalogCacheComputeHashIndex %s %d %x",
315 cacheInP->cc_relname,
319 switch (cacheInP->cc_nkeys)
323 (*cacheInP->cc_hashfunc[3]) (cacheInP->cc_skey[3].sk_argument) << 9;
327 (*cacheInP->cc_hashfunc[2]) (cacheInP->cc_skey[2].sk_argument) << 6;
331 (*cacheInP->cc_hashfunc[1]) (cacheInP->cc_skey[1].sk_argument) << 3;
335 (*cacheInP->cc_hashfunc[0]) (cacheInP->cc_skey[0].sk_argument);
338 elog(FATAL, "CCComputeHashIndex: %d cc_nkeys", cacheInP->cc_nkeys);
341 hashIndex %= (uint32) cacheInP->cc_size;
342 return (Index) hashIndex;
345 /* --------------------------------
346 * CatalogCacheComputeTupleHashIndex
347 * --------------------------------
350 CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
356 /* XXX is this really needed? */
357 if (cacheInOutP->relationId == InvalidOid)
358 CatalogCacheInitializeCache(cacheInOutP, relation);
360 switch (cacheInOutP->cc_nkeys)
363 cacheInOutP->cc_skey[3].sk_argument =
364 (cacheInOutP->cc_key[3] == ObjectIdAttributeNumber)
365 ? (Datum) tuple->t_data->t_oid
367 cacheInOutP->cc_key[3],
368 RelationGetDescr(relation),
373 cacheInOutP->cc_skey[2].sk_argument =
374 (cacheInOutP->cc_key[2] == ObjectIdAttributeNumber)
375 ? (Datum) tuple->t_data->t_oid
377 cacheInOutP->cc_key[2],
378 RelationGetDescr(relation),
383 cacheInOutP->cc_skey[1].sk_argument =
384 (cacheInOutP->cc_key[1] == ObjectIdAttributeNumber)
385 ? (Datum) tuple->t_data->t_oid
387 cacheInOutP->cc_key[1],
388 RelationGetDescr(relation),
393 cacheInOutP->cc_skey[0].sk_argument =
394 (cacheInOutP->cc_key[0] == ObjectIdAttributeNumber)
395 ? (Datum) tuple->t_data->t_oid
397 cacheInOutP->cc_key[0],
398 RelationGetDescr(relation),
403 elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys",
404 cacheInOutP->cc_nkeys);
408 return CatalogCacheComputeHashIndex(cacheInOutP);
411 /* --------------------------------
414 * NB: assumes caller has switched to CacheCxt
415 * --------------------------------
418 CatCacheRemoveCTup(CatCache *cache, Dlelem *elt)
424 if (!elt) /* probably-useless safety check */
427 /* We need to zap both linked-list elements as well as the tuple */
429 ct = (CatCTup *) DLE_VAL(elt);
430 other_elt = ct->ct_node;
431 other_ct = (CatCTup *) DLE_VAL(other_elt);
433 heap_freetuple(ct->ct_tup);
436 DLFreeElem(other_elt);
445 /* --------------------------------
446 * CatalogCacheIdInvalidate()
448 * Invalidate a tuple given a cache id. In this case the id should always
449 * be found (whether the cache has opened its relation or not). Of course,
450 * if the cache has yet to open its relation, there will be no tuples so
452 * --------------------------------
455 CatalogCacheIdInvalidate(int cacheId, /* XXX */
462 MemoryContext oldcxt;
468 Assert(hashIndex < NCCBUCK);
469 Assert(ItemPointerIsValid(pointer));
470 CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
473 * switch to the cache context for our memory allocations
477 CacheCxt = CreateGlobalMemory("Cache");
478 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
481 * inspect every cache that could contain the tuple
484 for (ccp = Caches; ccp; ccp = ccp->cc_next)
486 if (cacheId != ccp->id)
489 * inspect the hash bucket until we find a match or exhaust
492 for (elt = DLGetHead(ccp->cc_cache[hashIndex]);
494 elt = DLGetSucc(elt))
496 ct = (CatCTup *) DLE_VAL(elt);
497 if (ItemPointerEquals(pointer, &ct->ct_tup->t_self))
502 * if we found a matching tuple, invalidate it.
508 CatCacheRemoveCTup(ccp, elt);
510 CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");
513 if (cacheId != InvalidCatalogCacheId)
518 * return to the proper memory context
521 MemoryContextSwitchTo(oldcxt);
524 /* ----------------------------------------------------------------
528 * InitIndexedSysCache
531 * RelationInvalidateCatalogCacheTuple
532 * ----------------------------------------------------------------
534 /* --------------------------------
536 * --------------------------------
541 MemoryContext oldcxt;
542 struct catcache *cache;
544 CACHE1_elog(DEBUG, "ResetSystemCache called");
547 * first switch to the cache context so our allocations
548 * do not vanish at the end of a transaction
552 CacheCxt = CreateGlobalMemory("Cache");
554 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
557 * here we purge the contents of all the caches
559 * for each system cache
560 * for each hash bucket
561 * for each tuple in hash bucket
565 for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
569 for (hash = 0; hash < NCCBUCK; hash += 1)
574 for (elt = DLGetHead(cache->cc_cache[hash]); elt; elt = nextelt)
576 nextelt = DLGetSucc(elt);
577 CatCacheRemoveCTup(cache, elt);
578 if (cache->cc_ntup < 0)
580 "ResetSystemCache: cc_ntup<0 (software error)");
583 cache->cc_ntup = 0; /* in case of WARN error above */
584 cache->busy = false; /* to recover from recursive-use error */
587 CACHE1_elog(DEBUG, "end of ResetSystemCache call");
590 * back to the old context before we return...
593 MemoryContextSwitchTo(oldcxt);
596 /* --------------------------------
597 * SystemCacheRelationFlushed
599 * This is called by RelationFlushRelation() to clear out cached information
600 * about a relation being dropped. (This could be a DROP TABLE command,
601 * or a temp table being dropped at end of transaction, or a table created
602 * during the current transaction that is being dropped because of abort.)
603 * Remove all cache entries relevant to the specified relation OID.
605 * A special case occurs when relId is itself one of the cacheable system
606 * tables --- although those'll never be dropped, they can get flushed from
607 * the relcache (VACUUM causes this, for example). In that case we need
608 * to flush all cache entries from that table. The brute-force method
609 * currently used takes care of that quite handily. (At one point we
610 * also tried to force re-execution of CatalogCacheInitializeCache for
611 * the cache(s) on that table. This is a bad idea since it leads to all
612 * kinds of trouble if a cache flush occurs while loading cache entries.
613 * We now avoid the need to do it by copying cc_tupdesc out of the relcache,
614 * rather than relying on the relcache to keep a tupdesc for us. Of course
615 * this assumes the tupdesc of a cachable system table will not change...)
616 * --------------------------------
619 SystemCacheRelationFlushed(Oid relId)
623 * XXX Ideally we'd search the caches and just zap entries that
624 * actually refer to or come from the indicated relation. For now, we
625 * take the brute-force approach: just flush the caches entirely.
630 /* --------------------------------
631 * InitIndexedSysCache
633 * This allocates and initializes a cache for a system catalog relation.
634 * Actually, the cache is only partially initialized to avoid opening the
635 * relation. The relation will be opened and the rest of the cache
636 * structure initialized on the first access.
637 * --------------------------------
640 #define InitSysCache_DEBUG1 \
642 elog(DEBUG, "InitSysCache: rid=%u id=%d nkeys=%d size=%d\n", \
643 cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); \
644 for (i = 0; i < nkeys; i += 1) \
646 elog(DEBUG, "InitSysCache: key=%d skey=[%d %d %d %d]\n", \
648 cp->cc_skey[i].sk_flags, \
649 cp->cc_skey[i].sk_attno, \
650 cp->cc_skey[i].sk_procedure, \
651 cp->cc_skey[i].sk_argument); \
656 #define InitSysCache_DEBUG1
660 InitSysCache(char *relname,
665 HeapTuple (*iScanfuncP) ())
669 MemoryContext oldcxt;
673 indname = (iname) ? iname : NULL;
676 * first switch to the cache context so our allocations
677 * do not vanish at the end of a transaction
681 CacheCxt = CreateGlobalMemory("Cache");
683 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
686 * allocate a new cache structure
689 cp = (CatCache *) palloc(sizeof(CatCache));
690 MemSet((char *) cp, 0, sizeof(CatCache));
693 * initialize the cache buckets (each bucket is a list header)
694 * and the LRU tuple list
700 * We can only do this optimization because the number of hash
701 * buckets never changes. Without it, we call palloc() too much.
702 * We could move this to dllist.c, but the way we do this is not
703 * dynamic/portable, so why allow other routines to use it.
705 Dllist *cache_begin = palloc((NCCBUCK + 1) * sizeof(Dllist));
707 for (i = 0; i <= NCCBUCK; ++i)
709 cp->cc_cache[i] = &cache_begin[i];
710 cp->cc_cache[i]->dll_head = 0;
711 cp->cc_cache[i]->dll_tail = 0;
715 cp->cc_lrulist = DLNewList();
718 * Caches is the pointer to the head of the list of all the
719 * system caches. here we add the new cache to the top of the list.
722 cp->cc_next = Caches; /* list of caches (single link) */
726 * initialize the cache's relation information for the relation
727 * corresponding to this cache and initialize some of the the new
728 * cache's other internal fields.
731 cp->relationId = InvalidOid;
732 cp->indexId = InvalidOid;
733 cp->cc_relname = relname;
734 cp->cc_indname = indname;
735 cp->cc_tupdesc = (TupleDesc) NULL;
738 cp->cc_maxtup = MAXTUP;
739 cp->cc_size = NCCBUCK;
740 cp->cc_nkeys = nkeys;
741 cp->cc_iscanfunc = iScanfuncP;
744 * partially initialize the cache's key information
745 * CatalogCacheInitializeCache() will do the rest
748 for (i = 0; i < nkeys; ++i)
750 cp->cc_key[i] = key[i];
752 elog(FATAL, "InitSysCache: called with 0 key[%d]", i);
755 if (key[i] != ObjectIdAttributeNumber)
756 elog(FATAL, "InitSysCache: called with %d key[%d]", key[i], i);
759 cp->cc_hashfunc[i] = GetCCHashFunc(OIDOID);
760 ScanKeyEntryInitialize(&cp->cc_skey[i],
763 (RegProcedure) F_OIDEQ,
769 cp->cc_skey[i].sk_attno = key[i];
773 * all done. new cache is initialized. print some debugging
774 * information, if appropriate.
780 * back to the old context before we return...
783 MemoryContextSwitchTo(oldcxt);
788 /* --------------------------------
789 * SearchSelfReferences
791 * This call searches for self-referencing information,
792 * which causes infinite recursion in the system catalog cache.
793 * This code short-circuits the normal index lookup for cache loads
794 * in those cases and replaces it with a heap scan.
796 * cache should already be initailized
797 * --------------------------------
800 SearchSelfReferences(struct catcache * cache)
805 if (cache->id == INDEXRELID)
807 static Oid indexSelfOid = InvalidOid;
808 static HeapTuple indexSelfTuple = NULL;
810 if (!OidIsValid(indexSelfOid))
815 /* Find oid of pg_index_indexrelid_index */
816 rel = heap_openr(RelationRelationName, AccessShareLock);
817 ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname,
818 F_NAMEEQ, PointerGetDatum(IndexRelidIndex));
819 sd = heap_beginscan(rel, false, SnapshotNow, 1, &key);
820 ntp = heap_getnext(sd, 0);
821 if (!HeapTupleIsValid(ntp))
822 elog(ERROR, "SearchSelfReferences: %s not found in %s",
823 IndexRelidIndex, RelationRelationName);
824 indexSelfOid = ntp->t_data->t_oid;
826 heap_close(rel, AccessShareLock);
828 /* Looking for something other than pg_index_indexrelid_index? */
829 if ((Oid) cache->cc_skey[0].sk_argument != indexSelfOid)
830 return (HeapTuple) 0;
832 /* Do we need to load our private copy of the tuple? */
833 if (!HeapTupleIsValid(indexSelfTuple))
836 MemoryContext oldcxt;
839 CacheCxt = CreateGlobalMemory("Cache");
840 rel = heap_open(cache->relationId, AccessShareLock);
841 sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
842 ntp = heap_getnext(sd, 0);
843 if (!HeapTupleIsValid(ntp))
844 elog(ERROR, "SearchSelfReferences: tuple not found");
845 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
846 indexSelfTuple = heap_copytuple(ntp);
847 MemoryContextSwitchTo(oldcxt);
849 heap_close(rel, AccessShareLock);
851 return indexSelfTuple;
853 else if (cache->id == OPEROID)
855 /* bootstrapping this requires preloading a range of rows. bjm */
856 static HeapTuple operatorSelfTuple[MAX_OIDCMP - MIN_OIDCMP + 1];
857 Oid lookup_oid = (Oid) cache->cc_skey[0].sk_argument;
859 if (lookup_oid < MIN_OIDCMP || lookup_oid > MAX_OIDCMP)
860 return (HeapTuple) 0;
862 if (!HeapTupleIsValid(operatorSelfTuple[lookup_oid - MIN_OIDCMP]))
865 MemoryContext oldcxt;
868 CacheCxt = CreateGlobalMemory("Cache");
869 rel = heap_open(cache->relationId, AccessShareLock);
870 sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
871 ntp = heap_getnext(sd, 0);
872 if (!HeapTupleIsValid(ntp))
873 elog(ERROR, "SearchSelfReferences: tuple not found");
874 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
875 operatorSelfTuple[lookup_oid - MIN_OIDCMP] = heap_copytuple(ntp);
876 MemoryContextSwitchTo(oldcxt);
878 heap_close(rel, AccessShareLock);
880 return operatorSelfTuple[lookup_oid - MIN_OIDCMP];
883 return (HeapTuple) 0;
887 /* --------------------------------
890 * This call searches a system cache for a tuple, opening the relation
891 * if necessary (the first access to a particular cache).
892 * --------------------------------
895 SearchSysCache(struct catcache * cache,
906 HeapTuple ntp = NULL;
909 MemoryContext oldcxt;
912 * one-time startup overhead
915 if (cache->relationId == InvalidOid)
916 CatalogCacheInitializeCache(cache, NULL);
919 * initialize the search key information
922 cache->cc_skey[0].sk_argument = v1;
923 cache->cc_skey[1].sk_argument = v2;
924 cache->cc_skey[2].sk_argument = v3;
925 cache->cc_skey[3].sk_argument = v4;
928 * resolve self referencing informtion
930 if ((ntp = SearchSelfReferences(cache)))
934 * find the hash bucket in which to look for the tuple
937 hash = CatalogCacheComputeHashIndex(cache);
940 * scan the hash bucket until we find a match or exhaust our tuples
943 for (elt = DLGetHead(cache->cc_cache[hash]);
945 elt = DLGetSucc(elt))
949 ct = (CatCTup *) DLE_VAL(elt);
951 * see if the cached tuple matches our key.
952 * (should we be worried about time ranges? -cim 10/2/90)
955 HeapKeyTest(ct->ct_tup,
965 * if we found a tuple in the cache, move it to the top of the
966 * lru list, and return it. We also move it to the front of the
967 * list for its hashbucket, in order to speed subsequent searches.
968 * (The most frequently accessed elements in any hashbucket will
969 * tend to be near the front of the hashbucket's list.)
974 Dlelem *old_lru_elt = ((CatCTup *) DLE_VAL(elt))->ct_node;
976 DLMoveToFront(old_lru_elt);
980 CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",
981 cache->cc_relname, hash);
982 #endif /* CACHEDEBUG */
988 * Tuple was not found in cache, so we have to try and
989 * retrieve it directly from the relation. If it's found,
990 * we add it to the cache.
992 * To guard against possible infinite recursion, we mark this cache
993 * "busy" while trying to load a new entry for it. It is OK to
994 * recursively invoke SearchSysCache for a different cache, but
995 * a recursive call for the same cache will error out. (We could
996 * store the specific key(s) being looked for, and consider only
997 * a recursive request for the same key to be an error, but this
998 * simple scheme is sufficient for now.)
1003 elog(ERROR, "SearchSysCache: recursive use of cache %d", cache->id);
1007 * open the relation associated with the cache
1010 relation = heap_open(cache->relationId, AccessShareLock);
1011 CACHE2_elog(DEBUG, "SearchSysCache(%s)",
1012 RelationGetRelationName(relation));
1015 * Switch to the cache memory context.
1020 CacheCxt = CreateGlobalMemory("Cache");
1022 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1025 * Scan the relation to find the tuple. If there's an index, and
1026 * if this isn't bootstrap (initdb) time, use the index.
1029 CACHE1_elog(DEBUG, "SearchSysCache: performing scan");
1031 if ((RelationGetForm(relation))->relhasindex
1032 && !IsIgnoringSystemIndexes())
1035 * Switch back to old memory context so memory not freed
1036 * in the scan function will go away at transaction end.
1037 * wieck - 10/18/1996
1042 MemoryContextSwitchTo(oldcxt);
1043 Assert(cache->cc_iscanfunc);
1044 switch (cache->cc_nkeys)
1047 indextp = cache->cc_iscanfunc(relation, v1, v2, v3, v4);
1050 indextp = cache->cc_iscanfunc(relation, v1, v2, v3);
1053 indextp = cache->cc_iscanfunc(relation, v1, v2);
1056 indextp = cache->cc_iscanfunc(relation, v1);
1063 * Back to Cache context. If we got a tuple copy it
1064 * into our context. wieck - 10/18/1996
1065 * And free the tuple that was allocated in the
1066 * transaction's context. tgl - 02/03/2000
1069 if (HeapTupleIsValid(indextp))
1071 MemoryContextSwitchTo((MemoryContext) CacheCxt);
1072 ntp = heap_copytuple(indextp);
1073 MemoryContextSwitchTo(oldcxt);
1074 heap_freetuple(indextp);
1076 MemoryContextSwitchTo((MemoryContext) CacheCxt);
1083 * As above do the lookup in the callers memory
1085 * wieck - 10/18/1996
1088 MemoryContextSwitchTo(oldcxt);
1090 sd = heap_beginscan(relation, 0, SnapshotNow,
1091 cache->cc_nkeys, cache->cc_skey);
1093 ntp = heap_getnext(sd, 0);
1095 MemoryContextSwitchTo((MemoryContext) CacheCxt);
1097 if (HeapTupleIsValid(ntp))
1099 CACHE1_elog(DEBUG, "SearchSysCache: found tuple");
1100 ntp = heap_copytuple(ntp);
1101 /* We should not free the result of heap_getnext... */
1104 MemoryContextSwitchTo(oldcxt);
1108 MemoryContextSwitchTo((MemoryContext) CacheCxt);
1111 cache->busy = false;
1114 * scan is complete. if tup is valid, we can add it to the cache.
1115 * note we have already copied it into the cache memory context.
1118 if (HeapTupleIsValid(ntp))
1121 * allocate a new cache tuple holder, store the pointer
1122 * to the heap tuple there and initialize the list pointers.
1128 * this is a little cumbersome here because we want the Dlelem's
1129 * in both doubly linked lists to point to one another. That makes
1130 * it easier to remove something from both the cache bucket and
1131 * the lru list at the same time
1133 nct = (CatCTup *) palloc(sizeof(CatCTup));
1135 elt = DLNewElem(nct);
1136 nct2 = (CatCTup *) palloc(sizeof(CatCTup));
1138 lru_elt = DLNewElem(nct2);
1139 nct2->ct_node = elt;
1140 nct->ct_node = lru_elt;
1142 DLAddHead(cache->cc_lrulist, lru_elt);
1143 DLAddHead(cache->cc_cache[hash], elt);
1146 * If we've exceeded the desired size of this cache,
1147 * throw away the least recently used entry.
1150 if (++cache->cc_ntup > cache->cc_maxtup)
1154 elt = DLGetTail(cache->cc_lrulist);
1155 ct = (CatCTup *) DLE_VAL(elt);
1157 if (ct != nct) /* shouldn't be possible, but be safe... */
1159 CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",
1160 RelationGetRelationName(relation));
1162 CatCacheRemoveCTup(cache, elt);
1166 CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples",
1167 RelationGetRelationName(relation),
1168 cache->cc_ntup, cache->cc_maxtup);
1169 CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d",
1170 RelationGetRelationName(relation), hash);
1174 * close the relation, switch back to the original memory context
1175 * and return the tuple we found (or NULL)
1178 heap_close(relation, AccessShareLock);
1180 MemoryContextSwitchTo(oldcxt);
1185 /* --------------------------------
1186 * RelationInvalidateCatalogCacheTuple()
1188 * Invalidate a tuple from a specific relation. This call determines the
1189 * cache in question and calls CatalogCacheIdInvalidate(). It is -ok-
1190 * if the relation cannot be found, it simply means this backend has yet
1192 * --------------------------------
1195 RelationInvalidateCatalogCacheTuple(Relation relation,
1197 void (*function) (int, Index, ItemPointer))
1199 struct catcache *ccp;
1200 MemoryContext oldcxt;
1207 Assert(RelationIsValid(relation));
1208 Assert(HeapTupleIsValid(tuple));
1209 Assert(PointerIsValid(function));
1210 CACHE1_elog(DEBUG, "RelationInvalidateCatalogCacheTuple: called");
1213 * switch to the cache memory context
1217 CacheCxt = CreateGlobalMemory("Cache");
1218 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
1222 * if the cache contains tuples from the specified relation
1223 * call the invalidation function on the tuples
1224 * in the proper hash bucket
1227 relationId = RelationGetRelid(relation);
1229 for (ccp = Caches; ccp; ccp = ccp->cc_next)
1231 if (relationId != ccp->relationId)
1235 /* OPT inline simplification of CatalogCacheIdInvalidate */
1236 if (!PointerIsValid(function))
1237 function = CatalogCacheIdInvalidate;
1240 (*function) (ccp->id,
1241 CatalogCacheComputeTupleHashIndex(ccp, relation, tuple),
1246 * return to the proper memory context
1249 MemoryContextSwitchTo(oldcxt);
1251 /* sendpm('I', "Invalidated tuple"); */