diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 10b73845c2268db4bf2e74ba8d112c1c8d064093..df31659b90e5d3792685153f1c04271da0ab9dc3 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.128 2006/03/05 15:58:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.129 2006/06/15 02:08:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,20 +37,6 @@
 
  /* #define CACHEDEBUG */	/* turns DEBUG elogs on */
 
-/*
- * Constants related to size of the catcache.
- *
- * NCCBUCKETS must be a power of two and must be less than 64K (because
- * SharedInvalCatcacheMsg crams hash indexes into a uint16 field).	In
- * practice it should be a lot less, anyway, to avoid chewing up too much
- * space on hash bucket headers.
- *
- * MAXCCTUPLES could be as small as a few hundred, if per-backend memory
- * consumption is at a premium.
- */
-#define NCCBUCKETS 256			/* Hash buckets per CatCache */
-#define MAXCCTUPLES 5000		/* Maximum # of tuples in all caches */
-
 /*
  * Given a hash value and the size of the hash table, find the bucket
  * in which the hash value belongs. Since the hash table must contain
@@ -89,7 +75,7 @@ static uint32 CatalogCacheComputeTupleHashValue(CatCache *cache,
 								  HeapTuple tuple);
 
 #ifdef CATCACHE_STATS
-static void CatCachePrintStats(void);
+static void CatCachePrintStats(int code, Datum arg);
 #endif
 static void CatCacheRemoveCTup(CatCache *cache, CatCTup *ct);
 static void CatCacheRemoveCList(CatCache *cache, CatCList *cl);
@@ -97,7 +83,6 @@ static void CatalogCacheInitializeCache(CatCache *cache);
 static CatCTup *CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,
 						uint32 hashValue, Index hashIndex,
 						bool negative);
-static void CatalogCacheCleanup(CatCTup *savect);
 static HeapTuple build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys);
 
 
@@ -281,7 +266,7 @@ CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple)
 #ifdef CATCACHE_STATS
 
 static void
-CatCachePrintStats(void)
+CatCachePrintStats(int code, Datum arg)
 {
 	CatCache   *cache;
 	long		cc_searches = 0;
@@ -289,18 +274,14 @@ CatCachePrintStats(void)
 	long		cc_neg_hits = 0;
 	long		cc_newloads = 0;
 	long		cc_invals = 0;
-	long		cc_discards = 0;
 	long		cc_lsearches = 0;
 	long		cc_lhits = 0;
 
-	elog(DEBUG2, "catcache stats dump: %d/%d tuples in catcaches",
-		 CacheHdr->ch_ntup, CacheHdr->ch_maxtup);
-
 	for (cache = CacheHdr->ch_caches; cache; cache = cache->cc_next)
 	{
 		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 discards, %ld lsrch, %ld lhits",
+		elog(DEBUG2, "catcache %s/%u: %d tup, %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,
@@ -312,7 +293,6 @@ CatCachePrintStats(void)
 			 cache->cc_searches - cache->cc_hits - cache->cc_neg_hits - cache->cc_newloads,
 			 cache->cc_searches - cache->cc_hits - cache->cc_neg_hits,
 			 cache->cc_invals,
-			 cache->cc_discards,
 			 cache->cc_lsearches,
 			 cache->cc_lhits);
 		cc_searches += cache->cc_searches;
@@ -320,11 +300,10 @@ CatCachePrintStats(void)
 		cc_neg_hits += cache->cc_neg_hits;
 		cc_newloads += cache->cc_newloads;
 		cc_invals += cache->cc_invals;
-		cc_discards += cache->cc_discards;
 		cc_lsearches += cache->cc_lsearches;
 		cc_lhits += cache->cc_lhits;
 	}
-	elog(DEBUG2, "catcache totals: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld discards, %ld lsrch, %ld lhits",
+	elog(DEBUG2, "catcache totals: %d tup, %ld srch, %ld+%ld=%ld hits, %ld+%ld=%ld loads, %ld invals, %ld lsrch, %ld lhits",
 		 CacheHdr->ch_ntup,
 		 cc_searches,
 		 cc_hits,
@@ -334,7 +313,6 @@ CatCachePrintStats(void)
 		 cc_searches - cc_hits - cc_neg_hits - cc_newloads,
 		 cc_searches - cc_hits - cc_neg_hits,
 		 cc_invals,
-		 cc_discards,
 		 cc_lsearches,
 		 cc_lhits);
 }
@@ -367,8 +345,7 @@ CatCacheRemoveCTup(CatCache *cache, CatCTup *ct)
 		return;					/* nothing left to do */
 	}
 
-	/* delink from linked lists */
-	DLRemove(&ct->lrulist_elem);
+	/* delink from linked list */
 	DLRemove(&ct->cache_elem);
 
 	/* free associated tuple data */
@@ -568,11 +545,13 @@ AtEOXact_CatCache(bool isCommit)
 	if (assert_enabled)
 	{
 		CatCache   *ccp;
-		Dlelem	   *elt;
 
-		/* Check CatCLists */
 		for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
 		{
+			Dlelem	   *elt;
+			int			i;
+
+			/* Check CatCLists */
 			for (elt = DLGetHead(&ccp->cc_lists); elt; elt = DLGetSucc(elt))
 			{
 				CatCList   *cl = (CatCList *) DLE_VAL(elt);
@@ -581,16 +560,21 @@ AtEOXact_CatCache(bool isCommit)
 				Assert(cl->refcount == 0);
 				Assert(!cl->dead);
 			}
-		}
 
-		/* Check individual tuples */
-		for (elt = DLGetHead(&CacheHdr->ch_lrulist); elt; elt = DLGetSucc(elt))
-		{
-			CatCTup    *ct = (CatCTup *) DLE_VAL(elt);
+			/* Check individual tuples */
+			for (i = 0; i < ccp->cc_nbuckets; i++)
+			{
+				for (elt = DLGetHead(&ccp->cc_bucket[i]);
+					 elt;
+					 elt = DLGetSucc(elt))
+				{
+					CatCTup    *ct = (CatCTup *) DLE_VAL(elt);
 
-			Assert(ct->ct_magic == CT_MAGIC);
-			Assert(ct->refcount == 0);
-			Assert(!ct->dead);
+					Assert(ct->ct_magic == CT_MAGIC);
+					Assert(ct->refcount == 0);
+					Assert(!ct->dead);
+				}
+			}
 		}
 	}
 #endif
@@ -796,12 +780,27 @@ InitCatCache(int id,
 			 Oid indexoid,
 			 int reloidattr,
 			 int nkeys,
-			 const int *key)
+			 const int *key,
+			 int nbuckets)
 {
 	CatCache   *cp;
 	MemoryContext oldcxt;
 	int			i;
 
+	/*
+	 * nbuckets is the number of hash buckets to use in this catcache.
+	 * Currently we just use a hard-wired estimate of an appropriate size
+	 * for each cache; maybe later make them dynamically resizable?
+	 *
+	 * nbuckets must be a power of two.  We check this via Assert rather than
+	 * a full runtime check because the values will be coming from constant
+	 * tables.
+	 *
+	 * If you're confused by the power-of-two check, see comments in
+	 * bitmapset.c for an explanation.
+	 */
+	Assert(nbuckets > 0 && (nbuckets & -nbuckets) == nbuckets);
+
 	/*
 	 * first switch to the cache context so our allocations do not vanish at
 	 * the end of a transaction
@@ -812,17 +811,15 @@ InitCatCache(int id,
 	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/*
-	 * if first time through, initialize the cache group header, including
-	 * global LRU list header
+	 * if first time through, initialize the cache group header
 	 */
 	if (CacheHdr == NULL)
 	{
 		CacheHdr = (CatCacheHeader *) palloc(sizeof(CatCacheHeader));
 		CacheHdr->ch_caches = NULL;
 		CacheHdr->ch_ntup = 0;
-		CacheHdr->ch_maxtup = MAXCCTUPLES;
-		DLInitList(&CacheHdr->ch_lrulist);
 #ifdef CATCACHE_STATS
+		/* set up to dump stats at backend exit */
 		on_proc_exit(CatCachePrintStats, 0);
 #endif
 	}
@@ -832,7 +829,7 @@ InitCatCache(int id,
 	 *
 	 * Note: we assume zeroing initializes the Dllist headers correctly
 	 */
-	cp = (CatCache *) palloc0(sizeof(CatCache) + NCCBUCKETS * sizeof(Dllist));
+	cp = (CatCache *) palloc0(sizeof(CatCache) + nbuckets * sizeof(Dllist));
 
 	/*
 	 * initialize the cache's relation information for the relation
@@ -847,7 +844,7 @@ InitCatCache(int id,
 	cp->cc_tupdesc = (TupleDesc) NULL;
 	cp->cc_reloidattr = reloidattr;
 	cp->cc_ntup = 0;
-	cp->cc_nbuckets = NCCBUCKETS;
+	cp->cc_nbuckets = nbuckets;
 	cp->cc_nkeys = nkeys;
 	for (i = 0; i < nkeys; ++i)
 		cp->cc_key[i] = key[i];
@@ -1162,13 +1159,11 @@ SearchCatCache(CatCache *cache,
 			continue;
 
 		/*
-		 * we found a match in the cache: move it to the front of the global
-		 * LRU list.  We also move it to the front of the list for its
-		 * hashbucket, in order to speed subsequent searches.  (The most
-		 * frequently accessed elements in any hashbucket will tend to be near
-		 * the front of the hashbucket's list.)
+		 * We found a match in the cache.  Move it to the front of the list
+		 * for its hashbucket, in order to speed subsequent searches.  (The
+		 * most frequently accessed elements in any hashbucket will tend to be
+		 * near the front of the hashbucket's list.)
 		 */
-		DLMoveToFront(&ct->lrulist_elem);
 		DLMoveToFront(&ct->cache_elem);
 
 		/*
@@ -1414,14 +1409,12 @@ SearchCatCacheList(CatCache *cache,
 			continue;
 
 		/*
-		 * We found a matching list: mark it as touched since the last
-		 * CatalogCacheCleanup() sweep.  Also move the list to the front of
-		 * the cache's list-of-lists, to speed subsequent searches. (We do not
+		 * We found a matching list.  Move the list to the front of the
+		 * cache's list-of-lists, to speed subsequent searches.  (We do not
 		 * move the members to the fronts of their hashbucket lists, however,
 		 * since there's no point in that unless they are searched for
 		 * individually.)
 		 */
-		cl->touched = true;
 		DLMoveToFront(&cl->cache_elem);
 
 		/* Bump the list's refcount and return it */
@@ -1504,10 +1497,7 @@ SearchCatCacheList(CatCache *cache,
 				if (ct->c_list)
 					continue;
 
-				/* Found a match, so move it to front */
-				DLMoveToFront(&ct->lrulist_elem);
-
-				break;
+				break;			/* A-OK */
 			}
 
 			if (elt == NULL)
@@ -1577,7 +1567,6 @@ SearchCatCacheList(CatCache *cache,
 	cl->refcount = 0;			/* for the moment */
 	cl->dead = false;
 	cl->ordered = ordered;
-	cl->touched = false;		/* we already moved members to front */
 	cl->nkeys = nkeys;
 	cl->hash_value = lHashValue;
 	cl->n_members = nmembers;
@@ -1654,11 +1643,10 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,
 
 	/*
 	 * Finish initializing the CatCTup header, and add it to the cache's
-	 * linked lists and counts.
+	 * linked list and counts.
 	 */
 	ct->ct_magic = CT_MAGIC;
 	ct->my_cache = cache;
-	DLInitElem(&ct->lrulist_elem, (void *) ct);
 	DLInitElem(&ct->cache_elem, (void *) ct);
 	ct->c_list = NULL;
 	ct->refcount = 0;			/* for the moment */
@@ -1666,97 +1654,14 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp,
 	ct->negative = negative;
 	ct->hash_value = hashValue;
 
-	DLAddHead(&CacheHdr->ch_lrulist, &ct->lrulist_elem);
 	DLAddHead(&cache->cc_bucket[hashIndex], &ct->cache_elem);
 
 	cache->cc_ntup++;
 	CacheHdr->ch_ntup++;
 
-	/*
-	 * If we've exceeded the desired size of the caches, try to throw away the
-	 * least recently used entry(s).  NB: be careful not to throw away the
-	 * newly-built entry...
-	 */
-	if (CacheHdr->ch_ntup > CacheHdr->ch_maxtup)
-		CatalogCacheCleanup(ct);
-
 	return ct;
 }
 
-/*
- * CatalogCacheCleanup
- *		Try to reduce the size of the catcaches when they get too big
- *
- * savect can be NULL, or a specific CatCTup not to remove even if it
- * has zero refcount.
- */
-static void
-CatalogCacheCleanup(CatCTup *savect)
-{
-	int			tup_target;
-	CatCache   *ccp;
-	Dlelem	   *elt,
-			   *prevelt;
-
-	/*
-	 * Each time we have to do this, try to cut the cache size down to about
-	 * 90% of the maximum.
-	 */
-	tup_target = (CacheHdr->ch_maxtup * 9) / 10;
-
-	/*
-	 * Our strategy for managing CatCLists is that, each time we have to throw
-	 * away some cache entries, we first move-to-front all the members of
-	 * CatCLists that have been touched since the last cleanup sweep. Then we
-	 * do strict LRU elimination by individual tuples, zapping a list if any
-	 * of its members gets zapped.	Before PostgreSQL 8.1, we moved members to
-	 * front each time their owning list was touched, which was arguably more
-	 * fair in balancing list members against standalone tuples --- but the
-	 * overhead for large lists was horrendous.  This scheme is more heavily
-	 * biased towards preserving lists, but that is not necessarily bad
-	 * either.
-	 */
-	for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
-	{
-		for (elt = DLGetHead(&ccp->cc_lists); elt; elt = DLGetSucc(elt))
-		{
-			CatCList   *cl = (CatCList *) DLE_VAL(elt);
-
-			Assert(cl->cl_magic == CL_MAGIC);
-			if (cl->touched && !cl->dead)
-			{
-				int			i;
-
-				for (i = 0; i < cl->n_members; i++)
-					DLMoveToFront(&cl->members[i]->lrulist_elem);
-			}
-			cl->touched = false;
-		}
-	}
-
-	/* Now get rid of unreferenced tuples in reverse global LRU order */
-	for (elt = DLGetTail(&CacheHdr->ch_lrulist); elt; elt = prevelt)
-	{
-		CatCTup    *ct = (CatCTup *) DLE_VAL(elt);
-
-		prevelt = DLGetPred(elt);
-
-		if (ct->refcount == 0 &&
-			(ct->c_list == NULL || ct->c_list->refcount == 0) &&
-			ct != savect)
-		{
-#ifdef CATCACHE_STATS
-			ct->my_cache->cc_discards++;
-#endif
-			CatCacheRemoveCTup(ct->my_cache, ct);
-
-			/* Quit when we've removed enough tuples */
-			if (CacheHdr->ch_ntup <= tup_target)
-				break;
-		}
-	}
-}
-
 /*
  * build_dummy_tuple
  *		Generate a palloc'd HeapTuple that contains the specified key
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index ffcb26e3c551080d0e9b53c651a4b17d3cd64f75..d23fbb9ce2b463586982d09572c09ced200eccd7 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.103 2006/05/03 22:45:26 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.104 2006/06/15 02:08:09 tgl Exp $
  *
  * NOTES
  *	  These routines allow the parser/planner/executor to perform
@@ -55,14 +55,18 @@
 	the list sorted alphabetically and adjust the cache numbers
 	accordingly.
 
-	Add your entry to the cacheinfo[] array below.	All cache lists are
-	alphabetical, so add it in the proper place.  Specify the relation
-	OID, index OID, number of keys, and key attribute numbers.	If the
-	relation contains tuples that are associated with a particular relation
-	(for example, its attributes, rules, triggers, etc) then specify the
-	attribute number that contains the OID of the associated relation.
-	This is used by CatalogCacheFlushRelation() to remove the correct
-	tuples during a table drop or relcache invalidation event.
+	Add your entry to the cacheinfo[] array below. All cache lists are
+	alphabetical, so add it in the proper place.  Specify the relation OID,
+	index OID, number of keys, key attribute numbers, and number of hash
+	buckets.  If the relation contains tuples that are associated with a
+	particular relation (for example, its attributes, rules, triggers, etc)
+	then specify the attribute number that contains the OID of the associated
+	relation.  This is used by CatalogCacheFlushRelation() to remove the
+	correct tuples during a table drop or relcache invalidation event.
+
+	The number of hash buckets must be a power of 2.  It's reasonable to
+	set this to the number of entries that might be in the particular cache
+	in a medium-size database.
 
 	There must be a unique index underlying each syscache (ie, an index
 	whose key is the same as that of the cache).  If there is not one
@@ -90,6 +94,7 @@ struct cachedesc
 	int			reloidattr;		/* attr number of rel OID reference, or 0 */
 	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 */
 };
 
 static const struct cachedesc cacheinfo[] = {
@@ -102,7 +107,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		32
+	},
 	{AccessMethodRelationId,	/* AMNAME */
 		AmNameIndexId,
 		0,
@@ -112,7 +119,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		4
+	},
 	{AccessMethodRelationId,	/* AMOID */
 		AmOidIndexId,
 		0,
@@ -122,7 +131,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		4
+	},
 	{AccessMethodOperatorRelationId,	/* AMOPOPID */
 		AccessMethodOperatorIndexId,
 		0,
@@ -132,7 +143,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_amop_amopclaid,
 			0,
 			0
-	}},
+		},
+		64
+	},
 	{AccessMethodOperatorRelationId,	/* AMOPSTRATEGY */
 		AccessMethodStrategyIndexId,
 		0,
@@ -142,7 +155,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_amop_amopsubtype,
 			Anum_pg_amop_amopstrategy,
 			0
-	}},
+		},
+		64
+	},
 	{AccessMethodProcedureRelationId,	/* AMPROCNUM */
 		AccessMethodProcedureIndexId,
 		0,
@@ -152,7 +167,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_amproc_amprocsubtype,
 			Anum_pg_amproc_amprocnum,
 			0
-	}},
+		},
+		64
+	},
 	{AttributeRelationId,		/* ATTNAME */
 		AttributeRelidNameIndexId,
 		Anum_pg_attribute_attrelid,
@@ -162,7 +179,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_attribute_attname,
 			0,
 			0
-	}},
+		},
+		2048
+	},
 	{AttributeRelationId,		/* ATTNUM */
 		AttributeRelidNumIndexId,
 		Anum_pg_attribute_attrelid,
@@ -172,7 +191,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_attribute_attnum,
 			0,
 			0
-	}},
+		},
+		2048
+	},
 	{AuthMemRelationId,			/* AUTHMEMMEMROLE */
 		AuthMemMemRoleIndexId,
 		0,
@@ -182,7 +203,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_auth_members_roleid,
 			0,
 			0
-	}},
+		},
+		128
+	},
 	{AuthMemRelationId,			/* AUTHMEMROLEMEM */
 		AuthMemRoleMemIndexId,
 		0,
@@ -192,7 +215,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_auth_members_member,
 			0,
 			0
-	}},
+		},
+		128
+	},
 	{AuthIdRelationId,			/* AUTHNAME */
 		AuthIdRolnameIndexId,
 		0,
@@ -202,7 +227,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		128
+	},
 	{AuthIdRelationId,			/* AUTHOID */
 		AuthIdOidIndexId,
 		0,
@@ -212,7 +239,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		128
+	},
 	{
 		CastRelationId,			/* CASTSOURCETARGET */
 		CastSourceTargetIndexId,
@@ -223,7 +252,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_cast_casttarget,
 			0,
 			0
-	}},
+		},
+		256
+	},
 	{OperatorClassRelationId,	/* CLAAMNAMENSP */
 		OpclassAmNameNspIndexId,
 		0,
@@ -233,7 +264,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_opclass_opcname,
 			Anum_pg_opclass_opcnamespace,
 			0
-	}},
+		},
+		64
+	},
 	{OperatorClassRelationId,	/* CLAOID */
 		OpclassOidIndexId,
 		0,
@@ -243,7 +276,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		64
+	},
 	{ConversionRelationId,		/* CONDEFAULT */
 		ConversionDefaultIndexId,
 		0,
@@ -253,7 +288,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_conversion_conforencoding,
 			Anum_pg_conversion_contoencoding,
 			ObjectIdAttributeNumber,
-	}},
+		},
+		128
+	},
 	{ConversionRelationId,		/* CONNAMENSP */
 		ConversionNameNspIndexId,
 		0,
@@ -263,7 +300,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_conversion_connamespace,
 			0,
 			0
-	}},
+		},
+		128
+	},
 	{ConversionRelationId,		/* CONOID */
 		ConversionOidIndexId,
 		0,
@@ -273,7 +312,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		128
+	},
 	{DatabaseRelationId,		/* DATABASEOID */
 		DatabaseOidIndexId,
 		0,
@@ -283,7 +324,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		4
+	},
 	{IndexRelationId,			/* INDEXRELID */
 		IndexRelidIndexId,
 		Anum_pg_index_indrelid,
@@ -293,7 +336,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		1024
+	},
 	{InheritsRelationId,		/* INHRELID */
 		InheritsRelidSeqnoIndexId,
 		Anum_pg_inherits_inhrelid,
@@ -303,7 +348,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_inherits_inhseqno,
 			0,
 			0
-	}},
+		},
+		256
+	},
 	{LanguageRelationId,		/* LANGNAME */
 		LanguageNameIndexId,
 		0,
@@ -313,7 +360,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		4
+	},
 	{LanguageRelationId,		/* LANGOID */
 		LanguageOidIndexId,
 		0,
@@ -323,7 +372,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		4
+	},
 	{NamespaceRelationId,		/* NAMESPACENAME */
 		NamespaceNameIndexId,
 		0,
@@ -333,7 +384,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		256
+	},
 	{NamespaceRelationId,		/* NAMESPACEOID */
 		NamespaceOidIndexId,
 		0,
@@ -343,7 +396,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		256
+	},
 	{OperatorRelationId,		/* OPERNAMENSP */
 		OperatorNameNspIndexId,
 		0,
@@ -353,7 +408,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_operator_oprleft,
 			Anum_pg_operator_oprright,
 			Anum_pg_operator_oprnamespace
-	}},
+		},
+		1024
+	},
 	{OperatorRelationId,		/* OPEROID */
 		OperatorOidIndexId,
 		0,
@@ -363,7 +420,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		1024
+	},
 	{ProcedureRelationId,		/* PROCNAMEARGSNSP */
 		ProcedureNameArgsNspIndexId,
 		0,
@@ -373,7 +432,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_proc_proargtypes,
 			Anum_pg_proc_pronamespace,
 			0
-	}},
+		},
+		2048
+	},
 	{ProcedureRelationId,		/* PROCOID */
 		ProcedureOidIndexId,
 		0,
@@ -383,7 +444,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		2048
+	},
 	{RelationRelationId,		/* RELNAMENSP */
 		ClassNameNspIndexId,
 		ObjectIdAttributeNumber,
@@ -393,7 +456,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_class_relnamespace,
 			0,
 			0
-	}},
+		},
+		1024
+	},
 	{RelationRelationId,		/* RELOID */
 		ClassOidIndexId,
 		ObjectIdAttributeNumber,
@@ -403,7 +468,9 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}},
+		},
+		1024
+	},
 	{RewriteRelationId,			/* RULERELNAME */
 		RewriteRelRulenameIndexId,
 		Anum_pg_rewrite_ev_class,
@@ -413,7 +480,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_rewrite_rulename,
 			0,
 			0
-	}},
+		},
+		1024
+	},
 	{StatisticRelationId,		/* STATRELATT */
 		StatisticRelidAttnumIndexId,
 		Anum_pg_statistic_starelid,
@@ -423,7 +492,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_statistic_staattnum,
 			0,
 			0
-	}},
+		},
+		1024
+	},
 	{TypeRelationId,			/* TYPENAMENSP */
 		TypeNameNspIndexId,
 		Anum_pg_type_typrelid,
@@ -433,7 +504,9 @@ static const struct cachedesc cacheinfo[] = {
 			Anum_pg_type_typnamespace,
 			0,
 			0
-	}},
+		},
+		1024
+	},
 	{TypeRelationId,			/* TYPEOID */
 		TypeOidIndexId,
 		Anum_pg_type_typrelid,
@@ -443,11 +516,12 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0,
 			0
-	}}
+		},
+		1024
+	}
 };
 
-static CatCache *SysCache[
-						  lengthof(cacheinfo)];
+static CatCache *SysCache[lengthof(cacheinfo)];
 static int	SysCacheSize = lengthof(cacheinfo);
 static bool CacheInitialized = false;
 
@@ -476,7 +550,8 @@ InitCatalogCache(void)
 										 cacheinfo[cacheId].indoid,
 										 cacheinfo[cacheId].reloidattr,
 										 cacheinfo[cacheId].nkeys,
-										 cacheinfo[cacheId].key);
+										 cacheinfo[cacheId].key,
+										 cacheinfo[cacheId].nbuckets);
 		if (!PointerIsValid(SysCache[cacheId]))
 			elog(ERROR, "could not initialize cache %u (%d)",
 				 cacheinfo[cacheId].reloid, cacheId);
diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h
index c0111c50b6ecec21f3e0fbf5dc90d6e866e17a51..65d286c7b3b0a7ce5befb09fae01412ce4c8f286 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/catcache.h,v 1.58 2006/03/05 15:59:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/catcache.h,v 1.59 2006/06/15 02:08:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -60,7 +60,6 @@ typedef struct catcache
 	 * searches, each of which will result in loading a negative entry
 	 */
 	long		cc_invals;		/* # of entries invalidated from cache */
-	long		cc_discards;	/* # of entries discarded due to overflow */
 	long		cc_lsearches;	/* total # list-searches */
 	long		cc_lhits;		/* # of matches against existing lists */
 #endif
@@ -75,11 +74,10 @@ typedef struct catctup
 	CatCache   *my_cache;		/* link to owning catcache */
 
 	/*
-	 * Each tuple in a cache is a member of two Dllists: one lists all the
-	 * elements in all the caches in LRU order, and the other lists just the
-	 * elements in one hashbucket of one cache, also in LRU order.
+	 * Each tuple in a cache is a member of a Dllist that stores the elements
+	 * of its hash bucket.  We keep each Dllist in LRU order to speed repeated
+	 * lookups.
 	 */
-	Dlelem		lrulist_elem;	/* list member of global LRU list */
 	Dlelem		cache_elem;		/* list member of per-bucket list */
 
 	/*
@@ -125,9 +123,8 @@ typedef struct catclist
 	 * table rows satisfying the partial key.  (Note: none of these will be
 	 * negative cache entries.)
 	 *
-	 * A CatCList is only a member of a per-cache list; we do not do separate
-	 * LRU management for CatCLists.  See CatalogCacheCleanup() for the
-	 * details of the management algorithm.
+	 * A CatCList is only a member of a per-cache list; we do not currently
+	 * divide them into hash buckets.
 	 *
 	 * A list marked "dead" must not be returned by subsequent searches.
 	 * However, it won't be physically deleted from the cache until its
@@ -143,7 +140,6 @@ typedef struct catclist
 	int			refcount;		/* number of active references */
 	bool		dead;			/* dead but not yet removed? */
 	bool		ordered;		/* members listed in index order? */
-	bool		touched;		/* used since last CatalogCacheCleanup? */
 	short		nkeys;			/* number of lookup keys specified */
 	uint32		hash_value;		/* hash value for lookup keys */
 	HeapTupleData tuple;		/* header for tuple holding keys */
@@ -156,8 +152,6 @@ typedef struct catcacheheader
 {
 	CatCache   *ch_caches;		/* head of list of CatCache structs */
 	int			ch_ntup;		/* # of tuples in all caches */
-	int			ch_maxtup;		/* max # of tuples allowed (LRU) */
-	Dllist		ch_lrulist;		/* overall LRU list, most recent first */
 } CatCacheHeader;
 
 
@@ -169,7 +163,8 @@ extern void AtEOXact_CatCache(bool isCommit);
 
 extern CatCache *InitCatCache(int id, Oid reloid, Oid indexoid,
 			 int reloidattr,
-			 int nkeys, const int *key);
+			 int nkeys, const int *key,
+			 int nbuckets);
 extern void InitCatCachePhase2(CatCache *cache);
 
 extern HeapTuple SearchCatCache(CatCache *cache,