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

785 {
786  slist_iter iter;
787 
788  CACHE_elog(DEBUG2, "CatalogCacheFlushCatalog called for %u", catId);
789 
791  {
792  CatCache *cache = slist_container(CatCache, cc_next, iter.cur);
793 
794  /* Does this cache store tuples of the target catalog? */
795  if (cache->cc_reloid == catId)
796  {
797  /* Yes, so flush all its contents */
798  ResetCatalogCache(cache);
799 
800  /* Tell inval.c to call syscache callbacks for this cache */
801  CallSyscacheCallbacks(cache->id, 0);
802  }
803  }
804 
805  CACHE_elog(DEBUG2, "end of CatalogCacheFlushCatalog call");
806 }
static CatCacheHeader * CacheHdr
Definition: catcache.c:65
static void ResetCatalogCache(CatCache *cache)
Definition: catcache.c:702
#define CACHE_elog(...)
Definition: catcache.c:61
#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 607 of file catcache.c.

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

681 {
682  /*
683  * Purely for paranoia, check that context doesn't exist; caller probably
684  * did so already.
685  */
686  if (!CacheMemoryContext)
688  "CacheMemoryContext",
690 }
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 1613 of file catcache.c.

1618 {
1619  /*
1620  * one-time startup overhead for each cache
1621  */
1622  if (cache->cc_tupdesc == NULL)
1624 
1625  /*
1626  * calculate the hash value
1627  */
1628  return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, v1, v2, v3, v4);
1629 }
static void CatalogCacheInitializeCache(CatCache *cache)
Definition: catcache.c:1036
static uint32 CatalogCacheComputeHashValue(CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4)
Definition: catcache.c:326
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 828 of file catcache.c.

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

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

2292 {
2293  slist_iter iter;
2294  Oid reloid;
2295 
2296  CACHE_elog(DEBUG2, "PrepareToInvalidateCacheTuple: called");
2297 
2298  /*
2299  * sanity checks
2300  */
2301  Assert(RelationIsValid(relation));
2302  Assert(HeapTupleIsValid(tuple));
2303  Assert(PointerIsValid(function));
2304  Assert(CacheHdr != NULL);
2305 
2306  reloid = RelationGetRelid(relation);
2307 
2308  /* ----------------
2309  * for each cache
2310  * if the cache contains tuples from the specified relation
2311  * compute the tuple's hash value(s) in this cache,
2312  * and call the passed function to register the information.
2313  * ----------------
2314  */
2315 
2317  {
2318  CatCache *ccp = slist_container(CatCache, cc_next, iter.cur);
2319  uint32 hashvalue;
2320  Oid dbid;
2321 
2322  if (ccp->cc_reloid != reloid)
2323  continue;
2324 
2325  /* Just in case cache hasn't finished initialization yet... */
2326  if (ccp->cc_tupdesc == NULL)
2328 
2329  hashvalue = CatalogCacheComputeTupleHashValue(ccp, ccp->cc_nkeys, tuple);
2330  dbid = ccp->cc_relisshared ? (Oid) 0 : MyDatabaseId;
2331 
2332  (*function) (ccp->id, hashvalue, dbid);
2333 
2334  if (newtuple)
2335  {
2336  uint32 newhashvalue;
2337 
2338  newhashvalue = CatalogCacheComputeTupleHashValue(ccp, ccp->cc_nkeys, newtuple);
2339 
2340  if (newhashvalue != hashvalue)
2341  (*function) (ccp->id, newhashvalue, dbid);
2342  }
2343  }
2344 }
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:368
Oid MyDatabaseId
Definition: globals.c:92
#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 1574 of file catcache.c.

1575 {
1577 }
static void ReleaseCatCacheWithOwner(HeapTuple tuple, ResourceOwner resowner)
Definition: catcache.c:1580
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165

References CurrentResourceOwner, and ReleaseCatCacheWithOwner().

Referenced by ReleaseSysCache().

◆ ReleaseCatCacheList()

◆ ResetCatalogCaches()

void ResetCatalogCaches ( void  )

Definition at line 754 of file catcache.c.

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

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

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

References catcache::cc_nkeys, and SearchCatCacheInternal().

Referenced by SearchSysCache().

◆ SearchCatCache1()

HeapTuple SearchCatCache1 ( CatCache cache,
Datum  v1 
)

Definition at line 1279 of file catcache.c.

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

References SearchCatCacheInternal().

Referenced by SearchSysCache1().

◆ SearchCatCache2()

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

Definition at line 1287 of file catcache.c.

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

References SearchCatCacheInternal().

Referenced by SearchSysCache2().

◆ SearchCatCache3()

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

Definition at line 1295 of file catcache.c.

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

References SearchCatCacheInternal().

Referenced by SearchSysCache3().

◆ SearchCatCache4()

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

Definition at line 1303 of file catcache.c.

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

References SearchCatCacheInternal().

Referenced by SearchSysCache4().

◆ SearchCatCacheList()

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

Definition at line 1647 of file catcache.c.

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