Allow table AM to store complex data structures in rd_amcache
authorAlexander Korotkov <akorotkov@postgresql.org>
Thu, 21 Mar 2024 21:00:34 +0000 (23:00 +0200)
committerAlexander Korotkov <akorotkov@postgresql.org>
Thu, 21 Mar 2024 21:00:34 +0000 (23:00 +0200)
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
src/backend/utils/cache/relcache.c
src/include/access/tableam.h
src/include/utils/rel.h

index 680a50bf8b161bb37576efad4b962631a6d73f0e..4dd1341f606cb371ee6687f5098459017b9d08f5 100644 (file)
@@ -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,
index 2cd19d603fba7ce941e41f15d2fe231f62eca879..dcd18e462686c1581dcec4bb80ad9430420e502d 100644 (file)
@@ -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
index 8249b37bbf16266a4918a8787005395ce63beb2e..fd474b74883c6dcbc43daf0a4ef45af0176f0fe3 100644 (file)
@@ -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
index 87002049538a8990aa64a9814a4e3a88dd350eea..f25f769af2b2a0a7352dc957692d4a07874d59ba 100644 (file)
@@ -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 */