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 CatalogCacheFlushCatalog (Oid catId)
 
void CatCacheInvalidate (CatCache *cache, uint32 hashValue)
 
void PrepareToInvalidateCacheTuple (Relation relation, HeapTuple tuple, HeapTuple newtuple, void(*function)(int, uint32, Oid))
 

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 162 of file catcache.h.

◆ CT_MAGIC

#define CT_MAGIC   0x57261502

Definition at line 91 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 783 of file catcache.c.

784 {
785  slist_iter iter;
786 
787  CACHE_elog(DEBUG2, "CatalogCacheFlushCatalog called for %u", catId);
788 
790  {
791  CatCache *cache = slist_container(CatCache, cc_next, iter.cur);
792 
793  /* Does this cache store tuples of the target catalog? */
794  if (cache->cc_reloid == catId)
795  {
796  /* Yes, so flush all its contents */
797  ResetCatalogCache(cache);
798 
799  /* Tell inval.c to call syscache callbacks for this cache */
800  CallSyscacheCallbacks(cache->id, 0);
801  }
802  }
803 
804  CACHE_elog(DEBUG2, "end of CatalogCacheFlushCatalog call");
805 }
static CatCacheHeader * CacheHdr
Definition: catcache.c:64
static void ResetCatalogCache(CatCache *cache)
Definition: catcache.c:701
#define CACHE_elog(...)
Definition: catcache.c:60
#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:1577
Oid cc_reloid
Definition: catcache.h:60
int id
Definition: catcache.h:46
slist_head ch_caches
Definition: catcache.h:186
slist_node * cur
Definition: ilist.h:259

References 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 606 of file catcache.c.

607 {
608  Index hashIndex;
609  dlist_mutable_iter iter;
610 
611  CACHE_elog(DEBUG2, "CatCacheInvalidate: called");
612 
613  /*
614  * We don't bother to check whether the cache has finished initialization
615  * yet; if not, there will be no entries in it so no problem.
616  */
617 
618  /*
619  * Invalidate *all* CatCLists in this cache; it's too hard to tell which
620  * searches might still be correct, so just zap 'em all.
621  */
622  for (int i = 0; i < cache->cc_nlbuckets; i++)
623  {
624  dlist_head *bucket = &cache->cc_lbucket[i];
625 
626  dlist_foreach_modify(iter, bucket)
627  {
628  CatCList *cl = dlist_container(CatCList, cache_elem, iter.cur);
629 
630  if (cl->refcount > 0)
631  cl->dead = true;
632  else
633  CatCacheRemoveCList(cache, cl);
634  }
635  }
636 
637  /*
638  * inspect the proper hash bucket for tuple matches
639  */
640  hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
641  dlist_foreach_modify(iter, &cache->cc_bucket[hashIndex])
642  {
643  CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur);
644 
645  if (hashValue == ct->hash_value)
646  {
647  if (ct->refcount > 0 ||
648  (ct->c_list && ct->c_list->refcount > 0))
649  {
650  ct->dead = true;
651  /* list, if any, was marked dead above */
652  Assert(ct->c_list == NULL || ct->c_list->dead);
653  }
654  else
655  CatCacheRemoveCTup(cache, ct);
656  CACHE_elog(DEBUG2, "CatCacheInvalidate: invalidated");
657 #ifdef CATCACHE_STATS
658  cache->cc_invals++;
659 #endif
660  /* could be multiple matches, so keep looking! */
661  }
662  }
663 }
#define Assert(condition)
Definition: c.h:858
unsigned int Index
Definition: c.h:614
static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
Definition: catcache.c:509
static void CatCacheRemoveCList(CatCache *cache, CatCList *cl)
Definition: catcache.c:551
#define HASH_INDEX(h, sz)
Definition: catcache.c:50
#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:73
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:174
bool dead
Definition: catcache.h:175
int refcount
Definition: catcache.h:120
struct catclist * c_list
Definition: catcache.h:132
bool dead
Definition: catcache.h:121
uint32 hash_value
Definition: catcache.h:93
dlist_node * cur
Definition: ilist.h:200

References Assert, catctup::c_list, CACHE_elog, 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, catctup::refcount, and catclist::refcount.

Referenced by SysCacheInvalidate().

◆ CreateCacheMemoryContext()

void CreateCacheMemoryContext ( void  )

Definition at line 679 of file catcache.c.

680 {
681  /*
682  * Purely for paranoia, check that context doesn't exist; caller probably
683  * did so already.
684  */
685  if (!CacheMemoryContext)
687  "CacheMemoryContext",
689 }
MemoryContext TopMemoryContext
Definition: mcxt.c:149
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
#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 1612 of file catcache.c.

1617 {
1618  /*
1619  * one-time startup overhead for each cache
1620  */
1621  if (cache->cc_tupdesc == NULL)
1623 
1624  /*
1625  * calculate the hash value
1626  */
1627  return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, v1, v2, v3, v4);
1628 }
static void CatalogCacheInitializeCache(CatCache *cache)
Definition: catcache.c:1035
static uint32 CatalogCacheComputeHashValue(CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4)
Definition: catcache.c:325
int cc_nkeys
Definition: catcache.h:54
TupleDesc cc_tupdesc
Definition: catcache.h:48

References CatalogCacheComputeHashValue(), CatalogCacheInitializeCache(), catcache::cc_nkeys, and catcache::cc_tupdesc.

Referenced by GetSysCacheHashValue().

◆ InitCatCache()

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

Definition at line 827 of file catcache.c.

833 {
834  CatCache *cp;
835  MemoryContext oldcxt;
836  int i;
837 
838  /*
839  * nbuckets is the initial number of hash buckets to use in this catcache.
840  * It will be enlarged later if it becomes too full.
841  *
842  * nbuckets must be a power of two. We check this via Assert rather than
843  * a full runtime check because the values will be coming from constant
844  * tables.
845  *
846  * If you're confused by the power-of-two check, see comments in
847  * bitmapset.c for an explanation.
848  */
849  Assert(nbuckets > 0 && (nbuckets & -nbuckets) == nbuckets);
850 
851  /*
852  * first switch to the cache context so our allocations do not vanish at
853  * the end of a transaction
854  */
855  if (!CacheMemoryContext)
857 
859 
860  /*
861  * if first time through, initialize the cache group header
862  */
863  if (CacheHdr == NULL)
864  {
867  CacheHdr->ch_ntup = 0;
868 #ifdef CATCACHE_STATS
869  /* set up to dump stats at backend exit */
870  on_proc_exit(CatCachePrintStats, 0);
871 #endif
872  }
873 
874  /*
875  * Allocate a new cache structure, aligning to a cacheline boundary
876  *
877  * Note: we rely on zeroing to initialize all the dlist headers correctly
878  */
881  cp->cc_bucket = palloc0(nbuckets * sizeof(dlist_head));
882 
883  /*
884  * Many catcaches never receive any list searches. Therefore, we don't
885  * allocate the cc_lbuckets till we get a list search.
886  */
887  cp->cc_lbucket = NULL;
888 
889  /*
890  * initialize the cache's relation information for the relation
891  * corresponding to this cache, and initialize some of the new cache's
892  * other internal fields. But don't open the relation yet.
893  */
894  cp->id = id;
895  cp->cc_relname = "(not known yet)";
896  cp->cc_reloid = reloid;
897  cp->cc_indexoid = indexoid;
898  cp->cc_relisshared = false; /* temporary */
899  cp->cc_tupdesc = (TupleDesc) NULL;
900  cp->cc_ntup = 0;
901  cp->cc_nlist = 0;
902  cp->cc_nbuckets = nbuckets;
903  cp->cc_nlbuckets = 0;
904  cp->cc_nkeys = nkeys;
905  for (i = 0; i < nkeys; ++i)
906  {
908  cp->cc_keyno[i] = key[i];
909  }
910 
911  /*
912  * new cache is initialized as far as we can go for now. print some
913  * debugging information, if appropriate.
914  */
916 
917  /*
918  * add completed cache to top of group header's list
919  */
921 
922  /*
923  * back to the old context before we return...
924  */
925  MemoryContextSwitchTo(oldcxt);
926 
927  return cp;
928 }
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
void CreateCacheMemoryContext(void)
Definition: catcache.c:679
#define InitCatCache_DEBUG2
Definition: catcache.c:823
#define MCXT_ALLOC_ZERO
Definition: fe_memutils.h:18
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:1346
void * palloc_aligned(Size size, Size alignto, int flags)
Definition: mcxt.c:1510
void * palloc(Size size)
Definition: mcxt.c:1316
#define PG_CACHE_LINE_SIZE
MemoryContextSwitchTo(old_ctx)
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
struct TupleDescData * TupleDesc
Definition: tupdesc.h:89

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(), palloc(), palloc0(), palloc_aligned(), PG_CACHE_LINE_SIZE, slist_init(), and slist_push_head().

Referenced by InitCatalogCache().

◆ InitCatCachePhase2()

void InitCatCachePhase2 ( CatCache cache,
bool  touch_index 
)

Definition at line 1144 of file catcache.c.

1145 {
1146  if (cache->cc_tupdesc == NULL)
1148 
1149  if (touch_index &&
1150  cache->id != AMOID &&
1151  cache->id != AMNAME)
1152  {
1153  Relation idesc;
1154 
1155  /*
1156  * We must lock the underlying catalog before opening the index to
1157  * avoid deadlock, since index_open could possibly result in reading
1158  * this same catalog, and if anyone else is exclusive-locking this
1159  * catalog and index they'll be doing it in that order.
1160  */
1162  idesc = index_open(cache->cc_indexoid, AccessShareLock);
1163 
1164  /*
1165  * While we've got the index open, let's check that it's unique (and
1166  * not just deferrable-unique, thank you very much). This is just to
1167  * catch thinkos in definitions of new catcaches, so we don't worry
1168  * about the pg_am indexes not getting tested.
1169  */
1170  Assert(idesc->rd_index->indisunique &&
1171  idesc->rd_index->indimmediate);
1172 
1173  index_close(idesc, AccessShareLock);
1175  }
1176 }
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:227
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
#define AccessShareLock
Definition: lockdefs.h:36
Form_pg_index rd_index
Definition: rel.h:192

References AccessShareLock, Assert, CatalogCacheInitializeCache(), catcache::cc_indexoid, catcache::cc_reloid, catcache::cc_tupdesc, 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 function 
)

Definition at line 2250 of file catcache.c.

2254 {
2255  slist_iter iter;
2256  Oid reloid;
2257 
2258  CACHE_elog(DEBUG2, "PrepareToInvalidateCacheTuple: called");
2259 
2260  /*
2261  * sanity checks
2262  */
2263  Assert(RelationIsValid(relation));
2264  Assert(HeapTupleIsValid(tuple));
2265  Assert(PointerIsValid(function));
2266  Assert(CacheHdr != NULL);
2267 
2268  reloid = RelationGetRelid(relation);
2269 
2270  /* ----------------
2271  * for each cache
2272  * if the cache contains tuples from the specified relation
2273  * compute the tuple's hash value(s) in this cache,
2274  * and call the passed function to register the information.
2275  * ----------------
2276  */
2277 
2279  {
2280  CatCache *ccp = slist_container(CatCache, cc_next, iter.cur);
2281  uint32 hashvalue;
2282  Oid dbid;
2283 
2284  if (ccp->cc_reloid != reloid)
2285  continue;
2286 
2287  /* Just in case cache hasn't finished initialization yet... */
2288  if (ccp->cc_tupdesc == NULL)
2290 
2291  hashvalue = CatalogCacheComputeTupleHashValue(ccp, ccp->cc_nkeys, tuple);
2292  dbid = ccp->cc_relisshared ? (Oid) 0 : MyDatabaseId;
2293 
2294  (*function) (ccp->id, hashvalue, dbid);
2295 
2296  if (newtuple)
2297  {
2298  uint32 newhashvalue;
2299 
2300  newhashvalue = CatalogCacheComputeTupleHashValue(ccp, ccp->cc_nkeys, newtuple);
2301 
2302  if (newhashvalue != hashvalue)
2303  (*function) (ccp->id, newhashvalue, dbid);
2304  }
2305  }
2306 }
unsigned int uint32
Definition: c.h:506
#define PointerIsValid(pointer)
Definition: c.h:763
static uint32 CatalogCacheComputeTupleHashValue(CatCache *cache, int nkeys, HeapTuple tuple)
Definition: catcache.c:367
Oid MyDatabaseId
Definition: globals.c:91
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationIsValid(relation)
Definition: rel.h:478

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

Referenced by CacheInvalidateHeapTuple().

◆ ReleaseCatCache()

void ReleaseCatCache ( HeapTuple  tuple)

Definition at line 1573 of file catcache.c.

1574 {
1576 }
static void ReleaseCatCacheWithOwner(HeapTuple tuple, ResourceOwner resowner)
Definition: catcache.c:1579
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165

References CurrentResourceOwner, and ReleaseCatCacheWithOwner().

Referenced by ReleaseSysCache().

◆ ReleaseCatCacheList()

◆ ResetCatalogCaches()

void ResetCatalogCaches ( void  )

Definition at line 753 of file catcache.c.

754 {
755  slist_iter iter;
756 
757  CACHE_elog(DEBUG2, "ResetCatalogCaches called");
758 
760  {
761  CatCache *cache = slist_container(CatCache, cc_next, iter.cur);
762 
763  ResetCatalogCache(cache);
764  }
765 
766  CACHE_elog(DEBUG2, "end of ResetCatalogCaches call");
767 }

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

Referenced by InvalidateSystemCachesExtended().

◆ SearchCatCache()

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

Definition at line 1261 of file catcache.c.

1266 {
1267  return SearchCatCacheInternal(cache, cache->cc_nkeys, v1, v2, v3, v4);
1268 }
static HeapTuple SearchCatCacheInternal(CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4)
Definition: catcache.c:1312

References catcache::cc_nkeys, and SearchCatCacheInternal().

Referenced by SearchSysCache().

◆ SearchCatCache1()

HeapTuple SearchCatCache1 ( CatCache cache,
Datum  v1 
)

Definition at line 1278 of file catcache.c.

1280 {
1281  return SearchCatCacheInternal(cache, 1, v1, 0, 0, 0);
1282 }

References SearchCatCacheInternal().

Referenced by SearchSysCache1().

◆ SearchCatCache2()

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

Definition at line 1286 of file catcache.c.

1288 {
1289  return SearchCatCacheInternal(cache, 2, v1, v2, 0, 0);
1290 }

References SearchCatCacheInternal().

Referenced by SearchSysCache2().

◆ SearchCatCache3()

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

Definition at line 1294 of file catcache.c.

1296 {
1297  return SearchCatCacheInternal(cache, 3, v1, v2, v3, 0);
1298 }

References SearchCatCacheInternal().

Referenced by SearchSysCache3().

◆ SearchCatCache4()

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

Definition at line 1302 of file catcache.c.

1304 {
1305  return SearchCatCacheInternal(cache, 4, v1, v2, v3, v4);
1306 }

References SearchCatCacheInternal().

Referenced by SearchSysCache4().

◆ SearchCatCacheList()

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

Definition at line 1646 of file catcache.c.

1651 {
1652  Datum v4 = 0; /* dummy last-column value */
1654  uint32 lHashValue;
1655  Index lHashIndex;
1656  dlist_iter iter;
1657  dlist_head *lbucket;
1658  CatCList *cl;
1659  CatCTup *ct;
1660  List *volatile ctlist;
1661  ListCell *ctlist_item;
1662  int nmembers;
1663  bool ordered;
1664  HeapTuple ntp;
1665  MemoryContext oldcxt;
1666  int i;
1667 
1668  /*
1669  * one-time startup overhead for each cache
1670  */
1671  if (unlikely(cache->cc_tupdesc == NULL))
1673 
1674  Assert(nkeys > 0 && nkeys < cache->cc_nkeys);
1675 
1676 #ifdef CATCACHE_STATS
1677  cache->cc_lsearches++;
1678 #endif
1679 
1680  /* Initialize local parameter array */
1681  arguments[0] = v1;
1682  arguments[1] = v2;
1683  arguments[2] = v3;
1684  arguments[3] = v4;
1685 
1686  /*
1687  * If we haven't previously done a list search in this cache, create the
1688  * bucket header array; otherwise, consider whether it's time to enlarge
1689  * it.
1690  */
1691  if (cache->cc_lbucket == NULL)
1692  {
1693  /* Arbitrary initial size --- must be a power of 2 */
1694  int nbuckets = 16;
1695 
1696  cache->cc_lbucket = (dlist_head *)
1698  nbuckets * sizeof(dlist_head));
1699  /* Don't set cc_nlbuckets if we get OOM allocating cc_lbucket */
1700  cache->cc_nlbuckets = nbuckets;
1701  }
1702  else
1703  {
1704  /*
1705  * If the hash table has become too full, enlarge the buckets array.
1706  * Quite arbitrarily, we enlarge when fill factor > 2.
1707  */
1708  if (cache->cc_nlist > cache->cc_nlbuckets * 2)
1709  RehashCatCacheLists(cache);
1710  }
1711 
1712  /*
1713  * Find the hash bucket in which to look for the CatCList.
1714  */
1715  lHashValue = CatalogCacheComputeHashValue(cache, nkeys, v1, v2, v3, v4);
1716  lHashIndex = HASH_INDEX(lHashValue, cache->cc_nlbuckets);
1717 
1718  /*
1719  * scan the items until we find a match or exhaust our list
1720  *
1721  * Note: it's okay to use dlist_foreach here, even though we modify the
1722  * dlist within the loop, because we don't continue the loop afterwards.
1723  */
1724  lbucket = &cache->cc_lbucket[lHashIndex];
1725  dlist_foreach(iter, lbucket)
1726  {
1727  cl = dlist_container(CatCList, cache_elem, iter.cur);
1728 
1729  if (cl->dead)
1730  continue; /* ignore dead entries */
1731 
1732  if (cl->hash_value != lHashValue)
1733  continue; /* quickly skip entry if wrong hash val */
1734 
1735  /*
1736  * see if the cached list matches our key.
1737  */
1738  if (cl->nkeys != nkeys)
1739  continue;
1740 
1741  if (!CatalogCacheCompareTuple(cache, nkeys, cl->keys, arguments))
1742  continue;
1743 
1744  /*
1745  * We found a matching list. Move the list to the front of the list
1746  * for its hashbucket, so as to speed subsequent searches. (We do not
1747  * move the members to the fronts of their hashbucket lists, however,
1748  * since there's no point in that unless they are searched for
1749  * individually.)
1750  */
1751  dlist_move_head(lbucket, &cl->cache_elem);
1752 
1753  /* Bump the list's refcount and return it */
1755  cl->refcount++;
1757 
1758  CACHE_elog(DEBUG2, "SearchCatCacheList(%s): found list",
1759  cache->cc_relname);
1760 
1761 #ifdef CATCACHE_STATS
1762  cache->cc_lhits++;
1763 #endif
1764 
1765  return cl;
1766  }
1767 
1768  /*
1769  * List was not found in cache, so we have to build it by reading the
1770  * relation. For each matching tuple found in the relation, use an
1771  * existing cache entry if possible, else build a new one.
1772  *
1773  * We have to bump the member refcounts temporarily to ensure they won't
1774  * get dropped from the cache while loading other members. We use a PG_TRY
1775  * block to ensure we can undo those refcounts if we get an error before
1776  * we finish constructing the CatCList. ctlist must be valid throughout
1777  * the PG_TRY block.
1778  */
1779  ctlist = NIL;
1780 
1781  PG_TRY();
1782  {
1783  ScanKeyData cur_skey[CATCACHE_MAXKEYS];
1784  Relation relation;
1785  SysScanDesc scandesc;
1786  bool stale;
1787 
1788  relation = table_open(cache->cc_reloid, AccessShareLock);
1789 
1790  do
1791  {
1792  /*
1793  * Ok, need to make a lookup in the relation, copy the scankey and
1794  * fill out any per-call fields. (We must re-do this when
1795  * retrying, because systable_beginscan scribbles on the scankey.)
1796  */
1797  memcpy(cur_skey, cache->cc_skey, sizeof(ScanKeyData) * cache->cc_nkeys);
1798  cur_skey[0].sk_argument = v1;
1799  cur_skey[1].sk_argument = v2;
1800  cur_skey[2].sk_argument = v3;
1801  cur_skey[3].sk_argument = v4;
1802 
1803  scandesc = systable_beginscan(relation,
1804  cache->cc_indexoid,
1805  IndexScanOK(cache, cur_skey),
1806  NULL,
1807  nkeys,
1808  cur_skey);
1809 
1810  /* The list will be ordered iff we are doing an index scan */
1811  ordered = (scandesc->irel != NULL);
1812 
1813  stale = false;
1814 
1815  while (HeapTupleIsValid(ntp = systable_getnext(scandesc)))
1816  {
1817  uint32 hashValue;
1818  Index hashIndex;
1819  bool found = false;
1820  dlist_head *bucket;
1821 
1822  /*
1823  * See if there's an entry for this tuple already.
1824  */
1825  ct = NULL;
1826  hashValue = CatalogCacheComputeTupleHashValue(cache, cache->cc_nkeys, ntp);
1827  hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
1828 
1829  bucket = &cache->cc_bucket[hashIndex];
1830  dlist_foreach(iter, bucket)
1831  {
1832  ct = dlist_container(CatCTup, cache_elem, iter.cur);
1833 
1834  if (ct->dead || ct->negative)
1835  continue; /* ignore dead and negative entries */
1836 
1837  if (ct->hash_value != hashValue)
1838  continue; /* quickly skip entry if wrong hash val */
1839 
1840  if (!ItemPointerEquals(&(ct->tuple.t_self), &(ntp->t_self)))
1841  continue; /* not same tuple */
1842 
1843  /*
1844  * Found a match, but can't use it if it belongs to
1845  * another list already
1846  */
1847  if (ct->c_list)
1848  continue;
1849 
1850  found = true;
1851  break; /* A-OK */
1852  }
1853 
1854  if (!found)
1855  {
1856  /* We didn't find a usable entry, so make a new one */
1857  ct = CatalogCacheCreateEntry(cache, ntp, scandesc, NULL,
1858  hashValue, hashIndex);
1859  /* upon failure, we must start the scan over */
1860  if (ct == NULL)
1861  {
1862  /*
1863  * Release refcounts on any items we already had. We
1864  * dare not try to free them if they're now
1865  * unreferenced, since an error while doing that would
1866  * result in the PG_CATCH below doing extra refcount
1867  * decrements. Besides, we'll likely re-adopt those
1868  * items in the next iteration, so it's not worth
1869  * complicating matters to try to get rid of them.
1870  */
1871  foreach(ctlist_item, ctlist)
1872  {
1873  ct = (CatCTup *) lfirst(ctlist_item);
1874  Assert(ct->c_list == NULL);
1875  Assert(ct->refcount > 0);
1876  ct->refcount--;
1877  }
1878  /* Reset ctlist in preparation for new try */
1879  ctlist = NIL;
1880  stale = true;
1881  break;
1882  }
1883  }
1884 
1885  /* Careful here: add entry to ctlist, then bump its refcount */
1886  /* This way leaves state correct if lappend runs out of memory */
1887  ctlist = lappend(ctlist, ct);
1888  ct->refcount++;
1889  }
1890 
1891  systable_endscan(scandesc);
1892  } while (stale);
1893 
1894  table_close(relation, AccessShareLock);
1895 
1896  /* Make sure the resource owner has room to remember this entry. */
1898 
1899  /* Now we can build the CatCList entry. */
1901  nmembers = list_length(ctlist);
1902  cl = (CatCList *)
1903  palloc(offsetof(CatCList, members) + nmembers * sizeof(CatCTup *));
1904 
1905  /* Extract key values */
1906  CatCacheCopyKeys(cache->cc_tupdesc, nkeys, cache->cc_keyno,
1907  arguments, cl->keys);
1908  MemoryContextSwitchTo(oldcxt);
1909 
1910  /*
1911  * We are now past the last thing that could trigger an elog before we
1912  * have finished building the CatCList and remembering it in the
1913  * resource owner. So it's OK to fall out of the PG_TRY, and indeed
1914  * we'd better do so before we start marking the members as belonging
1915  * to the list.
1916  */
1917  }
1918  PG_CATCH();
1919  {
1920  foreach(ctlist_item, ctlist)
1921  {
1922  ct = (CatCTup *) lfirst(ctlist_item);
1923  Assert(ct->c_list == NULL);
1924  Assert(ct->refcount > 0);
1925  ct->refcount--;
1926  if (
1927 #ifndef CATCACHE_FORCE_RELEASE
1928  ct->dead &&
1929 #endif
1930  ct->refcount == 0 &&
1931  (ct->c_list == NULL || ct->c_list->refcount == 0))
1932  CatCacheRemoveCTup(cache, ct);
1933  }
1934 
1935  PG_RE_THROW();
1936  }
1937  PG_END_TRY();
1938 
1939  cl->cl_magic = CL_MAGIC;
1940  cl->my_cache = cache;
1941  cl->refcount = 0; /* for the moment */
1942  cl->dead = false;
1943  cl->ordered = ordered;
1944  cl->nkeys = nkeys;
1945  cl->hash_value = lHashValue;
1946  cl->n_members = nmembers;
1947 
1948  i = 0;
1949  foreach(ctlist_item, ctlist)
1950  {
1951  cl->members[i++] = ct = (CatCTup *) lfirst(ctlist_item);
1952  Assert(ct->c_list == NULL);
1953  ct->c_list = cl;
1954  /* release the temporary refcount on the member */
1955  Assert(ct->refcount > 0);
1956  ct->refcount--;
1957  /* mark list dead if any members already dead */
1958  if (ct->dead)
1959  cl->dead = true;
1960  }
1961  Assert(i == nmembers);
1962 
1963  /*
1964  * Add the CatCList to the appropriate bucket, and count it.
1965  */
1966  dlist_push_head(lbucket, &cl->cache_elem);
1967 
1968  cache->cc_nlist++;
1969 
1970  /* Finally, bump the list's refcount and return it */
1971  cl->refcount++;
1973 
1974  CACHE_elog(DEBUG2, "SearchCatCacheList(%s): made list of %d members",
1975  cache->cc_relname, nmembers);
1976 
1977  return cl;
1978 }
#define unlikely(x)
Definition: c.h:311
static CatCTup * CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, SysScanDesc scandesc, Datum *arguments, uint32 hashValue, Index hashIndex)
Definition: catcache.c:2026
static void CatCacheCopyKeys(TupleDesc tupdesc, int nkeys, int *attnos, Datum *srckeys, Datum *dstkeys)
Definition: catcache.c:2180
static bool CatalogCacheCompareTuple(const CatCache *cache, int nkeys, const Datum *cachekeys, const Datum *searchkeys)
Definition: catcache.c:422
static void RehashCatCacheLists(CatCache *cp)
Definition: catcache.c:972
static void ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
Definition: catcache.c:150
static bool IndexScanOK(CatCache *cache, ScanKey cur_skey)
Definition: catcache.c:1196
#define CATCACHE_MAXKEYS
Definition: catcache.h:35
#define CL_MAGIC
Definition: catcache.h:162
#define PG_RE_THROW()
Definition: elog.h:411
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_CATCH(...)
Definition: elog.h:380
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
#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
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:35
List * lappend(List *list, void *datum)
Definition: list.c:339
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1214
#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
uintptr_t Datum
Definition: postgres.h:64
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:442
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
Datum sk_argument
Definition: skey.h:72
Relation irel
Definition: relscan.h:184
ScanKeyData cc_skey[CATCACHE_MAXKEYS]
Definition: catcache.h:64
dlist_node cache_elem
Definition: catcache.h:166
CatCache * my_cache
Definition: catcache.h:179
int cl_magic
Definition: catcache.h:161
short nkeys
Definition: catcache.h:177
Datum keys[CATCACHE_MAXKEYS]
Definition: catcache.h:172
bool ordered
Definition: catcache.h:176
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:180
uint32 hash_value
Definition: catcache.h:164
int n_members
Definition: catcache.h:178
bool negative
Definition: catcache.h:122
HeapTupleData tuple
Definition: catcache.h:123
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, catclist::cache_elem, CACHE_elog, CacheMemoryContext, CatalogCacheCompareTuple(), CatalogCacheComputeHashValue(), CatalogCacheComputeTupleHashValue(), CatalogCacheCreateEntry(), CatalogCacheInitializeCache(), 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, dlist_iter::cur, CurrentResourceOwner, catctup::dead, catclist::dead, DEBUG2, dlist_container, dlist_foreach, dlist_move_head(), dlist_push_head(), HASH_INDEX, catctup::hash_value, catclist::hash_value, HeapTupleIsValid, i, IndexScanOK(), SysScanDescData::irel, ItemPointerEquals(), catclist::keys, lappend(), lfirst, list_length(), catclist::members, MemoryContextAllocZero(), MemoryContextSwitchTo(), catclist::my_cache, catclist::n_members, catctup::negative, 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(), catctup::tuple, and unlikely.

Referenced by SearchSysCacheList().

Variable Documentation

◆ CacheMemoryContext

PGDLLIMPORT MemoryContext CacheMemoryContext
extern

Definition at line 152 of file mcxt.c.