catcache.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:29k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * catcache.c
  4.  *   System catalog cache for tuples matching a key.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.43.2.1 1999/08/02 05:24:59 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "access/genam.h"
  16. #include "access/heapam.h"
  17. #include "access/valid.h"
  18. #include "catalog/pg_type.h"
  19. #include "miscadmin.h"
  20. #include "utils/builtins.h"
  21. #include "utils/catcache.h"
  22. static void CatCacheRemoveCTup(CatCache *cache, Dlelem *e);
  23. static Index CatalogCacheComputeHashIndex(struct catcache * cacheInP);
  24. static Index CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
  25.   Relation relation, HeapTuple tuple);
  26. static void CatalogCacheInitializeCache(struct catcache * cache,
  27. Relation relation);
  28. static long comphash(long l, char *v);
  29. /* ----------------
  30.  * variables, macros and other stuff
  31.  *
  32.  * note CCSIZE allocates 51 buckets .. one was already allocated in
  33.  * the catcache structure.
  34.  * ----------------
  35.  */
  36. #ifdef CACHEDEBUG
  37. #define CACHE1_elog(a,b) elog(a,b)
  38. #define CACHE2_elog(a,b,c) elog(a,b,c)
  39. #define CACHE3_elog(a,b,c,d) elog(a,b,c,d)
  40. #define CACHE4_elog(a,b,c,d,e) elog(a,b,c,d,e)
  41. #define CACHE5_elog(a,b,c,d,e,f) elog(a,b,c,d,e,f)
  42. #define CACHE6_elog(a,b,c,d,e,f,g) elog(a,b,c,d,e,f,g)
  43. #else
  44. #define CACHE1_elog(a,b)
  45. #define CACHE2_elog(a,b,c)
  46. #define CACHE3_elog(a,b,c,d)
  47. #define CACHE4_elog(a,b,c,d,e)
  48. #define CACHE5_elog(a,b,c,d,e,f)
  49. #define CACHE6_elog(a,b,c,d,e,f,g)
  50. #endif
  51. static CatCache   *Caches = NULL; /* head of list of caches */
  52. GlobalMemory CacheCxt; /* context in which caches are allocated */
  53. /* CacheCxt is global because relcache uses it too. */
  54. /* ----------------
  55.  * EQPROC is used in CatalogCacheInitializeCache
  56.  * XXX this should be replaced by catalog lookups soon
  57.  * ----------------
  58.  */
  59. static long eqproc[] = {
  60. F_BOOLEQ, 0l, F_CHAREQ, F_NAMEEQ, 0l,
  61. F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, 0l, F_TEXTEQ,
  62. F_OIDEQ, 0l, 0l, 0l, F_OID8EQ
  63. };
  64. #define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-16]
  65. /* ----------------------------------------------------------------
  66.  * internal support functions
  67.  * ----------------------------------------------------------------
  68.  */
  69. /* --------------------------------
  70.  * CatalogCacheInitializeCache
  71.  * --------------------------------
  72.  */
  73. #ifdef CACHEDEBUG
  74. #define CatalogCacheInitializeCache_DEBUG1 
  75. do { 
  76. elog(DEBUG, "CatalogCacheInitializeCache: cache @%08lx", cache); 
  77. if (relation) 
  78. elog(DEBUG, "CatalogCacheInitializeCache: called w/relation(inval)"); 
  79. else 
  80. elog(DEBUG, "CatalogCacheInitializeCache: called w/relname %s", 
  81. cache->cc_relname) 
  82. } while(0)
  83. #define CatalogCacheInitializeCache_DEBUG2 
  84. do { 
  85. if (cache->cc_key[i] > 0) { 
  86. elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d, %d", 
  87. i+1, cache->cc_nkeys, cache->cc_key[i], 
  88. relation->rd_att->attrs[cache->cc_key[i] - 1]->attlen); 
  89. } else { 
  90. elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d", 
  91. i+1, cache->cc_nkeys, cache->cc_key[i]); 
  92. } while(0)
  93. #else
  94. #define CatalogCacheInitializeCache_DEBUG1
  95. #define CatalogCacheInitializeCache_DEBUG2
  96. #endif
  97. static void
  98. CatalogCacheInitializeCache(struct catcache * cache,
  99. Relation relation)
  100. {
  101. MemoryContext oldcxt;
  102. short didopen = 0;
  103. short i;
  104. TupleDesc tupdesc;
  105. CatalogCacheInitializeCache_DEBUG1;
  106. /* ----------------
  107.  * first switch to the cache context so our allocations
  108.  * do not vanish at the end of a transaction
  109.  * ----------------
  110.  */
  111. if (!CacheCxt)
  112. CacheCxt = CreateGlobalMemory("Cache");
  113. oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
  114. /* ----------------
  115.  * If no relation was passed we must open it to get access to
  116.  * its fields.  If one of the other caches has already opened
  117.  * it we use heap_open() instead of heap_openr()
  118.  * ----------------
  119.  */
  120. if (!RelationIsValid(relation))
  121. {
  122. struct catcache *cp;
  123. /* ----------------
  124.  * scan the caches to see if any other cache has opened the relation
  125.  * ----------------
  126.  */
  127. for (cp = Caches; cp; cp = cp->cc_next)
  128. {
  129. if (strncmp(cp->cc_relname, cache->cc_relname, NAMEDATALEN) == 0)
  130. {
  131. if (cp->relationId != InvalidOid)
  132. break;
  133. }
  134. }
  135. /* ----------------
  136.  * open the relation by name or by id
  137.  * ----------------
  138.  */
  139. if (cp)
  140. relation = heap_open(cp->relationId);
  141. else
  142. relation = heap_openr(cache->cc_relname);
  143. didopen = 1;
  144. }
  145. /* ----------------
  146.  * initialize the cache's relation id
  147.  * ----------------
  148.  */
  149. Assert(RelationIsValid(relation));
  150. cache->relationId = RelationGetRelid(relation);
  151. tupdesc = cache->cc_tupdesc = RelationGetDescr(relation);
  152. CACHE3_elog(DEBUG, "CatalogCacheInitializeCache: relid %u, %d keys",
  153. cache->relationId, cache->cc_nkeys);
  154. /* ----------------
  155.  * initialize cache's key information
  156.  * ----------------
  157.  */
  158. for (i = 0; i < cache->cc_nkeys; ++i)
  159. {
  160. CatalogCacheInitializeCache_DEBUG2;
  161. if (cache->cc_key[i] > 0)
  162. {
  163. /*
  164.  * Yoiks.  The implementation of the hashing code and the
  165.  * implementation of int28's are at loggerheads.  The right
  166.  * thing to do is to throw out the implementation of int28's
  167.  * altogether; until that happens, we do the right thing here
  168.  * to guarantee that the hash key generator doesn't try to
  169.  * dereference an int2 by mistake.
  170.  */
  171. if (tupdesc->attrs[cache->cc_key[i] - 1]->atttypid == INT28OID)
  172. cache->cc_klen[i] = sizeof(short);
  173. else
  174. cache->cc_klen[i] = tupdesc->attrs[cache->cc_key[i] - 1]->attlen;
  175. cache->cc_skey[i].sk_procedure = EQPROC(tupdesc->attrs[cache->cc_key[i] - 1]->atttypid);
  176. fmgr_info(cache->cc_skey[i].sk_procedure,
  177.   &cache->cc_skey[i].sk_func);
  178. cache->cc_skey[i].sk_nargs = cache->cc_skey[i].sk_func.fn_nargs;
  179. CACHE5_elog(DEBUG, "CatalogCacheInit %s %d %d %x",
  180. &relation->rd_rel->relname,
  181. i,
  182. tupdesc->attrs[cache->cc_key[i] - 1]->attlen,
  183. cache);
  184. }
  185. }
  186. /* ----------------
  187.  * close the relation if we opened it
  188.  * ----------------
  189.  */
  190. if (didopen)
  191. heap_close(relation);
  192. /* ----------------
  193.  * initialize index information for the cache.  this
  194.  * should only be done once per cache.
  195.  * ----------------
  196.  */
  197. if (cache->cc_indname != NULL && cache->indexId == InvalidOid)
  198. {
  199. if (RelationGetForm(relation)->relhasindex)
  200. {
  201. /*
  202.  * If the index doesn't exist we are in trouble.
  203.  */
  204. relation = index_openr(cache->cc_indname);
  205. Assert(relation);
  206. cache->indexId = RelationGetRelid(relation);
  207. index_close(relation);
  208. }
  209. else
  210. cache->cc_indname = NULL;
  211. }
  212. /* ----------------
  213.  * return to the proper memory context
  214.  * ----------------
  215.  */
  216. MemoryContextSwitchTo(oldcxt);
  217. }
  218. /* --------------------------------
  219.  * CatalogCacheSetId
  220.  *
  221.  * XXX temporary function
  222.  * --------------------------------
  223.  */
  224. #ifdef NOT_USED
  225. void
  226. CatalogCacheSetId(CatCache *cacheInOutP, int id)
  227. {
  228. Assert(id == InvalidCatalogCacheId || id >= 0);
  229. cacheInOutP->id = id;
  230. }
  231. #endif
  232. /* ----------------
  233.  * comphash
  234.  * Compute a hash value, somehow.
  235.  *
  236.  * XXX explain algorithm here.
  237.  *
  238.  * l is length of the attribute value, v
  239.  * v is the attribute value ("Datum")
  240.  * ----------------
  241.  */
  242. static long
  243. comphash(long l, char *v)
  244. {
  245. long i;
  246. NameData n;
  247. CACHE3_elog(DEBUG, "comphash (%d,%x)", l, v);
  248. switch (l)
  249. {
  250. case 1:
  251. case 2:
  252. case 4:
  253. return (long) v;
  254. }
  255. if (l == NAMEDATALEN)
  256. {
  257. /*
  258.  * if it's a name, make sure that the values are null-padded.
  259.  *
  260.  * Note that this other fixed-length types can also have the same
  261.  * typelen so this may break them   - XXX
  262.  */
  263. namestrcpy(&n, v);
  264. v = n.data;
  265. }
  266. else if (l < 0)
  267. l = VARSIZE(v);
  268. i = 0;
  269. while (l--)
  270. i += *v++;
  271. return i;
  272. }
  273. /* --------------------------------
  274.  * CatalogCacheComputeHashIndex
  275.  * --------------------------------
  276.  */
  277. static Index
  278. CatalogCacheComputeHashIndex(struct catcache * cacheInP)
  279. {
  280. Index hashIndex;
  281. hashIndex = 0x0;
  282. CACHE6_elog(DEBUG, "CatalogCacheComputeHashIndex %s %d %d %d %x",
  283. cacheInP->cc_relname,
  284. cacheInP->cc_nkeys,
  285. cacheInP->cc_klen[0],
  286. cacheInP->cc_klen[1],
  287. cacheInP);
  288. switch (cacheInP->cc_nkeys)
  289. {
  290. case 4:
  291. hashIndex ^= comphash(cacheInP->cc_klen[3],
  292.  (char *) cacheInP->cc_skey[3].sk_argument) << 9;
  293. /* FALLTHROUGH */
  294. case 3:
  295. hashIndex ^= comphash(cacheInP->cc_klen[2],
  296.  (char *) cacheInP->cc_skey[2].sk_argument) << 6;
  297. /* FALLTHROUGH */
  298. case 2:
  299. hashIndex ^= comphash(cacheInP->cc_klen[1],
  300.  (char *) cacheInP->cc_skey[1].sk_argument) << 3;
  301. /* FALLTHROUGH */
  302. case 1:
  303. hashIndex ^= comphash(cacheInP->cc_klen[0],
  304.   (char *) cacheInP->cc_skey[0].sk_argument);
  305. break;
  306. default:
  307. elog(FATAL, "CCComputeHashIndex: %d cc_nkeys", cacheInP->cc_nkeys);
  308. break;
  309. }
  310. hashIndex %= cacheInP->cc_size;
  311. return hashIndex;
  312. }
  313. /* --------------------------------
  314.  * CatalogCacheComputeTupleHashIndex
  315.  * --------------------------------
  316.  */
  317. static Index
  318. CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
  319.   Relation relation,
  320.   HeapTuple tuple)
  321. {
  322. bool isNull = '';
  323. if (cacheInOutP->relationId == InvalidOid)
  324. CatalogCacheInitializeCache(cacheInOutP, relation);
  325. switch (cacheInOutP->cc_nkeys)
  326. {
  327. case 4:
  328. cacheInOutP->cc_skey[3].sk_argument =
  329. (cacheInOutP->cc_key[3] == ObjectIdAttributeNumber)
  330. ? (Datum) tuple->t_data->t_oid
  331. : fastgetattr(tuple,
  332.   cacheInOutP->cc_key[3],
  333.   RelationGetDescr(relation),
  334.   &isNull);
  335. Assert(!isNull);
  336. /* FALLTHROUGH */
  337. case 3:
  338. cacheInOutP->cc_skey[2].sk_argument =
  339. (cacheInOutP->cc_key[2] == ObjectIdAttributeNumber)
  340. ? (Datum) tuple->t_data->t_oid
  341. : fastgetattr(tuple,
  342.   cacheInOutP->cc_key[2],
  343.   RelationGetDescr(relation),
  344.   &isNull);
  345. Assert(!isNull);
  346. /* FALLTHROUGH */
  347. case 2:
  348. cacheInOutP->cc_skey[1].sk_argument =
  349. (cacheInOutP->cc_key[1] == ObjectIdAttributeNumber)
  350. ? (Datum) tuple->t_data->t_oid
  351. : fastgetattr(tuple,
  352.   cacheInOutP->cc_key[1],
  353.   RelationGetDescr(relation),
  354.   &isNull);
  355. Assert(!isNull);
  356. /* FALLTHROUGH */
  357. case 1:
  358. cacheInOutP->cc_skey[0].sk_argument =
  359. (cacheInOutP->cc_key[0] == ObjectIdAttributeNumber)
  360. ? (Datum) tuple->t_data->t_oid
  361. : fastgetattr(tuple,
  362.   cacheInOutP->cc_key[0],
  363.   RelationGetDescr(relation),
  364.   &isNull);
  365. Assert(!isNull);
  366. break;
  367. default:
  368. elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys",
  369.  cacheInOutP->cc_nkeys
  370. );
  371. break;
  372. }
  373. return CatalogCacheComputeHashIndex(cacheInOutP);
  374. }
  375. /* --------------------------------
  376.  * CatCacheRemoveCTup
  377.  * --------------------------------
  378.  */
  379. static void
  380. CatCacheRemoveCTup(CatCache *cache, Dlelem *elt)
  381. {
  382. CatCTup    *ct;
  383. CatCTup    *other_ct;
  384. Dlelem    *other_elt;
  385. if (elt)
  386. ct = (CatCTup *) DLE_VAL(elt);
  387. else
  388. return;
  389. other_elt = ct->ct_node;
  390. other_ct = (CatCTup *) DLE_VAL(other_elt);
  391. DLRemove(other_elt);
  392. DLFreeElem(other_elt);
  393. free(other_ct);
  394. DLRemove(elt);
  395. DLFreeElem(elt);
  396. free(ct);
  397. --cache->cc_ntup;
  398. }
  399. /* --------------------------------
  400.  * CatalogCacheIdInvalidate()
  401.  *
  402.  * Invalidate a tuple given a cache id.  In this case the id should always
  403.  * be found (whether the cache has opened its relation or not).  Of course,
  404.  * if the cache has yet to open its relation, there will be no tuples so
  405.  * no problem.
  406.  * --------------------------------
  407.  */
  408. void
  409. CatalogCacheIdInvalidate(int cacheId, /* XXX */
  410.  Index hashIndex,
  411.  ItemPointer pointer)
  412. {
  413. CatCache   *ccp;
  414. CatCTup    *ct;
  415. Dlelem    *elt;
  416. MemoryContext oldcxt;
  417. /* ----------------
  418.  * sanity checks
  419.  * ----------------
  420.  */
  421. Assert(hashIndex < NCCBUCK);
  422. Assert(ItemPointerIsValid(pointer));
  423. CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
  424. /* ----------------
  425.  * switch to the cache context for our memory allocations
  426.  * ----------------
  427.  */
  428. if (!CacheCxt)
  429. CacheCxt = CreateGlobalMemory("Cache");
  430. oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
  431. /* ----------------
  432.  * inspect every cache that could contain the tuple
  433.  * ----------------
  434.  */
  435. for (ccp = Caches; ccp; ccp = ccp->cc_next)
  436. {
  437. if (cacheId != ccp->id)
  438. continue;
  439. /* ----------------
  440.  * inspect the hash bucket until we find a match or exhaust
  441.  * ----------------
  442.  */
  443. for (elt = DLGetHead(ccp->cc_cache[hashIndex]);
  444.  elt;
  445.  elt = DLGetSucc(elt))
  446. {
  447. ct = (CatCTup *) DLE_VAL(elt);
  448. if (ItemPointerEquals(pointer, &ct->ct_tup->t_self))
  449. break;
  450. }
  451. /* ----------------
  452.  * if we found a matching tuple, invalidate it.
  453.  * ----------------
  454.  */
  455. if (elt)
  456. {
  457. CatCacheRemoveCTup(ccp, elt);
  458. CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");
  459. }
  460. if (cacheId != InvalidCatalogCacheId)
  461. break;
  462. }
  463. /* ----------------
  464.  * return to the proper memory context
  465.  * ----------------
  466.  */
  467. MemoryContextSwitchTo(oldcxt);
  468. /* sendpm('I', "Invalidated tuple"); */
  469. }
  470. /* ----------------------------------------------------------------
  471.  *    public functions
  472.  *
  473.  * ResetSystemCache
  474.  * InitIndexedSysCache
  475.  * InitSysCache
  476.  * SearchSysCache
  477.  * RelationInvalidateCatalogCacheTuple
  478.  * ----------------------------------------------------------------
  479.  */
  480. /* --------------------------------
  481.  * ResetSystemCache
  482.  * --------------------------------
  483.  */
  484. void
  485. ResetSystemCache()
  486. {
  487. MemoryContext oldcxt;
  488. struct catcache *cache;
  489. CACHE1_elog(DEBUG, "ResetSystemCache called");
  490. /* ----------------
  491.  * first switch to the cache context so our allocations
  492.  * do not vanish at the end of a transaction
  493.  * ----------------
  494.  */
  495. if (!CacheCxt)
  496. CacheCxt = CreateGlobalMemory("Cache");
  497. oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
  498. /* ----------------
  499.  * here we purge the contents of all the caches
  500.  *
  501.  * for each system cache
  502.  *    for each hash bucket
  503.  *    for each tuple in hash bucket
  504.  *    remove the tuple
  505.  * ----------------
  506.  */
  507. for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
  508. {
  509. int hash;
  510. for (hash = 0; hash < NCCBUCK; hash += 1)
  511. {
  512. Dlelem    *elt,
  513.    *nextelt;
  514. for (elt = DLGetHead(cache->cc_cache[hash]); elt; elt = nextelt)
  515. {
  516. nextelt = DLGetSucc(elt);
  517. CatCacheRemoveCTup(cache, elt);
  518. if (cache->cc_ntup < 0)
  519. elog(NOTICE,
  520.  "ResetSystemCache: cc_ntup<0 (software error)");
  521. }
  522. }
  523. cache->cc_ntup = 0; /* in case of WARN error above */
  524. cache->busy = false; /* to recover from recursive-use error */
  525. }
  526. CACHE1_elog(DEBUG, "end of ResetSystemCache call");
  527. /* ----------------
  528.  * back to the old context before we return...
  529.  * ----------------
  530.  */
  531. MemoryContextSwitchTo(oldcxt);
  532. }
  533. /* --------------------------------
  534.  * SystemCacheRelationFlushed
  535.  *
  536.  * This is called by RelationFlushRelation() to clear out cached information
  537.  * about a relation being dropped.  (This could be a DROP TABLE command,
  538.  * or a temp table being dropped at end of transaction, or a table created
  539.  * during the current transaction that is being dropped because of abort.)
  540.  * Remove all cache entries relevant to the specified relation OID.
  541.  *
  542.  * A special case occurs when relId is itself one of the cacheable system
  543.  * tables --- although those'll never be dropped, they can get flushed from
  544.  * the relcache (VACUUM causes this, for example).  In that case we need to
  545.  * force the next SearchSysCache() call to reinitialize the cache itself,
  546.  * because we have info (such as cc_tupdesc) that is pointing at the about-
  547.  * to-be-deleted relcache entry.
  548.  * --------------------------------
  549.  */
  550. void
  551. SystemCacheRelationFlushed(Oid relId)
  552. {
  553. struct catcache *cache;
  554. /*
  555.  * XXX Ideally we'd search the caches and just zap entries that actually
  556.  * refer to the indicated relation.  For now, we take the brute-force
  557.  * approach: just flush the caches entirely.
  558.  */
  559. ResetSystemCache();
  560. /*
  561.  * If relcache is dropping a system relation's cache entry, mark the
  562.  * associated cache structures invalid, so we can rebuild them from
  563.  * scratch (not just repopulate them) next time they are used.
  564.  */
  565. for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
  566. {
  567. if (cache->relationId == relId)
  568. cache->relationId = InvalidOid;
  569. }
  570. }
  571. /* --------------------------------
  572.  * InitIndexedSysCache
  573.  *
  574.  * This allocates and initializes a cache for a system catalog relation.
  575.  * Actually, the cache is only partially initialized to avoid opening the
  576.  * relation.  The relation will be opened and the rest of the cache
  577.  * structure initialized on the first access.
  578.  * --------------------------------
  579.  */
  580. #ifdef CACHEDEBUG
  581. #define InitSysCache_DEBUG1 
  582. do { 
  583. elog(DEBUG, "InitSysCache: rid=%u id=%d nkeys=%d size=%dn", 
  584. cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); 
  585. for (i = 0; i < nkeys; i += 1) 
  586. elog(DEBUG, "InitSysCache: key=%d len=%d skey=[%d %d %d %d]n", 
  587.  cp->cc_key[i], cp->cc_klen[i], 
  588.  cp->cc_skey[i].sk_flags, 
  589.  cp->cc_skey[i].sk_attno, 
  590.  cp->cc_skey[i].sk_procedure, 
  591.  cp->cc_skey[i].sk_argument); 
  592. } while(0)
  593. #else
  594. #define InitSysCache_DEBUG1
  595. #endif
  596. CatCache   *
  597. InitSysCache(char *relname,
  598.  char *iname,
  599.  int id,
  600.  int nkeys,
  601.  int *key,
  602.  HeapTuple (*iScanfuncP) ())
  603. {
  604. CatCache   *cp;
  605. int i;
  606. MemoryContext oldcxt;
  607. char    *indname;
  608. indname = (iname) ? iname : NULL;
  609. /* ----------------
  610.  * first switch to the cache context so our allocations
  611.  * do not vanish at the end of a transaction
  612.  * ----------------
  613.  */
  614. if (!CacheCxt)
  615. CacheCxt = CreateGlobalMemory("Cache");
  616. oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
  617. /* ----------------
  618.  * allocate a new cache structure
  619.  * ----------------
  620.  */
  621. cp = (CatCache *) palloc(sizeof(CatCache));
  622. MemSet((char *) cp, 0, sizeof(CatCache));
  623. /* ----------------
  624.  * initialize the cache buckets (each bucket is a list header)
  625.  * and the LRU tuple list
  626.  * ----------------
  627.  */
  628. {
  629. /*
  630.  * We can only do this optimization because the number of hash
  631.  * buckets never changes.  Without it, we call malloc() too much.
  632.  * We could move this to dllist.c, but the way we do this is not
  633.  * dynamic/portabl, so why allow other routines to use it.
  634.  */
  635. Dllist    *cache_begin = malloc((NCCBUCK + 1) * sizeof(Dllist));
  636. for (i = 0; i <= NCCBUCK; ++i)
  637. {
  638. cp->cc_cache[i] = &cache_begin[i];
  639. cp->cc_cache[i]->dll_head = 0;
  640. cp->cc_cache[i]->dll_tail = 0;
  641. }
  642. }
  643. cp->cc_lrulist = DLNewList();
  644. /* ----------------
  645.  * Caches is the pointer to the head of the list of all the
  646.  * system caches. here we add the new cache to the top of the list.
  647.  * ----------------
  648.  */
  649. cp->cc_next = Caches; /* list of caches (single link) */
  650. Caches = cp;
  651. /* ----------------
  652.  * initialize the cache's relation information for the relation
  653.  * corresponding to this cache and initialize some of the the new
  654.  * cache's other internal fields.
  655.  * ----------------
  656.  */
  657. cp->relationId = InvalidOid;
  658. cp->indexId = InvalidOid;
  659. cp->cc_relname = relname;
  660. cp->cc_indname = indname;
  661. cp->cc_tupdesc = (TupleDesc) NULL;
  662. cp->id = id;
  663. cp->busy = false;
  664. cp->cc_maxtup = MAXTUP;
  665. cp->cc_size = NCCBUCK;
  666. cp->cc_nkeys = nkeys;
  667. cp->cc_iscanfunc = iScanfuncP;
  668. /* ----------------
  669.  * initialize the cache's key information
  670.  * ----------------
  671.  */
  672. for (i = 0; i < nkeys; ++i)
  673. {
  674. cp->cc_key[i] = key[i];
  675. if (!key[i])
  676. elog(FATAL, "InitSysCache: called with 0 key[%d]", i);
  677. if (key[i] < 0)
  678. {
  679. if (key[i] != ObjectIdAttributeNumber)
  680. elog(FATAL, "InitSysCache: called with %d key[%d]", key[i], i);
  681. else
  682. {
  683. cp->cc_klen[i] = sizeof(Oid);
  684. /*
  685.  * ScanKeyEntryData and struct skey are equivalent. It
  686.  * looks like a move was made to obsolete struct skey, but
  687.  * it didn't reach this file.  Someday we should clean up
  688.  * this code and consolidate to ScanKeyEntry - mer 10 Nov
  689.  * 1991
  690.  */
  691. ScanKeyEntryInitialize(&cp->cc_skey[i],
  692.    (bits16) 0,
  693.    (AttrNumber) key[i],
  694.    (RegProcedure) F_OIDEQ,
  695.    (Datum) 0);
  696. continue;
  697. }
  698. }
  699. cp->cc_skey[i].sk_attno = key[i];
  700. }
  701. /* ----------------
  702.  * all done.  new cache is initialized.  print some debugging
  703.  * information, if appropriate.
  704.  * ----------------
  705.  */
  706. InitSysCache_DEBUG1;
  707. /* ----------------
  708.  * back to the old context before we return...
  709.  * ----------------
  710.  */
  711. MemoryContextSwitchTo(oldcxt);
  712. return cp;
  713. }
  714. /* --------------------------------
  715.  * SearchSysCache
  716.  *
  717.  * This call searches a system cache for a tuple, opening the relation
  718.  * if necessary (the first access to a particular cache).
  719.  * --------------------------------
  720.  */
  721. HeapTuple
  722. SearchSysCache(struct catcache * cache,
  723.    Datum v1,
  724.    Datum v2,
  725.    Datum v3,
  726.    Datum v4)
  727. {
  728. unsigned hash;
  729. CatCTup    *ct = NULL;
  730. CatCTup    *nct;
  731. CatCTup    *nct2;
  732. Dlelem    *elt;
  733. HeapTuple ntp = 0;
  734. Relation relation;
  735. MemoryContext oldcxt;
  736. /* ----------------
  737.  * sanity checks
  738.  * ----------------
  739.  */
  740. if (cache->relationId == InvalidOid)
  741. CatalogCacheInitializeCache(cache, NULL);
  742. /* ----------------
  743.  * initialize the search key information
  744.  * ----------------
  745.  */
  746. cache->cc_skey[0].sk_argument = v1;
  747. cache->cc_skey[1].sk_argument = v2;
  748. cache->cc_skey[2].sk_argument = v3;
  749. cache->cc_skey[3].sk_argument = v4;
  750. /* ----------------
  751.  * find the hash bucket in which to look for the tuple
  752.  * ----------------
  753.  */
  754. hash = CatalogCacheComputeHashIndex(cache);
  755. /* ----------------
  756.  * scan the hash bucket until we find a match or exhaust our tuples
  757.  * ----------------
  758.  */
  759. for (elt = DLGetHead(cache->cc_cache[hash]);
  760.  elt;
  761.  elt = DLGetSucc(elt))
  762. {
  763. bool res;
  764. ct = (CatCTup *) DLE_VAL(elt);
  765. /* ----------------
  766.  * see if the cached tuple matches our key.
  767.  * (should we be worried about time ranges? -cim 10/2/90)
  768.  * ----------------
  769.  */
  770. HeapKeyTest(ct->ct_tup,
  771. cache->cc_tupdesc,
  772. cache->cc_nkeys,
  773. cache->cc_skey,
  774. res);
  775. if (res)
  776. break;
  777. }
  778. /* ----------------
  779.  * if we found a tuple in the cache, move it to the top of the
  780.  * lru list, and return it.  We also move it to the front of the
  781.  * list for its hashbucket, in order to speed subsequent searches.
  782.  * (The most frequently accessed elements in any hashbucket will
  783.  * tend to be near the front of the hashbucket's list.)
  784.  * ----------------
  785.  */
  786. if (elt)
  787. {
  788. Dlelem    *old_lru_elt = ((CatCTup *) DLE_VAL(elt))->ct_node;
  789. DLMoveToFront(old_lru_elt);
  790. DLMoveToFront(elt);
  791. #ifdef CACHEDEBUG
  792. relation = heap_open(cache->relationId);
  793. CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",
  794. RelationGetRelationName(relation), hash);
  795. heap_close(relation);
  796. #endif  /* CACHEDEBUG */
  797. return ct->ct_tup;
  798. }
  799. /* ----------------
  800.  * Tuple was not found in cache, so we have to try and
  801.  * retrieve it directly from the relation.  If it's found,
  802.  * we add it to the cache.
  803.  *
  804.  * To guard against possible infinite recursion, we mark this cache
  805.  * "busy" while trying to load a new entry for it.  It is OK to
  806.  * recursively invoke SearchSysCache for a different cache, but
  807.  * a recursive call for the same cache will error out.  (We could
  808.  * store the specific key(s) being looked for, and consider only
  809.  * a recursive request for the same key to be an error, but this
  810.  * simple scheme is sufficient for now.)
  811.  * ----------------
  812.  */
  813. if (cache->busy)
  814. {
  815. elog(ERROR, "SearchSysCache: recursive use of cache %d", cache->id);
  816. }
  817. cache->busy = true;
  818. /* ----------------
  819.  * open the relation associated with the cache
  820.  * ----------------
  821.  */
  822. relation = heap_open(cache->relationId);
  823. CACHE2_elog(DEBUG, "SearchSysCache(%s)",
  824. RelationGetRelationName(relation));
  825. /* ----------------
  826.  * Switch to the cache memory context.
  827.  * ----------------
  828.  */
  829. if (!CacheCxt)
  830. CacheCxt = CreateGlobalMemory("Cache");
  831. oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
  832. /* ----------------
  833.  * Scan the relation to find the tuple.  If there's an index, and
  834.  * if this isn't bootstrap (initdb) time, use the index.
  835.  * ----------------
  836.  */
  837. CACHE2_elog(DEBUG, "SearchSysCache: performing scan (override==%d)",
  838. heapisoverride());
  839. if ((RelationGetForm(relation))->relhasindex
  840. && !IsBootstrapProcessingMode())
  841. {
  842. /* ----------
  843.  * Switch back to old memory context so memory not freed
  844.  * in the scan function will go away at transaction end.
  845.  * wieck - 10/18/1996
  846.  * ----------
  847.  */
  848. MemoryContextSwitchTo(oldcxt);
  849. Assert(cache->cc_iscanfunc);
  850. switch (cache->cc_nkeys)
  851. {
  852. case 4:
  853. ntp = cache->cc_iscanfunc(relation, v1, v2, v3, v4);
  854. break;
  855. case 3:
  856. ntp = cache->cc_iscanfunc(relation, v1, v2, v3);
  857. break;
  858. case 2:
  859. ntp = cache->cc_iscanfunc(relation, v1, v2);
  860. break;
  861. case 1:
  862. ntp = cache->cc_iscanfunc(relation, v1);
  863. break;
  864. }
  865. /* ----------
  866.  * Back to Cache context. If we got a tuple copy it
  867.  * into our context.
  868.  * wieck - 10/18/1996
  869.  * ----------
  870.  */
  871. MemoryContextSwitchTo((MemoryContext) CacheCxt);
  872. if (HeapTupleIsValid(ntp))
  873. ntp = heap_copytuple(ntp);
  874. }
  875. else
  876. {
  877. HeapScanDesc sd;
  878. /* ----------
  879.  * As above do the lookup in the callers memory
  880.  * context.
  881.  * wieck - 10/18/1996
  882.  * ----------
  883.  */
  884. MemoryContextSwitchTo(oldcxt);
  885. sd = heap_beginscan(relation, 0, SnapshotNow,
  886. cache->cc_nkeys, cache->cc_skey);
  887. ntp = heap_getnext(sd, 0);
  888. MemoryContextSwitchTo((MemoryContext) CacheCxt);
  889. if (HeapTupleIsValid(ntp))
  890. {
  891. CACHE1_elog(DEBUG, "SearchSysCache: found tuple");
  892. ntp = heap_copytuple(ntp);
  893. }
  894. MemoryContextSwitchTo(oldcxt);
  895. heap_endscan(sd);
  896. MemoryContextSwitchTo((MemoryContext) CacheCxt);
  897. }
  898. cache->busy = false;
  899. /* ----------------
  900.  * scan is complete.  if tup is valid, we copy it and add the copy to
  901.  * the cache.
  902.  * ----------------
  903.  */
  904. if (HeapTupleIsValid(ntp))
  905. {
  906. /* ----------------
  907.  * allocate a new cache tuple holder, store the pointer
  908.  * to the heap tuple there and initialize the list pointers.
  909.  * ----------------
  910.  */
  911. Dlelem    *lru_elt;
  912. /*
  913.  * this is a little cumbersome here because we want the Dlelem's
  914.  * in both doubly linked lists to point to one another. That makes
  915.  * it easier to remove something from both the cache bucket and
  916.  * the lru list at the same time
  917.  */
  918. nct = (CatCTup *) malloc(sizeof(CatCTup));
  919. nct->ct_tup = ntp;
  920. elt = DLNewElem(nct);
  921. nct2 = (CatCTup *) malloc(sizeof(CatCTup));
  922. nct2->ct_tup = ntp;
  923. lru_elt = DLNewElem(nct2);
  924. nct2->ct_node = elt;
  925. nct->ct_node = lru_elt;
  926. DLAddHead(cache->cc_lrulist, lru_elt);
  927. DLAddHead(cache->cc_cache[hash], elt);
  928. /* ----------------
  929.  * If we've exceeded the desired size of this cache,
  930.  * throw away the least recently used entry.
  931.  * ----------------
  932.  */
  933. if (++cache->cc_ntup > cache->cc_maxtup)
  934. {
  935. CatCTup    *ct;
  936. elt = DLGetTail(cache->cc_lrulist);
  937. ct = (CatCTup *) DLE_VAL(elt);
  938. if (ct != nct) /* shouldn't be possible, but be safe... */
  939. {
  940. CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",
  941. RelationGetRelationName(relation));
  942. CatCacheRemoveCTup(cache, elt);
  943. }
  944. }
  945. CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples",
  946. RelationGetRelationName(relation),
  947. cache->cc_ntup, cache->cc_maxtup);
  948. CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d",
  949. RelationGetRelationName(relation), hash);
  950. }
  951. /* ----------------
  952.  * close the relation, switch back to the original memory context
  953.  * and return the tuple we found (or NULL)
  954.  * ----------------
  955.  */
  956. heap_close(relation);
  957. MemoryContextSwitchTo(oldcxt);
  958. return ntp;
  959. }
  960. /* --------------------------------
  961.  * RelationInvalidateCatalogCacheTuple()
  962.  *
  963.  * Invalidate a tuple from a specific relation.  This call determines the
  964.  * cache in question and calls CatalogCacheIdInvalidate().  It is -ok-
  965.  * if the relation cannot be found, it simply means this backend has yet
  966.  * to open it.
  967.  * --------------------------------
  968.  */
  969. void
  970. RelationInvalidateCatalogCacheTuple(Relation relation,
  971. HeapTuple tuple,
  972.   void (*function) (int, Index, ItemPointer))
  973. {
  974. struct catcache *ccp;
  975. MemoryContext oldcxt;
  976. Oid relationId;
  977. /* ----------------
  978.  * sanity checks
  979.  * ----------------
  980.  */
  981. Assert(RelationIsValid(relation));
  982. Assert(HeapTupleIsValid(tuple));
  983. Assert(PointerIsValid(function));
  984. CACHE1_elog(DEBUG, "RelationInvalidateCatalogCacheTuple: called");
  985. /* ----------------
  986.  * switch to the cache memory context
  987.  * ----------------
  988.  */
  989. if (!CacheCxt)
  990. CacheCxt = CreateGlobalMemory("Cache");
  991. oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
  992. /* ----------------
  993.  * for each cache
  994.  *    if the cache contains tuples from the specified relation
  995.  *    call the invalidation function on the tuples
  996.  *    in the proper hash bucket
  997.  * ----------------
  998.  */
  999. relationId = RelationGetRelid(relation);
  1000. for (ccp = Caches; ccp; ccp = ccp->cc_next)
  1001. {
  1002. if (relationId != ccp->relationId)
  1003. continue;
  1004. #ifdef NOT_USED
  1005. /* OPT inline simplification of CatalogCacheIdInvalidate */
  1006. if (!PointerIsValid(function))
  1007. function = CatalogCacheIdInvalidate;
  1008. #endif
  1009. (*function) (ccp->id,
  1010.  CatalogCacheComputeTupleHashIndex(ccp, relation, tuple),
  1011.  &tuple->t_self);
  1012. heap_close(relation);
  1013. }
  1014. /* ----------------
  1015.  * return to the proper memory context
  1016.  * ----------------
  1017.  */
  1018. MemoryContextSwitchTo(oldcxt);
  1019. /* sendpm('I', "Invalidated tuple"); */
  1020. }