@@ -89,6 +89,8 @@ static void CatCachePrintStats(int code, Datum arg);
89
89
#endif
90
90
static void CatCacheRemoveCTup (CatCache * cache , CatCTup * ct );
91
91
static void CatCacheRemoveCList (CatCache * cache , CatCList * cl );
92
+ static void RehashCatCache (CatCache * cp );
93
+ static void RehashCatCacheLists (CatCache * cp );
92
94
static void CatalogCacheInitializeCache (CatCache * cache );
93
95
static CatCTup * CatalogCacheCreateEntry (CatCache * cache ,
94
96
HeapTuple ntp , SysScanDesc scandesc ,
@@ -393,6 +395,7 @@ CatCachePrintStats(int code, Datum arg)
393
395
long cc_neg_hits = 0 ;
394
396
long cc_newloads = 0 ;
395
397
long cc_invals = 0 ;
398
+ long cc_nlists = 0 ;
396
399
long cc_lsearches = 0 ;
397
400
long cc_lhits = 0 ;
398
401
@@ -402,7 +405,7 @@ CatCachePrintStats(int code, Datum arg)
402
405
403
406
if (cache -> cc_ntup == 0 && cache -> cc_searches == 0 )
404
407
continue ; /* don't print unused caches */
405
- elog (DEBUG2 , "catcache %s/%u: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits" ,
408
+ elog (DEBUG2 , "catcache %s/%u: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %d lists, % ld lsrch, %ld lhits" ,
406
409
cache -> cc_relname ,
407
410
cache -> cc_indexoid ,
408
411
cache -> cc_ntup ,
@@ -414,17 +417,19 @@ CatCachePrintStats(int code, Datum arg)
414
417
cache -> cc_searches - cache -> cc_hits - cache -> cc_neg_hits - cache -> cc_newloads ,
415
418
cache -> cc_searches - cache -> cc_hits - cache -> cc_neg_hits ,
416
419
cache -> cc_invals ,
420
+ cache -> cc_nlist ,
417
421
cache -> cc_lsearches ,
418
422
cache -> cc_lhits );
419
423
cc_searches += cache -> cc_searches ;
420
424
cc_hits += cache -> cc_hits ;
421
425
cc_neg_hits += cache -> cc_neg_hits ;
422
426
cc_newloads += cache -> cc_newloads ;
423
427
cc_invals += cache -> cc_invals ;
428
+ cc_nlists += cache -> cc_nlist ;
424
429
cc_lsearches += cache -> cc_lsearches ;
425
430
cc_lhits += cache -> cc_lhits ;
426
431
}
427
- elog (DEBUG2 , "catcache totals: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits" ,
432
+ elog (DEBUG2 , "catcache totals: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lists, %ld lsrch, %ld lhits" ,
428
433
CacheHdr -> ch_ntup ,
429
434
cc_searches ,
430
435
cc_hits ,
@@ -434,6 +439,7 @@ CatCachePrintStats(int code, Datum arg)
434
439
cc_searches - cc_hits - cc_neg_hits - cc_newloads ,
435
440
cc_searches - cc_hits - cc_neg_hits ,
436
441
cc_invals ,
442
+ cc_nlists ,
437
443
cc_lsearches ,
438
444
cc_lhits );
439
445
}
@@ -522,6 +528,8 @@ CatCacheRemoveCList(CatCache *cache, CatCList *cl)
522
528
cache -> cc_keyno , cl -> keys );
523
529
524
530
pfree (cl );
531
+
532
+ -- cache -> cc_nlist ;
525
533
}
526
534
527
535
@@ -560,14 +568,19 @@ CatCacheInvalidate(CatCache *cache, uint32 hashValue)
560
568
* Invalidate *all* CatCLists in this cache; it's too hard to tell which
561
569
* searches might still be correct, so just zap 'em all.
562
570
*/
563
- dlist_foreach_modify ( iter , & cache -> cc_lists )
571
+ for ( int i = 0 ; i < cache -> cc_nlbuckets ; i ++ )
564
572
{
565
- CatCList * cl = dlist_container ( CatCList , cache_elem , iter . cur ) ;
573
+ dlist_head * bucket = & cache -> cc_lbucket [ i ] ;
566
574
567
- if (cl -> refcount > 0 )
568
- cl -> dead = true;
569
- else
570
- CatCacheRemoveCList (cache , cl );
575
+ dlist_foreach_modify (iter , bucket )
576
+ {
577
+ CatCList * cl = dlist_container (CatCList , cache_elem , iter .cur );
578
+
579
+ if (cl -> refcount > 0 )
580
+ cl -> dead = true;
581
+ else
582
+ CatCacheRemoveCList (cache , cl );
583
+ }
571
584
}
572
585
573
586
/*
@@ -640,14 +653,19 @@ ResetCatalogCache(CatCache *cache)
640
653
int i ;
641
654
642
655
/* Remove each list in this cache, or at least mark it dead */
643
- dlist_foreach_modify ( iter , & cache -> cc_lists )
656
+ for ( i = 0 ; i < cache -> cc_nlbuckets ; i ++ )
644
657
{
645
- CatCList * cl = dlist_container ( CatCList , cache_elem , iter . cur ) ;
658
+ dlist_head * bucket = & cache -> cc_lbucket [ i ] ;
646
659
647
- if (cl -> refcount > 0 )
648
- cl -> dead = true;
649
- else
650
- CatCacheRemoveCList (cache , cl );
660
+ dlist_foreach_modify (iter , bucket )
661
+ {
662
+ CatCList * cl = dlist_container (CatCList , cache_elem , iter .cur );
663
+
664
+ if (cl -> refcount > 0 )
665
+ cl -> dead = true;
666
+ else
667
+ CatCacheRemoveCList (cache , cl );
668
+ }
651
669
}
652
670
653
671
/* Remove each tuple in this cache, or at least mark it dead */
@@ -811,6 +829,12 @@ InitCatCache(int id,
811
829
MCXT_ALLOC_ZERO );
812
830
cp -> cc_bucket = palloc0 (nbuckets * sizeof (dlist_head ));
813
831
832
+ /*
833
+ * Many catcaches never receive any list searches. Therefore, we don't
834
+ * allocate the cc_lbuckets till we get a list search.
835
+ */
836
+ cp -> cc_lbucket = NULL ;
837
+
814
838
/*
815
839
* initialize the cache's relation information for the relation
816
840
* corresponding to this cache, and initialize some of the new cache's
@@ -823,7 +847,9 @@ InitCatCache(int id,
823
847
cp -> cc_relisshared = false; /* temporary */
824
848
cp -> cc_tupdesc = (TupleDesc ) NULL ;
825
849
cp -> cc_ntup = 0 ;
850
+ cp -> cc_nlist = 0 ;
826
851
cp -> cc_nbuckets = nbuckets ;
852
+ cp -> cc_nlbuckets = 0 ;
827
853
cp -> cc_nkeys = nkeys ;
828
854
for (i = 0 ; i < nkeys ; ++ i )
829
855
cp -> cc_keyno [i ] = key [i ];
@@ -885,6 +911,44 @@ RehashCatCache(CatCache *cp)
885
911
cp -> cc_bucket = newbucket ;
886
912
}
887
913
914
+ /*
915
+ * Enlarge a catcache's list storage, doubling the number of buckets.
916
+ */
917
+ static void
918
+ RehashCatCacheLists (CatCache * cp )
919
+ {
920
+ dlist_head * newbucket ;
921
+ int newnbuckets ;
922
+ int i ;
923
+
924
+ elog (DEBUG1 , "rehashing catalog cache id %d for %s; %d lists, %d buckets" ,
925
+ cp -> id , cp -> cc_relname , cp -> cc_nlist , cp -> cc_nlbuckets );
926
+
927
+ /* Allocate a new, larger, hash table. */
928
+ newnbuckets = cp -> cc_nlbuckets * 2 ;
929
+ newbucket = (dlist_head * ) MemoryContextAllocZero (CacheMemoryContext , newnbuckets * sizeof (dlist_head ));
930
+
931
+ /* Move all entries from old hash table to new. */
932
+ for (i = 0 ; i < cp -> cc_nlbuckets ; i ++ )
933
+ {
934
+ dlist_mutable_iter iter ;
935
+
936
+ dlist_foreach_modify (iter , & cp -> cc_lbucket [i ])
937
+ {
938
+ CatCList * cl = dlist_container (CatCList , cache_elem , iter .cur );
939
+ int hashIndex = HASH_INDEX (cl -> hash_value , newnbuckets );
940
+
941
+ dlist_delete (iter .cur );
942
+ dlist_push_head (& newbucket [hashIndex ], & cl -> cache_elem );
943
+ }
944
+ }
945
+
946
+ /* Switch to the new array. */
947
+ pfree (cp -> cc_lbucket );
948
+ cp -> cc_nlbuckets = newnbuckets ;
949
+ cp -> cc_lbucket = newbucket ;
950
+ }
951
+
888
952
/*
889
953
* CatalogCacheInitializeCache
890
954
*
@@ -1527,7 +1591,9 @@ SearchCatCacheList(CatCache *cache,
1527
1591
Datum v4 = 0 ; /* dummy last-column value */
1528
1592
Datum arguments [CATCACHE_MAXKEYS ];
1529
1593
uint32 lHashValue ;
1594
+ Index lHashIndex ;
1530
1595
dlist_iter iter ;
1596
+ dlist_head * lbucket ;
1531
1597
CatCList * cl ;
1532
1598
CatCTup * ct ;
1533
1599
List * volatile ctlist ;
@@ -1541,7 +1607,7 @@ SearchCatCacheList(CatCache *cache,
1541
1607
/*
1542
1608
* one-time startup overhead for each cache
1543
1609
*/
1544
- if (cache -> cc_tupdesc == NULL )
1610
+ if (unlikely ( cache -> cc_tupdesc == NULL ) )
1545
1611
CatalogCacheInitializeCache (cache );
1546
1612
1547
1613
Assert (nkeys > 0 && nkeys < cache -> cc_nkeys );
@@ -1557,19 +1623,45 @@ SearchCatCacheList(CatCache *cache,
1557
1623
arguments [3 ] = v4 ;
1558
1624
1559
1625
/*
1560
- * compute a hash value of the given keys for faster search. We don't
1561
- * presently divide the CatCList items into buckets, but this still lets
1562
- * us skip non-matching items quickly most of the time.
1626
+ * If we haven't previously done a list search in this cache, create the
1627
+ * bucket header array; otherwise, consider whether it's time to enlarge
1628
+ * it.
1629
+ */
1630
+ if (cache -> cc_lbucket == NULL )
1631
+ {
1632
+ /* Arbitrary initial size --- must be a power of 2 */
1633
+ int nbuckets = 16 ;
1634
+
1635
+ cache -> cc_lbucket = (dlist_head * )
1636
+ MemoryContextAllocZero (CacheMemoryContext ,
1637
+ nbuckets * sizeof (dlist_head ));
1638
+ /* Don't set cc_nlbuckets if we get OOM allocating cc_lbucket */
1639
+ cache -> cc_nlbuckets = nbuckets ;
1640
+ }
1641
+ else
1642
+ {
1643
+ /*
1644
+ * If the hash table has become too full, enlarge the buckets array.
1645
+ * Quite arbitrarily, we enlarge when fill factor > 2.
1646
+ */
1647
+ if (cache -> cc_nlist > cache -> cc_nlbuckets * 2 )
1648
+ RehashCatCacheLists (cache );
1649
+ }
1650
+
1651
+ /*
1652
+ * Find the hash bucket in which to look for the CatCList.
1563
1653
*/
1564
1654
lHashValue = CatalogCacheComputeHashValue (cache , nkeys , v1 , v2 , v3 , v4 );
1655
+ lHashIndex = HASH_INDEX (lHashValue , cache -> cc_nlbuckets );
1565
1656
1566
1657
/*
1567
1658
* scan the items until we find a match or exhaust our list
1568
1659
*
1569
1660
* Note: it's okay to use dlist_foreach here, even though we modify the
1570
1661
* dlist within the loop, because we don't continue the loop afterwards.
1571
1662
*/
1572
- dlist_foreach (iter , & cache -> cc_lists )
1663
+ lbucket = & cache -> cc_lbucket [lHashIndex ];
1664
+ dlist_foreach (iter , lbucket )
1573
1665
{
1574
1666
cl = dlist_container (CatCList , cache_elem , iter .cur );
1575
1667
@@ -1589,13 +1681,13 @@ SearchCatCacheList(CatCache *cache,
1589
1681
continue ;
1590
1682
1591
1683
/*
1592
- * We found a matching list. Move the list to the front of the
1593
- * cache's list-of-lists, to speed subsequent searches. (We do not
1684
+ * We found a matching list. Move the list to the front of the list
1685
+ * for its hashbucket, so as to speed subsequent searches. (We do not
1594
1686
* move the members to the fronts of their hashbucket lists, however,
1595
1687
* since there's no point in that unless they are searched for
1596
1688
* individually.)
1597
1689
*/
1598
- dlist_move_head (& cache -> cc_lists , & cl -> cache_elem );
1690
+ dlist_move_head (lbucket , & cl -> cache_elem );
1599
1691
1600
1692
/* Bump the list's refcount and return it */
1601
1693
ResourceOwnerEnlargeCatCacheListRefs (CurrentResourceOwner );
@@ -1806,7 +1898,12 @@ SearchCatCacheList(CatCache *cache,
1806
1898
}
1807
1899
Assert (i == nmembers );
1808
1900
1809
- dlist_push_head (& cache -> cc_lists , & cl -> cache_elem );
1901
+ /*
1902
+ * Add the CatCList to the appropriate bucket, and count it.
1903
+ */
1904
+ dlist_push_head (lbucket , & cl -> cache_elem );
1905
+
1906
+ cache -> cc_nlist ++ ;
1810
1907
1811
1908
/* Finally, bump the list's refcount and return it */
1812
1909
cl -> refcount ++ ;
0 commit comments