8000 Avoid searching for the target catcache in CatalogCacheIdInvalidate. · dinesh372/postgres@3569a9a · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 3569a9a

Browse files
committed
Avoid searching for the target catcache in CatalogCacheIdInvalidate.
A test case provided by Mathieu Fenniak shows that the initial search for the target catcache in CatalogCacheIdInvalidate consumes a very significant amount of overhead in cases where cache invalidation is triggered but has little useful work to do. There is no good reason for that search to exist at all, as the index array maintained by syscache.c allows direct lookup of the catcache from its ID. We just need a frontend function in syscache.c, matching the division of labor for most other cache-accessing operations. While there's more that can be done in this area, this patch alone reduces the runtime of Mathieu's example by 2X. We can hope that it offers some useful benefit in other cases too, although usually cache invalidation overhead is not such a striking fraction of the total runtime. Back-patch to 9.4 where logical decoding was introduced. It might be worth going further back, but presently the only case we know of where cache invalidation is really a significant burden is in logical decoding. Also, older branches have fewer catcaches, reducing the possible benefit. (Note: although this nominally changes catcache's API, we have always documented CatalogCacheIdInvalidate as a private function, so I would have little sympathy for an external module calling it directly. So backpatching should be fine.) Discussion: https://postgr.es/m/CAHoiPjzea6N0zuCi=+f9v_j94nfsy6y8SU7-=bp4=7qw6_i=Rg@mail.gmail.com
1 parent 054a897 commit 3569a9a

File tree

5 files changed

+64
-55
lines changed

5 files changed

+64
-55
lines changed

src/backend/utils/cache/catcache.c

Lines changed: 39 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ CatCacheRemoveCList(CatCache *cache, CatCList *cl)
427427

428428

429429
/*
430-
* CatalogCacheIdInvalidate
430+
* CatCacheInvalidate
431431
*
432432
* Invalidate entries in the specified cache, given a hash value.
433433
*
@@ -445,71 +445,57 @@ CatCacheRemoveCList(CatCache *cache, CatCList *cl)
445445
* This routine is only quasi-public: it should only be used by inval.c.
446446
*/
447447
void
448-
CatalogCacheIdInvalidate(int cacheId, uint32 hashValue)
448+
CatCacheInvalidate(CatCache *cache, uint32 hashValue)
449449
{
450-
slist_iter cache_iter;
450+
Index hashIndex;
451+
dlist_mutable_iter iter;
451452

452-
CACHE1_elog(DEBUG2, "CatalogCacheIdInvalidate: called");
453+
CACHE1_elog(DEBUG2, "CatCacheInvalidate: called");
453454

454455
/*
455-
* inspect caches to find the proper cache
456+
* We don't bother to check whether the cache has finished initialization
457+
* yet; if not, there will be no entries in it so no problem.
456458
*/
457-
slist_foreach(cache_iter, &CacheHdr->ch_caches)
458-
{
459-
CatCache *ccp = slist_container(CatCache, cc_next, cache_iter.cur);
460-
Index hashIndex;
461-
dlist_mutable_iter iter;
462-
463-
if (cacheId != ccp->id)
464-
continue;
465459

466-
/*
467-
* We don't bother to check whether the cache has finished
468-
* initialization yet; if not, there will be no entries in it so no
469-
* problem.
470-
*/
460+
/*
461+
* Invalidate *all* CatCLists in this cache; it's too hard to tell which
462+
* searches might still be correct, so just zap 'em all.
463+
*/
464+
dlist_foreach_modify(iter, &cache->cc_lists)
465+
{
466+
CatCList *cl = dlist_container(CatCList, cache_elem, iter.cur);
471467

472-
/*
473-
* Invalidate *all* CatCLists in this cache; it's too hard to tell
474-
* which searches might still be correct, so just zap 'em all.
475-
*/
476-
dlist_foreach_modify(iter, &ccp->cc_lists)
477-
{
478-
CatCList *cl = dlist_container(CatCList, cache_elem, iter.cur);
468+
if (cl->refcount > 0)
469+
cl->dead = true;
470+
else
471+
CatCacheRemoveCList(cache, cl);
472+
}
479473

480-
if (cl->refcount > 0)
481-
cl->dead = true;
482-
else
483-
CatCacheRemoveCList(ccp, cl);
484-
}
474+
/*
475+
* inspect the proper hash bucket for tuple matches
476+
*/
477+
hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
478+
dlist_foreach_modify(iter, &cache->cc_bucket[hashIndex])
479+
{
480+
CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur);
485481

486-
/*
487-
* inspect the proper hash bucket for tuple matches
488-
*/
489-
hashIndex = HASH_INDEX(hashValue, ccp->cc_nbuckets);
490-
dlist_foreach_modify(iter, &ccp->cc_bucket[hashIndex])
482+
if (hashValue == ct->hash_value)
491483
{
492-
CatCTup *ct = dlist_container(CatCTup, cache_elem, iter.cur);
493-
494-
if (hashValue == ct->hash_value)
484+
if (ct->refcount > 0 ||
485+
(ct->c_list && ct->c_list->refcount > 0))
495486
{
496-
if (ct->refcount > 0 ||
497-
(ct->c_list && ct->c_list->refcount > 0))
498-
{
499-
ct->dead = true;
500-
/* list, if any, was marked dead above */
501-
Assert(ct->c_list == NULL || ct->c_list->dead);
502-
}
503-
else
504-
CatCacheRemoveCTup(ccp, ct);
505-
CACHE1_elog(DEBUG2, "CatalogCacheIdInvalidate: invalidated");
487+
ct->dead = true;
488+
/* list, if any, was marked dead above */
489+
Assert(ct->c_list == NULL || ct->c_list->dead);
490+
}
491+
else
492+
CatCacheRemoveCTup(cache, ct);
493+
CACHE1_elog(DEBUG2, "CatCacheInvalidate: invalidated");
506494
#ifdef CATCACHE_STATS
507-
ccp->cc_invals++;
495+
cache->cc_invals++;
508496
#endif
509-
/* could be multiple matches, so keep looking! */
510-
}
497+
/* could be multiple matches, so keep looking! */
511498
}
512-
break; /* need only search this one cache */
513499
}
514500
}
515501

@@ -1830,7 +1816,7 @@ build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys)
18301816
* the specified relation, find all catcaches it could be in, compute the
18311817
* correct hash value for each such catcache, and call the specified
18321818
* function to record the cache id and hash value in inval.c's lists.
1833-
* CatalogCacheIdInvalidate will be called later, if appropriate,
1819+
* SysCacheInvalidate will be called later, if appropriate,
18341820
* using the recorded information.
18351821
*
18361822
* For an insert or delete, tuple is the target tuple and newtuple is NULL.

src/backend/utils/cache/inval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
543543
{
544544
InvalidateCatalogSnapshot();
545545

546-
CatalogCacheIdInvalidate(msg->cc.id, msg->cc.hashValue);
546+
SysCacheInvalidate(msg->cc.id, msg->cc.hashValue);
547547

548548
CallSyscacheCallbacks(msg->cc.id, msg->cc.hashValue);
549549
}

src/backend/utils/cache/syscache.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,27 @@ SearchSysCacheList(int cacheId, int nkeys,
12111211
key1, key2, key3, key4);
12121212
}
12131213

1214+
/*
1215+
* SysCacheInvalidate
1216+
*
1217+
* Invalidate entries in the specified cache, given a hash value.
1218+
* See CatCacheInvalidate() for more info.
1219+
*
1220+
* This routine is only quasi-public: it should only be used by inval.c.
1221+
*/
1222+
void
1223+
SysCacheInvalidate(int cacheId, uint32 hashValue)
1224+
{
1225+
if (cacheId < 0 || cacheId >= SysCacheSize)
1226+
elog(ERROR, "invalid cache ID: %d", cacheId);
1227+
1228+
/* if this cache isn't initialized yet, no need to do anything */
1229+
if (!PointerIsValid(SysCache[cacheId]))
1230+
return;
1231+
1232+
CatCacheInvalidate(SysCache[cacheId], hashValue);
1233+
}
1234+
12141235
/*
12151236
* Certain relations that do not have system caches send snapshot invalidation
12161237
* messages in lieu of catcache messages. This is for the benefit of

src/include/utils/catcache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ extern void ReleaseCatCacheList(CatCList *list);
185185

186186
extern void ResetCatalogCaches(void);
187187
extern void CatalogCacheFlushCatalog(Oid catId);
188-
extern void CatalogCacheIdInvalidate(int cacheId, uint32 hashValue);
188+
extern void CatCacheInvalidate(CatCache *cache, uint32 hashValue);
189189
extern void PrepareToInvalidateCacheTuple(Relation relation,
190190
HeapTuple tuple,
191191
HeapTuple newtuple,

src/include/utils/syscache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ struct catclist;
129129
extern struct catclist *SearchSysCacheList(int cacheId, int nkeys,
130130
Datum key1, Datum key2, Datum key3, Datum key4);
131131

132+
extern void SysCacheInvalidate(int cacheId, uint32 hashValue);
133+
132134
extern bool RelationInvalidatesSnapshotsOnly(Oid relid);
133135
extern bool RelationHasSysCache(Oid relid);
134136
extern bool RelationSupportsSysCache(Oid relid);

0 commit comments

Comments
 (0)
0