From 02eb07ea89d27f1d05a5055bf779042d2953b4e7 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Thu, 21 Mar 2024 23:00:34 +0200 Subject: [PATCH] Allow table AM to store complex data structures in rd_amcache The new table AM method free_rd_amcache is responsible for freeing all the memory related to rd_amcache and setting free_rd_amcache to NULL. If the new method is not specified, we still assume rd_amcache to be a single chunk of memory, which could be just pfree'd. Discussion: https://postgr.es/m/CAPpHfdurb9ycV8udYqM%3Do0sPS66PJ4RCBM1g-bBpvzUfogY0EA%40mail.gmail.com Reviewed-by: Matthias van de Meent, Mark Dilger, Pavel Borisov Reviewed-by: Nikita Malakhov, Japin Li --- src/backend/access/heap/heapam_handler.c | 1 + src/backend/utils/cache/relcache.c | 11 +++----- src/include/access/tableam.h | 34 ++++++++++++++++++++++++ src/include/utils/rel.h | 10 ++++--- 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 680a50bf8b..4dd1341f60 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -2582,6 +2582,7 @@ static const TableAmRoutine heapam_methods = { .index_build_range_scan = heapam_index_build_range_scan, .index_validate_scan = heapam_index_validate_scan, + .free_rd_amcache = NULL, .relation_size = table_block_relation_size, .relation_needs_toast_table = heapam_relation_needs_toast_table, .relation_toast_am = heapam_relation_toast_am, diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 2cd19d603f..dcd18e4626 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -2262,9 +2262,7 @@ RelationReloadIndexInfo(Relation relation) RelationCloseSmgr(relation); /* Must free any AM cached data upon relcache flush */ - if (relation->rd_amcache) - pfree(relation->rd_amcache); - relation->rd_amcache = NULL; + table_free_rd_amcache(relation); /* * If it's a shared index, we might be called before backend startup has @@ -2484,8 +2482,7 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc) pfree(relation->rd_options); if (relation->rd_indextuple) pfree(relation->rd_indextuple); - if (relation->rd_amcache) - pfree(relation->rd_amcache); + table_free_rd_amcache(relation); if (relation->rd_fdwroutine) pfree(relation->rd_fdwroutine); if (relation->rd_indexcxt) @@ -2547,9 +2544,7 @@ RelationClearRelation(Relation relation, bool rebuild) RelationCloseSmgr(relation); /* Free AM cached data, if any */ - if (relation->rd_amcache) - pfree(relation->rd_amcache); - relation->rd_amcache = NULL; + table_free_rd_amcache(relation); /* * Treat nailed-in system relations separately, they always need to be diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index 8249b37bbf..fd474b7488 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -708,6 +708,14 @@ typedef struct TableAmRoutine * ------------------------------------------------------------------------ */ + /* + * This callback frees relation private cache data stored in rd_amcache. + * After the call all memory related to rd_amcache must be freed, + * rd_amcache must be set to NULL. If this callback is not provided, + * rd_amcache is assumed to point to a single memory chunk. + */ + void (*free_rd_amcache) (Relation rel); + /* * See table_relation_size(). * @@ -1847,6 +1855,32 @@ table_index_validate_scan(Relation table_rel, * ---------------------------------------------------------------------------- */ +/* + * Frees relation private cache data stored in rd_amcache. Uses + * free_rd_amcache method if provided. Assumes rd_amcache to point to single + * memory chunk otherwise. + */ +static inline void +table_free_rd_amcache(Relation rel) +{ + if (rel->rd_tableam && rel->rd_tableam->free_rd_amcache) + { + rel->rd_tableam->free_rd_amcache(rel); + + /* + * We are assuming free_rd_amcache() did clear the cache and left NULL + * in rd_amcache. + */ + Assert(rel->rd_amcache == NULL); + } + else + { + if (rel->rd_amcache) + pfree(rel->rd_amcache); + rel->rd_amcache = NULL; + } +} + /* * Return the current size of `rel` in bytes. If `forkNumber` is * InvalidForkNumber, return the relation's overall size, otherwise the size diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 8700204953..f25f769af2 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -221,10 +221,12 @@ typedef struct RelationData * rd_amcache is available for index and table AMs to cache private data * about the relation. This must be just a cache since it may get reset * at any time (in particular, it will get reset by a relcache inval - * message for the relation). If used, it must point to a single memory - * chunk palloc'd in CacheMemoryContext, or in rd_indexcxt for an index - * relation. A relcache reset will include freeing that chunk and setting - * rd_amcache = NULL. + * message for the relation). If used for table AM it must point to a + * single memory chunk palloc'd in CacheMemoryContext, or more complex + * data structure in that memory context to be freed by free_rd_amcache + * method. If used for index AM it must point to a single memory chunk + * palloc'd in rd_indexcxt memory context. A relcache reset will include + * freeing that chunk and setting rd_amcache = NULL. */ void *rd_amcache; /* available for use by index/table AM */