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.23 1998/02/23 17:43:19 scrappy Exp $
13 * XXX This needs to use exception.h to handle recovery when
14 * an abort occurs during DisableCache.
16 *-------------------------------------------------------------------------
20 #include "access/heapam.h"
21 #include "access/genam.h"
22 #include "utils/tqual.h"
23 #include "utils/builtins.h"
24 #include "utils/portal.h"
25 #include "utils/catcache.h"
26 #include "utils/elog.h"
27 #include "utils/palloc.h"
28 #include "utils/mcxt.h"
29 #include "utils/rel.h"
30 #include "storage/bufpage.h"
31 #include "access/valid.h"
32 #include "miscadmin.h"
33 #include "fmgr.h" /* for F_BOOLEQ, etc. DANGER */
34 #include "catalog/pg_type.h" /* for OID of int28 type */
35 #include "lib/dllist.h"
37 static void CatCacheRemoveCTup(CatCache *cache, Dlelem *e);
38 static Index CatalogCacheComputeHashIndex(struct catcache * cacheInP);
40 CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
41 Relation relation, HeapTuple tuple);
43 CatalogCacheInitializeCache(struct catcache * cache,
45 static long comphash(long l, char *v);
48 * variables, macros and other stuff
50 * note CCSIZE allocates 51 buckets .. one was already allocated in
51 * the catcache structure.
56 #define CACHE1_elog(a,b) elog(a,b)
57 #define CACHE2_elog(a,b,c) elog(a,b,c)
58 #define CACHE3_elog(a,b,c,d) elog(a,b,c,d)
59 #define CACHE4_elog(a,b,c,d,e) elog(a,b,c,d,e)
60 #define CACHE5_elog(a,b,c,d,e,f) elog(a,b,c,d,e,f)
61 #define CACHE6_elog(a,b,c,d,e,f,g) elog(a,b,c,d,e,f,g)
63 #define CACHE1_elog(a,b)
64 #define CACHE2_elog(a,b,c)
65 #define CACHE3_elog(a,b,c,d)
66 #define CACHE4_elog(a,b,c,d,e)
67 #define CACHE5_elog(a,b,c,d,e,f)
68 #define CACHE6_elog(a,b,c,d,e,f,g)
71 CatCache *Caches = NULL;
72 GlobalMemory CacheCxt;
74 static int DisableCache;
77 * EQPROC is used in CatalogCacheInitializeCache
78 * XXX this should be replaced by catalog lookups soon
81 static long eqproc[] = {
82 F_BOOLEQ, 0l, F_CHAREQ, F_CHAR16EQ, 0l,
83 F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, 0l, F_TEXTEQ,
84 F_OIDEQ, 0l, 0l, 0l, F_OID8EQ
87 #define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-16]
89 /* ----------------------------------------------------------------
90 * internal support functions
91 * ----------------------------------------------------------------
93 /* --------------------------------
94 * CatalogCacheInitializeCache
95 * --------------------------------
98 #define CatalogCacheInitializeCache_DEBUG1 \
99 elog(DEBUG, "CatalogCacheInitializeCache: cache @%08lx", cache); \
101 elog(DEBUG, "CatalogCacheInitializeCache: called w/relation(inval)"); \
103 elog(DEBUG, "CatalogCacheInitializeCache: called w/relname %s", \
105 #define CatalogCacheInitializeCache_DEBUG2 \
106 if (cache->cc_key[i] > 0) { \
107 elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d, %d", \
108 i+1, cache->cc_nkeys, cache->cc_key[i], \
109 relation->rd_att->attrs[cache->cc_key[i] - 1]->attlen); \
111 elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d", \
112 i+1, cache->cc_nkeys, cache->cc_key[i]); \
115 #define CatalogCacheInitializeCache_DEBUG1
116 #define CatalogCacheInitializeCache_DEBUG2
120 CatalogCacheInitializeCache(struct catcache * cache,
123 MemoryContext oldcxt;
128 CatalogCacheInitializeCache_DEBUG1;
131 * first switch to the cache context so our allocations
132 * do not vanish at the end of a transaction
136 CacheCxt = CreateGlobalMemory("Cache");
137 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
140 * If no relation was passed we must open it to get access to
141 * its fields. If one of the other caches has already opened
142 * it we use heap_open() instead of heap_openr()
145 if (!RelationIsValid(relation))
150 * scan the caches to see if any other cache has opened the relation
153 for (cp = Caches; cp; cp = cp->cc_next)
155 if (strncmp(cp->cc_relname, cache->cc_relname, NAMEDATALEN) == 0)
157 if (cp->relationId != InvalidOid)
163 * open the relation by name or by id
167 relation = heap_open(cp->relationId);
170 relation = heap_openr(cache->cc_relname);
177 * initialize the cache's relation id
180 Assert(RelationIsValid(relation));
181 cache->relationId = RelationGetRelationId(relation);
182 tupdesc = cache->cc_tupdesc = RelationGetTupleDescriptor(relation);
184 CACHE3_elog(DEBUG, "CatalogCacheInitializeCache: relid %d, %d keys",
185 cache->relationId, cache->cc_nkeys);
188 * initialize cache's key information
191 for (i = 0; i < cache->cc_nkeys; ++i)
193 CatalogCacheInitializeCache_DEBUG2;
195 if (cache->cc_key[i] > 0)
199 * Yoiks. The implementation of the hashing code and the
200 * implementation of int28's are at loggerheads. The right
201 * thing to do is to throw out the implementation of int28's
202 * altogether; until that happens, we do the right thing here
203 * to guarantee that the hash key generator doesn't try to
204 * dereference an int2 by mistake.
207 if (tupdesc->attrs[cache->cc_key[i] - 1]->atttypid == INT28OID)
208 cache->cc_klen[i] = sizeof(short);
210 cache->cc_klen[i] = tupdesc->attrs[cache->cc_key[i] - 1]->attlen;
212 cache->cc_skey[i].sk_procedure =
213 EQPROC(tupdesc->attrs[cache->cc_key[i] - 1]->atttypid);
215 fmgr_info(cache->cc_skey[i].sk_procedure,
216 &cache->cc_skey[i].sk_func);
217 cache->cc_skey[i].sk_nargs = cache->cc_skey[i].sk_func.fn_nargs;
219 CACHE5_elog(DEBUG, "CatalogCacheInit %16s %d %d %x",
220 &relation->rd_rel->relname,
222 tupdesc->attrs[cache->cc_key[i] - 1]->attlen,
228 * close the relation if we opened it
232 heap_close(relation);
235 * initialize index information for the cache. this
236 * should only be done once per cache.
239 if (cache->cc_indname != NULL && cache->indexId == InvalidOid)
241 if (RelationGetRelationTupleForm(relation)->relhasindex)
245 * If the index doesn't exist we are in trouble.
247 relation = index_openr(cache->cc_indname);
249 cache->indexId = RelationGetRelationId(relation);
250 index_close(relation);
253 cache->cc_indname = NULL;
257 * return to the proper memory context
260 MemoryContextSwitchTo(oldcxt);
263 /* --------------------------------
266 * XXX temporary function
267 * --------------------------------
271 CatalogCacheSetId(CatCache *cacheInOutP, int id)
273 Assert(id == InvalidCatalogCacheId || id >= 0);
274 cacheInOutP->id = id;
281 * Compute a hash value, somehow.
283 * XXX explain algorithm here.
285 * l is length of the attribute value, v
286 * v is the attribute value ("Datum")
290 comphash(long l, char *v)
295 CACHE3_elog(DEBUG, "comphash (%d,%x)", l, v);
305 if (l == NAMEDATALEN)
309 * if it's a name, make sure that the values are null-padded.
311 * Note that this other fixed-length types can also have the same
312 * typelen so this may break them - XXX
328 /* --------------------------------
329 * CatalogCacheComputeHashIndex
330 * --------------------------------
333 CatalogCacheComputeHashIndex(struct catcache * cacheInP)
338 CACHE6_elog(DEBUG, "CatalogCacheComputeHashIndex %s %d %d %d %x",
339 cacheInP->cc_relname,
341 cacheInP->cc_klen[0],
342 cacheInP->cc_klen[1],
345 switch (cacheInP->cc_nkeys)
348 hashIndex ^= comphash(cacheInP->cc_klen[3],
349 (char *) cacheInP->cc_skey[3].sk_argument) << 9;
352 hashIndex ^= comphash(cacheInP->cc_klen[2],
353 (char *) cacheInP->cc_skey[2].sk_argument) << 6;
356 hashIndex ^= comphash(cacheInP->cc_klen[1],
357 (char *) cacheInP->cc_skey[1].sk_argument) << 3;
360 hashIndex ^= comphash(cacheInP->cc_klen[0],
361 (char *) cacheInP->cc_skey[0].sk_argument);
364 elog(FATAL, "CCComputeHashIndex: %d cc_nkeys", cacheInP->cc_nkeys);
367 hashIndex %= cacheInP->cc_size;
371 /* --------------------------------
372 * CatalogCacheComputeTupleHashIndex
373 * --------------------------------
376 CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
382 if (cacheInOutP->relationId == InvalidOid)
383 CatalogCacheInitializeCache(cacheInOutP, relation);
384 switch (cacheInOutP->cc_nkeys)
387 cacheInOutP->cc_skey[3].sk_argument =
388 (cacheInOutP->cc_key[3] == ObjectIdAttributeNumber)
389 ? (Datum) tuple->t_oid
391 cacheInOutP->cc_key[3],
392 RelationGetTupleDescriptor(relation),
397 cacheInOutP->cc_skey[2].sk_argument =
398 (cacheInOutP->cc_key[2] == ObjectIdAttributeNumber)
399 ? (Datum) tuple->t_oid
401 cacheInOutP->cc_key[2],
402 RelationGetTupleDescriptor(relation),
407 cacheInOutP->cc_skey[1].sk_argument =
408 (cacheInOutP->cc_key[1] == ObjectIdAttributeNumber)
409 ? (Datum) tuple->t_oid
411 cacheInOutP->cc_key[1],
412 RelationGetTupleDescriptor(relation),
417 cacheInOutP->cc_skey[0].sk_argument =
418 (cacheInOutP->cc_key[0] == ObjectIdAttributeNumber)
419 ? (Datum) tuple->t_oid
421 cacheInOutP->cc_key[0],
422 RelationGetTupleDescriptor(relation),
427 elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys",
428 cacheInOutP->cc_nkeys
434 CatalogCacheComputeHashIndex(cacheInOutP);
437 /* --------------------------------
439 * --------------------------------
442 CatCacheRemoveCTup(CatCache *cache, Dlelem *elt)
449 ct = (CatCTup *) DLE_VAL(elt);
453 other_elt = ct->ct_node;
454 other_ct = (CatCTup *) DLE_VAL(other_elt);
456 DLFreeElem(other_elt);
464 /* --------------------------------
465 * CatalogCacheIdInvalidate()
467 * Invalidate a tuple given a cache id. In this case the id should always
468 * be found (whether the cache has opened its relation or not). Of course,
469 * if the cache has yet to open its relation, there will be no tuples so
471 * --------------------------------
474 CatalogCacheIdInvalidate(int cacheId, /* XXX */
481 MemoryContext oldcxt;
487 Assert(hashIndex < NCCBUCK);
488 Assert(ItemPointerIsValid(pointer));
489 CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
492 * switch to the cache context for our memory allocations
496 CacheCxt = CreateGlobalMemory("Cache");
497 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
500 * inspect every cache that could contain the tuple
503 for (ccp = Caches; ccp; ccp = ccp->cc_next)
505 if (cacheId != ccp->id)
508 * inspect the hash bucket until we find a match or exhaust
511 for (elt = DLGetHead(ccp->cc_cache[hashIndex]);
513 elt = DLGetSucc(elt))
515 ct = (CatCTup *) DLE_VAL(elt);
516 if (ItemPointerEquals(pointer, &ct->ct_tup->t_ctid))
521 * if we found a matching tuple, invalidate it.
527 CatCacheRemoveCTup(ccp, elt);
529 CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");
532 if (cacheId != InvalidCatalogCacheId)
537 * return to the proper memory context
540 MemoryContextSwitchTo(oldcxt);
541 /* sendpm('I', "Invalidated tuple"); */
544 /* ----------------------------------------------------------------
548 * InitIndexedSysCache
551 * RelationInvalidateCatalogCacheTuple
552 * ----------------------------------------------------------------
554 /* --------------------------------
556 * --------------------------------
561 MemoryContext oldcxt;
562 struct catcache *cache;
568 CACHE1_elog(DEBUG, "ResetSystemCache called");
571 elog(ERROR, "ResetSystemCache: Called while cache disabled");
576 * first switch to the cache context so our allocations
577 * do not vanish at the end of a transaction
581 CacheCxt = CreateGlobalMemory("Cache");
583 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
586 * here we purge the contents of all the caches
588 * for each system cache
589 * for each hash bucket
590 * for each tuple in hash bucket
594 for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
598 for (hash = 0; hash < NCCBUCK; hash += 1)
603 for (elt = DLGetHead(cache->cc_cache[hash]); elt; elt = nextelt)
605 nextelt = DLGetSucc(elt);
606 CatCacheRemoveCTup(cache, elt);
607 if (cache->cc_ntup == -1)
608 elog(ERROR, "ResetSystemCache: cc_ntup<0 (software error)");
611 cache->cc_ntup = 0; /* in case of WARN error above */
614 CACHE1_elog(DEBUG, "end of ResetSystemCache call");
617 * back to the old context before we return...
620 MemoryContextSwitchTo(oldcxt);
623 /* --------------------------------
624 * SystemCacheRelationFlushed
626 * RelationFlushRelation() frees some information referenced in the
627 * cache structures. So we get informed when this is done and arrange
628 * for the next SearchSysCache() call that this information is setup
630 * --------------------------------
633 SystemCacheRelationFlushed(Oid relId)
635 struct catcache *cache;
637 for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
639 if (cache->relationId == relId)
641 cache->relationId = InvalidOid;
646 /* --------------------------------
647 * InitIndexedSysCache
649 * This allocates and initializes a cache for a system catalog relation.
650 * Actually, the cache is only partially initialized to avoid opening the
651 * relation. The relation will be opened and the rest of the cache
652 * structure initialized on the first access.
653 * --------------------------------
656 #define InitSysCache_DEBUG1 \
657 elog(DEBUG, "InitSysCache: rid=%d id=%d nkeys=%d size=%d\n", \
658 cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); \
659 for (i = 0; i < nkeys; i += 1) { \
660 elog(DEBUG, "InitSysCache: key=%d len=%d skey=[%d %d %d %d]\n", \
661 cp->cc_key[i], cp->cc_klen[i], \
662 cp->cc_skey[i].sk_flags, \
663 cp->cc_skey[i].sk_attno, \
664 cp->cc_skey[i].sk_procedure, \
665 cp->cc_skey[i].sk_argument); \
668 #define InitSysCache_DEBUG1
672 InitSysCache(char *relname,
677 HeapTuple (*iScanfuncP) ())
681 MemoryContext oldcxt;
685 indname = (iname) ? iname : NULL;
688 * first switch to the cache context so our allocations
689 * do not vanish at the end of a transaction
693 CacheCxt = CreateGlobalMemory("Cache");
695 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
698 * allocate a new cache structure
701 cp = (CatCache *) palloc(sizeof(CatCache));
702 MemSet((char *) cp, 0, sizeof(CatCache));
705 * initialize the cache buckets (each bucket is a list header)
706 * and the LRU tuple list
712 * We can only do this optimization because the number of hash
713 * buckets never changes. Without it, we call malloc() too much.
714 * We could move this to dllist.c, but the way we do this is not
715 * dynamic/portabl, so why allow other routines to use it.
717 Dllist *cache_begin = malloc((NCCBUCK + 1) * sizeof(Dllist));
719 for (i = 0; i <= NCCBUCK; ++i)
721 cp->cc_cache[i] = &cache_begin[i];
722 cp->cc_cache[i]->dll_head = 0;
723 cp->cc_cache[i]->dll_tail = 0;
727 cp->cc_lrulist = DLNewList();
730 * Caches is the pointer to the head of the list of all the
731 * system caches. here we add the new cache to the top of the list.
734 cp->cc_next = Caches; /* list of caches (single link) */
738 * initialize the cache's relation information for the relation
739 * corresponding to this cache and initialize some of the the new
740 * cache's other internal fields.
743 cp->relationId = InvalidOid;
744 cp->indexId = InvalidOid;
745 cp->cc_relname = relname;
746 cp->cc_indname = indname;
747 cp->cc_tupdesc = (TupleDesc) NULL;
749 cp->cc_maxtup = MAXTUP;
750 cp->cc_size = NCCBUCK;
751 cp->cc_nkeys = nkeys;
752 cp->cc_iscanfunc = iScanfuncP;
755 * initialize the cache's key information
758 for (i = 0; i < nkeys; ++i)
760 cp->cc_key[i] = key[i];
763 elog(FATAL, "InitSysCache: called with 0 key[%d]", i);
767 if (key[i] != ObjectIdAttributeNumber)
769 elog(FATAL, "InitSysCache: called with %d key[%d]", key[i], i);
773 cp->cc_klen[i] = sizeof(Oid);
776 * ScanKeyEntryData and struct skey are equivalent. It
777 * looks like a move was made to obsolete struct skey, but
778 * it didn't reach this file. Someday we should clean up
779 * this code and consolidate to ScanKeyEntry - mer 10 Nov
782 ScanKeyEntryInitialize(&cp->cc_skey[i],
785 (RegProcedure) F_OIDEQ,
791 cp->cc_skey[i].sk_attno = key[i];
795 * all done. new cache is initialized. print some debugging
796 * information, if appropriate.
802 * back to the old context before we return...
805 MemoryContextSwitchTo(oldcxt);
810 /* --------------------------------
813 * This call searches a system cache for a tuple, opening the relation
814 * if necessary (the first access to a particular cache).
815 * --------------------------------
818 SearchSysCache(struct catcache * cache,
833 MemoryContext oldcxt;
839 if (cache->relationId == InvalidOid)
840 CatalogCacheInitializeCache(cache, NULL);
843 * initialize the search key information
846 cache->cc_skey[0].sk_argument = v1;
847 cache->cc_skey[1].sk_argument = v2;
848 cache->cc_skey[2].sk_argument = v3;
849 cache->cc_skey[3].sk_argument = v4;
852 * find the hash bucket in which to look for the tuple
855 hash = CatalogCacheComputeHashIndex(cache);
858 * scan the hash bucket until we find a match or exhaust our tuples
861 for (elt = DLGetHead(cache->cc_cache[hash]);
863 elt = DLGetSucc(elt))
867 ct = (CatCTup *) DLE_VAL(elt);
869 * see if the cached tuple matches our key.
870 * (should we be worried about time ranges? -cim 10/2/90)
873 HeapKeyTest(ct->ct_tup,
883 * if we found a tuple in the cache, move it to the top of the
884 * lru list, and return it.
891 old_lru_elt = ((CatCTup *) DLE_VAL(elt))->ct_node;
892 DLRemove(old_lru_elt);
893 DLAddHead(cache->cc_lrulist, old_lru_elt);
896 relation = heap_open(cache->relationId);
897 CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",
898 RelationGetRelationName(relation), hash);
899 heap_close(relation);
900 #endif /* CACHEDEBUG */
906 * Tuple was not found in cache, so we have to try and
907 * retrieve it directly from the relation. If it's found,
908 * we add it to the cache. We must avoid recursion here,
909 * so we disable cache operations. If operations are
910 * currently disabled and we couldn't find the requested item
911 * in the cache, then this may be a recursive request, and we
912 * abort with an error.
918 elog(ERROR, "SearchSysCache: Called while cache disabled");
919 return ((HeapTuple) NULL);
923 * open the relation associated with the cache
926 relation = heap_open(cache->relationId);
927 CACHE2_elog(DEBUG, "SearchSysCache(%s)",
928 RelationGetRelationName(relation));
931 * DisableCache and then switch to the cache memory context.
937 CacheCxt = CreateGlobalMemory("Cache");
939 oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
942 * Scan the relation to find the tuple. If there's an index, and
943 * if this isn't bootstrap (initdb) time, use the index.
946 CACHE2_elog(DEBUG, "SearchSysCache: performing scan (override==%d)",
949 if ((RelationGetRelationTupleForm(relation))->relhasindex
950 && !IsBootstrapProcessingMode())
953 * Switch back to old memory context so memory not freed
954 * in the scan function will go away at transaction end.
958 MemoryContextSwitchTo(oldcxt);
959 Assert(cache->cc_iscanfunc);
960 switch (cache->cc_nkeys)
963 ntp = cache->cc_iscanfunc(relation, v1, v2, v3, v4);
966 ntp = cache->cc_iscanfunc(relation, v1, v2, v3);
969 ntp = cache->cc_iscanfunc(relation, v1, v2);
972 ntp = cache->cc_iscanfunc(relation, v1);
976 * Back to Cache context. If we got a tuple copy it
981 MemoryContextSwitchTo((MemoryContext) CacheCxt);
982 if (HeapTupleIsValid(ntp))
984 ntp = heap_copytuple(ntp);
992 * As above do the lookup in the callers memory
997 MemoryContextSwitchTo(oldcxt);
999 sd = heap_beginscan(relation, 0, false,
1000 cache->cc_nkeys, cache->cc_skey);
1002 /* should this buffer be ReleaseBuffer'd? --djm 8/20/96 */
1003 ntp = heap_getnext(sd, 0, &buffer);
1005 MemoryContextSwitchTo((MemoryContext) CacheCxt);
1007 if (HeapTupleIsValid(ntp))
1009 CACHE1_elog(DEBUG, "SearchSysCache: found tuple");
1010 ntp = heap_copytuple(ntp);
1013 MemoryContextSwitchTo(oldcxt);
1017 MemoryContextSwitchTo((MemoryContext) CacheCxt);
1023 * scan is complete. if tup is valid, we copy it and add the copy to
1027 if (HeapTupleIsValid(ntp))
1030 * allocate a new cache tuple holder, store the pointer
1031 * to the heap tuple there and initialize the list pointers.
1037 * this is a little cumbersome here because we want the Dlelem's
1038 * in both doubly linked lists to point to one another. That makes
1039 * it easier to remove something from both the cache bucket and
1040 * the lru list at the same time
1042 nct = (CatCTup *) malloc(sizeof(CatCTup));
1044 elt = DLNewElem(nct);
1045 nct2 = (CatCTup *) malloc(sizeof(CatCTup));
1047 lru_elt = DLNewElem(nct2);
1048 nct2->ct_node = elt;
1049 nct->ct_node = lru_elt;
1051 DLAddHead(cache->cc_lrulist, lru_elt);
1052 DLAddHead(cache->cc_cache[hash], elt);
1055 * deal with hash bucket overflow
1058 if (++cache->cc_ntup > cache->cc_maxtup)
1062 elt = DLGetTail(cache->cc_lrulist);
1063 ct = (CatCTup *) DLE_VAL(elt);
1067 CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",
1068 RelationGetRelationName(relation));
1070 CatCacheRemoveCTup(cache, elt);
1075 CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples",
1076 RelationGetRelationName(relation),
1077 cache->cc_ntup, cache->cc_maxtup);
1078 CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d",
1079 RelationGetRelationName(relation), hash);
1083 * close the relation, switch back to the original memory context
1084 * and return the tuple we found (or NULL)
1087 heap_close(relation);
1089 MemoryContextSwitchTo(oldcxt);
1093 /* --------------------------------
1094 * RelationInvalidateCatalogCacheTuple()
1096 * Invalidate a tuple from a specific relation. This call determines the
1097 * cache in question and calls CatalogCacheIdInvalidate(). It is -ok-
1098 * if the relation cannot be found, it simply means this backend has yet
1100 * --------------------------------
1103 RelationInvalidateCatalogCacheTuple(Relation relation,
1105 void (*function) (int, Index, ItemPointer))
1107 struct catcache *ccp;
1108 MemoryContext oldcxt;
1115 Assert(RelationIsValid(relation));
1116 Assert(HeapTupleIsValid(tuple));
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 = RelationGetRelationId(relation);
1136 for (ccp = Caches; ccp; ccp = ccp->cc_next)
1138 if (relationId != ccp->relationId)
1141 /* OPT inline simplification of CatalogCacheIdInvalidate */
1142 if (!PointerIsValid(function))
1144 function = CatalogCacheIdInvalidate;
1147 (*function) (ccp->id,
1148 CatalogCacheComputeTupleHashIndex(ccp, relation, tuple),
1151 heap_close(relation);
1155 * return to the proper memory context
1158 MemoryContextSwitchTo(oldcxt);
1160 /* sendpm('I', "Invalidated tuple"); */