@@ -88,6 +88,8 @@ static void CatCachePrintStats(int code, Datum arg);
88
88
#endif
89
89
static void CatCacheRemoveCTup (CatCache * cache , CatCTup * ct );
90
90
static void CatCacheRemoveCList (CatCache * cache , CatCList * cl );
91
+ static void RehashCatCache (CatCache * cp );
92
+ static void RehashCatCacheLists (CatCache * cp );
91
93
static void CatalogCacheInitializeCache (CatCache * cache );
92
94
static CatCTup * CatalogCacheCreateEntry (CatCache * cache ,
93
95
HeapTuple ntp , SysScanDesc scandesc ,
@@ -444,6 +446,7 @@ CatCachePrintStats(int code, Datum arg)
444
446
long cc_neg_hits = 0 ;
445
447
long cc_newloads = 0 ;
446
448
long cc_invals = 0 ;
449
+ long cc_nlists = 0 ;
447
450
long cc_lsearches = 0 ;
448
451
long cc_lhits = 0 ;
449
452
@@ -453,7 +456,7 @@ CatCachePrintStats(int code, Datum arg)
453
456
454
457
if (cache -> cc_ntup == 0 && cache -> cc_searches == 0 )
455
458
continue ; /* don't print unused caches */
456
- elog (DEBUG2 , "catcache %s/%u: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits" ,
459
+ 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" ,
457
460
cache -> cc_relname ,
458
461
cache -> cc_indexoid ,
459
462
cache -> cc_ntup ,
@@ -465,17 +468,19 @@ CatCachePrintStats(int code, Datum arg)
465
468
cache -> cc_searches - cache -> cc_hits - cache -> cc_neg_hits - cache -> cc_newloads ,
466
469
cache -> cc_searches - cache -> cc_hits - cache -> cc_neg_hits ,
467
470
cache -> cc_invals ,
471
+ cache -> cc_nlist ,
468
472
cache -> cc_lsearches ,
469
473
cache -> cc_lhits );
470
474
cc_searches += cache -> cc_searches ;
471
475
cc_hits += cache -> cc_hits ;
472
476
cc_neg_hits += cache -> cc_neg_hits ;
473
477
cc_newloads += cache -> cc_newloads ;
474
478
cc_invals += cache -> cc_invals ;
479
+ cc_nlists += cache -> cc_nlist ;
475
480
cc_lsearches += cache -> cc_lsearches ;
476
481
cc_lhits += cache -> cc_lhits ;
477
482
}
478
- elog (DEBUG2 , "catcache totals: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits" ,
483
+ elog (DEBUG2 , "catcache totals: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lists, %ld lsrch, %ld lhits" ,
479
484
CacheHdr -> ch_ntup ,
480
485
cc_searches ,
481
486
cc_hits ,
@@ -485,6 +490,7 @@ CatCachePrintStats(int code, Datum arg)
485
490
cc_searches - cc_hits - cc_neg_hits - cc_newloads ,
486
491
cc_searches - cc_hits - cc_neg_hits ,
487
492
cc_invals ,
493
+ cc_nlists ,
488
494
cc_lsearches ,
489
495
cc_lhits );
490
496
}
@@ -573,6 +579,8 @@ CatCacheRemoveCList(CatCache *cache, CatCList *cl)
573
579
cache -> cc_keyno , cl -> keys );
574
580
575
581
pfree (cl );
582
+
583
+ -- cache -> cc_nlist ;
576
584
}
577
585
578
586
@@ -611,14 +619,19 @@ CatCacheInvalidate(CatCache *cache, uint32 hashValue)
611
619
* Invalidate *all* CatCLists in this cache; it's too hard to tell which
612
620
* searches might still be correct, so just zap 'em all.
613
621
*/
614
- dlist_foreach_modify ( iter , & cache -> cc_lists )
622
+ for ( int i = 0 ; i < cache -> cc_nlbuckets ; i ++ )
615
623
{
616
- CatCList * cl = dlist_container ( CatCList , cache_elem , iter . cur ) ;
624
+ dlist_head * bucket = & cache -> cc_lbucket [ i ] ;
617
625
618
- if (cl -> refcount > 0 )
619
- cl -> dead = true;
620
- else
621
- CatCacheRemoveCList (cache , cl );
626
+ dlist_foreach_modify (iter , bucket )
627
+ {
628
+ CatCList * cl = dlist_container (CatCList , cache_elem , iter .cur );
629
+
630
+ if (cl -> refcount > 0 )
631
+ cl -> dead = true;
632
+ else
633
+ CatCacheRemoveCList (cache , cl );
634
+ }
622
635
}
623
636
624
637
/*
@@ -691,14 +704,19 @@ ResetCatalogCache(CatCache *cache)
691
704
int i ;
692
705
693
706
/* Remove each list in this cache, or at least mark it dead */
694
- dlist_foreach_modify ( iter , & cache -> cc_lists )
707
+ for ( i = 0 ; i < cache -> cc_nlbuckets ; i ++ )
695
708
{
696
- CatCList * cl = dlist_container ( CatCList , cache_elem , iter . cur ) ;
709
+ dlist_head * bucket = & cache -> cc_lbucket [ i ] ;
697
710
698
- if (cl -> refcount > 0 )
699
- cl -> dead = true;
700
- else
701
- CatCacheRemoveCList (cache , cl );
711
+ dlist_foreach_modify (iter , bucket )
712
+ {
713
+ CatCList * cl = dlist_container (CatCList , cache_elem , iter .cur );
714
+
715
+ if (cl -> refcount > 0 )
716
+ cl -> dead = true;
717
+ else
718
+ CatCacheRemoveCList (cache , cl );
719
+ }
702
720
}
703
721
704
722
/* Remove each tuple in this cache, or at least mark it dead */
@@ -862,6 +880,12 @@ InitCatCache(int id,
862
880
MCXT_ALLOC_ZERO );
863
881
cp -> cc_bucket = palloc0 (nbuckets * sizeof (dlist_head ));
864
882
883
+ /*
884
+ * Many catcaches never receive any list searches. Therefore, we don't
885
+ * allocate the cc_lbuckets till we get a list search.
886
+ */
887
+ cp -> cc_lbucket = NULL ;
888
+
865
889
/*
866
890
* initialize the cache's relation information for the relation
867
891
* corresponding to this cache, and initialize some of the new cache's
@@ -874,7 +898,9 @@ InitCatCache(int id,
874
898
cp -> cc_relisshared = false; /* temporary */
875
899
cp -> cc_tupdesc = (TupleDesc ) NULL ;
876
900
cp -> cc_ntup = 0 ;
901
+ cp -> cc_nlist = 0 ;
877
902
cp -> cc_nbuckets = nbuckets ;
903
+ cp -> cc_nlbuckets = 0 ;
878
904
cp -> cc_nkeys = nkeys ;
879
905
for (i = 0 ; i < nkeys ; ++ i )
880
906
{
@@ -939,6 +965,44 @@ RehashCatCache(CatCache *cp)
939
965
cp -> cc_bucket = newbucket ;
940
966
}
941
967
968
+ /*
969
+ * Enlarge a catcache's list storage, doubling the number of buckets.
970
+ */
971
+ static void
972
+ RehashCatCacheLists (CatCache * cp )
973
+ {
974
+ dlist_head * newbucket ;
975
+ int newnbuckets ;
976
+ int i ;
977
+
978
+ elog (DEBUG1 , "rehashing catalog cache id %d for %s; %d lists, %d buckets" ,
979
+ cp -> id , cp -> cc_relname , cp -> cc_nlist , cp -> cc_nlbuckets );
980
+
981
+ /* Allocate a new, larger, hash table. */
982
+ newnbuckets = cp -> cc_nlbuckets * 2 ;
983
+ newbucket = (dlist_head * ) MemoryContextAllocZero (CacheMemoryContext , newnbuckets * sizeof (dlist_head ));
984
+
985
+ /* Move all entries from old hash table to new. */
986
+ for (i = 0 ; i < cp -> cc_nlbuckets ; i ++ )
987
+ {
988
+ dlist_mutable_iter iter ;
989
+
990
+ dlist_foreach_modify (iter , & cp -> cc_lbucket [i ])
991
+ {
992
+ CatCList * cl = dlist_container (CatCList , cache_elem , iter .cur );
993
+ int hashIndex = HASH_INDEX (cl -> hash_value , newnbuckets );
994
+
995
+ dlist_delete (iter .cur );
996
+ dlist_push_head (& newbucket [hashIndex ], & cl -> cache_elem );
997
+ }
998
+ }
999
+
1000
+ /* Switch to the new array. */
1001
+ pfree (cp -> cc_lbucket );
1002
+ cp -> cc_nlbuckets = newnbuckets ;
1003
+ cp -> cc_lbucket = newbucket ;
1004
+ }
1005
+
942
1006
/*
943
1007
* CatalogCacheInitializeCache
944
1008
*
@@ -1588,7 +1652,9 @@ SearchCatCacheList(CatCache *cache,
1588
1652
Datum v4 = 0 ; /* dummy last-column value */
1589
1653
Datum arguments [CATCACHE_MAXKEYS ];
1590
1654
uint32 lHashValue ;
1655
+ Index lHashIndex ;
1591
1656
dlist_iter iter ;
1657
+ dlist_head * lbucket ;
1592
1658
CatCList * cl ;
1593
1659
CatCTup * ct ;
1594
1660
List * volatile ctlist ;
@@ -1602,7 +1668,7 @@ SearchCatCacheList(CatCache *cache,
1602
1668
/*
1603
1669
* one-time startup overhead for each cache
1604
1670
*/
1605
- if (cache -> cc_tupdesc == NULL )
1671
+ if (unlikely ( cache -> cc_tupdesc == NULL ) )
1606
1672
CatalogCacheInitializeCache (cache );
1607
1673
1608
1674
Assert (nkeys > 0 && nkeys < cache -> cc_nkeys );
@@ -1618,19 +1684,45 @@ SearchCatCacheList(CatCache *cache,
1618
1684
arguments [3 ] = v4 ;
1619
1685
1620
1686
/*
1621
- * compute a hash value of the given keys for faster search. We don't
1622
- * presently divide the CatCList items into buckets, but this still lets
1623
- * us skip non-matching items quickly most of the time.
1687
+ * If we haven't previously done a list search in this cache, create the
1688
+ * bucket header array; otherwise, consider whether it's time to enlarge
1689
+ * it.
1690
+ */
1691
+ if (cache -> cc_lbucket == NULL )
1692
+ {
1693
+ /* Arbitrary initial size --- must be a power of 2 */
1694
+ int nbuckets = 16 ;
1695
+
1696
+ cache -> cc_lbucket = (dlist_head * )
1697
+ MemoryContextAllocZero (CacheMemoryContext ,
1698
+ nbuckets * sizeof (dlist_head ));
1699
+ /* Don't set cc_nlbuckets if we get OOM allocating cc_lbucket */
1700
+ cache -> cc_nlbuckets = nbuckets ;
1701
+ }
1702
+ else
1703
+ {
1704
+ /*
1705
+ * If the hash table has become too full, enlarge the buckets array.
1706
+ * Quite arbitrarily, we enlarge when fill factor > 2.
1707
+ */
1708
+ if (cache -> cc_nlist > cache -> cc_nlbuckets * 2 )
1709
+ RehashCatCacheLists (cache );
1710
+ }
1711
+
1712
+ /*
1713
+ * Find the hash bucket in which to look for the CatCList.
1624
1714
*/
1625
1715
lHashValue = CatalogCacheComputeHashValue (cache , nkeys , v1 , v2 , v3 , v4 );
1716
+ lHashIndex = HASH_INDEX (lHashValue , cache -> cc_nlbuckets );
1626
1717
1627
1718
/*
1628
1719
* scan the items until we find a match or exhaust our list
1629
1720
*
1630
1721
* Note: it's okay to use dlist_foreach here, even though we modify the
1631
1722
* dlist within the loop, because we don't continue the loop afterwards.
1632
1723
*/
1633
- dlist_foreach (iter , & cache -> cc_lists )
1724
+ lbucket = & cache -> cc_lbucket [lHashIndex ];
1725
+ dlist_foreach (iter , lbucket )
1634
1726
{
1635
1727
cl = dlist_container (CatCList , cache_elem , iter .cur );
1636
1728
@@ -1650,13 +1742,13 @@ SearchCatCacheList(CatCache *cache,
1650
1742
continue ;
1651
1743
1652
1744
/*
1653
- * We found a matching list. Move the list to the front of the
1654
- * cache's list-of-lists, to speed subsequent searches. (We do not
1745
+ * We found a matching list. Move the list to the front of the list
1746
+ * for its hashbucket, so as to speed subsequent searches. (We do not
1655
1747
* move the members to the fronts of their hashbucket lists, however,
1656
1748
* since there's no point in that unless they are searched for
1657
1749
* individually.)
1658
1750
*/
1659
- dlist_move_head (& cache -> cc_lists , & cl -> cache_elem );
1751
+ dlist_move_head (lbucket , & cl -> cache_elem );
1660
1752
1661
1753
/* Bump the list's refcount and return it */
1662
1754
ResourceOwnerEnlarge (CurrentResourceOwner );
@@ -1868,7 +1960,12 @@ SearchCatCacheList(CatCache *cache,
1868
1960
}
1869
1961
Assert (i == nmembers );
1870
1962
1871
- dlist_push_head (& cache -> cc_lists , & cl -> cache_elem );
1963
+ /*
1964
+ * Add the CatCList to the appropriate bucket, and count it.
1965
+ */
1966
+ dlist_push_head (lbucket , & cl -> cache_elem );
1967
+
1968
+ cache -> cc_nlist ++ ;
1872
1969
1873
1970
/* Finally, bump the list's refcount and return it */
1874
1971
cl -> refcount ++ ;
0 commit comments