PostgreSQL Source Code  git master
catcache.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heaptoast.h"
#include "access/relscan.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "common/hashfn.h"
#include "miscadmin.h"
#include "port/pg_bitutils.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/resowner_private.h"
#include "utils/syscache.h"
Include dependency graph for catcache.c:

Go to the source code of this file.

Macros

#define HASH_INDEX(h, sz)   ((Index) ((h) & ((sz) - 1)))
 
#define CACHE_elog(...)
 
#define InitCatCache_DEBUG2
 
#define CatalogCacheInitializeCache_DEBUG1
 
#define CatalogCacheInitializeCache_DEBUG2
 

Functions

static HeapTuple SearchCatCacheInternal (CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4)
 
static pg_noinline HeapTuple SearchCatCacheMiss (CatCache *cache, int nkeys, uint32 hashValue, Index hashIndex, Datum v1, Datum v2, Datum v3, Datum v4)
 
static uint32 CatalogCacheComputeHashValue (CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4)
 
static uint32 CatalogCacheComputeTupleHashValue (CatCache *cache, int nkeys, HeapTuple tuple)
 
static bool CatalogCacheCompareTuple (const CatCache *cache, int nkeys, const Datum *cachekeys, const Datum *searchkeys)
 
static void CatCacheRemoveCTup (CatCache *cache, CatCTup *ct)
 
static void CatCacheRemoveCList (CatCache *cache, CatCList *cl)
 
static void CatalogCacheInitializeCache (CatCache *cache)
 
static CatCTupCatalogCacheCreateEntry (CatCache *cache, HeapTuple ntp, Datum *arguments, uint32 hashValue, Index hashIndex, bool negative)
 
static void CatCacheFreeKeys (TupleDesc tupdesc, int nkeys, int *attnos, Datum *keys)
 
static void CatCacheCopyKeys (TupleDesc tupdesc, int nkeys, int *attnos, Datum *srckeys, Datum *dstkeys)
 
static bool chareqfast (Datum a, Datum b)
 
static uint32 charhashfast (Datum datum)
 
static bool nameeqfast (Datum a, Datum b)
 
static uint32 namehashfast (Datum datum)
 
static bool int2eqfast (Datum a, Datum b)
 
static uint32 int2hashfast (Datum datum)
 
static bool int4eqfast (Datum a, Datum b)
 
static uint32 int4hashfast (Datum datum)
 
static bool texteqfast (Datum a, Datum b)
 
static uint32 texthashfast (Datum datum)
 
static bool oidvectoreqfast (Datum a, Datum b)
 
static uint32 oidvectorhashfast (Datum datum)
 
static void GetCCHashEqFuncs (Oid keytype, CCHashFN *hashfunc, RegProcedure *eqfunc, CCFastEqualFN *fasteqfunc)
 
void CatCacheInvalidate (CatCache *cache, uint32 hashValue)
 
void CreateCacheMemoryContext (void)
 
static void ResetCatalogCache (CatCache *cache)
 
void ResetCatalogCaches (void)
 
void CatalogCacheFlushCatalog (Oid catId)
 
CatCacheInitCatCache (int id, Oid reloid, Oid indexoid, int nkeys, const int *key, int nbuckets)
 
static void RehashCatCache (CatCache *cp)
 
void InitCatCachePhase2 (CatCache *cache, bool touch_index)
 
static bool IndexScanOK (CatCache *cache, ScanKey cur_skey)
 
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 PrepareToInvalidateCacheTuple (Relation relation, HeapTuple tuple, HeapTuple newtuple, void(*function)(int, uint32, Oid))
 
void PrintCatCacheLeakWarning (HeapTuple tuple)
 
void PrintCatCacheListLeakWarning (CatCList *list)
 

Variables

static CatCacheHeaderCacheHdr = NULL
 

Macro Definition Documentation

◆ CACHE_elog

#define CACHE_elog (   ...)

Definition at line 60 of file catcache.c.

◆ CatalogCacheInitializeCache_DEBUG1

#define CatalogCacheInitializeCache_DEBUG1

Definition at line 911 of file catcache.c.

◆ CatalogCacheInitializeCache_DEBUG2

#define CatalogCacheInitializeCache_DEBUG2

Definition at line 912 of file catcache.c.

◆ HASH_INDEX

#define HASH_INDEX (   h,
  sz 
)    ((Index) ((h) & ((sz) - 1)))

Definition at line 50 of file catcache.c.

◆ InitCatCache_DEBUG2

#define InitCatCache_DEBUG2

Definition at line 753 of file catcache.c.

Function Documentation

◆ CatalogCacheCompareTuple()

static bool CatalogCacheCompareTuple ( const CatCache cache,
int  nkeys,
const Datum cachekeys,
const Datum searchkeys 
)
inlinestatic

Definition at line 368 of file catcache.c.

371 {
372  const CCFastEqualFN *cc_fastequal = cache->cc_fastequal;
373  int i;
374 
375  for (i = 0; i < nkeys; i++)
376  {
377  if (!(cc_fastequal[i]) (cachekeys[i], searchkeys[i]))
378  return false;
379  }
380  return true;
381 }
bool(* CCFastEqualFN)(Datum a, Datum b)
Definition: catcache.h:42
int i
Definition: isn.c:73
CCFastEqualFN cc_fastequal[CATCACHE_MAXKEYS]
Definition: catcache.h:51

References catcache::cc_fastequal, and i.

Referenced by SearchCatCacheInternal(), and SearchCatCacheList().

◆ CatalogCacheComputeHashValue()

static uint32 CatalogCacheComputeHashValue ( CatCache cache,
int  nkeys,
Datum  v1,
Datum  v2,
Datum  v3,
Datum  v4 
)
static

Definition at line 271 of file catcache.c.

273 {
274  uint32 hashValue = 0;
275  uint32 oneHash;
276  CCHashFN *cc_hashfunc = cache->cc_hashfunc;
277 
278  CACHE_elog(DEBUG2, "CatalogCacheComputeHashValue %s %d %p",
279  cache->cc_relname, nkeys, cache);
280 
281  switch (nkeys)
282  {
283  case 4:
284  oneHash = (cc_hashfunc[3]) (v4);
285  hashValue ^= pg_rotate_left32(oneHash, 24);
286  /* FALLTHROUGH */
287  case 3:
288  oneHash = (cc_hashfunc[2]) (v3);
289  hashValue ^= pg_rotate_left32(oneHash, 16);
290  /* FALLTHROUGH */
291  case 2:
292  oneHash = (cc_hashfunc[1]) (v2);
293  hashValue ^= pg_rotate_left32(oneHash, 8);
294  /* FALLTHROUGH */
295  case 1:
296  oneHash = (cc_hashfunc[0]) (v1);
297  hashValue ^= oneHash;
298  break;
299  default:
300  elog(FATAL, "wrong number of hash keys: %d", nkeys);
301  break;
302  }
303 
304  return hashValue;
305 }
unsigned int uint32
Definition: c.h:490
#define CACHE_elog(...)
Definition: catcache.c:60
uint32(* CCHashFN)(Datum datum)
Definition: catcache.h:39
#define FATAL
Definition: elog.h:41
#define DEBUG2
Definition: elog.h:29
static uint32 pg_rotate_left32(uint32 word, int n)
Definition: pg_bitutils.h:322
const char * cc_relname
Definition: catcache.h:57
CCHashFN cc_hashfunc[CATCACHE_MAXKEYS]
Definition: catcache.h:50

References CACHE_elog, catcache::cc_hashfunc, catcache::cc_relname, DEBUG2, elog(), FATAL, and pg_rotate_left32().

Referenced by CatalogCacheComputeTupleHashValue(), GetCatCacheHashValue(), SearchCatCacheInternal(), and SearchCatCacheList().

◆ CatalogCacheComputeTupleHashValue()

static uint32 CatalogCacheComputeTupleHashValue ( CatCache cache,
int  nkeys,
HeapTuple  tuple 
)
static

Definition at line 313 of file catcache.c.

314 {
315  Datum v1 = 0,
316  v2 = 0,
317  v3 = 0,
318  v4 = 0;
319  bool isNull = false;
320  int *cc_keyno = cache->cc_keyno;
321  TupleDesc cc_tupdesc = cache->cc_tupdesc;
322 
323  /* Now extract key fields from tuple, insert into scankey */
324  switch (nkeys)
325  {
326  case 4:
327  v4 = fastgetattr(tuple,
328  cc_keyno[3],
329  cc_tupdesc,
330  &isNull);
331  Assert(!isNull);
332  /* FALLTHROUGH */
333  case 3:
334  v3 = fastgetattr(tuple,
335  cc_keyno[2],
336  cc_tupdesc,
337  &isNull);
338  Assert(!isNull);
339  /* FALLTHROUGH */
340  case 2:
341  v2 = fastgetattr(tuple,
342  cc_keyno[1],
343  cc_tupdesc,
344  &isNull);
345  Assert(!isNull);
346  /* FALLTHROUGH */
347  case 1:
348  v1 = fastgetattr(tuple,
349  cc_keyno[0],
350  cc_tupdesc,
351  &isNull);
352  Assert(!isNull);
353  break;
354  default:
355  elog(FATAL, "wrong number of hash keys: %d", nkeys);
356  break;
357  }
358 
359  return CatalogCacheComputeHashValue(cache, nkeys, v1, v2, v3, v4);
360 }
static uint32 CatalogCacheComputeHashValue(CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4)
Definition: catcache.c:271
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:749
Assert(fmt[strlen(fmt) - 1] !='\n')
uintptr_t Datum
Definition: postgres.h:64
int cc_keyno[CATCACHE_MAXKEYS]
Definition: catcache.h:53
TupleDesc cc_tupdesc
Definition: catcache.h:48

References Assert(), CatalogCacheComputeHashValue(), catcache::cc_keyno, catcache::cc_tupdesc, elog(), fastgetattr(), and FATAL.

Referenced by PrepareToInvalidateCacheTuple(), and SearchCatCacheList().

◆ CatalogCacheCreateEntry()

static CatCTup * CatalogCacheCreateEntry ( CatCache cache,
HeapTuple  ntp,
Datum arguments,
uint32  hashValue,
Index  hashIndex,
bool  negative 
)
static

Definition at line 1799 of file catcache.c.

1802 {
1803  CatCTup *ct;
1804  HeapTuple dtp;
1805  MemoryContext oldcxt;
1806 
1807  /* negative entries have no tuple associated */
1808  if (ntp)
1809  {
1810  int i;
1811 
1812  Assert(!negative);
1813 
1814  /*
1815  * If there are any out-of-line toasted fields in the tuple, expand
1816  * them in-line. This saves cycles during later use of the catcache
1817  * entry, and also protects us against the possibility of the toast
1818  * tuples being freed before we attempt to fetch them, in case of
1819  * something using a slightly stale catcache entry.
1820  */
1821  if (HeapTupleHasExternal(ntp))
1822  dtp = toast_flatten_tuple(ntp, cache->cc_tupdesc);
1823  else
1824  dtp = ntp;
1825 
1826  /* Allocate memory for CatCTup and the cached tuple in one go */
1828 
1829  ct = (CatCTup *) palloc(sizeof(CatCTup) +
1830  MAXIMUM_ALIGNOF + dtp->t_len);
1831  ct->tuple.t_len = dtp->t_len;
1832  ct->tuple.t_self = dtp->t_self;
1833  ct->tuple.t_tableOid = dtp->t_tableOid;
1834  ct->tuple.t_data = (HeapTupleHeader)
1835  MAXALIGN(((char *) ct) + sizeof(CatCTup));
1836  /* copy tuple contents */
1837  memcpy((char *) ct->tuple.t_data,
1838  (const char *) dtp->t_data,
1839  dtp->t_len);
1840  MemoryContextSwitchTo(oldcxt);
1841 
1842  if (dtp != ntp)
1843  heap_freetuple(dtp);
1844 
1845  /* extract keys - they'll point into the tuple if not by-value */
1846  for (i = 0; i < cache->cc_nkeys; i++)
1847  {
1848  Datum atp;
1849  bool isnull;
1850 
1851  atp = heap_getattr(&ct->tuple,
1852  cache->cc_keyno[i],
1853  cache->cc_tupdesc,
1854  &isnull);
1855  Assert(!isnull);
1856  ct->keys[i] = atp;
1857  }
1858  }
1859  else
1860  {
1861  Assert(negative);
1863  ct = (CatCTup *) palloc(sizeof(CatCTup));
1864 
1865  /*
1866  * Store keys - they'll point into separately allocated memory if not
1867  * by-value.
1868  */
1869  CatCacheCopyKeys(cache->cc_tupdesc, cache->cc_nkeys, cache->cc_keyno,
1870  arguments, ct->keys);
1871  MemoryContextSwitchTo(oldcxt);
1872  }
1873 
1874  /*
1875  * Finish initializing the CatCTup header, and add it to the cache's
1876  * linked list and counts.
1877  */
1878  ct->ct_magic = CT_MAGIC;
1879  ct->my_cache = cache;
1880  ct->c_list = NULL;
1881  ct->refcount = 0; /* for the moment */
1882  ct->dead = false;
1883  ct->negative = negative;
1884  ct->hash_value = hashValue;
1885 
1886  dlist_push_head(&cache->cc_bucket[hashIndex], &ct->cache_elem);
1887 
1888  cache->cc_ntup++;
1889  CacheHdr->ch_ntup++;
1890 
1891  /*
1892  * If the hash table has become too full, enlarge the buckets array. Quite
1893  * arbitrarily, we enlarge when fill factor > 2.
1894  */
1895  if (cache->cc_ntup > cache->cc_nbuckets * 2)
1896  RehashCatCache(cache);
1897 
1898  return ct;
1899 }
#define MAXALIGN(LEN)
Definition: c.h:795
static void RehashCatCache(CatCache *cp)
Definition: catcache.c:853
static void CatCacheCopyKeys(TupleDesc tupdesc, int nkeys, int *attnos, Datum *srckeys, Datum *dstkeys)
Definition: catcache.c:1930
static CatCacheHeader * CacheHdr
Definition: catcache.c:64
#define CT_MAGIC
Definition: catcache.h:89
HeapTuple toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc)
Definition: heaptoast.c:350
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:671
static void dlist_push_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:347
MemoryContext CacheMemoryContext
Definition: mcxt.c:144
void * palloc(Size size)
Definition: mcxt.c:1210
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
dlist_head * cc_bucket
Definition: catcache.h:49
int cc_nkeys
Definition: catcache.h:56
int cc_nbuckets
Definition: catcache.h:47
int cc_ntup
Definition: catcache.h:55
int ct_magic
Definition: catcache.h:88
int refcount
Definition: catcache.h:118
bool negative
Definition: catcache.h:120
dlist_node cache_elem
Definition: catcache.h:104
HeapTupleData tuple
Definition: catcache.h:121
CatCache * my_cache
Definition: catcache.h:132
struct catclist * c_list
Definition: catcache.h:130
Datum keys[CATCACHE_MAXKEYS]
Definition: catcache.h:97
bool dead
Definition: catcache.h:119
uint32 hash_value
Definition: catcache.h:91

References Assert(), catctup::c_list, catctup::cache_elem, CacheHdr, CacheMemoryContext, CatCacheCopyKeys(), catcache::cc_bucket, catcache::cc_keyno, catcache::cc_nbuckets, catcache::cc_nkeys, catcache::cc_ntup, catcache::cc_tupdesc, catcacheheader::ch_ntup, catctup::ct_magic, CT_MAGIC, catctup::dead, dlist_push_head(), catctup::hash_value, heap_freetuple(), heap_getattr(), HeapTupleHasExternal, i, catctup::keys, MAXALIGN, MemoryContextSwitchTo(), catctup::my_cache, catctup::negative, palloc(), catctup::refcount, RehashCatCache(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, toast_flatten_tuple(), and catctup::tuple.

Referenced by SearchCatCacheList(), and SearchCatCacheMiss().

◆ CatalogCacheFlushCatalog()

void CatalogCacheFlushCatalog ( Oid  catId)

Definition at line 713 of file catcache.c.

714 {
715  slist_iter iter;
716 
717  CACHE_elog(DEBUG2, "CatalogCacheFlushCatalog called for %u", catId);
718 
720  {
721  CatCache *cache = slist_container(CatCache, cc_next, iter.cur);
722 
723  /* Does this cache store tuples of the target catalog? */
724  if (cache->cc_reloid == catId)
725  {
726  /* Yes, so flush all its contents */
727  ResetCatalogCache(cache);
728 
729  /* Tell inval.c to call syscache callbacks for this cache */
730  CallSyscacheCallbacks(cache->id, 0);
731  }
732  }
733 
734  CACHE_elog(DEBUG2, "end of CatalogCacheFlushCatalog call");
735 }
static void ResetCatalogCache(CatCache *cache)
Definition: catcache.c:636
#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:1580
Oid cc_reloid
Definition: catcache.h:58
int id
Definition: catcache.h:46
slist_head ch_caches
Definition: catcache.h:184
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().

◆ CatalogCacheInitializeCache()

static void CatalogCacheInitializeCache ( CatCache cache)
static

Definition at line 916 of file catcache.c.

917 {
918  Relation relation;
919  MemoryContext oldcxt;
920  TupleDesc tupdesc;
921  int i;
922 
924 
925  relation = table_open(cache->cc_reloid, AccessShareLock);
926 
927  /*
928  * switch to the cache context so our allocations do not vanish at the end
929  * of a transaction
930  */
931  Assert(CacheMemoryContext != NULL);
932 
934 
935  /*
936  * copy the relcache's tuple descriptor to permanent cache storage
937  */
938  tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(relation));
939 
940  /*
941  * save the relation's name and relisshared flag, too (cc_relname is used
942  * only for debugging purposes)
943  */
944  cache->cc_relname = pstrdup(RelationGetRelationName(relation));
945  cache->cc_relisshared = RelationGetForm(relation)->relisshared;
946 
947  /*
948  * return to the caller's memory context and close the rel
949  */
950  MemoryContextSwitchTo(oldcxt);
951 
952  table_close(relation, AccessShareLock);
953 
954  CACHE_elog(DEBUG2, "CatalogCacheInitializeCache: %s, %d keys",
955  cache->cc_relname, cache->cc_nkeys);
956 
957  /*
958  * initialize cache's key information
959  */
960  for (i = 0; i < cache->cc_nkeys; ++i)
961  {
962  Oid keytype;
963  RegProcedure eqfunc;
964 
966 
967  if (cache->cc_keyno[i] > 0)
968  {
969  Form_pg_attribute attr = TupleDescAttr(tupdesc,
970  cache->cc_keyno[i] - 1);
971 
972  keytype = attr->atttypid;
973  /* cache key columns should always be NOT NULL */
974  Assert(attr->attnotnull);
975  }
976  else
977  {
978  if (cache->cc_keyno[i] < 0)
979  elog(FATAL, "sys attributes are not supported in caches");
980  keytype = OIDOID;
981  }
982 
983  GetCCHashEqFuncs(keytype,
984  &cache->cc_hashfunc[i],
985  &eqfunc,
986  &cache->cc_fastequal[i]);
987 
988  /*
989  * Do equality-function lookup (we assume this won't need a catalog
990  * lookup for any supported type)
991  */
992  fmgr_info_cxt(eqfunc,
993  &cache->cc_skey[i].sk_func,
995 
996  /* Initialize sk_attno suitably for HeapKeyTest() and heap scans */
997  cache->cc_skey[i].sk_attno = cache->cc_keyno[i];
998 
999  /* Fill in sk_strategy as well --- always standard equality */
1001  cache->cc_skey[i].sk_subtype = InvalidOid;
1002  /* If a catcache key requires a collation, it must be C collation */
1003  cache->cc_skey[i].sk_collation = C_COLLATION_OID;
1004 
1005  CACHE_elog(DEBUG2, "CatalogCacheInitializeCache %s %d %p",
1006  cache->cc_relname, i, cache);
1007  }
1008 
1009  /*
1010  * mark this cache fully initialized
1011  */
1012  cache->cc_tupdesc = tupdesc;
1013 }
regproc RegProcedure
Definition: c.h:634
#define CatalogCacheInitializeCache_DEBUG1
Definition: catcache.c:911
static void GetCCHashEqFuncs(Oid keytype, CCHashFN *hashfunc, RegProcedure *eqfunc, CCFastEqualFN *fasteqfunc)
Definition: catcache.c:201
#define CatalogCacheInitializeCache_DEBUG2
Definition: catcache.c:912
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
#define AccessShareLock
Definition: lockdefs.h:36
char * pstrdup(const char *in)
Definition: mcxt.c:1624
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetForm(relation)
Definition: rel.h:497
#define RelationGetDescr(relation)
Definition: rel.h:529
#define RelationGetRelationName(relation)
Definition: rel.h:537
#define BTEqualStrategyNumber
Definition: stratnum.h:31
FmgrInfo sk_func
Definition: skey.h:71
Oid sk_subtype
Definition: skey.h:69
Oid sk_collation
Definition: skey.h:70
StrategyNumber sk_strategy
Definition: skey.h:68
AttrNumber sk_attno
Definition: skey.h:67
bool cc_relisshared
Definition: catcache.h:60
ScanKeyData cc_skey[CATCACHE_MAXKEYS]
Definition: catcache.h:62
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc)
Definition: tupdesc.c:151
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References AccessShareLock, Assert(), BTEqualStrategyNumber, CACHE_elog, CacheMemoryContext, CatalogCacheInitializeCache_DEBUG1, CatalogCacheInitializeCache_DEBUG2, catcache::cc_fastequal, catcache::cc_hashfunc, catcache::cc_keyno, catcache::cc_nkeys, catcache::cc_relisshared, catcache::cc_relname, catcache::cc_reloid, catcache::cc_skey, catcache::cc_tupdesc, CreateTupleDescCopyConstr(), DEBUG2, elog(), FATAL, fmgr_info_cxt(), GetCCHashEqFuncs(), i, InvalidOid, MemoryContextSwitchTo(), pstrdup(), RelationGetDescr, RelationGetForm, RelationGetRelationName, ScanKeyData::sk_attno, ScanKeyData::sk_collation, ScanKeyData::sk_func, ScanKeyData::sk_strategy, ScanKeyData::sk_subtype, table_close(), table_open(), and TupleDescAttr.

Referenced by GetCatCacheHashValue(), InitCatCachePhase2(), PrepareToInvalidateCacheTuple(), SearchCatCacheInternal(), and SearchCatCacheList().

◆ CatCacheCopyKeys()

static void CatCacheCopyKeys ( TupleDesc  tupdesc,
int  nkeys,
int *  attnos,
Datum srckeys,
Datum dstkeys 
)
static

Definition at line 1930 of file catcache.c.

1932 {
1933  int i;
1934 
1935  /*
1936  * XXX: memory and lookup performance could possibly be improved by
1937  * storing all keys in one allocation.
1938  */
1939 
1940  for (i = 0; i < nkeys; i++)
1941  {
1942  int attnum = attnos[i];
1943  Form_pg_attribute att = TupleDescAttr(tupdesc, attnum - 1);
1944  Datum src = srckeys[i];
1945  NameData srcname;
1946 
1947  /*
1948  * Must be careful in case the caller passed a C string where a NAME
1949  * is wanted: convert the given argument to a correctly padded NAME.
1950  * Otherwise the memcpy() done by datumCopy() could fall off the end
1951  * of memory.
1952  */
1953  if (att->atttypid == NAMEOID)
1954  {
1955  namestrcpy(&srcname, DatumGetCString(src));
1956  src = NameGetDatum(&srcname);
1957  }
1958 
1959  dstkeys[i] = datumCopy(src,
1960  att->attbyval,
1961  att->attlen);
1962  }
1963 }
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
void namestrcpy(Name name, const char *str)
Definition: name.c:233
int16 attnum
Definition: pg_attribute.h:74
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
Definition: c.h:725

References attnum, datumCopy(), DatumGetCString(), i, NameGetDatum(), namestrcpy(), and TupleDescAttr.

Referenced by CatalogCacheCreateEntry(), and SearchCatCacheList().

◆ CatCacheFreeKeys()

static void CatCacheFreeKeys ( TupleDesc  tupdesc,
int  nkeys,
int *  attnos,
Datum keys 
)
static

Definition at line 1905 of file catcache.c.

1906 {
1907  int i;
1908 
1909  for (i = 0; i < nkeys; i++)
1910  {
1911  int attnum = attnos[i];
1912  Form_pg_attribute att;
1913 
1914  /* system attribute are not supported in caches */
1915  Assert(attnum > 0);
1916 
1917  att = TupleDescAttr(tupdesc, attnum - 1);
1918 
1919  if (!att->attbyval)
1920  pfree(DatumGetPointer(keys[i]));
1921  }
1922 }
void pfree(void *pointer)
Definition: mcxt.c:1436
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312

References Assert(), attnum, DatumGetPointer(), i, pfree(), and TupleDescAttr.

Referenced by CatCacheRemoveCList(), and CatCacheRemoveCTup().

◆ CatCacheInvalidate()

void CatCacheInvalidate ( CatCache cache,
uint32  hashValue 
)

Definition at line 546 of file catcache.c.

547 {
548  Index hashIndex;
549  dlist_mutable_iter iter;
550 
551  CACHE_elog(DEBUG2, "CatCacheInvalidate: called");
552 
553  /*
554  * We don't bother to check whether the cache has finished initialization
555  * yet; if not, there will be no entries in it so no problem.
556  */
557 
558  /*
559  * Invalidate *all* CatCLists in this cache; it's too hard to tell which
560  * searches might still be correct, so just zap 'em all.
561  */
562  dlist_foreach_modify(iter, &cache->cc_lists)
563  {
564  CatCList *cl = dlist_container(CatCList, cache_elem, iter.cur);
565 
566  if (cl->refcount > 0)
567  cl->dead = true;
568  else
569  CatCacheRemoveCList(cache, cl);
570  }
571 
572  /*
573  * inspect the proper hash bucket for tuple matches
574  */
575  hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
576  dlist_foreach_modify(iter, &cache->cc_bucket[hashIndex])
577  {
578  CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur);
579 
580  if (hashValue == ct->hash_value)
581  {
582  if (ct->refcount > 0 ||
583  (ct->c_list && ct->c_list->refcount > 0))
584  {
585  ct->dead = true;
586  /* list, if any, was marked dead above */
587  Assert(ct->c_list == NULL || ct->c_list->dead);
588  }
589  else
590  CatCacheRemoveCTup(cache, ct);
591  CACHE_elog(DEBUG2, "CatCacheInvalidate: invalidated");
592 #ifdef CATCACHE_STATS
593  cache->cc_invals++;
594 #endif
595  /* could be multiple matches, so keep looking! */
596  }
597  }
598 }
unsigned int Index
Definition: c.h:598
static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
Definition: catcache.c:451
static void CatCacheRemoveCList(CatCache *cache, CatCList *cl)
Definition: catcache.c:493
#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
dlist_head cc_lists
Definition: catcache.h:54
int refcount
Definition: catcache.h:172
bool dead
Definition: catcache.h:173
dlist_node * cur
Definition: ilist.h:200

References Assert(), catctup::c_list, CACHE_elog, CatCacheRemoveCList(), CatCacheRemoveCTup(), catcache::cc_bucket, catcache::cc_lists, catcache::cc_nbuckets, dlist_mutable_iter::cur, catctup::dead, catclist::dead, DEBUG2, dlist_container, dlist_foreach_modify, HASH_INDEX, catctup::hash_value, catctup::refcount, and catclist::refcount.

Referenced by SysCacheInvalidate().

◆ CatCacheRemoveCList()

static void CatCacheRemoveCList ( CatCache cache,
CatCList cl 
)
static

Definition at line 493 of file catcache.c.

494 {
495  int i;
496 
497  Assert(cl->refcount == 0);
498  Assert(cl->my_cache == cache);
499 
500  /* delink from member tuples */
501  for (i = cl->n_members; --i >= 0;)
502  {
503  CatCTup *ct = cl->members[i];
504 
505  Assert(ct->c_list == cl);
506  ct->c_list = NULL;
507  /* if the member is dead and now has no references, remove it */
508  if (
509 #ifndef CATCACHE_FORCE_RELEASE
510  ct->dead &&
511 #endif
512  ct->refcount == 0)
513  CatCacheRemoveCTup(cache, ct);
514  }
515 
516  /* delink from linked list */
517  dlist_delete(&cl->cache_elem);
518 
519  /* free associated column data */
520  CatCacheFreeKeys(cache->cc_tupdesc, cl->nkeys,
521  cache->cc_keyno, cl->keys);
522 
523  pfree(cl);
524 }
static void CatCacheFreeKeys(TupleDesc tupdesc, int nkeys, int *attnos, Datum *keys)
Definition: catcache.c:1905
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
dlist_node cache_elem
Definition: catcache.h:164
CatCache * my_cache
Definition: catcache.h:177
short nkeys
Definition: catcache.h:175
Datum keys[CATCACHE_MAXKEYS]
Definition: catcache.h:170
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
int n_members
Definition: catcache.h:176

References Assert(), catctup::c_list, catclist::cache_elem, CatCacheFreeKeys(), CatCacheRemoveCTup(), catcache::cc_keyno, catcache::cc_tupdesc, catctup::dead, dlist_delete(), i, catclist::keys, catclist::members, catclist::my_cache, catclist::n_members, catclist::nkeys, pfree(), catctup::refcount, and catclist::refcount.

Referenced by CatCacheInvalidate(), CatCacheRemoveCTup(), ReleaseCatCacheList(), and ResetCatalogCache().

◆ CatCacheRemoveCTup()

static void CatCacheRemoveCTup ( CatCache cache,
CatCTup ct 
)
static

Definition at line 451 of file catcache.c.

452 {
453  Assert(ct->refcount == 0);
454  Assert(ct->my_cache == cache);
455 
456  if (ct->c_list)
457  {
458  /*
459  * The cleanest way to handle this is to call CatCacheRemoveCList,
460  * which will recurse back to me, and the recursive call will do the
461  * work. Set the "dead" flag to make sure it does recurse.
462  */
463  ct->dead = true;
464  CatCacheRemoveCList(cache, ct->c_list);
465  return; /* nothing left to do */
466  }
467 
468  /* delink from linked list */
469  dlist_delete(&ct->cache_elem);
470 
471  /*
472  * Free keys when we're dealing with a negative entry, normal entries just
473  * point into tuple, allocated together with the CatCTup.
474  */
475  if (ct->negative)
476  CatCacheFreeKeys(cache->cc_tupdesc, cache->cc_nkeys,
477  cache->cc_keyno, ct->keys);
478 
479  pfree(ct);
480 
481  --cache->cc_ntup;
482  --CacheHdr->ch_ntup;
483 }

References Assert(), catctup::c_list, catctup::cache_elem, CacheHdr, CatCacheFreeKeys(), CatCacheRemoveCList(), catcache::cc_keyno, catcache::cc_nkeys, catcache::cc_ntup, catcache::cc_tupdesc, catcacheheader::ch_ntup, catctup::dead, dlist_delete(), catctup::keys, catctup::my_cache, catctup::negative, pfree(), and catctup::refcount.

Referenced by CatCacheInvalidate(), CatCacheRemoveCList(), ReleaseCatCache(), ResetCatalogCache(), and SearchCatCacheList().

◆ chareqfast()

static bool chareqfast ( Datum  a,
Datum  b 
)
static

Definition at line 118 of file catcache.c.

119 {
120  return DatumGetChar(a) == DatumGetChar(b);
121 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69
static char DatumGetChar(Datum X)
Definition: postgres.h:112

References a, b, and DatumGetChar().

Referenced by GetCCHashEqFuncs().

◆ charhashfast()

static uint32 charhashfast ( Datum  datum)
static

Definition at line 124 of file catcache.c.

125 {
126  return murmurhash32((int32) DatumGetChar(datum));
127 }
signed int int32
Definition: c.h:478
static uint32 murmurhash32(uint32 data)
Definition: hashfn.h:92

References DatumGetChar(), and murmurhash32().

Referenced by GetCCHashEqFuncs().

◆ CreateCacheMemoryContext()

void CreateCacheMemoryContext ( void  )

Definition at line 614 of file catcache.c.

615 {
616  /*
617  * Purely for paranoia, check that context doesn't exist; caller probably
618  * did so already.
619  */
620  if (!CacheMemoryContext)
622  "CacheMemoryContext",
624 }
MemoryContext TopMemoryContext
Definition: mcxt.c:141
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153

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

1472 {
1473  /*
1474  * one-time startup overhead for each cache
1475  */
1476  if (cache->cc_tupdesc == NULL)
1478 
1479  /*
1480  * calculate the hash value
1481  */
1482  return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, v1, v2, v3, v4);
1483 }
static void CatalogCacheInitializeCache(CatCache *cache)
Definition: catcache.c:916

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

Referenced by GetSysCacheHashValue().

◆ GetCCHashEqFuncs()

static void GetCCHashEqFuncs ( Oid  keytype,
CCHashFN hashfunc,
RegProcedure eqfunc,
CCFastEqualFN fasteqfunc 
)
static

Definition at line 201 of file catcache.c.

202 {
203  switch (keytype)
204  {
205  case BOOLOID:
206  *hashfunc = charhashfast;
207  *fasteqfunc = chareqfast;
208  *eqfunc = F_BOOLEQ;
209  break;
210  case CHAROID:
211  *hashfunc = charhashfast;
212  *fasteqfunc = chareqfast;
213  *eqfunc = F_CHAREQ;
214  break;
215  case NAMEOID:
216  *hashfunc = namehashfast;
217  *fasteqfunc = nameeqfast;
218  *eqfunc = F_NAMEEQ;
219  break;
220  case INT2OID:
221  *hashfunc = int2hashfast;
222  *fasteqfunc = int2eqfast;
223  *eqfunc = F_INT2EQ;
224  break;
225  case INT4OID:
226  *hashfunc = int4hashfast;
227  *fasteqfunc = int4eqfast;
228  *eqfunc = F_INT4EQ;
229  break;
230  case TEXTOID:
231  *hashfunc = texthashfast;
232  *fasteqfunc = texteqfast;
233  *eqfunc = F_TEXTEQ;
234  break;
235  case OIDOID:
236  case REGPROCOID:
237  case REGPROCEDUREOID:
238  case REGOPEROID:
239  case REGOPERATOROID:
240  case REGCLASSOID:
241  case REGTYPEOID:
242  case REGCOLLATIONOID:
243  case REGCONFIGOID:
244  case REGDICTIONARYOID:
245  case REGROLEOID:
246  case REGNAMESPACEOID:
247  *hashfunc = int4hashfast;
248  *fasteqfunc = int4eqfast;
249  *eqfunc = F_OIDEQ;
250  break;
251  case OIDVECTOROID:
252  *hashfunc = oidvectorhashfast;
253  *fasteqfunc = oidvectoreqfast;
254  *eqfunc = F_OIDVECTOREQ;
255  break;
256  default:
257  elog(FATAL, "type %u not supported as catcache key", keytype);
258  *hashfunc = NULL; /* keep compiler quiet */
259 
260  *eqfunc = InvalidOid;
261  break;
262  }
263 }
static bool chareqfast(Datum a, Datum b)
Definition: catcache.c:118
static bool int4eqfast(Datum a, Datum b)
Definition: catcache.c:159
static bool int2eqfast(Datum a, Datum b)
Definition: catcache.c:147
static uint32 int4hashfast(Datum datum)
Definition: catcache.c:165
static uint32 namehashfast(Datum datum)
Definition: catcache.c:139
static bool nameeqfast(Datum a, Datum b)
Definition: catcache.c:130
static uint32 charhashfast(Datum datum)
Definition: catcache.c:124
static uint32 oidvectorhashfast(Datum datum)
Definition: catcache.c:194
static bool texteqfast(Datum a, Datum b)
Definition: catcache.c:171
static bool oidvectoreqfast(Datum a, Datum b)
Definition: catcache.c:188
static uint32 int2hashfast(Datum datum)
Definition: catcache.c:153
static uint32 texthashfast(Datum datum)
Definition: catcache.c:181

References chareqfast(), charhashfast(), elog(), FATAL, int2eqfast(), int2hashfast(), int4eqfast(), int4hashfast(), InvalidOid, nameeqfast(), namehashfast(), oidvectoreqfast(), oidvectorhashfast(), texteqfast(), and texthashfast().

Referenced by CatalogCacheInitializeCache().

◆ IndexScanOK()

static bool IndexScanOK ( CatCache cache,
ScanKey  cur_skey 
)
static

Definition at line 1077 of file catcache.c.

1078 {
1079  switch (cache->id)
1080  {
1081  case INDEXRELID:
1082 
1083  /*
1084  * Rather than tracking exactly which indexes have to be loaded
1085  * before we can use indexscans (which changes from time to time),
1086  * just force all pg_index searches to be heap scans until we've
1087  * built the critical relcaches.
1088  */
1090  return false;
1091  break;
1092 
1093  case AMOID:
1094  case AMNAME:
1095 
1096  /*
1097  * Always do heap scans in pg_am, because it's so small there's
1098  * not much point in an indexscan anyway. We *must* do this when
1099  * initially building critical relcache entries, but we might as
1100  * well just always do it.
1101  */
1102  return false;
1103 
1104  case AUTHNAME:
1105  case AUTHOID:
1106  case AUTHMEMMEMROLE:
1107  case DATABASEOID:
1108 
1109  /*
1110  * Protect authentication lookups occurring before relcache has
1111  * collected entries for shared indexes.
1112  */
1114  return false;
1115  break;
1116 
1117  default:
1118  break;
1119  }
1120 
1121  /* Normal case, allow index scan */
1122  return true;
1123 }
bool criticalRelcachesBuilt
Definition: relcache.c:140
bool criticalSharedRelcachesBuilt
Definition: relcache.c:146
@ AMNAME
Definition: syscache.h:35
@ AMOID
Definition: syscache.h:36
@ AUTHOID
Definition: syscache.h:45
@ INDEXRELID
Definition: syscache.h:66
@ AUTHNAME
Definition: syscache.h:44
@ AUTHMEMMEMROLE
Definition: syscache.h:42
@ DATABASEOID
Definition: syscache.h:55

References AMNAME, AMOID, AUTHMEMMEMROLE, AUTHNAME, AUTHOID, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DATABASEOID, catcache::id, and INDEXRELID.

Referenced by SearchCatCacheList(), and SearchCatCacheMiss().

◆ InitCatCache()

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

Definition at line 757 of file catcache.c.

763 {
764  CatCache *cp;
765  MemoryContext oldcxt;
766  int i;
767 
768  /*
769  * nbuckets is the initial number of hash buckets to use in this catcache.
770  * It will be enlarged later if it becomes too full.
771  *
772  * nbuckets must be a power of two. We check this via Assert rather than
773  * a full runtime check because the values will be coming from constant
774  * tables.
775  *
776  * If you're confused by the power-of-two check, see comments in
777  * bitmapset.c for an explanation.
778  */
779  Assert(nbuckets > 0 && (nbuckets & -nbuckets) == nbuckets);
780 
781  /*
782  * first switch to the cache context so our allocations do not vanish at
783  * the end of a transaction
784  */
785  if (!CacheMemoryContext)
787 
789 
790  /*
791  * if first time through, initialize the cache group header
792  */
793  if (CacheHdr == NULL)
794  {
797  CacheHdr->ch_ntup = 0;
798 #ifdef CATCACHE_STATS
799  /* set up to dump stats at backend exit */
800  on_proc_exit(CatCachePrintStats, 0);
801 #endif
802  }
803 
804  /*
805  * Allocate a new cache structure, aligning to a cacheline boundary
806  *
807  * Note: we rely on zeroing to initialize all the dlist headers correctly
808  */
811  cp->cc_bucket = palloc0(nbuckets * sizeof(dlist_head));
812 
813  /*
814  * initialize the cache's relation information for the relation
815  * corresponding to this cache, and initialize some of the new cache's
816  * other internal fields. But don't open the relation yet.
817  */
818  cp->id = id;
819  cp->cc_relname = "(not known yet)";
820  cp->cc_reloid = reloid;
821  cp->cc_indexoid = indexoid;
822  cp->cc_relisshared = false; /* temporary */
823  cp->cc_tupdesc = (TupleDesc) NULL;
824  cp->cc_ntup = 0;
825  cp->cc_nbuckets = nbuckets;
826  cp->cc_nkeys = nkeys;
827  for (i = 0; i < nkeys; ++i)
828  cp->cc_keyno[i] = key[i];
829 
830  /*
831  * new cache is initialized as far as we can go for now. print some
832  * debugging information, if appropriate.
833  */
835 
836  /*
837  * add completed cache to top of group header's list
838  */
840 
841  /*
842  * back to the old context before we return...
843  */
844  MemoryContextSwitchTo(oldcxt);
845 
846  return cp;
847 }
void CreateCacheMemoryContext(void)
Definition: catcache.c:614
#define InitCatCache_DEBUG2
Definition: catcache.c:753
#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:305
void * palloc0(Size size)
Definition: mcxt.c:1241
void * palloc_aligned(Size size, Size alignto, int flags)
Definition: mcxt.c:1426
#define PG_CACHE_LINE_SIZE
slist_node cc_next
Definition: catcache.h:61
Oid cc_indexoid
Definition: catcache.h:59
struct TupleDescData * TupleDesc
Definition: tupdesc.h:89

References Assert(), CacheHdr, CacheMemoryContext, catcache::cc_bucket, catcache::cc_indexoid, catcache::cc_keyno, catcache::cc_nbuckets, catcache::cc_next, catcache::cc_nkeys, 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 1025 of file catcache.c.

1026 {
1027  if (cache->cc_tupdesc == NULL)
1029 
1030  if (touch_index &&
1031  cache->id != AMOID &&
1032  cache->id != AMNAME)
1033  {
1034  Relation idesc;
1035 
1036  /*
1037  * We must lock the underlying catalog before opening the index to
1038  * avoid deadlock, since index_open could possibly result in reading
1039  * this same catalog, and if anyone else is exclusive-locking this
1040  * catalog and index they'll be doing it in that order.
1041  */
1043  idesc = index_open(cache->cc_indexoid, AccessShareLock);
1044 
1045  /*
1046  * While we've got the index open, let's check that it's unique (and
1047  * not just deferrable-unique, thank you very much). This is just to
1048  * catch thinkos in definitions of new catcaches, so we don't worry
1049  * about the pg_am indexes not getting tested.
1050  */
1051  Assert(idesc->rd_index->indisunique &&
1052  idesc->rd_index->indimmediate);
1053 
1054  index_close(idesc, AccessShareLock);
1056  }
1057 }
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:228
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
Form_pg_index rd_index
Definition: rel.h:190

References AccessShareLock, AMNAME, AMOID, 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().

◆ int2eqfast()

static bool int2eqfast ( Datum  a,
Datum  b 
)
static

Definition at line 147 of file catcache.c.

148 {
149  return DatumGetInt16(a) == DatumGetInt16(b);
150 }
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:162

References a, b, and DatumGetInt16().

Referenced by GetCCHashEqFuncs().

◆ int2hashfast()

static uint32 int2hashfast ( Datum  datum)
static

Definition at line 153 of file catcache.c.

154 {
155  return murmurhash32((int32) DatumGetInt16(datum));
156 }

References DatumGetInt16(), and murmurhash32().

Referenced by GetCCHashEqFuncs().

◆ int4eqfast()

static bool int4eqfast ( Datum  a,
Datum  b 
)
static

Definition at line 159 of file catcache.c.

160 {
161  return DatumGetInt32(a) == DatumGetInt32(b);
162 }
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202

References a, b, and DatumGetInt32().

Referenced by GetCCHashEqFuncs().

◆ int4hashfast()

static uint32 int4hashfast ( Datum  datum)
static

Definition at line 165 of file catcache.c.

166 {
167  return murmurhash32((int32) DatumGetInt32(datum));
168 }

References DatumGetInt32(), and murmurhash32().

Referenced by GetCCHashEqFuncs().

◆ nameeqfast()

static bool nameeqfast ( Datum  a,
Datum  b 
)
static

Definition at line 130 of file catcache.c.

131 {
132  char *ca = NameStr(*DatumGetName(a));
133  char *cb = NameStr(*DatumGetName(b));
134 
135  return strncmp(ca, cb, NAMEDATALEN) == 0;
136 }
#define NameStr(name)
Definition: c.h:730
#define NAMEDATALEN
static Name DatumGetName(Datum X)
Definition: postgres.h:360

References a, b, DatumGetName(), NAMEDATALEN, and NameStr.

Referenced by GetCCHashEqFuncs().

◆ namehashfast()

static uint32 namehashfast ( Datum  datum)
static

Definition at line 139 of file catcache.c.

140 {
141  char *key = NameStr(*DatumGetName(datum));
142 
143  return hash_any((unsigned char *) key, strlen(key));
144 }
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31

References DatumGetName(), hash_any(), sort-test::key, and NameStr.

Referenced by GetCCHashEqFuncs().

◆ oidvectoreqfast()

static bool oidvectoreqfast ( Datum  a,
Datum  b 
)
static

Definition at line 188 of file catcache.c.

189 {
191 }
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
Datum oidvectoreq(PG_FUNCTION_ARGS)
Definition: oid.c:347
static bool DatumGetBool(Datum X)
Definition: postgres.h:90

References a, b, DatumGetBool(), DirectFunctionCall2, and oidvectoreq().

Referenced by GetCCHashEqFuncs().

◆ oidvectorhashfast()

static uint32 oidvectorhashfast ( Datum  datum)
static

Definition at line 194 of file catcache.c.

195 {
197 }
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
Datum hashoidvector(PG_FUNCTION_ARGS)
Definition: hashfunc.c:234

References DatumGetInt32(), DirectFunctionCall1, and hashoidvector().

Referenced by GetCCHashEqFuncs().

◆ PrepareToInvalidateCacheTuple()

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

Definition at line 2000 of file catcache.c.

2004 {
2005  slist_iter iter;
2006  Oid reloid;
2007 
2008  CACHE_elog(DEBUG2, "PrepareToInvalidateCacheTuple: called");
2009 
2010  /*
2011  * sanity checks
2012  */
2013  Assert(RelationIsValid(relation));
2014  Assert(HeapTupleIsValid(tuple));
2015  Assert(PointerIsValid(function));
2016  Assert(CacheHdr != NULL);
2017 
2018  reloid = RelationGetRelid(relation);
2019 
2020  /* ----------------
2021  * for each cache
2022  * if the cache contains tuples from the specified relation
2023  * compute the tuple's hash value(s) in this cache,
2024  * and call the passed function to register the information.
2025  * ----------------
2026  */
2027 
2029  {
2030  CatCache *ccp = slist_container(CatCache, cc_next, iter.cur);
2031  uint32 hashvalue;
2032  Oid dbid;
2033 
2034  if (ccp->cc_reloid != reloid)
2035  continue;
2036 
2037  /* Just in case cache hasn't finished initialization yet... */
2038  if (ccp->cc_tupdesc == NULL)
2040 
2041  hashvalue = CatalogCacheComputeTupleHashValue(ccp, ccp->cc_nkeys, tuple);
2042  dbid = ccp->cc_relisshared ? (Oid) 0 : MyDatabaseId;
2043 
2044  (*function) (ccp->id, hashvalue, dbid);
2045 
2046  if (newtuple)
2047  {
2048  uint32 newhashvalue;
2049 
2050  newhashvalue = CatalogCacheComputeTupleHashValue(ccp, ccp->cc_nkeys, newtuple);
2051 
2052  if (newhashvalue != hashvalue)
2053  (*function) (ccp->id, newhashvalue, dbid);
2054  }
2055  }
2056 }
#define PointerIsValid(pointer)
Definition: c.h:747
static uint32 CatalogCacheComputeTupleHashValue(CatCache *cache, int nkeys, HeapTuple tuple)
Definition: catcache.c:313
Oid MyDatabaseId
Definition: globals.c:89
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define RelationGetRelid(relation)
Definition: rel.h:503
#define RelationIsValid(relation)
Definition: rel.h:476

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().

◆ PrintCatCacheLeakWarning()

void PrintCatCacheLeakWarning ( HeapTuple  tuple)

Definition at line 2064 of file catcache.c.

2065 {
2066  CatCTup *ct = (CatCTup *) (((char *) tuple) -
2067  offsetof(CatCTup, tuple));
2068 
2069  /* Safety check to ensure we were handed a cache entry */
2070  Assert(ct->ct_magic == CT_MAGIC);
2071 
2072  elog(WARNING, "cache reference leak: cache %s (%d), tuple %u/%u has count %d",
2073  ct->my_cache->cc_relname, ct->my_cache->id,
2074  ItemPointerGetBlockNumber(&(tuple->t_self)),
2075  ItemPointerGetOffsetNumber(&(tuple->t_self)),
2076  ct->refcount);
2077 }
#define WARNING
Definition: elog.h:36
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition: itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103

References Assert(), catcache::cc_relname, catctup::ct_magic, CT_MAGIC, elog(), catcache::id, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), catctup::my_cache, catctup::refcount, HeapTupleData::t_self, and WARNING.

Referenced by ResourceOwnerReleaseInternal().

◆ PrintCatCacheListLeakWarning()

void PrintCatCacheListLeakWarning ( CatCList list)

Definition at line 2080 of file catcache.c.

2081 {
2082  elog(WARNING, "cache reference leak: cache %s (%d), list %p has count %d",
2083  list->my_cache->cc_relname, list->my_cache->id,
2084  list, list->refcount);
2085 }

References elog(), sort-test::list, and WARNING.

Referenced by ResourceOwnerReleaseInternal().

◆ RehashCatCache()

static void RehashCatCache ( CatCache cp)
static

Definition at line 853 of file catcache.c.

854 {
855  dlist_head *newbucket;
856  int newnbuckets;
857  int i;
858 
859  elog(DEBUG1, "rehashing catalog cache id %d for %s; %d tups, %d buckets",
860  cp->id, cp->cc_relname, cp->cc_ntup, cp->cc_nbuckets);
861 
862  /* Allocate a new, larger, hash table. */
863  newnbuckets = cp->cc_nbuckets * 2;
864  newbucket = (dlist_head *) MemoryContextAllocZero(CacheMemoryContext, newnbuckets * sizeof(dlist_head));
865 
866  /* Move all entries from old hash table to new. */
867  for (i = 0; i < cp->cc_nbuckets; i++)
868  {
869  dlist_mutable_iter iter;
870 
871  dlist_foreach_modify(iter, &cp->cc_bucket[i])
872  {
873  CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur);
874  int hashIndex = HASH_INDEX(ct->hash_value, newnbuckets);
875 
876  dlist_delete(iter.cur);
877  dlist_push_head(&newbucket[hashIndex], &ct->cache_elem);
878  }
879  }
880 
881  /* Switch to the new array. */
882  pfree(cp->cc_bucket);
883  cp->cc_nbuckets = newnbuckets;
884  cp->cc_bucket = newbucket;
885 }
#define DEBUG1
Definition: elog.h:30
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1048

References catctup::cache_elem, CacheMemoryContext, catcache::cc_bucket, catcache::cc_nbuckets, catcache::cc_ntup, catcache::cc_relname, dlist_mutable_iter::cur, DEBUG1, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_push_head(), elog(), HASH_INDEX, catctup::hash_value, i, catcache::id, MemoryContextAllocZero(), and pfree().

Referenced by CatalogCacheCreateEntry().

◆ ReleaseCatCache()

void ReleaseCatCache ( HeapTuple  tuple)

Definition at line 1435 of file catcache.c.

1436 {
1437  CatCTup *ct = (CatCTup *) (((char *) tuple) -
1438  offsetof(CatCTup, tuple));
1439 
1440  /* Safety checks to ensure we were handed a cache entry */
1441  Assert(ct->ct_magic == CT_MAGIC);
1442  Assert(ct->refcount > 0);
1443 
1444  ct->refcount--;
1446 
1447  if (
1448 #ifndef CATCACHE_FORCE_RELEASE
1449  ct->dead &&
1450 #endif
1451  ct->refcount == 0 &&
1452  (ct->c_list == NULL || ct->c_list->refcount == 0))
1453  CatCacheRemoveCTup(ct->my_cache, ct);
1454 }
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
void ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
Definition: resowner.c:1059

References Assert(), catctup::c_list, CatCacheRemoveCTup(), catctup::ct_magic, CT_MAGIC, CurrentResourceOwner, catctup::dead, catctup::my_cache, catctup::refcount, catclist::refcount, ResourceOwnerForgetCatCacheRef(), and catctup::tuple.

Referenced by ReleaseSysCache(), and ResourceOwnerReleaseInternal().

◆ ReleaseCatCacheList()

void ReleaseCatCacheList ( CatCList list)

Definition at line 1776 of file catcache.c.

1777 {
1778  /* Safety checks to ensure we were handed a cache entry */
1779  Assert(list->cl_magic == CL_MAGIC);
1780  Assert(list->refcount > 0);
1781  list->refcount--;
1783 
1784  if (
1785 #ifndef CATCACHE_FORCE_RELEASE
1786  list->dead &&
1787 #endif
1788  list->refcount == 0)
1789  CatCacheRemoveCList(list->my_cache, list);
1790 }
#define CL_MAGIC
Definition: catcache.h:160
void ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
Definition: resowner.c:1094

References Assert(), CatCacheRemoveCList(), CL_MAGIC, CurrentResourceOwner, sort-test::list, and ResourceOwnerForgetCatCacheListRef().

Referenced by AddEnumLabel(), blvalidate(), brinvalidate(), btvalidate(), ginvalidate(), gistvalidate(), hashvalidate(), opclass_for_family_datatype(), RenameEnumLabel(), ResourceOwnerReleaseInternal(), sepgsql_relation_drop(), spgvalidate(), and transformFrameOffset().

◆ ResetCatalogCache()

static void ResetCatalogCache ( CatCache cache)
static

Definition at line 636 of file catcache.c.

637 {
638  dlist_mutable_iter iter;
639  int i;
640 
641  /* Remove each list in this cache, or at least mark it dead */
642  dlist_foreach_modify(iter, &cache->cc_lists)
643  {
644  CatCList *cl = dlist_container(CatCList, cache_elem, iter.cur);
645 
646  if (cl->refcount > 0)
647  cl->dead = true;
648  else
649  CatCacheRemoveCList(cache, cl);
650  }
651 
652  /* Remove each tuple in this cache, or at least mark it dead */
653  for (i = 0; i < cache->cc_nbuckets; i++)
654  {
655  dlist_head *bucket = &cache->cc_bucket[i];
656 
657  dlist_foreach_modify(iter, bucket)
658  {
659  CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur);
660 
661  if (ct->refcount > 0 ||
662  (ct->c_list && ct->c_list->refcount > 0))
663  {
664  ct->dead = true;
665  /* list, if any, was marked dead above */
666  Assert(ct->c_list == NULL || ct->c_list->dead);
667  }
668  else
669  CatCacheRemoveCTup(cache, ct);
670 #ifdef CATCACHE_STATS
671  cache->cc_invals++;
672 #endif
673  }
674  }
675 }

References Assert(), catctup::c_list, CatCacheRemoveCList(), CatCacheRemoveCTup(), catcache::cc_bucket, catcache::cc_lists, catcache::cc_nbuckets, dlist_mutable_iter::cur, catctup::dead, catclist::dead, dlist_container, dlist_foreach_modify, i, catctup::refcount, and catclist::refcount.

Referenced by CatalogCacheFlushCatalog(), and ResetCatalogCaches().

◆ ResetCatalogCaches()

void ResetCatalogCaches ( void  )

Definition at line 683 of file catcache.c.

684 {
685  slist_iter iter;
686 
687  CACHE_elog(DEBUG2, "ResetCatalogCaches called");
688 
690  {
691  CatCache *cache = slist_container(CatCache, cc_next, iter.cur);
692 
693  ResetCatalogCache(cache);
694  }
695 
696  CACHE_elog(DEBUG2, "end of ResetCatalogCaches call");
697 }

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

1147 {
1148  return SearchCatCacheInternal(cache, cache->cc_nkeys, v1, v2, v3, v4);
1149 }
static HeapTuple SearchCatCacheInternal(CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4)
Definition: catcache.c:1193

References catcache::cc_nkeys, and SearchCatCacheInternal().

Referenced by SearchSysCache().

◆ SearchCatCache1()

HeapTuple SearchCatCache1 ( CatCache cache,
Datum  v1 
)

Definition at line 1159 of file catcache.c.

1161 {
1162  return SearchCatCacheInternal(cache, 1, v1, 0, 0, 0);
1163 }

References SearchCatCacheInternal().

Referenced by SearchSysCache1().

◆ SearchCatCache2()

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

Definition at line 1167 of file catcache.c.

1169 {
1170  return SearchCatCacheInternal(cache, 2, v1, v2, 0, 0);
1171 }

References SearchCatCacheInternal().

Referenced by SearchSysCache2().

◆ SearchCatCache3()

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

Definition at line 1175 of file catcache.c.

1177 {
1178  return SearchCatCacheInternal(cache, 3, v1, v2, v3, 0);
1179 }

References SearchCatCacheInternal().

Referenced by SearchSysCache3().

◆ SearchCatCache4()

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

Definition at line 1183 of file catcache.c.

1185 {
1186  return SearchCatCacheInternal(cache, 4, v1, v2, v3, v4);
1187 }

References SearchCatCacheInternal().

Referenced by SearchSysCache4().

◆ SearchCatCacheInternal()

static HeapTuple SearchCatCacheInternal ( CatCache cache,
int  nkeys,
Datum  v1,
Datum  v2,
Datum  v3,
Datum  v4 
)
inlinestatic

Definition at line 1193 of file catcache.c.

1199 {
1201  uint32 hashValue;
1202  Index hashIndex;
1203  dlist_iter iter;
1204  dlist_head *bucket;
1205  CatCTup *ct;
1206 
1207  /* Make sure we're in an xact, even if this ends up being a cache hit */
1209 
1210  Assert(cache->cc_nkeys == nkeys);
1211 
1212  /*
1213  * one-time startup overhead for each cache
1214  */
1215  if (unlikely(cache->cc_tupdesc == NULL))
1217 
1218 #ifdef CATCACHE_STATS
1219  cache->cc_searches++;
1220 #endif
1221 
1222  /* Initialize local parameter array */
1223  arguments[0] = v1;
1224  arguments[1] = v2;
1225  arguments[2] = v3;
1226  arguments[3] = v4;
1227 
1228  /*
1229  * find the hash bucket in which to look for the tuple
1230  */
1231  hashValue = CatalogCacheComputeHashValue(cache, nkeys, v1, v2, v3, v4);
1232  hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
1233 
1234  /*
1235  * scan the hash bucket until we find a match or exhaust our tuples
1236  *
1237  * Note: it's okay to use dlist_foreach here, even though we modify the
1238  * dlist within the loop, because we don't continue the loop afterwards.
1239  */
1240  bucket = &cache->cc_bucket[hashIndex];
1241  dlist_foreach(iter, bucket)
1242  {
1243  ct = dlist_container(CatCTup, cache_elem, iter.cur);
1244 
1245  if (ct->dead)
1246  continue; /* ignore dead entries */
1247 
1248  if (ct->hash_value != hashValue)
1249  continue; /* quickly skip entry if wrong hash val */
1250 
1251  if (!CatalogCacheCompareTuple(cache, nkeys, ct->keys, arguments))
1252  continue;
1253 
1254  /*
1255  * We found a match in the cache. Move it to the front of the list
1256  * for its hashbucket, in order to speed subsequent searches. (The
1257  * most frequently accessed elements in any hashbucket will tend to be
1258  * near the front of the hashbucket's list.)
1259  */
1260  dlist_move_head(bucket, &ct->cache_elem);
1261 
1262  /*
1263  * If it's a positive entry, bump its refcount and return it. If it's
1264  * negative, we can report failure to the caller.
1265  */
1266  if (!ct->negative)
1267  {
1269  ct->refcount++;
1271 
1272  CACHE_elog(DEBUG2, "SearchCatCache(%s): found in bucket %d",
1273  cache->cc_relname, hashIndex);
1274 
1275 #ifdef CATCACHE_STATS
1276  cache->cc_hits++;
1277 #endif
1278 
1279  return &ct->tuple;
1280  }
1281  else
1282  {
1283  CACHE_elog(DEBUG2, "SearchCatCache(%s): found neg entry in bucket %d",
1284  cache->cc_relname, hashIndex);
1285 
1286 #ifdef CATCACHE_STATS
1287  cache->cc_neg_hits++;
1288 #endif
1289 
1290  return NULL;
1291  }
1292  }
1293 
1294  return SearchCatCacheMiss(cache, nkeys, hashValue, hashIndex, v1, v2, v3, v4);
1295 }
#define unlikely(x)
Definition: c.h:295
static pg_noinline HeapTuple SearchCatCacheMiss(CatCache *cache, int nkeys, uint32 hashValue, Index hashIndex, Datum v1, Datum v2, Datum v3, Datum v4)
Definition: catcache.c:1305
static bool CatalogCacheCompareTuple(const CatCache *cache, int nkeys, const Datum *cachekeys, const Datum *searchkeys)
Definition: catcache.c:368
#define CATCACHE_MAXKEYS
Definition: catcache.h:35
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
static void dlist_move_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:467
void ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
Definition: resowner.c:1050
void ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
Definition: resowner.c:1039
dlist_node * cur
Definition: ilist.h:179
bool IsTransactionState(void)
Definition: xact.c:378

References Assert(), catctup::cache_elem, CACHE_elog, CatalogCacheCompareTuple(), CatalogCacheComputeHashValue(), CatalogCacheInitializeCache(), CATCACHE_MAXKEYS, catcache::cc_bucket, catcache::cc_nbuckets, catcache::cc_nkeys, catcache::cc_relname, catcache::cc_tupdesc, dlist_iter::cur, CurrentResourceOwner, catctup::dead, DEBUG2, dlist_container, dlist_foreach, dlist_move_head(), HASH_INDEX, catctup::hash_value, IsTransactionState(), catctup::keys, catctup::negative, catctup::refcount, ResourceOwnerEnlargeCatCacheRefs(), ResourceOwnerRememberCatCacheRef(), SearchCatCacheMiss(), catctup::tuple, and unlikely.

Referenced by SearchCatCache(), SearchCatCache1(), SearchCatCache2(), SearchCatCache3(), and SearchCatCache4().

◆ SearchCatCacheList()

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

Definition at line 1501 of file catcache.c.

1506 {
1507  Datum v4 = 0; /* dummy last-column value */
1509  uint32 lHashValue;
1510  dlist_iter iter;
1511  CatCList *cl;
1512  CatCTup *ct;
1513  List *volatile ctlist;
1514  ListCell *ctlist_item;
1515  int nmembers;
1516  bool ordered;
1517  HeapTuple ntp;
1518  MemoryContext oldcxt;
1519  int i;
1520 
1521  /*
1522  * one-time startup overhead for each cache
1523  */
1524  if (cache->cc_tupdesc == NULL)
1526 
1527  Assert(nkeys > 0 && nkeys < cache->cc_nkeys);
1528 
1529 #ifdef CATCACHE_STATS
1530  cache->cc_lsearches++;
1531 #endif
1532 
1533  /* Initialize local parameter array */
1534  arguments[0] = v1;
1535  arguments[1] = v2;
1536  arguments[2] = v3;
1537  arguments[3] = v4;
1538 
1539  /*
1540  * compute a hash value of the given keys for faster search. We don't
1541  * presently divide the CatCList items into buckets, but this still lets
1542  * us skip non-matching items quickly most of the time.
1543  */
1544  lHashValue = CatalogCacheComputeHashValue(cache, nkeys, v1, v2, v3, v4);
1545 
1546  /*
1547  * scan the items until we find a match or exhaust our list
1548  *
1549  * Note: it's okay to use dlist_foreach here, even though we modify the
1550  * dlist within the loop, because we don't continue the loop afterwards.
1551  */
1552  dlist_foreach(iter, &cache->cc_lists)
1553  {
1554  cl = dlist_container(CatCList, cache_elem, iter.cur);
1555 
1556  if (cl->dead)
1557  continue; /* ignore dead entries */
1558 
1559  if (cl->hash_value != lHashValue)
1560  continue; /* quickly skip entry if wrong hash val */
1561 
1562  /*
1563  * see if the cached list matches our key.
1564  */
1565  if (cl->nkeys != nkeys)
1566  continue;
1567 
1568  if (!CatalogCacheCompareTuple(cache, nkeys, cl->keys, arguments))
1569  continue;
1570 
1571  /*
1572  * We found a matching list. Move the list to the front of the
1573  * cache's list-of-lists, to speed subsequent searches. (We do not
1574  * move the members to the fronts of their hashbucket lists, however,
1575  * since there's no point in that unless they are searched for
1576  * individually.)
1577  */
1578  dlist_move_head(&cache->cc_lists, &cl->cache_elem);
1579 
1580  /* Bump the list's refcount and return it */
1582  cl->refcount++;
1584 
1585  CACHE_elog(DEBUG2, "SearchCatCacheList(%s): found list",
1586  cache->cc_relname);
1587 
1588 #ifdef CATCACHE_STATS
1589  cache->cc_lhits++;
1590 #endif
1591 
1592  return cl;
1593  }
1594 
1595  /*
1596  * List was not found in cache, so we have to build it by reading the
1597  * relation. For each matching tuple found in the relation, use an
1598  * existing cache entry if possible, else build a new one.
1599  *
1600  * We have to bump the member refcounts temporarily to ensure they won't
1601  * get dropped from the cache while loading other members. We use a PG_TRY
1602  * block to ensure we can undo those refcounts if we get an error before
1603  * we finish constructing the CatCList.
1604  */
1606 
1607  ctlist = NIL;
1608 
1609  PG_TRY();
1610  {
1611  ScanKeyData cur_skey[CATCACHE_MAXKEYS];
1612  Relation relation;
1613  SysScanDesc scandesc;
1614 
1615  /*
1616  * Ok, need to make a lookup in the relation, copy the scankey and
1617  * fill out any per-call fields.
1618  */
1619  memcpy(cur_skey, cache->cc_skey, sizeof(ScanKeyData) * cache->cc_nkeys);
1620  cur_skey[0].sk_argument = v1;
1621  cur_skey[1].sk_argument = v2;
1622  cur_skey[2].sk_argument = v3;
1623  cur_skey[3].sk_argument = v4;
1624 
1625  relation = table_open(cache->cc_reloid, AccessShareLock);
1626 
1627  scandesc = systable_beginscan(relation,
1628  cache->cc_indexoid,
1629  IndexScanOK(cache, cur_skey),
1630  NULL,
1631  nkeys,
1632  cur_skey);
1633 
1634  /* The list will be ordered iff we are doing an index scan */
1635  ordered = (scandesc->irel != NULL);
1636 
1637  while (HeapTupleIsValid(ntp = systable_getnext(scandesc)))
1638  {
1639  uint32 hashValue;
1640  Index hashIndex;
1641  bool found = false;
1642  dlist_head *bucket;
1643 
1644  /*
1645  * See if there's an entry for this tuple already.
1646  */
1647  ct = NULL;
1648  hashValue = CatalogCacheComputeTupleHashValue(cache, cache->cc_nkeys, ntp);
1649  hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
1650 
1651  bucket = &cache->cc_bucket[hashIndex];
1652  dlist_foreach(iter, bucket)
1653  {
1654  ct = dlist_container(CatCTup, cache_elem, iter.cur);
1655 
1656  if (ct->dead || ct->negative)
1657  continue; /* ignore dead and negative entries */
1658 
1659  if (ct->hash_value != hashValue)
1660  continue; /* quickly skip entry if wrong hash val */
1661 
1662  if (!ItemPointerEquals(&(ct->tuple.t_self), &(ntp->t_self)))
1663  continue; /* not same tuple */
1664 
1665  /*
1666  * Found a match, but can't use it if it belongs to another
1667  * list already
1668  */
1669  if (ct->c_list)
1670  continue;
1671 
1672  found = true;
1673  break; /* A-OK */
1674  }
1675 
1676  if (!found)
1677  {
1678  /* We didn't find a usable entry, so make a new one */
1679  ct = CatalogCacheCreateEntry(cache, ntp, arguments,
1680  hashValue, hashIndex,
1681  false);
1682  }
1683 
1684  /* Careful here: add entry to ctlist, then bump its refcount */
1685  /* This way leaves state correct if lappend runs out of memory */
1686  ctlist = lappend(ctlist, ct);
1687  ct->refcount++;
1688  }
1689 
1690  systable_endscan(scandesc);
1691 
1692  table_close(relation, AccessShareLock);
1693 
1694  /* Now we can build the CatCList entry. */
1696  nmembers = list_length(ctlist);
1697  cl = (CatCList *)
1698  palloc(offsetof(CatCList, members) + nmembers * sizeof(CatCTup *));
1699 
1700  /* Extract key values */
1701  CatCacheCopyKeys(cache->cc_tupdesc, nkeys, cache->cc_keyno,
1702  arguments, cl->keys);
1703  MemoryContextSwitchTo(oldcxt);
1704 
1705  /*
1706  * We are now past the last thing that could trigger an elog before we
1707  * have finished building the CatCList and remembering it in the
1708  * resource owner. So it's OK to fall out of the PG_TRY, and indeed
1709  * we'd better do so before we start marking the members as belonging
1710  * to the list.
1711  */
1712  }
1713  PG_CATCH();
1714  {
1715  foreach(ctlist_item, ctlist)
1716  {
1717  ct = (CatCTup *) lfirst(ctlist_item);
1718  Assert(ct->c_list == NULL);
1719  Assert(ct->refcount > 0);
1720  ct->refcount--;
1721  if (
1722 #ifndef CATCACHE_FORCE_RELEASE
1723  ct->dead &&
1724 #endif
1725  ct->refcount == 0 &&
1726  (ct->c_list == NULL || ct->c_list->refcount == 0))
1727  CatCacheRemoveCTup(cache, ct);
1728  }
1729 
1730  PG_RE_THROW();
1731  }
1732  PG_END_TRY();
1733 
1734  cl->cl_magic = CL_MAGIC;
1735  cl->my_cache = cache;
1736  cl->refcount = 0; /* for the moment */
1737  cl->dead = false;
1738  cl->ordered = ordered;
1739  cl->nkeys = nkeys;
1740  cl->hash_value = lHashValue;
1741  cl->n_members = nmembers;
1742 
1743  i = 0;
1744  foreach(ctlist_item, ctlist)
1745  {
1746  cl->members[i++] = ct = (CatCTup *) lfirst(ctlist_item);
1747  Assert(ct->c_list == NULL);
1748  ct->c_list = cl;
1749  /* release the temporary refcount on the member */
1750  Assert(ct->refcount > 0);
1751  ct->refcount--;
1752  /* mark list dead if any members already dead */
1753  if (ct->dead)
1754  cl->dead = true;
1755  }
1756  Assert(i == nmembers);
1757 
1758  dlist_push_head(&cache->cc_lists, &cl->cache_elem);
1759 
1760  /* Finally, bump the list's refcount and return it */
1761  cl->refcount++;
1763 
1764  CACHE_elog(DEBUG2, "SearchCatCacheList(%s): made list of %d members",
1765  cache->cc_relname, nmembers);
1766 
1767  return cl;
1768 }
static CatCTup * CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, Datum *arguments, uint32 hashValue, Index hashIndex, bool negative)
Definition: catcache.c:1799
static bool IndexScanOK(CatCache *cache, ScanKey cur_skey)
Definition: catcache.c:1077
#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:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:35
List * lappend(List *list, void *datum)
Definition: list.c:338
#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
void ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
Definition: resowner.c:1085
void ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
Definition: resowner.c:1074
Definition: pg_list.h:54
Datum sk_argument
Definition: skey.h:72
Relation irel
Definition: relscan.h:184
int cl_magic
Definition: catcache.h:159
bool ordered
Definition: catcache.h:174
uint32 hash_value
Definition: catcache.h:162

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_lists, catcache::cc_nbuckets, catcache::cc_nkeys, 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, 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, ResourceOwnerEnlargeCatCacheListRefs(), ResourceOwnerRememberCatCacheListRef(), ScanKeyData::sk_argument, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), and catctup::tuple.

Referenced by SearchSysCacheList().

◆ SearchCatCacheMiss()

static pg_noinline HeapTuple SearchCatCacheMiss ( CatCache cache,
int  nkeys,
uint32  hashValue,
Index  hashIndex,
Datum  v1,
Datum  v2,
Datum  v3,
Datum  v4 
)
static

Definition at line 1305 of file catcache.c.

1313 {
1314  ScanKeyData cur_skey[CATCACHE_MAXKEYS];
1315  Relation relation;
1316  SysScanDesc scandesc;
1317  HeapTuple ntp;
1318  CatCTup *ct;
1320 
1321  /* Initialize local parameter array */
1322  arguments[0] = v1;
1323  arguments[1] = v2;
1324  arguments[2] = v3;
1325  arguments[3] = v4;
1326 
1327  /*
1328  * Ok, need to make a lookup in the relation, copy the scankey and fill
1329  * out any per-call fields.
1330  */
1331  memcpy(cur_skey, cache->cc_skey, sizeof(ScanKeyData) * nkeys);
1332  cur_skey[0].sk_argument = v1;
1333  cur_skey[1].sk_argument = v2;
1334  cur_skey[2].sk_argument = v3;
1335  cur_skey[3].sk_argument = v4;
1336 
1337  /*
1338  * Tuple was not found in cache, so we have to try to retrieve it directly
1339  * from the relation. If found, we will add it to the cache; if not
1340  * found, we will add a negative cache entry instead.
1341  *
1342  * NOTE: it is possible for recursive cache lookups to occur while reading
1343  * the relation --- for example, due to shared-cache-inval messages being
1344  * processed during table_open(). This is OK. It's even possible for one
1345  * of those lookups to find and enter the very same tuple we are trying to
1346  * fetch here. If that happens, we will enter a second copy of the tuple
1347  * into the cache. The first copy will never be referenced again, and
1348  * will eventually age out of the cache, so there's no functional problem.
1349  * This case is rare enough that it's not worth expending extra cycles to
1350  * detect.
1351  */
1352  relation = table_open(cache->cc_reloid, AccessShareLock);
1353 
1354  scandesc = systable_beginscan(relation,
1355  cache->cc_indexoid,
1356  IndexScanOK(cache, cur_skey),
1357  NULL,
1358  nkeys,
1359  cur_skey);
1360 
1361  ct = NULL;
1362 
1363  while (HeapTupleIsValid(ntp = systable_getnext(scandesc)))
1364  {
1365  ct = CatalogCacheCreateEntry(cache, ntp, arguments,
1366  hashValue, hashIndex,
1367  false);
1368  /* immediately set the refcount to 1 */
1370  ct->refcount++;
1372  break; /* assume only one match */
1373  }
1374 
1375  systable_endscan(scandesc);
1376 
1377  table_close(relation, AccessShareLock);
1378 
1379  /*
1380  * If tuple was not found, we need to build a negative cache entry
1381  * containing a fake tuple. The fake tuple has the correct key columns,
1382  * but nulls everywhere else.
1383  *
1384  * In bootstrap mode, we don't build negative entries, because the cache
1385  * invalidation mechanism isn't alive and can't clear them if the tuple
1386  * gets created later. (Bootstrap doesn't do UPDATEs, so it doesn't need
1387  * cache inval for that.)
1388  */
1389  if (ct == NULL)
1390  {
1392  return NULL;
1393 
1394  ct = CatalogCacheCreateEntry(cache, NULL, arguments,
1395  hashValue, hashIndex,
1396  true);
1397 
1398  CACHE_elog(DEBUG2, "SearchCatCache(%s): Contains %d/%d tuples",
1399  cache->cc_relname, cache->cc_ntup, CacheHdr->ch_ntup);
1400  CACHE_elog(DEBUG2, "SearchCatCache(%s): put neg entry in bucket %d",
1401  cache->cc_relname, hashIndex);
1402 
1403  /*
1404  * We are not returning the negative entry to the caller, so leave its
1405  * refcount zero.
1406  */
1407 
1408  return NULL;
1409  }
1410 
1411  CACHE_elog(DEBUG2, "SearchCatCache(%s): Contains %d/%d tuples",
1412  cache->cc_relname, cache->cc_ntup, CacheHdr->ch_ntup);
1413  CACHE_elog(DEBUG2, "SearchCatCache(%s): put in bucket %d",
1414  cache->cc_relname, hashIndex);
1415 
1416 #ifdef CATCACHE_STATS
1417  cache->cc_newloads++;
1418 #endif
1419 
1420  return &ct->tuple;
1421 }
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:405

References AccessShareLock, CACHE_elog, CacheHdr, CatalogCacheCreateEntry(), CATCACHE_MAXKEYS, catcache::cc_indexoid, catcache::cc_ntup, catcache::cc_relname, catcache::cc_reloid, catcache::cc_skey, catcacheheader::ch_ntup, CurrentResourceOwner, DEBUG2, HeapTupleIsValid, IndexScanOK(), IsBootstrapProcessingMode, catctup::refcount, ResourceOwnerEnlargeCatCacheRefs(), ResourceOwnerRememberCatCacheRef(), ScanKeyData::sk_argument, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and catctup::tuple.

Referenced by SearchCatCacheInternal().

◆ texteqfast()

static bool texteqfast ( Datum  a,
Datum  b 
)
static

Definition at line 171 of file catcache.c.

172 {
173  /*
174  * The use of DEFAULT_COLLATION_OID is fairly arbitrary here. We just
175  * want to take the fast "deterministic" path in texteq().
176  */
177  return DatumGetBool(DirectFunctionCall2Coll(texteq, DEFAULT_COLLATION_OID, a, b));
178 }
Datum DirectFunctionCall2Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:784
Datum texteq(PG_FUNCTION_ARGS)
Definition: varlena.c:1616

References a, b, DatumGetBool(), DirectFunctionCall2Coll(), and texteq().

Referenced by GetCCHashEqFuncs().

◆ texthashfast()

static uint32 texthashfast ( Datum  datum)
static

Definition at line 181 of file catcache.c.

182 {
183  /* analogously here as in texteqfast() */
184  return DatumGetInt32(DirectFunctionCall1Coll(hashtext, DEFAULT_COLLATION_OID, datum));
185 }
Datum DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
Definition: fmgr.c:764
Datum hashtext(PG_FUNCTION_ARGS)
Definition: hashfunc.c:269

References DatumGetInt32(), DirectFunctionCall1Coll(), and hashtext().

Referenced by GetCCHashEqFuncs().

Variable Documentation

◆ CacheHdr