While debugging an out-of-memory situation, I noticed that the relcache entry of each index consumes 2k of memory. From a memory dump:

...
    pg_database_datname_index: 2048 total in 1 blocks; 712 free (0 chunks); 
1336 used
    pg_trigger_tgrelid_tgname_index: 2048 total in 1 blocks; 576 free (0 
chunks); 1472 used
    pg_rewrite_rel_rulename_index: 2048 total in 1 blocks; 576 free (0 chunks); 
1472 used
    pg_amproc_fam_proc_index: 2048 total in 1 blocks; 232 free (0 chunks); 1816 
used
    pg_opclass_oid_index: 2048 total in 1 blocks; 664 free (0 chunks); 1384 used
    pg_index_indexrelid_index: 2048 total in 1 blocks; 664 free (0 chunks); 
1384 used
    pg_attribute_relid_attnum_index: 2048 total in 1 blocks; 528 free (0 
chunks); 1520 used
    pg_class_oid_index: 2048 total in 1 blocks; 664 free (0 chunks); 1384 used

Looking closer at where that memory is spent, a lot of it goes into the FmgrInfo structs in RelationAmInfo. But some of them are outright unused (ambuild, ambuildempty, amcostestimate, amoptions), and a few others hardly are called so seldom that they hardly need to be cached (ambuildelete, ambacuumcleanup). Removing those fields, patch attached, reduces the memory usage nicely:

...
    pg_database_datname_index: 1024 total in 1 blocks; 200 free (0 chunks); 824 
used
    pg_trigger_tgrelid_tgname_index: 1024 total in 1 blocks; 64 free (0 
chunks); 960 used
    pg_rewrite_rel_rulename_index: 1024 total in 1 blocks; 64 free (0 chunks); 
960 used
    pg_amproc_fam_proc_index: 3072 total in 2 blocks; 1736 free (2 chunks); 
1336 used
    pg_opclass_oid_index: 1024 total in 1 blocks; 152 free (0 chunks); 872 used
    pg_index_indexrelid_index: 1024 total in 1 blocks; 152 free (0 chunks); 872 
used
    pg_attribute_relid_attnum_index: 1024 total in 1 blocks; 16 free (0 
chunks); 1008 used
    pg_class_oid_index: 1024 total in 1 blocks; 152 free (0 chunks); 872 used

This brings most index entries from two 1k blocks down to one 1k block. A backend seems to load about 60 indexes into the cache for system tables, so that saves about ~60 kB of memory for every backend at a minimum.

This isn't a huge difference, unless you access a huge number of indexes. But the patch is trivial, and every little helps. Any objections if I commit this to master?

- Heikki
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index ce94649..b9e519a 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -671,14 +671,19 @@ index_bulk_delete(IndexVacuumInfo *info,
 				  void *callback_state)
 {
 	Relation	indexRelation = info->index;
-	FmgrInfo   *procedure;
+	RegProcedure procOid;
+	FmgrInfo	procedure;
 	IndexBulkDeleteResult *result;
 
 	RELATION_CHECKS;
-	GET_REL_PROCEDURE(ambulkdelete);
+
+	procOid = indexRelation->rd_am->ambulkdelete;
+	if (!RegProcedureIsValid(procOid))
+		elog(ERROR, "invalid ambulkdelete regproc");
+	fmgr_info(procOid, &procedure);
 
 	result = (IndexBulkDeleteResult *)
-		DatumGetPointer(FunctionCall4(procedure,
+		DatumGetPointer(FunctionCall4(&procedure,
 									  PointerGetDatum(info),
 									  PointerGetDatum(stats),
 									  PointerGetDatum((Pointer) callback),
@@ -698,14 +703,19 @@ index_vacuum_cleanup(IndexVacuumInfo *info,
 					 IndexBulkDeleteResult *stats)
 {
 	Relation	indexRelation = info->index;
-	FmgrInfo   *procedure;
+	RegProcedure procOid;
+	FmgrInfo	procedure;
 	IndexBulkDeleteResult *result;
 
 	RELATION_CHECKS;
-	GET_REL_PROCEDURE(amvacuumcleanup);
+
+	procOid = indexRelation->rd_am->amvacuumcleanup;
+	if (!RegProcedureIsValid(procOid))
+		elog(ERROR, "invalid amvacuumcleanup regproc");
+	fmgr_info(procOid, &procedure);
 
 	result = (IndexBulkDeleteResult *)
-		DatumGetPointer(FunctionCall2(procedure,
+		DatumGetPointer(FunctionCall2(&procedure,
 									  PointerGetDatum(info),
 									  PointerGetDatum(stats)));
 
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index a4daf77..05f2011 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -47,8 +47,8 @@ typedef LockInfoData *LockInfo;
 
 
 /*
- * Cached lookup information for the index access method functions defined
- * by the pg_am row associated with an index relation.
+ * Cached lookup information for the frequently used index access method
+ * functions, defined by the pg_am row associated with an index relation.
  */
 typedef struct RelationAmInfo
 {
@@ -60,13 +60,7 @@ typedef struct RelationAmInfo
 	FmgrInfo	amendscan;
 	FmgrInfo	ammarkpos;
 	FmgrInfo	amrestrpos;
-	FmgrInfo	ambuild;
-	FmgrInfo	ambuildempty;
-	FmgrInfo	ambulkdelete;
-	FmgrInfo	amvacuumcleanup;
 	FmgrInfo	amcanreturn;
-	FmgrInfo	amcostestimate;
-	FmgrInfo	amoptions;
 } RelationAmInfo;
 
 
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to