Hello, thank you for lookin this. At Mon, 23 Jan 2017 16:54:36 -0600, Jim Nasby <jim.na...@bluetreble.com> wrote in <21803f50-a823-c444-ee2b-9a153114f...@bluetreble.com> > On 1/21/17 6:42 PM, Jim Nasby wrote: > > On 12/26/16 2:31 AM, Kyotaro HORIGUCHI wrote: > >> The points of discussion are the following, I think. > >> > >> 1. The first patch seems working well. It costs the time to scan > >> the whole of a catcache that have negative entries for other > >> reloids. However, such negative entries are created by rather > >> unusual usages. Accesing to undefined columns, and accessing > >> columns on which no statistics have created. The > >> whole-catcache scan occurs on ATTNAME, ATTNUM and > >> STATRELATTINH for every invalidation of a relcache entry. > > > > I took a look at this. It looks sane, though I've got a few minor > > comment tweaks: > > > > + * Remove negative cache tuples maching a partial key. > > s/maching/matching/ > > > > +/* searching with a paritial key needs scanning the whole cache */ > > > > s/needs/means/ > > > > + * a negative cache entry cannot be referenced so we can remove > > > > s/referenced/referenced,/ > > > > I was wondering if there's a way to test the performance impact of > > deleting negative entries.
Thanks for the pointing out. These are addressed. > I did a make installcheck run with CATCACHE_STATS to see how often we > get negative entries in the 3 caches affected by this patch. The > caches on pg_attribute get almost no negative entries. pg_statistic > gets a good amount of negative entries, presumably because we start > off with no entries in there. On a stable system that presumably won't > be an issue, but if temporary tables are in use and being analyzed I'd > think there could be a moderate amount of inval traffic on that > cache. I'll leave it to a committer to decide if they thing that's an > issue, but you might want to try and quantify how big a hit that is. I > think it'd also be useful to know how much bloat you were seeing in > the field. > > The patch is currently conflicting against master though, due to some > caches being added. Can you rebase? Six new syscaches in 665d1fa was conflicted and 3-way merge worked correctly. The new syscaches don't seem to be targets of this patch. > BTW, if you set a slightly larger > context size on the patch you might be able to avoid rebases; right > now the patch doesn't include enough context to uniquely identify the > chunks against cacheinfo[]. git format-patch -U5 fuses all hunks on cacheinfo[] together. I'm not sure that such a hunk can avoid rebases. Is this what you suggested? -U4 added an identifiable forward context line for some elements so the attached patch is made with four context lines. regards, -- Kyotaro Horiguchi NTT Open Source Software Center
>From 3e9932cff6a2db1d081821269f1bab8b39b0f4f0 Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp> Date: Thu, 15 Dec 2016 17:43:03 +0900 Subject: [PATCH 1/2] Cleanup negative cache of pg_statistic when dropping a relation. Accessing columns that don't have statistics causes 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 can be 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 | 295 +++++++++++++++++++++++++++---------- src/include/utils/catcache.h | 3 + src/include/utils/syscache.h | 2 + 4 files changed, 277 insertions(+), 80 deletions(-) diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index c27186f..6ff2c5e 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -303,12 +303,13 @@ CatCachePrintStats(int code, Datum arg) CatCache *cache = slist_container(CatCache, cc_next, iter.cur); 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, cache->cc_hits + cache->cc_neg_hits, @@ -373,8 +374,12 @@ 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; --CacheHdr->ch_ntup; @@ -636,8 +641,51 @@ 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 paritial 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; + + /* + * a negative cache entry cannot be referenced, so we can remove + * it unconditionally + */ + CatCacheRemoveCTup(cache, ct); + } + } +} + + +/* * ResetCatalogCaches * * Reset all caches when a shared cache inval event forces it */ @@ -782,8 +830,9 @@ InitCatCache(int id, cp->cc_indexoid = indexoid; 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) cp->cc_key[i] = key[i]; @@ -1278,10 +1327,10 @@ SearchCatCache(CatCache *cache, heap_freetuple(ntp); 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 * refcount zero. @@ -1730,8 +1779,10 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, dlist_push_head(&cache->cc_bucket[hashIndex], &ct->cache_elem); cache->cc_ntup++; CacheHdr->ch_ntup++; + if (negative) + cache->cc_nnegtup++; /* * If the hash table has become too full, enlarge the buckets array. Quite * arbitrarily, we enlarge when fill factor > 2. diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index bdfaa0c..c9f3bea 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -72,8 +72,10 @@ #include "catalog/pg_type.h" #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" /*--------------------------------------------------------------------------- @@ -117,8 +119,11 @@ struct cachedesc Oid indoid; /* OID of index relation for this cache */ 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; /* attr number of reloid, 0 if nothing to do */ }; static const struct cachedesc cacheinfo[] = { {AggregateRelationId, /* AGGFNOID */ @@ -129,9 +134,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 16 + 16, + 0 }, {AccessMethodRelationId, /* AMNAME */ AmNameIndexId, 1, @@ -140,9 +146,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 4 + 4, + 0 }, {AccessMethodRelationId, /* AMOID */ AmOidIndexId, 1, @@ -151,9 +158,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 4 + 4, + 0 }, {AccessMethodOperatorRelationId, /* AMOPOPID */ AccessMethodOperatorIndexId, 3, @@ -162,9 +170,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amop_amoppurpose, Anum_pg_amop_amopfamily, 0 }, - 64 + 64, + 0 }, {AccessMethodOperatorRelationId, /* AMOPSTRATEGY */ AccessMethodStrategyIndexId, 4, @@ -173,9 +182,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amop_amoplefttype, Anum_pg_amop_amoprighttype, Anum_pg_amop_amopstrategy }, - 64 + 64, + 0 }, {AccessMethodProcedureRelationId, /* AMPROCNUM */ AccessMethodProcedureIndexId, 4, @@ -184,9 +194,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amproc_amproclefttype, Anum_pg_amproc_amprocrighttype, Anum_pg_amproc_amprocnum }, - 16 + 16, + 0 }, {AttributeRelationId, /* ATTNAME */ AttributeRelidNameIndexId, 2, @@ -195,9 +206,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_attribute_attname, 0, 0 }, - 32 + 32, + Anum_pg_attribute_attrelid }, {AttributeRelationId, /* ATTNUM */ AttributeRelidNumIndexId, 2, @@ -206,9 +218,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_attribute_attnum, 0, 0 }, - 128 + 128, + Anum_pg_attribute_attrelid }, {AuthMemRelationId, /* AUTHMEMMEMROLE */ AuthMemMemRoleIndexId, 2, @@ -217,9 +230,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_auth_members_roleid, 0, 0 }, - 8 + 8, + 0 }, {AuthMemRelationId, /* AUTHMEMROLEMEM */ AuthMemRoleMemIndexId, 2, @@ -228,9 +242,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_auth_members_member, 0, 0 }, - 8 + 8, + 0 }, {AuthIdRelationId, /* AUTHNAME */ AuthIdRolnameIndexId, 1, @@ -239,9 +254,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {AuthIdRelationId, /* AUTHOID */ AuthIdOidIndexId, 1, @@ -250,21 +266,22 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, - { - CastRelationId, /* CASTSOURCETARGET */ + {CastRelationId, /* CASTSOURCETARGET */ CastSourceTargetIndexId, 2, { Anum_pg_cast_castsource, Anum_pg_cast_casttarget, 0, 0 }, - 256 + 256, + 0 }, {OperatorClassRelationId, /* CLAAMNAMENSP */ OpclassAmNameNspIndexId, 3, @@ -273,9 +290,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_opclass_opcname, Anum_pg_opclass_opcnamespace, 0 }, - 8 + 8, + 0 }, {OperatorClassRelationId, /* CLAOID */ OpclassOidIndexId, 1, @@ -284,9 +302,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {CollationRelationId, /* COLLNAMEENCNSP */ CollationNameEncNspIndexId, 3, @@ -295,9 +314,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_collation_collencoding, Anum_pg_collation_collnamespace, 0 }, - 8 + 8, + 0 }, {CollationRelationId, /* COLLOID */ CollationOidIndexId, 1, @@ -306,9 +326,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {ConversionRelationId, /* CONDEFAULT */ ConversionDefaultIndexId, 4, @@ -317,9 +338,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_conversion_conforencoding, Anum_pg_conversion_contoencoding, ObjectIdAttributeNumber, }, - 8 + 8, + 0 }, {ConversionRelationId, /* CONNAMENSP */ ConversionNameNspIndexId, 2, @@ -328,9 +350,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_conversion_connamespace, 0, 0 }, - 8 + 8, + 0 }, {ConstraintRelationId, /* CONSTROID */ ConstraintOidIndexId, 1, @@ -339,9 +362,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 16 + 16, + 0 }, {ConversionRelationId, /* CONVOID */ ConversionOidIndexId, 1, @@ -350,9 +374,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {DatabaseRelationId, /* DATABASEOID */ DatabaseOidIndexId, 1, @@ -361,9 +386,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 4 + 4, + 0 }, {DefaultAclRelationId, /* DEFACLROLENSPOBJ */ DefaultAclRoleNspObjIndexId, 3, @@ -372,9 +398,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_default_acl_defaclnamespace, Anum_pg_default_acl_defaclobjtype, 0 }, - 8 + 8, + 0 }, {EnumRelationId, /* ENUMOID */ EnumOidIndexId, 1, @@ -383,9 +410,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {EnumRelationId, /* ENUMTYPOIDNAME */ EnumTypIdLabelIndexId, 2, @@ -394,9 +422,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_enum_enumlabel, 0, 0 }, - 8 + 8, + 0 }, {EventTriggerRelationId, /* EVENTTRIGGERNAME */ EventTriggerNameIndexId, 1, @@ -405,9 +434,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {EventTriggerRelationId, /* EVENTTRIGGEROID */ EventTriggerOidIndexId, 1, @@ -416,9 +446,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPERNAME */ ForeignDataWrapperNameIndexId, 1, @@ -427,9 +458,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 2 + 2, + 0 }, {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPEROID */ ForeignDataWrapperOidIndexId, 1, @@ -438,9 +470,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 2 + 2, + 0 }, {ForeignServerRelationId, /* FOREIGNSERVERNAME */ ForeignServerNameIndexId, 1, @@ -449,9 +482,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 2 + 2, + 0 }, {ForeignServerRelationId, /* FOREIGNSERVEROID */ ForeignServerOidIndexId, 1, @@ -460,9 +494,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 2 + 2, + 0 }, {ForeignTableRelationId, /* FOREIGNTABLEREL */ ForeignTableRelidIndexId, 1, @@ -471,9 +506,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 4 + 4, + 0 }, {IndexRelationId, /* INDEXRELID */ IndexRelidIndexId, 1, @@ -482,9 +518,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 64 + 64, + 0 }, {LanguageRelationId, /* LANGNAME */ LanguageNameIndexId, 1, @@ -493,9 +530,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 4 + 4, + 0 }, {LanguageRelationId, /* LANGOID */ LanguageOidIndexId, 1, @@ -504,9 +542,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 4 + 4, + 0 }, {NamespaceRelationId, /* NAMESPACENAME */ NamespaceNameIndexId, 1, @@ -515,9 +554,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 4 + 4, + 0 }, {NamespaceRelationId, /* NAMESPACEOID */ NamespaceOidIndexId, 1, @@ -526,9 +566,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 16 + 16, + 0 }, {OperatorRelationId, /* OPERNAMENSP */ OperatorNameNspIndexId, 4, @@ -537,9 +578,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_operator_oprleft, Anum_pg_operator_oprright, Anum_pg_operator_oprnamespace }, - 256 + 256, + 0 }, {OperatorRelationId, /* OPEROID */ OperatorOidIndexId, 1, @@ -548,9 +590,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 32 + 32, + 0 }, {OperatorFamilyRelationId, /* OPFAMILYAMNAMENSP */ OpfamilyAmNameNspIndexId, 3, @@ -559,9 +602,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_opfamily_opfname, Anum_pg_opfamily_opfnamespace, 0 }, - 8 + 8, + 0 }, {OperatorFamilyRelationId, /* OPFAMILYOID */ OpfamilyOidIndexId, 1, @@ -570,9 +614,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {PartitionedRelationId, /* PARTRELID */ PartitionedRelidIndexId, 1, @@ -581,9 +626,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 32 + 32, + 0 }, {ProcedureRelationId, /* PROCNAMEARGSNSP */ ProcedureNameArgsNspIndexId, 3, @@ -592,9 +638,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_proc_proargtypes, Anum_pg_proc_pronamespace, 0 }, - 128 + 128, + 0 }, {ProcedureRelationId, /* PROCOID */ ProcedureOidIndexId, 1, @@ -603,9 +650,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 128 + 128, + 0 }, {RangeRelationId, /* RANGETYPE */ RangeTypidIndexId, 1, @@ -614,9 +662,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 4 + 4, + 0 }, {RelationRelationId, /* RELNAMENSP */ ClassNameNspIndexId, 2, @@ -625,9 +674,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_class_relnamespace, 0, 0 }, - 128 + 128, + 0 }, {RelationRelationId, /* RELOID */ ClassOidIndexId, 1, @@ -636,9 +686,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 128 + 128, + 0 }, {ReplicationOriginRelationId, /* REPLORIGIDENT */ ReplicationOriginIdentIndex, 1, @@ -647,9 +698,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 16 + 16, + 0 }, {ReplicationOriginRelationId, /* REPLORIGNAME */ ReplicationOriginNameIndex, 1, @@ -658,9 +710,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 16 + 16, + 0 }, {PublicationRelationId, /* PUBLICATIONOID */ PublicationObjectIndexId, 1, @@ -669,9 +722,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {PublicationRelationId, /* PUBLICATIONNAME */ PublicationNameIndexId, 1, @@ -680,9 +734,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 8 + 8, + 0 }, {PublicationRelRelationId, /* PUBLICATIONREL */ PublicationRelObjectIndexId, 1, @@ -691,9 +746,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 64 + 64, + 0 }, {PublicationRelRelationId, /* PUBLICATIONRELMAP */ PublicationRelMapIndexId, 2, @@ -702,9 +758,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_publication_rel_prpubid, 0, 0 }, - 64 + 64, + 0 }, {RewriteRelationId, /* RULERELNAME */ RewriteRelRulenameIndexId, 2, @@ -713,9 +770,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_rewrite_rulename, 0, 0 }, - 8 + 8, + 0 }, {SequenceRelationId, /* SEQRELID */ SequenceRelidIndexId, 1, @@ -724,9 +782,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 32 + 32, + 0 }, {StatisticRelationId, /* STATRELATTINH */ StatisticRelidAttnumInhIndexId, 3, @@ -735,9 +794,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_statistic_staattnum, Anum_pg_statistic_stainherit, 0 }, - 128 + 128, + Anum_pg_statistic_starelid }, {SubscriptionRelationId, /* SUBSCRIPTIONOID */ SubscriptionObjectIndexId, 1, @@ -746,9 +806,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 4 + 4, + 0 }, {SubscriptionRelationId, /* SUBSCRIPTIONNAME */ SubscriptionNameIndexId, 2, @@ -757,9 +818,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_subscription_subname, 0, 0 }, - 4 + 4, + 0 }, {TableSpaceRelationId, /* TABLESPACEOID */ TablespaceOidIndexId, 1, @@ -768,9 +830,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0, }, - 4 + 4, + 0 }, {TransformRelationId, /* TRFOID */ TransformOidIndexId, 1, @@ -779,9 +842,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0, }, - 16 + 16, + 0 }, {TransformRelationId, /* TRFTYPELANG */ TransformTypeLangIndexId, 2, @@ -790,9 +854,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_transform_trflang, 0, 0, }, - 16 + 16, + 0 }, {TSConfigMapRelationId, /* TSCONFIGMAP */ TSConfigMapIndexId, 3, @@ -801,9 +866,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_ts_config_map_maptokentype, Anum_pg_ts_config_map_mapseqno, 0 }, - 2 + 2, + 0 }, {TSConfigRelationId, /* TSCONFIGNAMENSP */ TSConfigNameNspIndexId, 2, @@ -812,9 +878,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_ts_config_cfgnamespace, 0, 0 }, - 2 + 2, + 0 }, {TSConfigRelationId, /* TSCONFIGOID */ TSConfigOidIndexId, 1, @@ -823,9 +890,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 2 + 2, + 0 }, {TSDictionaryRelationId, /* TSDICTNAMENSP */ TSDictionaryNameNspIndexId, 2, @@ -834,9 +902,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_ts_dict_dictnamespace, 0, 0 }, - 2 + 2, + 0 }, {TSDictionaryRelationId, /* TSDICTOID */ TSDictionaryOidIndexId, 1, @@ -845,9 +914,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 2 + 2, + 0 }, {TSParserRelationId, /* TSPARSERNAMENSP */ TSParserNameNspIndexId, 2, @@ -856,9 +926,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_ts_parser_prsnamespace, 0, 0 }, - 2 + 2, + 0 }, {TSParserRelationId, /* TSPARSEROID */ TSParserOidIndexId, 1, @@ -867,9 +938,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 2 + 2, + 0 }, {TSTemplateRelationId, /* TSTEMPLATENAMENSP */ TSTemplateNameNspIndexId, 2, @@ -878,9 +950,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_ts_template_tmplnamespace, 0, 0 }, - 2 + 2, + 0 }, {TSTemplateRelationId, /* TSTEMPLATEOID */ TSTemplateOidIndexId, 1, @@ -889,9 +962,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 2 + 2, + 0 }, {TypeRelationId, /* TYPENAMENSP */ TypeNameNspIndexId, 2, @@ -900,9 +974,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_type_typnamespace, 0, 0 }, - 64 + 64, + 0 }, {TypeRelationId, /* TYPEOID */ TypeOidIndexId, 1, @@ -911,9 +986,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 64 + 64, + 0 }, {UserMappingRelationId, /* USERMAPPINGOID */ UserMappingOidIndexId, 1, @@ -922,9 +998,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, 0 }, - 2 + 2, + 0 }, {UserMappingRelationId, /* USERMAPPINGUSERSERVER */ UserMappingUserServerIndexId, 2, @@ -933,9 +1010,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_user_mapping_umserver, 0, 0 }, - 2 + 2, + 0 } }; #define SysCacheSize ((int) lengthof(cacheinfo)) @@ -951,10 +1029,25 @@ static int SysCacheRelationOidSize; /* Sorted array of OIDs of tables and indexes used by caches */ 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 * @@ -993,8 +1086,23 @@ InitCatalogCache(void) SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] = cacheinfo[cacheId].indoid; /* see comments for RelationInvalidatesSnapshotsOnly */ Assert(!RelationInvalidatesSnapshotsOnly(cacheinfo[cacheId].reloid)); + + /* + * If this syscache has something to do with 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)); Assert(SysCacheSupportingRelOidSize <= lengthof(SysCacheSupportingRelOid)); @@ -1017,12 +1125,45 @@ InitCatalogCache(void) SysCacheSupportingRelOid[++j] = SysCacheSupportingRelOid[i]; } SysCacheSupportingRelOidSize = j + 1; + /* + * If any of syscache needs relcache invalidation callback, prepare the + * scankey for reloid comparison and register a relcache inval callback. + */ + if (relinval_callback_count > 0) + { + 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 funciton is 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 * access. diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h index 299d246..d56a1d7 100644 --- a/src/include/utils/catcache.h +++ b/src/include/utils/catcache.h @@ -43,8 +43,9 @@ typedef struct catcache Oid cc_indexoid; /* OID of index matching cache keys */ 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 */ PGFunction cc_hashfunc[CATCACHE_MAXKEYS]; /* hash function for each key */ @@ -187,8 +188,10 @@ extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys, Datum v1, Datum v2, 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 CatalogCacheIdInvalidate(int cacheId, uint32 hashValue); extern void PrepareToInvalidateCacheTuple(Relation relation, diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 66f60d2..25fddd4 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -112,8 +112,10 @@ 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, Datum key1, Datum key2, Datum key3, Datum key4); -- 2.9.2
>From 8664335f18638b6dcff30b0c30ff167175970cff Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp> Date: Fri, 16 Dec 2016 16:44:40 +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 an invalidated object. --- src/backend/utils/cache/catcache.c | 42 +++++ src/backend/utils/cache/inval.c | 8 +- src/backend/utils/cache/syscache.c | 319 ++++++++++++++++++++++++++++--------- src/include/utils/catcache.h | 3 + 4 files changed, 295 insertions(+), 77 deletions(-) diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 6ff2c5e..1554b22 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -1423,8 +1423,50 @@ GetCatCacheHashValue(CatCache *cache, */ return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, cur_skey); } +/* + * CollectOIDsForHashValue + * + * Collect OIDs corresnpond 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 initialized */ + 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 11f9218..7b78d09 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -549,11 +549,15 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg) if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid) { InvalidateCatalogSnapshot(); - CatalogCacheIdInvalidate(msg->cc.id, msg->cc.hashValue); - + /* + * Call the callbacks first so that the callbacks can access the + * entries corresponding to the hashValue. + */ CallSyscacheCallbacks(msg->cc.id, msg->cc.hashValue); + + CatalogCacheIdInvalidate(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 c9f3bea..b7f622a 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -110,8 +110,18 @@ *--------------------------------------------------------------------------- */ /* + * 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 { @@ -122,8 +132,16 @@ struct cachedesc int nbuckets; /* number of hash buckets for this cache */ /* relcache invalidation stuff */ AttrNumber relattrnum; /* attr number of reloid, 0 if nothing to do */ + + /* 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[] = { {AggregateRelationId, /* AGGFNOID */ @@ -135,9 +153,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 16, - 0 + 0, + -1, 0, 0 }, {AccessMethodRelationId, /* AMNAME */ AmNameIndexId, 1, @@ -147,9 +166,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {AccessMethodRelationId, /* AMOID */ AmOidIndexId, 1, @@ -159,9 +179,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {AccessMethodOperatorRelationId, /* AMOPOPID */ AccessMethodOperatorIndexId, 3, @@ -171,9 +192,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amop_amopfamily, 0 }, 64, - 0 + 0, + -1, 0, 0 }, {AccessMethodOperatorRelationId, /* AMOPSTRATEGY */ AccessMethodStrategyIndexId, 4, @@ -183,9 +205,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amop_amoprighttype, Anum_pg_amop_amopstrategy }, 64, - 0 + 0, + -1, 0, 0 }, {AccessMethodProcedureRelationId, /* AMPROCNUM */ AccessMethodProcedureIndexId, 4, @@ -195,9 +218,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_amproc_amprocrighttype, Anum_pg_amproc_amprocnum }, 16, - 0 + 0, + -1, 0, 0 }, {AttributeRelationId, /* ATTNAME */ AttributeRelidNameIndexId, 2, @@ -207,9 +231,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 32, - Anum_pg_attribute_attrelid + Anum_pg_attribute_attrelid, + -1, 0, 0 }, {AttributeRelationId, /* ATTNUM */ AttributeRelidNumIndexId, 2, @@ -219,9 +244,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 128, - Anum_pg_attribute_attrelid + Anum_pg_attribute_attrelid, + -1, 0, 0 }, {AuthMemRelationId, /* AUTHMEMMEMROLE */ AuthMemMemRoleIndexId, 2, @@ -231,9 +257,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {AuthMemRelationId, /* AUTHMEMROLEMEM */ AuthMemRoleMemIndexId, 2, @@ -243,9 +270,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {AuthIdRelationId, /* AUTHNAME */ AuthIdRolnameIndexId, 1, @@ -255,9 +283,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {AuthIdRelationId, /* AUTHOID */ AuthIdOidIndexId, 1, @@ -267,9 +296,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {CastRelationId, /* CASTSOURCETARGET */ CastSourceTargetIndexId, 2, @@ -279,9 +309,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 256, - 0 + 0, + -1, 0, 0 }, {OperatorClassRelationId, /* CLAAMNAMENSP */ OpclassAmNameNspIndexId, 3, @@ -291,9 +322,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_opclass_opcnamespace, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {OperatorClassRelationId, /* CLAOID */ OpclassOidIndexId, 1, @@ -303,9 +335,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {CollationRelationId, /* COLLNAMEENCNSP */ CollationNameEncNspIndexId, 3, @@ -315,9 +348,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_collation_collnamespace, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {CollationRelationId, /* COLLOID */ CollationOidIndexId, 1, @@ -327,9 +361,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {ConversionRelationId, /* CONDEFAULT */ ConversionDefaultIndexId, 4, @@ -339,9 +374,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_conversion_contoencoding, ObjectIdAttributeNumber, }, 8, - 0 + 0, + -1, 0, 0 }, {ConversionRelationId, /* CONNAMENSP */ ConversionNameNspIndexId, 2, @@ -351,9 +387,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {ConstraintRelationId, /* CONSTROID */ ConstraintOidIndexId, 1, @@ -363,9 +400,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 16, - 0 + 0, + -1, 0, 0 }, {ConversionRelationId, /* CONVOID */ ConversionOidIndexId, 1, @@ -375,9 +413,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {DatabaseRelationId, /* DATABASEOID */ DatabaseOidIndexId, 1, @@ -387,9 +426,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {DefaultAclRelationId, /* DEFACLROLENSPOBJ */ DefaultAclRoleNspObjIndexId, 3, @@ -399,9 +439,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_default_acl_defaclobjtype, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {EnumRelationId, /* ENUMOID */ EnumOidIndexId, 1, @@ -411,9 +452,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {EnumRelationId, /* ENUMTYPOIDNAME */ EnumTypIdLabelIndexId, 2, @@ -423,9 +465,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {EventTriggerRelationId, /* EVENTTRIGGERNAME */ EventTriggerNameIndexId, 1, @@ -435,9 +478,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {EventTriggerRelationId, /* EVENTTRIGGEROID */ EventTriggerOidIndexId, 1, @@ -447,9 +491,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPERNAME */ ForeignDataWrapperNameIndexId, 1, @@ -459,9 +504,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPEROID */ ForeignDataWrapperOidIndexId, 1, @@ -471,9 +517,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {ForeignServerRelationId, /* FOREIGNSERVERNAME */ ForeignServerNameIndexId, 1, @@ -483,9 +530,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {ForeignServerRelationId, /* FOREIGNSERVEROID */ ForeignServerOidIndexId, 1, @@ -495,9 +543,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {ForeignTableRelationId, /* FOREIGNTABLEREL */ ForeignTableRelidIndexId, 1, @@ -507,9 +556,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {IndexRelationId, /* INDEXRELID */ IndexRelidIndexId, 1, @@ -519,9 +569,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 64, - 0 + 0, + -1, 0, 0 }, {LanguageRelationId, /* LANGNAME */ LanguageNameIndexId, 1, @@ -531,9 +582,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {LanguageRelationId, /* LANGOID */ LanguageOidIndexId, 1, @@ -543,9 +595,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {NamespaceRelationId, /* NAMESPACENAME */ NamespaceNameIndexId, 1, @@ -555,9 +608,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {NamespaceRelationId, /* NAMESPACEOID */ NamespaceOidIndexId, 1, @@ -567,9 +621,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 16, - 0 + 0, + -1, 0, 0 }, {OperatorRelationId, /* OPERNAMENSP */ OperatorNameNspIndexId, 4, @@ -579,9 +634,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_operator_oprright, Anum_pg_operator_oprnamespace }, 256, - 0 + 0, + -1, 0, 0 }, {OperatorRelationId, /* OPEROID */ OperatorOidIndexId, 1, @@ -591,9 +647,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 32, - 0 + 0, + -1, 0, 0 }, {OperatorFamilyRelationId, /* OPFAMILYAMNAMENSP */ OpfamilyAmNameNspIndexId, 3, @@ -603,9 +660,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_opfamily_opfnamespace, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {OperatorFamilyRelationId, /* OPFAMILYOID */ OpfamilyOidIndexId, 1, @@ -615,9 +673,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {PartitionedRelationId, /* PARTRELID */ PartitionedRelidIndexId, 1, @@ -627,9 +686,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 32, - 0 + 0, + -1, 0, 0 }, {ProcedureRelationId, /* PROCNAMEARGSNSP */ ProcedureNameArgsNspIndexId, 3, @@ -639,9 +699,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_proc_pronamespace, 0 }, 128, - 0 + 0, + -1, 0, 0 }, {ProcedureRelationId, /* PROCOID */ ProcedureOidIndexId, 1, @@ -651,9 +712,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 128, - 0 + 0, + -1, 0, 0 }, {RangeRelationId, /* RANGETYPE */ RangeTypidIndexId, 1, @@ -663,9 +725,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {RelationRelationId, /* RELNAMENSP */ ClassNameNspIndexId, 2, @@ -675,9 +738,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 128, - 0 + 0, + NAMESPACEOID, ObjectIdAttributeNumber, Anum_pg_class_relnamespace }, {RelationRelationId, /* RELOID */ ClassOidIndexId, 1, @@ -687,9 +751,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 128, - 0 + 0, + -1, 0, 0 }, {ReplicationOriginRelationId, /* REPLORIGIDENT */ ReplicationOriginIdentIndex, 1, @@ -699,9 +764,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 16, - 0 + 0, + -1, 0, 0 }, {ReplicationOriginRelationId, /* REPLORIGNAME */ ReplicationOriginNameIndex, 1, @@ -711,9 +777,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 16, - 0 + 0, + -1, 0, 0 }, {PublicationRelationId, /* PUBLICATIONOID */ PublicationObjectIndexId, 1, @@ -723,9 +790,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {PublicationRelationId, /* PUBLICATIONNAME */ PublicationNameIndexId, 1, @@ -735,9 +803,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {PublicationRelRelationId, /* PUBLICATIONREL */ PublicationRelObjectIndexId, 1, @@ -747,9 +816,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 64, - 0 + 0, + -1, 0, 0 }, {PublicationRelRelationId, /* PUBLICATIONRELMAP */ PublicationRelMapIndexId, 2, @@ -759,9 +829,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 64, - 0 + 0, + -1, 0, 0 }, {RewriteRelationId, /* RULERELNAME */ RewriteRelRulenameIndexId, 2, @@ -771,9 +842,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 8, - 0 + 0, + -1, 0, 0 }, {SequenceRelationId, /* SEQRELID */ SequenceRelidIndexId, 1, @@ -783,9 +855,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 32, - 0 + 0, + -1, 0, 0 }, {StatisticRelationId, /* STATRELATTINH */ StatisticRelidAttnumInhIndexId, 3, @@ -795,9 +868,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_statistic_stainherit, 0 }, 128, - Anum_pg_statistic_starelid + Anum_pg_statistic_starelid, + -1, 0, 0 }, {SubscriptionRelationId, /* SUBSCRIPTIONOID */ SubscriptionObjectIndexId, 1, @@ -807,9 +881,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {SubscriptionRelationId, /* SUBSCRIPTIONNAME */ SubscriptionNameIndexId, 2, @@ -819,9 +894,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 4, - 0 + 0, + -1, 0, 0 }, {TableSpaceRelationId, /* TABLESPACEOID */ TablespaceOidIndexId, 1, @@ -831,9 +907,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, }, 4, - 0 + 0, + -1, 0, 0 }, {TransformRelationId, /* TRFOID */ TransformOidIndexId, 1, @@ -843,9 +920,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, }, 16, - 0 + 0, + -1, 0, 0 }, {TransformRelationId, /* TRFTYPELANG */ TransformTypeLangIndexId, 2, @@ -855,9 +933,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0, }, 16, - 0 + 0, + -1, 0, 0 }, {TSConfigMapRelationId, /* TSCONFIGMAP */ TSConfigMapIndexId, 3, @@ -867,9 +946,10 @@ static const struct cachedesc cacheinfo[] = { Anum_pg_ts_config_map_mapseqno, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSConfigRelationId, /* TSCONFIGNAMENSP */ TSConfigNameNspIndexId, 2, @@ -879,9 +959,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSConfigRelationId, /* TSCONFIGOID */ TSConfigOidIndexId, 1, @@ -891,9 +972,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSDictionaryRelationId, /* TSDICTNAMENSP */ TSDictionaryNameNspIndexId, 2, @@ -903,9 +985,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSDictionaryRelationId, /* TSDICTOID */ TSDictionaryOidIndexId, 1, @@ -915,9 +998,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSParserRelationId, /* TSPARSERNAMENSP */ TSParserNameNspIndexId, 2, @@ -927,9 +1011,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSParserRelationId, /* TSPARSEROID */ TSParserOidIndexId, 1, @@ -939,9 +1024,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSTemplateRelationId, /* TSTEMPLATENAMENSP */ TSTemplateNameNspIndexId, 2, @@ -951,9 +1037,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TSTemplateRelationId, /* TSTEMPLATEOID */ TSTemplateOidIndexId, 1, @@ -963,9 +1050,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {TypeRelationId, /* TYPENAMENSP */ TypeNameNspIndexId, 2, @@ -975,9 +1063,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 64, - 0 + 0, + -1, 0, 0 }, {TypeRelationId, /* TYPEOID */ TypeOidIndexId, 1, @@ -987,9 +1076,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 64, - 0 + 0, + -1, 0, 0 }, {UserMappingRelationId, /* USERMAPPINGOID */ UserMappingOidIndexId, 1, @@ -999,9 +1089,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 }, {UserMappingRelationId, /* USERMAPPINGUSERSERVER */ UserMappingUserServerIndexId, 2, @@ -1011,9 +1102,10 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }, 2, - 0 + 0, + -1, 0, 0 } }; #define SysCacheSize ((int) lengthof(cacheinfo)) @@ -1046,9 +1138,10 @@ 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); - +static void SysCacheSysCacheInvalCallback(Datum arg, int cacheid, + uint32 hashvalue); /* * InitCatalogCache - initialize the caches * * Note that no database access is done here; we only allocate memory @@ -1101,8 +1194,36 @@ InitCatalogCache(void) relinval_callback_list[relinval_callback_count].relkeynum = 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 belive 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)); Assert(SysCacheSupportingRelOidSize <= lengthof(SysCacheSupportingRelOid)); @@ -1477,8 +1598,56 @@ RelationInvalidatesSnapshotsOnly(Oid relid) return false; } /* + * 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 OIDs for target syscache entries. oids contains one value for + * most cases, but two or more for the case hashvalue has synonyms. At + * least one of them is the right OID but is cannot be distinguished using + * 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 RelationHasSysCache(Oid relid) diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h index d56a1d7..48c2a4a 100644 --- a/src/include/utils/catcache.h +++ b/src/include/utils/catcache.h @@ -183,8 +183,11 @@ extern void ReleaseCatCache(HeapTuple tuple); 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); extern void ReleaseCatCacheList(CatCList *list); -- 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