Thank you for reviewing this. At Sat, 2 Sep 2017 12:12:47 +1200, Thomas Munro <thomas.mu...@enterprisedb.com> wrote in <CAEepm=3wqpffskp_yhkuhlztoowzskguhjdsctvnbhq4dfe...@mail.gmail.com> > On Mon, Aug 28, 2017 at 9:24 PM, Kyotaro HORIGUCHI > <horiguchi.kyot...@lab.ntt.co.jp> wrote: > > This patch have had interferences from several commits after the > > last submission. I amended this patch to follow them (up to > > f97c55c), removed an unnecessary branch and edited some comments. > > Hi Kyotaro-san, > > This applies but several regression tests fail for me. Here is a > sample backtrace:
Sorry for the silly mistake. STAEXTNAMENSP and STATRELATTINH was missing additional elements in their definitions. Somehow I've removed them. The attached patch doesn't crash by regression test. And fixed some typos pointed by Robert and found by myself. regards. -- Kyotaro Horiguchi NTT Open Source Software Center
>From 215530f562eaa514437e811686f6e3e419fdd950 Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp> Date: Mon, 28 Aug 2017 11:36:21 +0900 Subject: [PATCH 1/2] Cleanup negative cache of pg_statistic when dropping a relation. Accessing columns that don't have statistics leaves negative entries in catcache for pg_statstic, but there's no chance to remove them. Especially when repeatedly creating then dropping temporary tables bloats catcache so much that memory pressure becomes significant. This patch removes negative entries in STATRELATTINH, ATTNAME and ATTNUM when corresponding relation is dropped. --- src/backend/utils/cache/catcache.c | 57 ++++++- src/backend/utils/cache/syscache.c | 302 +++++++++++++++++++++++++++---------- src/include/utils/catcache.h | 3 + src/include/utils/syscache.h | 2 + 4 files changed, 281 insertions(+), 83 deletions(-) diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index e092801..73e7a44 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -304,10 +304,11 @@ CatCachePrintStats(int code, Datum arg) if (cache->cc_ntup == 0 && cache->cc_searches == 0) continue; /* don't print unused caches */ - elog(DEBUG2, "catcache %s/%u: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits", + elog(DEBUG2, "catcache %s/%u: %d tup, %d negtup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits", cache->cc_relname, cache->cc_indexoid, cache->cc_ntup, + cache->cc_nnegtup, cache->cc_searches, cache->cc_hits, cache->cc_neg_hits, @@ -374,6 +375,10 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct) /* free associated tuple data */ if (ct->tuple.t_data != NULL) pfree(ct->tuple.t_data); + + if (ct->negative) + --cache->cc_nnegtup; + pfree(ct); --cache->cc_ntup; @@ -572,6 +577,49 @@ ResetCatalogCache(CatCache *cache) } /* + * CleanupCatCacheNegEntries + * + * Remove negative cache tuples matching a partial key. + * + */ +void +CleanupCatCacheNegEntries(CatCache *cache, ScanKeyData *skey) +{ + int i; + + /* If this cache has no negative entries, nothing to do */ + if (cache->cc_nnegtup == 0) + return; + + /* searching with a partial key means scanning the whole cache */ + for (i = 0; i < cache->cc_nbuckets; i++) + { + dlist_head *bucket = &cache->cc_bucket[i]; + dlist_mutable_iter iter; + + dlist_foreach_modify(iter, bucket) + { + CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur); + bool res; + + if (!ct->negative) + continue; + + HeapKeyTest(&ct->tuple, cache->cc_tupdesc, 1, skey, res); + if (!res) + continue; + + /* + * the negative cache entries can no longer be referenced, so we + * can remove it unconditionally + */ + CatCacheRemoveCTup(cache, ct); + } + } +} + + +/* * ResetCatalogCaches * * Reset all caches when a shared cache inval event forces it @@ -718,6 +766,7 @@ InitCatCache(int id, cp->cc_relisshared = false; /* temporary */ cp->cc_tupdesc = (TupleDesc) NULL; cp->cc_ntup = 0; + cp->cc_nnegtup = 0; cp->cc_nbuckets = nbuckets; cp->cc_nkeys = nkeys; for (i = 0; i < nkeys; ++i) @@ -1215,8 +1264,8 @@ SearchCatCache(CatCache *cache, CACHE4_elog(DEBUG2, "SearchCatCache(%s): Contains %d/%d tuples", cache->cc_relname, cache->cc_ntup, CacheHdr->ch_ntup); - CACHE3_elog(DEBUG2, "SearchCatCache(%s): put neg entry in bucket %d", - cache->cc_relname, hashIndex); + CACHE4_elog(DEBUG2, "SearchCatCache(%s): put neg entry in bucket %d, total %d", + cache->cc_relname, hashIndex, cache->cc_nnegtup); /* * We are not returning the negative entry to the caller, so leave its @@ -1667,6 +1716,8 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, cache->cc_ntup++; CacheHdr->ch_ntup++; + if (negative) + cache->cc_nnegtup++; /* * If the hash table has become too full, enlarge the buckets array. Quite diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 607fe9d..1faed74 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -75,6 +75,8 @@ #include "catalog/pg_user_mapping.h" #include "utils/rel.h" #include "utils/catcache.h" +#include "utils/fmgroids.h" +#include "utils/inval.h" #include "utils/syscache.h" @@ -118,6 +120,10 @@ struct cachedesc int nkeys; /* # of keys needed for cache lookup */ int key[4]; /* attribute numbers of key attrs */ int nbuckets; /* number of hash buckets for this cache */ + + /* relcache invalidation stuff */ + AttrNumber relattrnum; /* attrnum to retrieve reloid for + * invalidation, 0 if not needed */ }; static const struct cachedesc cacheinfo[] = { @@ -130,7 +136,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 16 + 16, + 0 }, {AccessMethodRelationId, /* AMNAME */ AmNameIndexId, @@ -141,7 +148,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {AccessMethodRelationId, /* AMOID */ AmOidIndexId, @@ -152,7 +160,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {AccessMethodOperatorRelationId, /* AMOPOPID */ AccessMethodOperatorIndexId, @@ -163,7 +172,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amop_amopfamily, 0 }, - 64 + 64, + 0 }, {AccessMethodOperatorRelationId, /* AMOPSTRATEGY */ AccessMethodStrategyIndexId, @@ -174,7 +184,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amop_amoprighttype, Anum_pg_amop_amopstrategy }, - 64 + 64, + 0 }, {AccessMethodProcedureRelationId, /* AMPROCNUM */ AccessMethodProcedureIndexId, @@ -185,7 +196,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amproc_amprocrighttype, Anum_pg_amproc_amprocnum }, - 16 + 16, + 0 }, {AttributeRelationId, /* ATTNAME */ AttributeRelidNameIndexId, @@ -196,7 +208,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 32 + 32, + Anum_pg_attribute_attrelid }, {AttributeRelationId, /* ATTNUM */ AttributeRelidNumIndexId, @@ -207,7 +220,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 128 + 128, + Anum_pg_attribute_attrelid }, {AuthMemRelationId, /* AUTHMEMMEMROLE */ AuthMemMemRoleIndexId, @@ -218,7 +232,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {AuthMemRelationId, /* AUTHMEMROLEMEM */ AuthMemRoleMemIndexId, @@ -229,7 +244,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {AuthIdRelationId, /* AUTHNAME */ AuthIdRolnameIndexId, @@ -240,7 +256,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {AuthIdRelationId, /* AUTHOID */ AuthIdOidIndexId, @@ -251,10 +268,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, - { - CastRelationId, /* CASTSOURCETARGET */ + {CastRelationId, /* CASTSOURCETARGET */ CastSourceTargetIndexId, 2, { @@ -263,7 +280,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 256 + 256, + 0 }, {OperatorClassRelationId, /* CLAAMNAMENSP */ OpclassAmNameNspIndexId, @@ -274,7 +292,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_opclass_opcnamespace, 0 }, - 8 + 8, + 0 }, {OperatorClassRelationId, /* CLAOID */ OpclassOidIndexId, @@ -285,7 +304,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {CollationRelationId, /* COLLNAMEENCNSP */ CollationNameEncNspIndexId, @@ -296,7 +316,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_collation_collnamespace, 0 }, - 8 + 8, + 0 }, {CollationRelationId, /* COLLOID */ CollationOidIndexId, @@ -307,7 +328,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {ConversionRelationId, /* CONDEFAULT */ ConversionDefaultIndexId, @@ -318,7 +340,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_conversion_contoencoding, ObjectIdAttributeNumber, }, - 8 + 8, + 0 }, {ConversionRelationId, /* CONNAMENSP */ ConversionNameNspIndexId, @@ -329,7 +352,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {ConstraintRelationId, /* CONSTROID */ ConstraintOidIndexId, @@ -340,7 +364,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 16 + 16, + 0 }, {ConversionRelationId, /* CONVOID */ ConversionOidIndexId, @@ -351,7 +376,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {DatabaseRelationId, /* DATABASEOID */ DatabaseOidIndexId, @@ -362,7 +388,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {DefaultAclRelationId, /* DEFACLROLENSPOBJ */ DefaultAclRoleNspObjIndexId, @@ -373,7 +400,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_default_acl_defaclobjtype, 0 }, - 8 + 8, + 0 }, {EnumRelationId, /* ENUMOID */ EnumOidIndexId, @@ -384,7 +412,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {EnumRelationId, /* ENUMTYPOIDNAME */ EnumTypIdLabelIndexId, @@ -395,7 +424,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {EventTriggerRelationId, /* EVENTTRIGGERNAME */ EventTriggerNameIndexId, @@ -406,7 +436,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {EventTriggerRelationId, /* EVENTTRIGGEROID */ EventTriggerOidIndexId, @@ -417,7 +448,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPERNAME */ ForeignDataWrapperNameIndexId, @@ -428,7 +460,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPEROID */ ForeignDataWrapperOidIndexId, @@ -439,7 +472,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {ForeignServerRelationId, /* FOREIGNSERVERNAME */ ForeignServerNameIndexId, @@ -450,7 +484,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {ForeignServerRelationId, /* FOREIGNSERVEROID */ ForeignServerOidIndexId, @@ -461,7 +496,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {ForeignTableRelationId, /* FOREIGNTABLEREL */ ForeignTableRelidIndexId, @@ -472,7 +508,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {IndexRelationId, /* INDEXRELID */ IndexRelidIndexId, @@ -483,7 +520,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 64 + 64, + 0 }, {LanguageRelationId, /* LANGNAME */ LanguageNameIndexId, @@ -494,7 +532,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {LanguageRelationId, /* LANGOID */ LanguageOidIndexId, @@ -505,7 +544,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {NamespaceRelationId, /* NAMESPACENAME */ NamespaceNameIndexId, @@ -516,7 +556,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {NamespaceRelationId, /* NAMESPACEOID */ NamespaceOidIndexId, @@ -527,7 +568,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 16 + 16, + 0 }, {OperatorRelationId, /* OPERNAMENSP */ OperatorNameNspIndexId, @@ -538,7 +580,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_operator_oprright, Anum_pg_operator_oprnamespace }, - 256 + 256, + 0 }, {OperatorRelationId, /* OPEROID */ OperatorOidIndexId, @@ -549,7 +592,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 32 + 32, + 0 }, {OperatorFamilyRelationId, /* OPFAMILYAMNAMENSP */ OpfamilyAmNameNspIndexId, @@ -560,7 +604,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_opfamily_opfnamespace, 0 }, - 8 + 8, + 0 }, {OperatorFamilyRelationId, /* OPFAMILYOID */ OpfamilyOidIndexId, @@ -571,7 +616,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {PartitionedRelationId, /* PARTRELID */ PartitionedRelidIndexId, @@ -582,7 +628,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 32 + 32, + 0 }, {ProcedureRelationId, /* PROCNAMEARGSNSP */ ProcedureNameArgsNspIndexId, @@ -593,7 +640,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_proc_pronamespace, 0 }, - 128 + 128, + 0 }, {ProcedureRelationId, /* PROCOID */ ProcedureOidIndexId, @@ -604,7 +652,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 128 + 128, + 0 }, {PublicationRelationId, /* PUBLICATIONNAME */ PublicationNameIndexId, @@ -615,7 +664,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {PublicationRelationId, /* PUBLICATIONOID */ PublicationObjectIndexId, @@ -626,7 +676,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {PublicationRelRelationId, /* PUBLICATIONREL */ PublicationRelObjectIndexId, @@ -637,7 +688,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 64 + 64, + 0 }, {PublicationRelRelationId, /* PUBLICATIONRELMAP */ PublicationRelPrrelidPrpubidIndexId, @@ -648,7 +700,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 64 + 64, + 0 }, {RangeRelationId, /* RANGETYPE */ RangeTypidIndexId, @@ -659,7 +712,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {RelationRelationId, /* RELNAMENSP */ ClassNameNspIndexId, @@ -670,7 +724,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 128 + 128, + 0 }, {RelationRelationId, /* RELOID */ ClassOidIndexId, @@ -681,7 +736,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 128 + 128, + 0 }, {ReplicationOriginRelationId, /* REPLORIGIDENT */ ReplicationOriginIdentIndex, @@ -692,7 +748,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 16 + 16, + 0 }, {ReplicationOriginRelationId, /* REPLORIGNAME */ ReplicationOriginNameIndex, @@ -703,7 +760,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 16 + 16, + 0 }, {RewriteRelationId, /* RULERELNAME */ RewriteRelRulenameIndexId, @@ -714,7 +772,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 8 + 8, + 0 }, {SequenceRelationId, /* SEQRELID */ SequenceRelidIndexId, @@ -725,7 +784,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 32 + 32, + 0 }, {StatisticExtRelationId, /* STATEXTNAMENSP */ StatisticExtNameIndexId, @@ -736,7 +796,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {StatisticExtRelationId, /* STATEXTOID */ StatisticExtOidIndexId, @@ -747,7 +808,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {StatisticRelationId, /* STATRELATTINH */ StatisticRelidAttnumInhIndexId, @@ -758,7 +820,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_statistic_stainherit, 0 }, - 128 + 128, + Anum_pg_statistic_starelid }, {SubscriptionRelationId, /* SUBSCRIPTIONNAME */ SubscriptionNameIndexId, @@ -769,7 +832,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {SubscriptionRelationId, /* SUBSCRIPTIONOID */ SubscriptionObjectIndexId, @@ -780,7 +844,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 4 + 4, + 0 }, {SubscriptionRelRelationId, /* SUBSCRIPTIONRELMAP */ SubscriptionRelSrrelidSrsubidIndexId, @@ -791,7 +856,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 64 + 64, + 0 }, {TableSpaceRelationId, /* TABLESPACEOID */ TablespaceOidIndexId, @@ -802,7 +868,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0, }, - 4 + 4, + 0 }, {TransformRelationId, /* TRFOID */ TransformOidIndexId, @@ -813,7 +880,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0, }, - 16 + 16, + 0 }, {TransformRelationId, /* TRFTYPELANG */ TransformTypeLangIndexId, @@ -824,7 +892,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0, }, - 16 + 16, + 0 }, {TSConfigMapRelationId, /* TSCONFIGMAP */ TSConfigMapIndexId, @@ -835,7 +904,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_ts_config_map_mapseqno, 0 }, - 2 + 2, + 0 }, {TSConfigRelationId, /* TSCONFIGNAMENSP */ TSConfigNameNspIndexId, @@ -846,7 +916,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {TSConfigRelationId, /* TSCONFIGOID */ TSConfigOidIndexId, @@ -857,7 +928,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {TSDictionaryRelationId, /* TSDICTNAMENSP */ TSDictionaryNameNspIndexId, @@ -868,7 +940,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {TSDictionaryRelationId, /* TSDICTOID */ TSDictionaryOidIndexId, @@ -879,7 +952,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {TSParserRelationId, /* TSPARSERNAMENSP */ TSParserNameNspIndexId, @@ -890,7 +964,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {TSParserRelationId, /* TSPARSEROID */ TSParserOidIndexId, @@ -901,7 +976,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {TSTemplateRelationId, /* TSTEMPLATENAMENSP */ TSTemplateNameNspIndexId, @@ -912,7 +988,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {TSTemplateRelationId, /* TSTEMPLATEOID */ TSTemplateOidIndexId, @@ -923,7 +1000,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {TypeRelationId, /* TYPENAMENSP */ TypeNameNspIndexId, @@ -934,7 +1012,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 64 + 64, + 0 }, {TypeRelationId, /* TYPEOID */ TypeOidIndexId, @@ -945,7 +1024,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 64 + 64, + 0 }, {UserMappingRelationId, /* USERMAPPINGOID */ UserMappingOidIndexId, @@ -956,7 +1036,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 }, {UserMappingRelationId, /* USERMAPPINGUSERSERVER */ UserMappingUserServerIndexId, @@ -967,7 +1048,8 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, - 2 + 2, + 0 } }; @@ -983,8 +1065,23 @@ static int SysCacheRelationOidSize; static Oid SysCacheSupportingRelOid[SysCacheSize * 2]; static int SysCacheSupportingRelOidSize; -static int oid_compare(const void *a, const void *b); +/* + * stuff for negative cache flushing by relcache invalidation + */ +#define MAX_RELINVAL_CALLBACKS 4 +typedef struct RELINVALCBParam +{ + CatCache *cache; + int relkeynum; +} RELINVALCBParam; + +RELINVALCBParam relinval_callback_list[MAX_RELINVAL_CALLBACKS]; +static int relinval_callback_count = 0; + +static ScanKeyData oideqscankey; /* ScanKey for reloid match */ +static int oid_compare(const void *a, const void *b); +static void SysCacheRelInvalCallback(Datum arg, Oid reloid); /* * InitCatalogCache - initialize the caches @@ -1028,6 +1125,21 @@ InitCatalogCache(void) cacheinfo[cacheId].indoid; /* see comments for RelationInvalidatesSnapshotsOnly */ Assert(!RelationInvalidatesSnapshotsOnly(cacheinfo[cacheId].reloid)); + + /* + * If this syscache is requesting relcache invalidation, register a + * callback + */ + if (cacheinfo[cacheId].relattrnum > 0) + { + Assert(relinval_callback_count < MAX_RELINVAL_CALLBACKS); + + relinval_callback_list[relinval_callback_count].cache = + SysCache[cacheId]; + relinval_callback_list[relinval_callback_count].relkeynum = + cacheinfo[cacheId].relattrnum; + relinval_callback_count++; + } } Assert(SysCacheRelationOidSize <= lengthof(SysCacheRelationOid)); @@ -1052,10 +1164,40 @@ InitCatalogCache(void) } SysCacheSupportingRelOidSize = j + 1; + /* + * prepare the scankey for reloid comparison and register a relcache inval + * callback. + */ + oideqscankey.sk_strategy = BTEqualStrategyNumber; + oideqscankey.sk_subtype = InvalidOid; + oideqscankey.sk_collation = InvalidOid; + fmgr_info_cxt(F_OIDEQ, &oideqscankey.sk_func, CacheMemoryContext); + CacheRegisterRelcacheCallback(SysCacheRelInvalCallback, (Datum) 0); + CacheInitialized = true; } /* + * Callback function for negative cache flushing by relcache invalidation + * scankey for this function has been prepared in InitCatalogCache. + */ +static void +SysCacheRelInvalCallback(Datum arg, Oid reloid) +{ + int i; + + for(i = 0 ; i < relinval_callback_count ; i++) + { + ScanKeyData skey; + + memcpy(&skey, &oideqscankey, sizeof(skey)); + skey.sk_attno = relinval_callback_list[i].relkeynum; + skey.sk_argument = ObjectIdGetDatum(reloid); + CleanupCatCacheNegEntries(relinval_callback_list[i].cache, &skey); + } +} + +/* * InitCatalogCachePhase2 - finish initializing the caches * * Finish initializing all the caches, including necessary database diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h index 200a302..6ef4e38 100644 --- a/src/include/utils/catcache.h +++ b/src/include/utils/catcache.h @@ -44,6 +44,7 @@ typedef struct catcache bool cc_relisshared; /* is relation shared across databases? */ TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */ int cc_ntup; /* # of tuples currently in this cache */ + int cc_nnegtup; /* # of negative tuples */ int cc_nbuckets; /* # of hash buckets in this cache */ int cc_nkeys; /* # of keys (1..CATCACHE_MAXKEYS) */ int cc_key[CATCACHE_MAXKEYS]; /* AttrNumber of each key */ @@ -187,6 +188,8 @@ extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys, Datum v3, Datum v4); extern void ReleaseCatCacheList(CatCList *list); +extern void +CleanupCatCacheNegEntries(CatCache *cache, ScanKeyData *skey); extern void ResetCatalogCaches(void); extern void CatalogCacheFlushCatalog(Oid catId); extern void CatCacheInvalidate(CatCache *cache, uint32 hashValue); diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 8352b40..ca3ddd5 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -118,6 +118,8 @@ extern void InitCatalogCachePhase2(void); extern HeapTuple SearchSysCache(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4); extern void ReleaseSysCache(HeapTuple tuple); +extern void CleanupNegativeCache(int cacheid, int nkeys, + Datum key1, Datum key2, Datum key3, Datum key4); /* convenience routines */ extern HeapTuple SearchSysCacheCopy(int cacheId, -- 2.9.2
>From afe3a3bb9ab902e3b18ab8eaa2d5ead90eed1ead Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp> Date: Mon, 28 Aug 2017 12:18:17 +0900 Subject: [PATCH 2/2] Cleanup negative cache of pg_class when dropping a schema This feature in turn is triggered by catcache invalidation. This patch provides a syscache invalidation callback to flush negative cache entries corresponding to invalidated objects. --- src/backend/utils/cache/catcache.c | 42 +++++ src/backend/utils/cache/inval.c | 7 +- src/backend/utils/cache/syscache.c | 327 ++++++++++++++++++++++++++++--------- src/include/utils/catcache.h | 3 + 4 files changed, 300 insertions(+), 79 deletions(-) diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 73e7a44..675413b 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -1360,6 +1360,48 @@ GetCatCacheHashValue(CatCache *cache, return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, cur_skey); } +/* + * CollectOIDsForHashValue + * + * Collect OIDs correspond to a hash value. attnum is the column to retrieve + * the OIDs. + */ +List * +CollectOIDsForHashValue(CatCache *cache, uint32 hashValue, int attnum) +{ + Index hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets); + dlist_head *bucket = &cache->cc_bucket[hashIndex]; + dlist_iter iter; + List *ret = NIL; + + /* Nothing to return before initialization */ + if (cache->cc_tupdesc == NULL) + return ret; + + /* Currently only OID key is supported */ + Assert(attnum <= cache->cc_tupdesc->natts); + Assert(attnum < 0 ? attnum == ObjectIdAttributeNumber : + cache->cc_tupdesc->attrs[attnum].atttypid == OIDOID); + + dlist_foreach(iter, bucket) + { + CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur); + bool isNull; + Datum oid; + + if (ct->dead) + continue; /* ignore dead entries */ + + if (ct->hash_value != hashValue) + continue; /* quickly skip entry if wrong hash val */ + + oid = heap_getattr(&ct->tuple, attnum, cache->cc_tupdesc, &isNull); + if (!isNull) + ret = lappend_oid(ret, DatumGetObjectId(oid)); + } + + return ret; +} /* * SearchCatCacheList diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index d0e54b8..57528a7 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -559,9 +559,14 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg) { InvalidateCatalogSnapshot(); + /* + * Call the callbacks first so that the callbacks can access the + * entries corresponding to the hashValue. + */ + CallSyscacheCallbacks(msg->cc.id, msg->cc.hashValue); + SysCacheInvalidate(msg->cc.id, msg->cc.hashValue); - CallSyscacheCallbacks(msg->cc.id, msg->cc.hashValue); } } else if (msg->id == SHAREDINVALCATALOG_ID) diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 1faed74..e8514dc 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -111,6 +111,16 @@ */ /* + * struct for flushing negative cache by syscache invalidation + */ +typedef struct SysCacheCBParam_T +{ + int trig_attnum; + int target_cacheid; + ScanKeyData skey; +} SysCacheCBParam; + +/* * struct cachedesc: information defining a single syscache */ struct cachedesc @@ -124,6 +134,14 @@ struct cachedesc /* relcache invalidation stuff */ AttrNumber relattrnum; /* attrnum to retrieve reloid for * invalidation, 0 if not needed */ + + /* catcache invalidation stuff */ + int trig_cacheid; /* cache id of triggering syscache: -1 means + * no triggering cache */ + int16 trig_attnum; /* key column in triggering cache. Must be an + * OID */ + int16 target_attnum; /* corresponding column in this cache. Must be + * an OID*/ }; static const struct cachedesc cacheinfo[] = { @@ -137,7 +155,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 16, - 0 + 0, + -1, 0, 0 }, {AccessMethodRelationId, /* AMNAME */ AmNameIndexId, @@ -149,7 +168,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {AccessMethodRelationId, /* AMOID */ AmOidIndexId, @@ -161,7 +181,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {AccessMethodOperatorRelationId, /* AMOPOPID */ AccessMethodOperatorIndexId, @@ -173,7 +194,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 64, - 0 + 0, + -1, 0, 0 }, {AccessMethodOperatorRelationId, /* AMOPSTRATEGY */ AccessMethodStrategyIndexId, @@ -185,7 +207,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amop_amopstrategy }, 64, - 0 + 0, + -1, 0, 0 }, {AccessMethodProcedureRelationId, /* AMPROCNUM */ AccessMethodProcedureIndexId, @@ -197,7 +220,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amproc_amprocnum }, 16, - 0 + 0, + -1, 0, 0 }, {AttributeRelationId, /* ATTNAME */ AttributeRelidNameIndexId, @@ -209,7 +233,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 32, - Anum_pg_attribute_attrelid + Anum_pg_attribute_attrelid, + -1, 0, 0 }, {AttributeRelationId, /* ATTNUM */ AttributeRelidNumIndexId, @@ -221,7 +246,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 128, - Anum_pg_attribute_attrelid + Anum_pg_attribute_attrelid, + -1, 0, 0 }, {AuthMemRelationId, /* AUTHMEMMEMROLE */ AuthMemMemRoleIndexId, @@ -233,7 +259,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {AuthMemRelationId, /* AUTHMEMROLEMEM */ AuthMemRoleMemIndexId, @@ -245,7 +272,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {AuthIdRelationId, /* AUTHNAME */ AuthIdRolnameIndexId, @@ -257,7 +285,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {AuthIdRelationId, /* AUTHOID */ AuthIdOidIndexId, @@ -269,7 +298,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {CastRelationId, /* CASTSOURCETARGET */ CastSourceTargetIndexId, @@ -281,7 +311,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 256, - 0 + 0, + -1, 0, 0 }, {OperatorClassRelationId, /* CLAAMNAMENSP */ OpclassAmNameNspIndexId, @@ -293,7 +324,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {OperatorClassRelationId, /* CLAOID */ OpclassOidIndexId, @@ -305,7 +337,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {CollationRelationId, /* COLLNAMEENCNSP */ CollationNameEncNspIndexId, @@ -317,7 +350,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {CollationRelationId, /* COLLOID */ CollationOidIndexId, @@ -329,7 +363,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {ConversionRelationId, /* CONDEFAULT */ ConversionDefaultIndexId, @@ -341,7 +376,8 @@ static const struct cachedesc cacheinfo[] = { ObjectIdAttributeNumber, }, 8, - 0 + 0, + -1, 0, 0 }, {ConversionRelationId, /* CONNAMENSP */ ConversionNameNspIndexId, @@ -353,7 +389,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {ConstraintRelationId, /* CONSTROID */ ConstraintOidIndexId, @@ -365,7 +402,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 16, - 0 + 0, + -1, 0, 0 }, {ConversionRelationId, /* CONVOID */ ConversionOidIndexId, @@ -377,7 +415,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {DatabaseRelationId, /* DATABASEOID */ DatabaseOidIndexId, @@ -389,7 +428,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {DefaultAclRelationId, /* DEFACLROLENSPOBJ */ DefaultAclRoleNspObjIndexId, @@ -401,7 +441,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {EnumRelationId, /* ENUMOID */ EnumOidIndexId, @@ -413,7 +454,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {EnumRelationId, /* ENUMTYPOIDNAME */ EnumTypIdLabelIndexId, @@ -425,7 +467,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {EventTriggerRelationId, /* EVENTTRIGGERNAME */ EventTriggerNameIndexId, @@ -437,7 +480,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {EventTriggerRelationId, /* EVENTTRIGGEROID */ EventTriggerOidIndexId, @@ -449,7 +493,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPERNAME */ ForeignDataWrapperNameIndexId, @@ -461,7 +506,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPEROID */ ForeignDataWrapperOidIndexId, @@ -473,7 +519,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {ForeignServerRelationId, /* FOREIGNSERVERNAME */ ForeignServerNameIndexId, @@ -485,7 +532,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {ForeignServerRelationId, /* FOREIGNSERVEROID */ ForeignServerOidIndexId, @@ -497,7 +545,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {ForeignTableRelationId, /* FOREIGNTABLEREL */ ForeignTableRelidIndexId, @@ -509,7 +558,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {IndexRelationId, /* INDEXRELID */ IndexRelidIndexId, @@ -521,7 +571,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 64, - 0 + 0, + -1, 0, 0 }, {LanguageRelationId, /* LANGNAME */ LanguageNameIndexId, @@ -533,7 +584,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {LanguageRelationId, /* LANGOID */ LanguageOidIndexId, @@ -545,7 +597,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {NamespaceRelationId, /* NAMESPACENAME */ NamespaceNameIndexId, @@ -557,7 +610,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {NamespaceRelationId, /* NAMESPACEOID */ NamespaceOidIndexId, @@ -569,7 +623,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 16, - 0 + 0, + -1, 0, 0 }, {OperatorRelationId, /* OPERNAMENSP */ OperatorNameNspIndexId, @@ -581,7 +636,8 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_operator_oprnamespace }, 256, - 0 + 0, + -1, 0, 0 }, {OperatorRelationId, /* OPEROID */ OperatorOidIndexId, @@ -593,7 +649,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 32, - 0 + 0, + -1, 0, 0 }, {OperatorFamilyRelationId, /* OPFAMILYAMNAMENSP */ OpfamilyAmNameNspIndexId, @@ -605,7 +662,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {OperatorFamilyRelationId, /* OPFAMILYOID */ OpfamilyOidIndexId, @@ -617,7 +675,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {PartitionedRelationId, /* PARTRELID */ PartitionedRelidIndexId, @@ -629,7 +688,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 32, - 0 + 0, + -1, 0, 0 }, {ProcedureRelationId, /* PROCNAMEARGSNSP */ ProcedureNameArgsNspIndexId, @@ -641,7 +701,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 128, - 0 + 0, + -1, 0, 0 }, {ProcedureRelationId, /* PROCOID */ ProcedureOidIndexId, @@ -653,7 +714,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 128, - 0 + 0, + -1, 0, 0 }, {PublicationRelationId, /* PUBLICATIONNAME */ PublicationNameIndexId, @@ -665,7 +727,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {PublicationRelationId, /* PUBLICATIONOID */ PublicationObjectIndexId, @@ -677,7 +740,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {PublicationRelRelationId, /* PUBLICATIONREL */ PublicationRelObjectIndexId, @@ -689,7 +753,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 64, - 0 + 0, + -1, 0, 0 }, {PublicationRelRelationId, /* PUBLICATIONRELMAP */ PublicationRelPrrelidPrpubidIndexId, @@ -701,7 +766,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 64, - 0 + 0, + -1, 0, 0 }, {RangeRelationId, /* RANGETYPE */ RangeTypidIndexId, @@ -713,7 +779,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {RelationRelationId, /* RELNAMENSP */ ClassNameNspIndexId, @@ -725,7 +792,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 128, - 0 + 0, + NAMESPACEOID, ObjectIdAttributeNumber, Anum_pg_class_relnamespace }, {RelationRelationId, /* RELOID */ ClassOidIndexId, @@ -737,7 +805,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 128, - 0 + 0, + -1, 0, 0 }, {ReplicationOriginRelationId, /* REPLORIGIDENT */ ReplicationOriginIdentIndex, @@ -749,7 +818,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 16, - 0 + 0, + -1, 0, 0 }, {ReplicationOriginRelationId, /* REPLORIGNAME */ ReplicationOriginNameIndex, @@ -761,7 +831,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 16, - 0 + 0, + -1, 0, 0 }, {RewriteRelationId, /* RULERELNAME */ RewriteRelRulenameIndexId, @@ -773,7 +844,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 8, - 0 + 0, + -1, 0, 0 }, {SequenceRelationId, /* SEQRELID */ SequenceRelidIndexId, @@ -785,7 +857,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 32, - 0 + 0, + -1, 0, 0 }, {StatisticExtRelationId, /* STATEXTNAMENSP */ StatisticExtNameIndexId, @@ -797,7 +870,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {StatisticExtRelationId, /* STATEXTOID */ StatisticExtOidIndexId, @@ -809,7 +883,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {StatisticRelationId, /* STATRELATTINH */ StatisticRelidAttnumInhIndexId, @@ -821,7 +896,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 128, - Anum_pg_statistic_starelid + Anum_pg_statistic_starelid, + -1, 0, 0 }, {SubscriptionRelationId, /* SUBSCRIPTIONNAME */ SubscriptionNameIndexId, @@ -833,7 +909,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {SubscriptionRelationId, /* SUBSCRIPTIONOID */ SubscriptionObjectIndexId, @@ -845,7 +922,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 4, - 0 + 0, + -1, 0, 0 }, {SubscriptionRelRelationId, /* SUBSCRIPTIONRELMAP */ SubscriptionRelSrrelidSrsubidIndexId, @@ -857,7 +935,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 64, - 0 + 0, + -1, 0, 0 }, {TableSpaceRelationId, /* TABLESPACEOID */ TablespaceOidIndexId, @@ -869,7 +948,8 @@ static const struct cachedesc cacheinfo[] = { 0, }, 4, - 0 + 0, + -1, 0, 0 }, {TransformRelationId, /* TRFOID */ TransformOidIndexId, @@ -881,7 +961,8 @@ static const struct cachedesc cacheinfo[] = { 0, }, 16, - 0 + 0, + -1, 0, 0 }, {TransformRelationId, /* TRFTYPELANG */ TransformTypeLangIndexId, @@ -893,7 +974,8 @@ static const struct cachedesc cacheinfo[] = { 0, }, 16, - 0 + 0, + -1, 0, 0 }, {TSConfigMapRelationId, /* TSCONFIGMAP */ TSConfigMapIndexId, @@ -905,7 +987,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSConfigRelationId, /* TSCONFIGNAMENSP */ TSConfigNameNspIndexId, @@ -917,7 +1000,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSConfigRelationId, /* TSCONFIGOID */ TSConfigOidIndexId, @@ -929,7 +1013,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSDictionaryRelationId, /* TSDICTNAMENSP */ TSDictionaryNameNspIndexId, @@ -941,7 +1026,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSDictionaryRelationId, /* TSDICTOID */ TSDictionaryOidIndexId, @@ -953,7 +1039,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSParserRelationId, /* TSPARSERNAMENSP */ TSParserNameNspIndexId, @@ -965,7 +1052,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSParserRelationId, /* TSPARSEROID */ TSParserOidIndexId, @@ -977,7 +1065,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSTemplateRelationId, /* TSTEMPLATENAMENSP */ TSTemplateNameNspIndexId, @@ -989,7 +1078,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSTemplateRelationId, /* TSTEMPLATEOID */ TSTemplateOidIndexId, @@ -1001,7 +1091,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TypeRelationId, /* TYPENAMENSP */ TypeNameNspIndexId, @@ -1013,7 +1104,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 64, - 0 + 0, + -1, 0, 0 }, {TypeRelationId, /* TYPEOID */ TypeOidIndexId, @@ -1025,7 +1117,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 64, - 0 + 0, + -1, 0, 0 }, {UserMappingRelationId, /* USERMAPPINGOID */ UserMappingOidIndexId, @@ -1037,7 +1130,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 }, {UserMappingRelationId, /* USERMAPPINGUSERSERVER */ UserMappingUserServerIndexId, @@ -1049,7 +1143,8 @@ static const struct cachedesc cacheinfo[] = { 0 }, 2, - 0 + 0, + -1, 0, 0 } }; @@ -1082,7 +1177,8 @@ static ScanKeyData oideqscankey; /* ScanKey for reloid match */ static int oid_compare(const void *a, const void *b); static void SysCacheRelInvalCallback(Datum arg, Oid reloid); - +static void SysCacheSysCacheInvalCallback(Datum arg, int cacheid, + uint32 hashvalue); /* * InitCatalogCache - initialize the caches * @@ -1140,6 +1236,34 @@ InitCatalogCache(void) cacheinfo[cacheId].relattrnum; relinval_callback_count++; } + + /* + * If this syscache has syscache invalidation trigger, register + * it. + */ + if (cacheinfo[cacheId].trig_cacheid >= 0) + { + SysCacheCBParam *param; + + param = MemoryContextAlloc(CacheMemoryContext, + sizeof(SysCacheCBParam)); + param->target_cacheid = cacheId; + + /* + * XXXX: Create a scankeydata for OID comparison. We don't have a + * means to check the type of the column in the system catalog at + * this time. So we have to believe the definition. + */ + fmgr_info_cxt(F_OIDEQ, ¶m->skey.sk_func, CacheMemoryContext); + param->skey.sk_attno = cacheinfo[cacheId].target_attnum; + param->trig_attnum = cacheinfo[cacheId].trig_attnum; + param->skey.sk_strategy = BTEqualStrategyNumber; + param->skey.sk_subtype = InvalidOid; + param->skey.sk_collation = InvalidOid; + CacheRegisterSyscacheCallback(cacheinfo[cacheId].trig_cacheid, + SysCacheSysCacheInvalCallback, + PointerGetDatum(param)); + } } Assert(SysCacheRelationOidSize <= lengthof(SysCacheRelationOid)); @@ -1534,6 +1658,53 @@ RelationInvalidatesSnapshotsOnly(Oid relid) } /* + * SysCacheSysCacheInvalCallback + * + * Callback function for negative cache flushing by syscache invalidation. + * Fetches an OID (not restricted to system oid column) from the invalidated + * tuple and flushes negative entries that matches the OID in the target + * syscache. + */ +static void +SysCacheSysCacheInvalCallback(Datum arg, int cacheid, uint32 hashValue) +{ + SysCacheCBParam *param; + CatCache *trigger_cache; /* triggering catcache */ + CatCache *target_cache; /* target catcache */ + List *oids; + ListCell *lc; + int trigger_cacheid = cacheid; + int target_cacheid; + + param = (SysCacheCBParam *)DatumGetPointer(arg); + target_cacheid = param->target_cacheid; + + trigger_cache = SysCache[trigger_cacheid]; + target_cache = SysCache[target_cacheid]; + + /* + * Collect candidate OIDs for target syscache entries. The result contains + * just one value for most cases, or two or more for the case hashvalue + * has synonyms. At least one of them is the right OID but it is + * undistinguishable from others by the given hash value. + * As the result some unnecessary entries may be flushed but it won't harm + * so much than letting them bloat catcaches. + */ + oids = + CollectOIDsForHashValue(trigger_cache, hashValue, param->trig_attnum); + + foreach (lc, oids) + { + ScanKeyData skey; + Oid oid = lfirst_oid (lc); + + memcpy(&skey, ¶m->skey, sizeof(skey)); + skey.sk_argument = ObjectIdGetDatum(oid); + CleanupCatCacheNegEntries(target_cache, &skey); + } +} + +/* * Test whether a relation has a system cache. */ bool diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h index 6ef4e38..7ead032 100644 --- a/src/include/utils/catcache.h +++ b/src/include/utils/catcache.h @@ -183,6 +183,9 @@ extern uint32 GetCatCacheHashValue(CatCache *cache, Datum v1, Datum v2, Datum v3, Datum v4); +extern List *CollectOIDsForHashValue(CatCache *cache, + uint32 hashValue, int attnum); + extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys, Datum v1, Datum v2, Datum v3, Datum v4); -- 2.9.2
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers