Re: [HACKERS] Protect syscache from bloating with negative cache entries

Поиск
Список
Период
Сортировка
От Kyotaro HORIGUCHI
Тема Re: [HACKERS] Protect syscache from bloating with negative cache entries
Дата
Msg-id 20171031.184622.92520047.horiguchi.kyotaro@lab.ntt.co.jp
обсуждение исходный текст
Ответ на Re: [HACKERS] Protect syscache from bloating with negative cache entries  (Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>)
Ответы Re: Protect syscache from bloating with negative cache entries  (Michael Paquier <michael.paquier@gmail.com>)
Список pgsql-hackers
This is a rebased version of the patch.

At Fri, 17 Mar 2017 14:23:13 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> wrote in
<20170317.142313.232290068.horiguchi.kyotaro@lab.ntt.co.jp>
> At Tue, 7 Mar 2017 19:23:14 -0800, David Steele <david@pgmasters.net> wrote in
<3b7b7f90-db46-8c37-c4f7-443330c3ae33@pgmasters.net>
> > On 3/3/17 4:54 PM, David Steele wrote:
> > 
> > > On 2/1/17 1:25 AM, Kyotaro HORIGUCHI wrote:
> > >> Hello, thank you for moving this to the next CF.
> > >>
> > >> At Wed, 1 Feb 2017 13:09:51 +0900, Michael Paquier
> > >> <michael.paquier@gmail.com> wrote in
> > >> <CAB7nPqRFhUv+GX=eH1bo7xYHS79-gRj1ecu2QoQtHvX9RS=JYA@mail.gmail.com>
> > >>> On Tue, Jan 24, 2017 at 4:58 PM, Kyotaro HORIGUCHI
> > >>> <horiguchi.kyotaro@lab.ntt.co.jp> wrote:
> > >>>> 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.
> > >>> To be honest, I am not completely sure what to think about this patch.
> > >>> Moved to next CF as there is a new version, and no new reviews to make
> > >>> the discussion perhaps move on.
> > >> I'm thinking the following is the status of this topic.
> > >>
> > >> - The patch stll is not getting conflicted.
> > >>
> > >> - This is not a hollistic measure for memory leak but surely
> > >>    saves some existing cases.
> > >>
> > >> - Shared catcache is another discussion (and won't really
> > >>    proposed in a short time due to the issue on locking.)
> > >>
> > >> - As I mentioned, a patch that caps the number of negative
> > >>    entries is avaiable (in first-created - first-delete manner)
> > >>    but it is having a loose end of how to determine the
> > >>    limitation.
> > > While preventing bloat in the syscache is a worthwhile goal, it
> > > appears
> > > there are a number of loose ends here and a new patch has not been
> > > provided.

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
From 9f2c81dbc9bc344cafd6995dfc5969d55a8457d9 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@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 arelation.

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 |  58 ++++++-src/backend/utils/cache/syscache.c | 302
+++++++++++++++++++++++++++----------src/include/utils/catcache.h      |   3 +src/include/utils/syscache.h       |   2
+4files changed, 282 insertions(+), 83 deletions(-)
 

diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 95a0742..bd303f3 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -423,10 +423,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,
%ldlhits",
 
+        elog(DEBUG2, "catcache %s/%u: %d tup, %d negtup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals,
%ldlsrch, %ld lhits",             cache->cc_relname,             cache->cc_indexoid,             cache->cc_ntup,
 
+             cache->cc_nnegtup,             cache->cc_searches,             cache->cc_hits,
cache->cc_neg_hits,
@@ -495,8 +496,11 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)     * point into tuple, allocated together with
theCatCTup.     */    if (ct->negative)
 
+    {        CatCacheFreeKeys(cache->cc_tupdesc, cache->cc_nkeys,                         cache->cc_keyno, ct->keys);
+        --cache->cc_nnegtup;
+    }    pfree(ct);
@@ -697,6 +701,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 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)
+        {
+            const CCFastEqualFN *cc_fastequal = cache->cc_fastequal;
+            CatCTup    *ct = dlist_container(CatCTup, cache_elem, iter.cur);
+            int            oid_attnum = skey->sk_attno - 1;
+
+            if (!ct->negative)
+                continue;
+
+            /* Compare the OIDs */
+            if (!(cc_fastequal[oid_attnum])(ct->keys[oid_attnum],
+                                            skey[0].sk_argument))
+                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
@@ -845,6 +894,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)
@@ -1420,8 +1470,8 @@ SearchCatCacheMiss(CatCache *cache,        CACHE4_elog(DEBUG2, "SearchCatCache(%s): Contains
%d/%dtuples",                    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
negativeentry to the caller, so leave its
 
@@ -1906,6 +1956,8 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, Datum *arguments,    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 888edbb..753c5f1 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
hashbuckets 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];staticint    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
necessarydatabase
 
diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h
index 74535eb..7564f42 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -59,6 +59,7 @@ typedef struct catcache    Oid            cc_indexoid;    /* OID of index matching cache keys */
bool       cc_relisshared; /* is relation shared across databases? */    slist_node    cc_next;        /* list link */
 
+    int            cc_nnegtup;        /* # of negative tuples */    ScanKeyData cc_skey[CATCACHE_MAXKEYS];    /*
precomputedkey info for heap                                             * scans */
 
@@ -217,6 +218,8 @@ extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys,                   Datum v3, Datum
v4);externvoid ReleaseCatCacheList(CatCList *list);
 
+extern void
+CleanupCatCacheNegEntries(CatCache *cache, ScanKeyData *skey);extern void ResetCatalogCaches(void);extern void
CatalogCacheFlushCatalog(OidcatId);extern void CatCacheInvalidate(CatCache *cache, uint32 hashValue);
 
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 8a0be41..26ac57c 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -132,6 +132,8 @@ extern HeapTuple SearchSysCache4(int cacheId,                Datum key1, Datum key2, Datum key3,
Datumkey4);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(intcacheId,
 
-- 
2.9.2

From 56b1eede29631df78cc622386693381b7aa76a51 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@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
+4files changed, 300 insertions(+), 79 deletions(-)
 

diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index bd303f3..a9ef028 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -1555,6 +1555,48 @@ GetCatCacheHashValue(CatCache *cache,    return CatalogCacheComputeHashValue(cache,
cache->cc_nkeys,v1, v2, v3, v4);}
 
+/*
+ * 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 0e61b4b..86e6f07 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 753c5f1..7dd61cd 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;        /*
attrnumto 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(constvoid *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));
@@ -1623,6 +1747,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 7564f42..562810f 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -213,6 +213,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

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Kyotaro HORIGUCHI
Дата:
Сообщение: Re: [HACKERS] Restricting maximum keep segments by repslots
Следующее
От: Kyotaro HORIGUCHI
Дата:
Сообщение: Re: [HACKERS] show "aggressive" or not in autovacuum logs