PostgreSQL Source Code git master
catcache.h File Reference
#include "access/htup.h"
#include "access/skey.h"
#include "lib/ilist.h"
#include "utils/relcache.h"
Include dependency graph for catcache.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  catcache
 
struct  catctup
 
struct  catclist
 
struct  catcacheheader
 

Macros

#define CATCACHE_MAXKEYS   4
 
#define CT_MAGIC   0x57261502
 
#define CL_MAGIC   0x52765103
 

Typedefs

typedef uint32(* CCHashFN) (Datum datum)
 
typedef bool(* CCFastEqualFN) (Datum a, Datum b)
 
typedef struct catcache CatCache
 
typedef struct catctup CatCTup
 
typedef struct catclist CatCList
 
typedef struct catcacheheader CatCacheHeader
 

Functions

void CreateCacheMemoryContext (void)
 
CatCacheInitCatCache (int id, Oid reloid, Oid indexoid, int nkeys, const int *key, int nbuckets)
 
void InitCatCachePhase2 (CatCache *cache, bool touch_index)
 
HeapTuple SearchCatCache (CatCache *cache, Datum v1, Datum v2, Datum v3, Datum v4)
 
HeapTuple SearchCatCache1 (CatCache *cache, Datum v1)
 
HeapTuple SearchCatCache2 (CatCache *cache, Datum v1, Datum v2)
 
HeapTuple SearchCatCache3 (CatCache *cache, Datum v1, Datum v2, Datum v3)
 
HeapTuple SearchCatCache4 (CatCache *cache, Datum v1, Datum v2, Datum v3, Datum v4)
 
void ReleaseCatCache (HeapTuple tuple)
 
uint32 GetCatCacheHashValue (CatCache *cache, Datum v1, Datum v2, Datum v3, Datum v4)
 
CatCListSearchCatCacheList (CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3)
 
void ReleaseCatCacheList (CatCList *list)
 
void ResetCatalogCaches (void)
 
void ResetCatalogCachesExt (bool debug_discard)
 
void CatalogCacheFlushCatalog (Oid catId)
 
void CatCacheInvalidate (CatCache *cache, uint32 hashValue)
 
void PrepareToInvalidateCacheTuple (Relation relation, HeapTuple tuple, HeapTuple newtuple, void(*function)(int, uint32, Oid, void *), void *context)
 

Variables

PGDLLIMPORT MemoryContext CacheMemoryContext
 

Macro Definition Documentation

◆ CATCACHE_MAXKEYS

#define CATCACHE_MAXKEYS   4

Definition at line 35 of file catcache.h.

◆ CL_MAGIC

#define CL_MAGIC   0x52765103

Definition at line 166 of file catcache.h.

◆ CT_MAGIC

#define CT_MAGIC   0x57261502

Definition at line 99 of file catcache.h.

Typedef Documentation

◆ CatCache

typedef struct catcache CatCache

◆ CatCacheHeader

◆ CatCList

typedef struct catclist CatCList

◆ CatCTup

typedef struct catctup CatCTup

◆ CCFastEqualFN

typedef bool(* CCFastEqualFN) (Datum a, Datum b)

Definition at line 42 of file catcache.h.

◆ CCHashFN

typedef uint32(* CCHashFN) (Datum datum)

Definition at line 39 of file catcache.h.

Function Documentation

◆ CatalogCacheFlushCatalog()

void CatalogCacheFlushCatalog ( Oid  catId)

Definition at line 841 of file catcache.c.

842{
843 slist_iter iter;
844
845 CACHE_elog(DEBUG2, "CatalogCacheFlushCatalog called for %u", catId);
846
848 {
849 CatCache *cache = slist_container(CatCache, cc_next, iter.cur);
850
851 /* Does this cache store tuples of the target catalog? */
852 if (cache->cc_reloid == catId)
853 {
854 /* Yes, so flush all its contents */
855 ResetCatalogCache(cache, false);
856
857 /* Tell inval.c to call syscache callbacks for this cache */
858 CallSyscacheCallbacks(cache->id, 0);
859 }
860 }
861
862 CACHE_elog(DEBUG2, "end of CatalogCacheFlushCatalog call");
863}
static void ResetCatalogCache(CatCache *cache, bool debug_discard)
Definition: catcache.c:743
static CatCacheHeader * CacheHdr
Definition: catcache.c:84
#define CACHE_elog(...)
Definition: catcache.c:80
#define DEBUG2
Definition: elog.h:29
#define slist_container(type, membername, ptr)
Definition: ilist.h:1106
#define slist_foreach(iter, lhead)
Definition: ilist.h:1132
void CallSyscacheCallbacks(int cacheid, uint32 hashvalue)
Definition: inval.c:1898
Oid cc_reloid
Definition: catcache.h:60
int id
Definition: catcache.h:46
slist_head ch_caches
Definition: catcache.h:188
slist_node * cur
Definition: ilist.h:259

References CatCInProgress::cache, CACHE_elog, CacheHdr, CallSyscacheCallbacks(), catcache::cc_reloid, catcacheheader::ch_caches, slist_iter::cur, DEBUG2, catcache::id, ResetCatalogCache(), slist_container, and slist_foreach.

Referenced by LocalExecuteInvalidationMessage().

◆ CatCacheInvalidate()

void CatCacheInvalidate ( CatCache cache,
uint32  hashValue 
)

Definition at line 632 of file catcache.c.

633{
634 Index hashIndex;
636
637 CACHE_elog(DEBUG2, "CatCacheInvalidate: called");
638
639 /*
640 * We don't bother to check whether the cache has finished initialization
641 * yet; if not, there will be no entries in it so no problem.
642 */
643
644 /*
645 * Invalidate *all* CatCLists in this cache; it's too hard to tell which
646 * searches might still be correct, so just zap 'em all.
647 */
648 for (int i = 0; i < cache->cc_nlbuckets; i++)
649 {
650 dlist_head *bucket = &cache->cc_lbucket[i];
651
652 dlist_foreach_modify(iter, bucket)
653 {
654 CatCList *cl = dlist_container(CatCList, cache_elem, iter.cur);
655
656 if (cl->refcount > 0)
657 cl->dead = true;
658 else
659 CatCacheRemoveCList(cache, cl);
660 }
661 }
662
663 /*
664 * inspect the proper hash bucket for tuple matches
665 */
666 hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
667 dlist_foreach_modify(iter, &cache->cc_bucket[hashIndex])
668 {
669 CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur);
670
671 if (hashValue == ct->hash_value)
672 {
673 if (ct->refcount > 0 ||
674 (ct->c_list && ct->c_list->refcount > 0))
675 {
676 ct->dead = true;
677 /* list, if any, was marked dead above */
678 Assert(ct->c_list == NULL || ct->c_list->dead);
679 }
680 else
681 CatCacheRemoveCTup(cache, ct);
682 CACHE_elog(DEBUG2, "CatCacheInvalidate: invalidated");
683#ifdef CATCACHE_STATS
684 cache->cc_invals++;
685#endif
686 /* could be multiple matches, so keep looking! */
687 }
688 }
689
690 /* Also invalidate any entries that are being built */
691 for (CatCInProgress *e = catcache_in_progress_stack; e != NULL; e = e->next)
692 {
693 if (e->cache == cache)
694 {
695 if (e->list || e->hash_value == hashValue)
696 e->dead = true;
697 }
698 }
699}
unsigned int Index
Definition: c.h:634
static CatCInProgress * catcache_in_progress_stack
Definition: catcache.c:61
static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
Definition: catcache.c:535
static void CatCacheRemoveCList(CatCache *cache, CatCList *cl)
Definition: catcache.c:577
#define HASH_INDEX(h, sz)
Definition: catcache.c:70
Assert(PointerIsAligned(start, uint64))
#define dlist_foreach_modify(iter, lhead)
Definition: ilist.h:640
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
int i
Definition: isn.c:77
e
Definition: preproc-init.c:82
struct CatCInProgress * next
Definition: catcache.c:58
dlist_head * cc_bucket
Definition: catcache.h:49
int cc_nbuckets
Definition: catcache.h:47
int cc_nlbuckets
Definition: catcache.h:57
dlist_head * cc_lbucket
Definition: catcache.h:58
int refcount
Definition: catcache.h:176
bool dead
Definition: catcache.h:177
int refcount
Definition: catcache.h:121
struct catclist * c_list
Definition: catcache.h:133
bool dead
Definition: catcache.h:122
uint32 hash_value
Definition: catcache.h:101
dlist_node * cur
Definition: ilist.h:200

References Assert(), catctup::c_list, CatCInProgress::cache, CACHE_elog, catcache_in_progress_stack, CatCacheRemoveCList(), CatCacheRemoveCTup(), catcache::cc_bucket, catcache::cc_lbucket, catcache::cc_nbuckets, catcache::cc_nlbuckets, dlist_mutable_iter::cur, catctup::dead, catclist::dead, DEBUG2, dlist_container, dlist_foreach_modify, HASH_INDEX, catctup::hash_value, i, CatCInProgress::next, catctup::refcount, and catclist::refcount.

Referenced by SysCacheInvalidate().

◆ CreateCacheMemoryContext()

void CreateCacheMemoryContext ( void  )

Definition at line 715 of file catcache.c.

716{
717 /*
718 * Purely for paranoia, check that context doesn't exist; caller probably
719 * did so already.
720 */
723 "CacheMemoryContext",
725}
MemoryContext TopMemoryContext
Definition: mcxt.c:166
MemoryContext CacheMemoryContext
Definition: mcxt.c:169
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CacheMemoryContext, and TopMemoryContext.

Referenced by assign_record_type_typmod(), BuildEventTriggerCache(), init_ts_config_cache(), InitCatCache(), InitializeAttoptCache(), InitializeRelfilenumberMap(), InitializeTableSpaceCache(), lookup_ts_dictionary_cache(), lookup_ts_parser_cache(), lookup_type_cache(), LookupOpclassInfo(), RelationBuildLocalRelation(), and RelationCacheInitialize().

◆ GetCatCacheHashValue()

uint32 GetCatCacheHashValue ( CatCache cache,
Datum  v1,
Datum  v2,
Datum  v3,
Datum  v4 
)

Definition at line 1707 of file catcache.c.

1712{
1713 /*
1714 * one-time startup overhead for each cache
1715 */
1717
1718 /*
1719 * calculate the hash value
1720 */
1721 return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, v1, v2, v3, v4);
1722}
static pg_attribute_always_inline void ConditionalCatalogCacheInitializeCache(CatCache *cache)
Definition: catcache.c:1085
static uint32 CatalogCacheComputeHashValue(CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4)
Definition: catcache.c:345
int cc_nkeys
Definition: catcache.h:54

References CatCInProgress::cache, CatalogCacheComputeHashValue(), catcache::cc_nkeys, and ConditionalCatalogCacheInitializeCache().

Referenced by GetSysCacheHashValue().

◆ InitCatCache()

CatCache * InitCatCache ( int  id,
Oid  reloid,
Oid  indexoid,
int  nkeys,
const int *  key,
int  nbuckets 
)

Definition at line 885 of file catcache.c.

891{
892 CatCache *cp;
893 MemoryContext oldcxt;
894 int i;
895
896 /*
897 * nbuckets is the initial number of hash buckets to use in this catcache.
898 * It will be enlarged later if it becomes too full.
899 *
900 * nbuckets must be a power of two. We check this via Assert rather than
901 * a full runtime check because the values will be coming from constant
902 * tables.
903 *
904 * If you're confused by the power-of-two check, see comments in
905 * bitmapset.c for an explanation.
906 */
907 Assert(nbuckets > 0 && (nbuckets & -nbuckets) == nbuckets);
908
909 /*
910 * first switch to the cache context so our allocations do not vanish at
911 * the end of a transaction
912 */
915
917
918 /*
919 * if first time through, initialize the cache group header
920 */
921 if (CacheHdr == NULL)
922 {
925 CacheHdr->ch_ntup = 0;
926#ifdef CATCACHE_STATS
927 /* set up to dump stats at backend exit */
928 on_proc_exit(CatCachePrintStats, 0);
929#endif
930 }
931
932 /*
933 * Allocate a new cache structure, aligning to a cacheline boundary
934 *
935 * Note: we rely on zeroing to initialize all the dlist headers correctly
936 */
939 cp->cc_bucket = palloc0(nbuckets * sizeof(dlist_head));
940
941 /*
942 * Many catcaches never receive any list searches. Therefore, we don't
943 * allocate the cc_lbuckets till we get a list search.
944 */
945 cp->cc_lbucket = NULL;
946
947 /*
948 * initialize the cache's relation information for the relation
949 * corresponding to this cache, and initialize some of the new cache's
950 * other internal fields. But don't open the relation yet.
951 */
952 cp->id = id;
953 cp->cc_relname = "(not known yet)";
954 cp->cc_reloid = reloid;
955 cp->cc_indexoid = indexoid;
956 cp->cc_relisshared = false; /* temporary */
957 cp->cc_tupdesc = (TupleDesc) NULL;
958 cp->cc_ntup = 0;
959 cp->cc_nlist = 0;
960 cp->cc_nbuckets = nbuckets;
961 cp->cc_nlbuckets = 0;
962 cp->cc_nkeys = nkeys;
963 for (i = 0; i < nkeys; ++i)
964 {
966 cp->cc_keyno[i] = key[i];
967 }
968
969 /*
970 * new cache is initialized as far as we can go for now. print some
971 * debugging information, if appropriate.
972 */
974
975 /*
976 * add completed cache to top of group header's list
977 */
979
980 /*
981 * back to the old context before we return...
982 */
983 MemoryContextSwitchTo(oldcxt);
984
985 return cp;
986}
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
void CreateCacheMemoryContext(void)
Definition: catcache.c:715
#define InitCatCache_DEBUG2
Definition: catcache.c:881
#define MCXT_ALLOC_ZERO
Definition: fe_memutils.h:30
#define palloc_object(type)
Definition: fe_memutils.h:74
static void slist_init(slist_head *head)
Definition: ilist.h:986
static void slist_push_head(slist_head *head, slist_node *node)
Definition: ilist.h:1006
void on_proc_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:309
void * palloc0(Size size)
Definition: mcxt.c:1417
void * palloc_aligned(Size size, Size alignto, int flags)
Definition: mcxt.c:1606
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define PG_CACHE_LINE_SIZE
const char * cc_relname
Definition: catcache.h:59
slist_node cc_next
Definition: catcache.h:63
int cc_keyno[CATCACHE_MAXKEYS]
Definition: catcache.h:53
Oid cc_indexoid
Definition: catcache.h:61
bool cc_relisshared
Definition: catcache.h:62
int cc_ntup
Definition: catcache.h:55
int cc_nlist
Definition: catcache.h:56
TupleDesc cc_tupdesc
Definition: catcache.h:48
struct TupleDescData * TupleDesc
Definition: tupdesc.h:145

References Assert(), AttributeNumberIsValid, CacheHdr, CacheMemoryContext, catcache::cc_bucket, catcache::cc_indexoid, catcache::cc_keyno, catcache::cc_lbucket, catcache::cc_nbuckets, catcache::cc_next, catcache::cc_nkeys, catcache::cc_nlbuckets, catcache::cc_nlist, catcache::cc_ntup, catcache::cc_relisshared, catcache::cc_relname, catcache::cc_reloid, catcache::cc_tupdesc, catcacheheader::ch_caches, catcacheheader::ch_ntup, CreateCacheMemoryContext(), i, catcache::id, InitCatCache_DEBUG2, sort-test::key, MCXT_ALLOC_ZERO, MemoryContextSwitchTo(), on_proc_exit(), palloc0(), palloc_aligned(), palloc_object, PG_CACHE_LINE_SIZE, slist_init(), and slist_push_head().

Referenced by InitCatalogCache().

◆ InitCatCachePhase2()

void InitCatCachePhase2 ( CatCache cache,
bool  touch_index 
)

Definition at line 1245 of file catcache.c.

1246{
1248
1249 if (touch_index &&
1250 cache->id != AMOID &&
1251 cache->id != AMNAME)
1252 {
1253 Relation idesc;
1254
1255 /*
1256 * We must lock the underlying catalog before opening the index to
1257 * avoid deadlock, since index_open could possibly result in reading
1258 * this same catalog, and if anyone else is exclusive-locking this
1259 * catalog and index they'll be doing it in that order.
1260 */
1262 idesc = index_open(cache->cc_indexoid, AccessShareLock);
1263
1264 /*
1265 * While we've got the index open, let's check that it's unique (and
1266 * not just deferrable-unique, thank you very much). This is just to
1267 * catch thinkos in definitions of new catcaches, so we don't worry
1268 * about the pg_am indexes not getting tested.
1269 */
1270 Assert(idesc->rd_index->indisunique &&
1271 idesc->rd_index->indimmediate);
1272
1275 }
1276}
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:229
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:107
#define AccessShareLock
Definition: lockdefs.h:36
Form_pg_index rd_index
Definition: rel.h:192

References AccessShareLock, Assert(), CatCInProgress::cache, catcache::cc_indexoid, catcache::cc_reloid, ConditionalCatalogCacheInitializeCache(), catcache::id, index_close(), index_open(), LockRelationOid(), RelationData::rd_index, and UnlockRelationOid().

Referenced by InitCatalogCachePhase2(), and SysCacheGetAttr().

◆ PrepareToInvalidateCacheTuple()

void PrepareToInvalidateCacheTuple ( Relation  relation,
HeapTuple  tuple,
HeapTuple  newtuple,
void(*)(int, uint32, Oid, void *)  function,
void *  context 
)

Definition at line 2394 of file catcache.c.

2399{
2400 slist_iter iter;
2401 Oid reloid;
2402
2403 CACHE_elog(DEBUG2, "PrepareToInvalidateCacheTuple: called");
2404
2405 /*
2406 * sanity checks
2407 */
2408 Assert(RelationIsValid(relation));
2409 Assert(HeapTupleIsValid(tuple));
2411 Assert(CacheHdr != NULL);
2412
2413 reloid = RelationGetRelid(relation);
2414
2415 /* ----------------
2416 * for each cache
2417 * if the cache contains tuples from the specified relation
2418 * compute the tuple's hash value(s) in this cache,
2419 * and call the passed function to register the information.
2420 * ----------------
2421 */
2422
2424 {
2425 CatCache *ccp = slist_container(CatCache, cc_next, iter.cur);
2426 uint32 hashvalue;
2427 Oid dbid;
2428
2429 if (ccp->cc_reloid != reloid)
2430 continue;
2431
2432 /* Just in case cache hasn't finished initialization yet... */
2434
2435 hashvalue = CatalogCacheComputeTupleHashValue(ccp, ccp->cc_nkeys, tuple);
2436 dbid = ccp->cc_relisshared ? (Oid) 0 : MyDatabaseId;
2437
2438 (*function) (ccp->id, hashvalue, dbid, context);
2439
2440 if (newtuple)
2441 {
2442 uint32 newhashvalue;
2443
2444 newhashvalue = CatalogCacheComputeTupleHashValue(ccp, ccp->cc_nkeys, newtuple);
2445
2446 if (newhashvalue != hashvalue)
2447 (*function) (ccp->id, newhashvalue, dbid, context);
2448 }
2449 }
2450}
uint32_t uint32
Definition: c.h:552
static uint32 CatalogCacheComputeTupleHashValue(CatCache *cache, int nkeys, HeapTuple tuple)
Definition: catcache.c:387
Oid MyDatabaseId
Definition: globals.c:94
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
on_exit_nicely_callback function
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetRelid(relation)
Definition: rel.h:515
#define RelationIsValid(relation)
Definition: rel.h:490

References Assert(), CACHE_elog, CacheHdr, CatalogCacheComputeTupleHashValue(), catcache::cc_nkeys, catcache::cc_relisshared, catcache::cc_reloid, catcacheheader::ch_caches, ConditionalCatalogCacheInitializeCache(), slist_iter::cur, DEBUG2, function, HeapTupleIsValid, catcache::id, MyDatabaseId, RelationGetRelid, RelationIsValid, slist_container, and slist_foreach.

Referenced by CacheInvalidateHeapTupleCommon().

◆ ReleaseCatCache()

void ReleaseCatCache ( HeapTuple  tuple)

Definition at line 1668 of file catcache.c.

1669{
1671}
static void ReleaseCatCacheWithOwner(HeapTuple tuple, ResourceOwner resowner)
Definition: catcache.c:1674
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173

References CurrentResourceOwner, and ReleaseCatCacheWithOwner().

Referenced by ReleaseSysCache().

◆ ReleaseCatCacheList()

◆ ResetCatalogCaches()

void ResetCatalogCaches ( void  )

Definition at line 805 of file catcache.c.

806{
808}
void ResetCatalogCachesExt(bool debug_discard)
Definition: catcache.c:811

References ResetCatalogCachesExt().

◆ ResetCatalogCachesExt()

void ResetCatalogCachesExt ( bool  debug_discard)

Definition at line 811 of file catcache.c.

812{
813 slist_iter iter;
814
815 CACHE_elog(DEBUG2, "ResetCatalogCaches called");
816
818 {
819 CatCache *cache = slist_container(CatCache, cc_next, iter.cur);
820
821 ResetCatalogCache(cache, debug_discard);
822 }
823
824 CACHE_elog(DEBUG2, "end of ResetCatalogCaches call");
825}

References CatCInProgress::cache, CACHE_elog, CacheHdr, catcacheheader::ch_caches, slist_iter::cur, DEBUG2, ResetCatalogCache(), slist_container, and slist_foreach.

Referenced by InvalidateSystemCachesExtended(), and ResetCatalogCaches().

◆ SearchCatCache()

HeapTuple SearchCatCache ( CatCache cache,
Datum  v1,
Datum  v2,
Datum  v3,
Datum  v4 
)

Definition at line 1361 of file catcache.c.

1366{
1367 return SearchCatCacheInternal(cache, cache->cc_nkeys, v1, v2, v3, v4);
1368}
static HeapTuple SearchCatCacheInternal(CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4)
Definition: catcache.c:1412

References CatCInProgress::cache, catcache::cc_nkeys, and SearchCatCacheInternal().

Referenced by SearchSysCache().

◆ SearchCatCache1()

HeapTuple SearchCatCache1 ( CatCache cache,
Datum  v1 
)

Definition at line 1378 of file catcache.c.

1380{
1381 return SearchCatCacheInternal(cache, 1, v1, 0, 0, 0);
1382}

References CatCInProgress::cache, and SearchCatCacheInternal().

Referenced by SearchSysCache1().

◆ SearchCatCache2()

HeapTuple SearchCatCache2 ( CatCache cache,
Datum  v1,
Datum  v2 
)

Definition at line 1386 of file catcache.c.

1388{
1389 return SearchCatCacheInternal(cache, 2, v1, v2, 0, 0);
1390}

References CatCInProgress::cache, and SearchCatCacheInternal().

Referenced by SearchSysCache2().

◆ SearchCatCache3()

HeapTuple SearchCatCache3 ( CatCache cache,
Datum  v1,
Datum  v2,
Datum  v3 
)

Definition at line 1394 of file catcache.c.

1396{
1397 return SearchCatCacheInternal(cache, 3, v1, v2, v3, 0);
1398}

References CatCInProgress::cache, and SearchCatCacheInternal().

Referenced by SearchSysCache3().

◆ SearchCatCache4()

HeapTuple SearchCatCache4 ( CatCache cache,
Datum  v1,
Datum  v2,
Datum  v3,
Datum  v4 
)

Definition at line 1402 of file catcache.c.

1404{
1405 return SearchCatCacheInternal(cache, 4, v1, v2, v3, v4);
1406}

References CatCInProgress::cache, and SearchCatCacheInternal().

Referenced by SearchSysCache4().

◆ SearchCatCacheList()

CatCList * SearchCatCacheList ( CatCache cache,
int  nkeys,
Datum  v1,
Datum  v2,
Datum  v3 
)

Definition at line 1740 of file catcache.c.

1745{
1746 Datum v4 = 0; /* dummy last-column value */
1748 uint32 lHashValue;
1749 Index lHashIndex;
1750 dlist_iter iter;
1751 dlist_head *lbucket;
1752 CatCList *cl;
1753 CatCTup *ct;
1754 List *volatile ctlist;
1755 ListCell *ctlist_item;
1756 int nmembers;
1757 bool ordered;
1758 HeapTuple ntp;
1759 MemoryContext oldcxt;
1760 int i;
1761 CatCInProgress *save_in_progress;
1762 CatCInProgress in_progress_ent;
1763
1764 /*
1765 * one-time startup overhead for each cache
1766 */
1768
1769 Assert(nkeys > 0 && nkeys < cache->cc_nkeys);
1770
1771#ifdef CATCACHE_STATS
1772 cache->cc_lsearches++;
1773#endif
1774
1775 /* Initialize local parameter array */
1776 arguments[0] = v1;
1777 arguments[1] = v2;
1778 arguments[2] = v3;
1779 arguments[3] = v4;
1780
1781 /*
1782 * If we haven't previously done a list search in this cache, create the
1783 * bucket header array; otherwise, consider whether it's time to enlarge
1784 * it.
1785 */
1786 if (cache->cc_lbucket == NULL)
1787 {
1788 /* Arbitrary initial size --- must be a power of 2 */
1789 int nbuckets = 16;
1790
1791 cache->cc_lbucket = (dlist_head *)
1793 nbuckets * sizeof(dlist_head));
1794 /* Don't set cc_nlbuckets if we get OOM allocating cc_lbucket */
1795 cache->cc_nlbuckets = nbuckets;
1796 }
1797 else
1798 {
1799 /*
1800 * If the hash table has become too full, enlarge the buckets array.
1801 * Quite arbitrarily, we enlarge when fill factor > 2.
1802 */
1803 if (cache->cc_nlist > cache->cc_nlbuckets * 2)
1804 RehashCatCacheLists(cache);
1805 }
1806
1807 /*
1808 * Find the hash bucket in which to look for the CatCList.
1809 */
1810 lHashValue = CatalogCacheComputeHashValue(cache, nkeys, v1, v2, v3, v4);
1811 lHashIndex = HASH_INDEX(lHashValue, cache->cc_nlbuckets);
1812
1813 /*
1814 * scan the items until we find a match or exhaust our list
1815 *
1816 * Note: it's okay to use dlist_foreach here, even though we modify the
1817 * dlist within the loop, because we don't continue the loop afterwards.
1818 */
1819 lbucket = &cache->cc_lbucket[lHashIndex];
1820 dlist_foreach(iter, lbucket)
1821 {
1822 cl = dlist_container(CatCList, cache_elem, iter.cur);
1823
1824 if (cl->dead)
1825 continue; /* ignore dead entries */
1826
1827 if (cl->hash_value != lHashValue)
1828 continue; /* quickly skip entry if wrong hash val */
1829
1830 /*
1831 * see if the cached list matches our key.
1832 */
1833 if (cl->nkeys != nkeys)
1834 continue;
1835
1836 if (!CatalogCacheCompareTuple(cache, nkeys, cl->keys, arguments))
1837 continue;
1838
1839 /*
1840 * We found a matching list. Move the list to the front of the list
1841 * for its hashbucket, so as to speed subsequent searches. (We do not
1842 * move the members to the fronts of their hashbucket lists, however,
1843 * since there's no point in that unless they are searched for
1844 * individually.)
1845 */
1846 dlist_move_head(lbucket, &cl->cache_elem);
1847
1848 /* Bump the list's refcount and return it */
1850 cl->refcount++;
1852
1853 CACHE_elog(DEBUG2, "SearchCatCacheList(%s): found list",
1854 cache->cc_relname);
1855
1856#ifdef CATCACHE_STATS
1857 cache->cc_lhits++;
1858#endif
1859
1860 return cl;
1861 }
1862
1863 /*
1864 * List was not found in cache, so we have to build it by reading the
1865 * relation. For each matching tuple found in the relation, use an
1866 * existing cache entry if possible, else build a new one.
1867 *
1868 * We have to bump the member refcounts temporarily to ensure they won't
1869 * get dropped from the cache while loading other members. We use a PG_TRY
1870 * block to ensure we can undo those refcounts if we get an error before
1871 * we finish constructing the CatCList. ctlist must be valid throughout
1872 * the PG_TRY block.
1873 */
1874 ctlist = NIL;
1875
1876 /*
1877 * Cache invalidation can happen while we're building the list.
1878 * CatalogCacheCreateEntry() handles concurrent invalidation of individual
1879 * tuples, but it's also possible that a new entry is concurrently added
1880 * that should be part of the list we're building. Register an
1881 * "in-progress" entry that will receive the invalidation, until we have
1882 * built the final list entry.
1883 */
1884 save_in_progress = catcache_in_progress_stack;
1885 in_progress_ent.next = catcache_in_progress_stack;
1886 in_progress_ent.cache = cache;
1887 in_progress_ent.hash_value = lHashValue;
1888 in_progress_ent.list = true;
1889 in_progress_ent.dead = false;
1890 catcache_in_progress_stack = &in_progress_ent;
1891
1892 PG_TRY();
1893 {
1894 ScanKeyData cur_skey[CATCACHE_MAXKEYS];
1895 Relation relation;
1896 SysScanDesc scandesc;
1897 bool first_iter = true;
1898
1899 relation = table_open(cache->cc_reloid, AccessShareLock);
1900
1901 /*
1902 * Ok, need to make a lookup in the relation, copy the scankey and
1903 * fill out any per-call fields.
1904 */
1905 memcpy(cur_skey, cache->cc_skey, sizeof(ScanKeyData) * cache->cc_nkeys);
1906 cur_skey[0].sk_argument = v1;
1907 cur_skey[1].sk_argument = v2;
1908 cur_skey[2].sk_argument = v3;
1909 cur_skey[3].sk_argument = v4;
1910
1911 /*
1912 * Scan the table for matching entries. If an invalidation arrives
1913 * mid-build, we will loop back here to retry.
1914 */
1915 do
1916 {
1917 /*
1918 * If we are retrying, release refcounts on any items created on
1919 * the previous iteration. We dare not try to free them if
1920 * they're now unreferenced, since an error while doing that would
1921 * result in the PG_CATCH below doing extra refcount decrements.
1922 * Besides, we'll likely re-adopt those items in the next
1923 * iteration, so it's not worth complicating matters to try to get
1924 * rid of them.
1925 */
1926 foreach(ctlist_item, ctlist)
1927 {
1928 ct = (CatCTup *) lfirst(ctlist_item);
1929 Assert(ct->c_list == NULL);
1930 Assert(ct->refcount > 0);
1931 ct->refcount--;
1932 }
1933 /* Reset ctlist in preparation for new try */
1934 ctlist = NIL;
1935 in_progress_ent.dead = false;
1936
1937 scandesc = systable_beginscan(relation,
1938 cache->cc_indexoid,
1939 IndexScanOK(cache),
1940 NULL,
1941 nkeys,
1942 cur_skey);
1943
1944 /* The list will be ordered iff we are doing an index scan */
1945 ordered = (scandesc->irel != NULL);
1946
1947 /* Injection point to help testing the recursive invalidation case */
1948 if (first_iter)
1949 {
1950 INJECTION_POINT("catcache-list-miss-systable-scan-started", NULL);
1951 first_iter = false;
1952 }
1953
1954 while (HeapTupleIsValid(ntp = systable_getnext(scandesc)) &&
1955 !in_progress_ent.dead)
1956 {
1957 uint32 hashValue;
1958 Index hashIndex;
1959 bool found = false;
1960 dlist_head *bucket;
1961
1962 /*
1963 * See if there's an entry for this tuple already.
1964 */
1965 ct = NULL;
1966 hashValue = CatalogCacheComputeTupleHashValue(cache, cache->cc_nkeys, ntp);
1967 hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
1968
1969 bucket = &cache->cc_bucket[hashIndex];
1970 dlist_foreach(iter, bucket)
1971 {
1972 ct = dlist_container(CatCTup, cache_elem, iter.cur);
1973
1974 if (ct->dead || ct->negative)
1975 continue; /* ignore dead and negative entries */
1976
1977 if (ct->hash_value != hashValue)
1978 continue; /* quickly skip entry if wrong hash val */
1979
1980 if (!ItemPointerEquals(&(ct->tuple.t_self), &(ntp->t_self)))
1981 continue; /* not same tuple */
1982
1983 /*
1984 * Found a match, but can't use it if it belongs to
1985 * another list already
1986 */
1987 if (ct->c_list)
1988 continue;
1989
1990 found = true;
1991 break; /* A-OK */
1992 }
1993
1994 if (!found)
1995 {
1996 /* We didn't find a usable entry, so make a new one */
1997 ct = CatalogCacheCreateEntry(cache, ntp, NULL,
1998 hashValue, hashIndex);
1999
2000 /* upon failure, we must start the scan over */
2001 if (ct == NULL)
2002 {
2003 in_progress_ent.dead = true;
2004 break;
2005 }
2006 }
2007
2008 /* Careful here: add entry to ctlist, then bump its refcount */
2009 /* This way leaves state correct if lappend runs out of memory */
2010 ctlist = lappend(ctlist, ct);
2011 ct->refcount++;
2012 }
2013
2014 systable_endscan(scandesc);
2015 } while (in_progress_ent.dead);
2016
2017 table_close(relation, AccessShareLock);
2018
2019 /* Make sure the resource owner has room to remember this entry. */
2021
2022 /* Now we can build the CatCList entry. */
2024 nmembers = list_length(ctlist);
2025 cl = (CatCList *)
2026 palloc(offsetof(CatCList, members) + nmembers * sizeof(CatCTup *));
2027
2028 /* Extract key values */
2029 CatCacheCopyKeys(cache->cc_tupdesc, nkeys, cache->cc_keyno,
2030 arguments, cl->keys);
2031 MemoryContextSwitchTo(oldcxt);
2032
2033 /*
2034 * We are now past the last thing that could trigger an elog before we
2035 * have finished building the CatCList and remembering it in the
2036 * resource owner. So it's OK to fall out of the PG_TRY, and indeed
2037 * we'd better do so before we start marking the members as belonging
2038 * to the list.
2039 */
2040 }
2041 PG_CATCH();
2042 {
2043 Assert(catcache_in_progress_stack == &in_progress_ent);
2044 catcache_in_progress_stack = save_in_progress;
2045
2046 foreach(ctlist_item, ctlist)
2047 {
2048 ct = (CatCTup *) lfirst(ctlist_item);
2049 Assert(ct->c_list == NULL);
2050 Assert(ct->refcount > 0);
2051 ct->refcount--;
2052 if (
2053#ifndef CATCACHE_FORCE_RELEASE
2054 ct->dead &&
2055#endif
2056 ct->refcount == 0 &&
2057 (ct->c_list == NULL || ct->c_list->refcount == 0))
2058 CatCacheRemoveCTup(cache, ct);
2059 }
2060
2061 PG_RE_THROW();
2062 }
2063 PG_END_TRY();
2064 Assert(catcache_in_progress_stack == &in_progress_ent);
2065 catcache_in_progress_stack = save_in_progress;
2066
2067 cl->cl_magic = CL_MAGIC;
2068 cl->my_cache = cache;
2069 cl->refcount = 0; /* for the moment */
2070 cl->dead = false;
2071 cl->ordered = ordered;
2072 cl->nkeys = nkeys;
2073 cl->hash_value = lHashValue;
2074 cl->n_members = nmembers;
2075
2076 i = 0;
2077 foreach(ctlist_item, ctlist)
2078 {
2079 cl->members[i++] = ct = (CatCTup *) lfirst(ctlist_item);
2080 Assert(ct->c_list == NULL);
2081 ct->c_list = cl;
2082 /* release the temporary refcount on the member */
2083 Assert(ct->refcount > 0);
2084 ct->refcount--;
2085 /* mark list dead if any members already dead */
2086 if (ct->dead)
2087 cl->dead = true;
2088 }
2089 Assert(i == nmembers);
2090
2091 /*
2092 * Add the CatCList to the appropriate bucket, and count it.
2093 */
2094 dlist_push_head(lbucket, &cl->cache_elem);
2095
2096 cache->cc_nlist++;
2097
2098 /* Finally, bump the list's refcount and return it */
2099 cl->refcount++;
2101
2102 CACHE_elog(DEBUG2, "SearchCatCacheList(%s): made list of %d members",
2103 cache->cc_relname, nmembers);
2104
2105 return cl;
2106}
static CatCTup * CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, Datum *arguments, uint32 hashValue, Index hashIndex)
Definition: catcache.c:2154
static bool IndexScanOK(CatCache *cache)
Definition: catcache.c:1296
static bool CatalogCacheCompareTuple(const CatCache *cache, int nkeys, const Datum *cachekeys, const Datum *searchkeys)
Definition: catcache.c:442
static void RehashCatCacheLists(CatCache *cp)
Definition: catcache.c:1037
static void CatCacheCopyKeys(TupleDesc tupdesc, int nkeys, const int *attnos, const Datum *srckeys, Datum *dstkeys)
Definition: catcache.c:2324
static void ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
Definition: catcache.c:169
#define CATCACHE_MAXKEYS
Definition: catcache.h:35
#define CL_MAGIC
Definition: catcache.h:166
#define PG_RE_THROW()
Definition: elog.h:405
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define PG_CATCH(...)
Definition: elog.h:382
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
static void dlist_push_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:347
static void dlist_move_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:467
#define INJECTION_POINT(name, arg)
bool ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2)
Definition: itemptr.c:35
List * lappend(List *list, void *datum)
Definition: list.c:339
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1266
void * palloc(Size size)
Definition: mcxt.c:1387
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
uint64_t Datum
Definition: postgres.h:70
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:449
uint32 hash_value
Definition: catcache.c:55
CatCache * cache
Definition: catcache.c:54
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
Datum sk_argument
Definition: skey.h:72
Relation irel
Definition: relscan.h:212
ScanKeyData cc_skey[CATCACHE_MAXKEYS]
Definition: catcache.h:64
dlist_node cache_elem
Definition: catcache.h:163
CatCache * my_cache
Definition: catcache.h:181
int cl_magic
Definition: catcache.h:165
short nkeys
Definition: catcache.h:179
Datum keys[CATCACHE_MAXKEYS]
Definition: catcache.h:174
bool ordered
Definition: catcache.h:178
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:182
uint32 hash_value
Definition: catcache.h:168
int n_members
Definition: catcache.h:180
bool negative
Definition: catcache.h:123
HeapTupleData tuple
Definition: catcache.h:124
dlist_node * cur
Definition: ilist.h:179
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References AccessShareLock, Assert(), catctup::c_list, CatCInProgress::cache, catclist::cache_elem, CACHE_elog, CacheMemoryContext, CatalogCacheCompareTuple(), CatalogCacheComputeHashValue(), CatalogCacheComputeTupleHashValue(), CatalogCacheCreateEntry(), catcache_in_progress_stack, CATCACHE_MAXKEYS, CatCacheCopyKeys(), CatCacheRemoveCTup(), catcache::cc_bucket, catcache::cc_indexoid, catcache::cc_keyno, catcache::cc_lbucket, catcache::cc_nbuckets, catcache::cc_nkeys, catcache::cc_nlbuckets, catcache::cc_nlist, catcache::cc_relname, catcache::cc_reloid, catcache::cc_skey, catcache::cc_tupdesc, catclist::cl_magic, CL_MAGIC, ConditionalCatalogCacheInitializeCache(), dlist_iter::cur, CurrentResourceOwner, CatCInProgress::dead, catctup::dead, catclist::dead, DEBUG2, dlist_container, dlist_foreach, dlist_move_head(), dlist_push_head(), HASH_INDEX, CatCInProgress::hash_value, catctup::hash_value, catclist::hash_value, HeapTupleIsValid, i, IndexScanOK(), INJECTION_POINT, SysScanDescData::irel, ItemPointerEquals(), catclist::keys, lappend(), lfirst, CatCInProgress::list, list_length(), catclist::members, MemoryContextAllocZero(), MemoryContextSwitchTo(), catclist::my_cache, catclist::n_members, catctup::negative, CatCInProgress::next, NIL, catclist::nkeys, catclist::ordered, palloc(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, catctup::refcount, catclist::refcount, RehashCatCacheLists(), ResourceOwnerEnlarge(), ResourceOwnerRememberCatCacheListRef(), ScanKeyData::sk_argument, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), and catctup::tuple.

Referenced by SearchSysCacheList().

Variable Documentation

◆ CacheMemoryContext

PGDLLIMPORT MemoryContext CacheMemoryContext
extern

Definition at line 169 of file mcxt.c.