Use bump context for TID bitmaps stored by vacuum
authorJohn Naylor <[email protected]>
Sun, 7 Apr 2024 05:27:34 +0000 (12:27 +0700)
committerJohn Naylor <[email protected]>
Mon, 8 Apr 2024 07:39:49 +0000 (14:39 +0700)
Vacuum does not pfree individual entries, and only frees the entire
storage space when finished with it. This allows using a bump context,
eliminating the chunk header in each leaf allocation. Most leaf
allocations will be 16 to 32 bytes, so that's a significant savings.
TidStoreCreateLocal gets a boolean parameter to indicate that the
created store is insert-only.

This requires a separate tree context for iteration, since we free
the iteration state after iteration completes.

Discussion: https://postgr.es/m/CANWCAZac%3DpBePg3rhX8nXkUuaLoiAJJLtmnCfZsPEAS4EtJ%3Dkg%40mail.gmail.com
Discussion: https://postgr.es/m/CANWCAZZQFfxvzO8yZHFWtQV+Z2gAMv1ku16Vu7KWmb5kZQyd1w@mail.gmail.com

src/backend/access/common/tidstore.c
src/backend/access/heap/vacuumlazy.c
src/include/access/tidstore.h
src/include/lib/radixtree.h
src/test/modules/test_tidstore/test_tidstore.c

index 629390a1f88e02d912e12abeb39ff02ba4778cda..211d63941c2c3185d8f1f736cc09ffc1d29dfd9d 100644 (file)
@@ -120,7 +120,7 @@ static void tidstore_iter_extract_tids(TidStoreIter *iter, BlockNumber blkno,
  * by TidStoreMemoryUsage().
  */
 TidStore *
-TidStoreCreateLocal(size_t max_bytes)
+TidStoreCreateLocal(size_t max_bytes, bool insert_only)
 {
    TidStore   *ts;
    size_t      initBlockSize = ALLOCSET_DEFAULT_INITSIZE;
@@ -138,11 +138,22 @@ TidStoreCreateLocal(size_t max_bytes)
        maxBlockSize = ALLOCSET_DEFAULT_INITSIZE;
 
    /* Create a memory context for the TID storage */
-   ts->rt_context = AllocSetContextCreate(CurrentMemoryContext,
+   if (insert_only)
+   {
+       ts->rt_context = BumpContextCreate(CurrentMemoryContext,
                                           "TID storage",
                                           minContextSize,
                                           initBlockSize,
                                           maxBlockSize);
+   }
+   else
+   {
+       ts->rt_context = AllocSetContextCreate(CurrentMemoryContext,
+                                              "TID storage",
+                                              minContextSize,
+                                              initBlockSize,
+                                              maxBlockSize);
+   }
 
    ts->tree.local = local_ts_create(ts->rt_context);
 
index c3a9dc1ad6d855d036f0e66cf7e563457d796c2f..de109acc89ae400347eac5040f420ea091121a1e 100644 (file)
@@ -2874,7 +2874,7 @@ dead_items_alloc(LVRelState *vacrel, int nworkers)
    dead_items_info->num_items = 0;
    vacrel->dead_items_info = dead_items_info;
 
-   vacrel->dead_items = TidStoreCreateLocal(dead_items_info->max_bytes);
+   vacrel->dead_items = TidStoreCreateLocal(dead_items_info->max_bytes, true);
 }
 
 /*
@@ -2910,7 +2910,7 @@ dead_items_reset(LVRelState *vacrel)
 
    /* Recreate the tidstore with the same max_bytes limitation */
    TidStoreDestroy(dead_items);
-   vacrel->dead_items = TidStoreCreateLocal(vacrel->dead_items_info->max_bytes);
+   vacrel->dead_items = TidStoreCreateLocal(vacrel->dead_items_info->max_bytes, true);
 
    /* Reset the counter */
    vacrel->dead_items_info->num_items = 0;
index f05d7487837a757ba6e2f40a7eea6219d093bb32..32aa9995193fa54e26ea31afb1fa7f3d89aaf6be 100644 (file)
@@ -29,7 +29,7 @@ typedef struct TidStoreIterResult
    OffsetNumber *offsets;
 } TidStoreIterResult;
 
-extern TidStore *TidStoreCreateLocal(size_t max_bytes);
+extern TidStore *TidStoreCreateLocal(size_t max_bytes, bool insert_only);
 extern TidStore *TidStoreCreateShared(size_t max_bytes, int tranche_id);
 extern TidStore *TidStoreAttach(dsa_handle area_handle, dsa_pointer handle);
 extern void TidStoreDetach(TidStore *ts);
index 6f36e8bfde300e46208b992d8d237b63cf647d7a..6764b58b52a233a9c335f2e69ecc48f62fc49d8e 100644 (file)
@@ -691,6 +691,7 @@ struct RT_RADIX_TREE
    /* leaf_context is used only for single-value leaves */
    MemoryContextData *leaf_context;
 #endif
+   MemoryContextData *iter_context;
 };
 
 /*
@@ -1796,6 +1797,14 @@ RT_CREATE(MemoryContext ctx)
    tree = (RT_RADIX_TREE *) palloc0(sizeof(RT_RADIX_TREE));
    tree->context = ctx;
 
+   /*
+    * Separate context for iteration in case the tree context doesn't support
+    * pfree
+    */
+   tree->iter_context = AllocSetContextCreate(ctx,
+                                              RT_STR(RT_PREFIX) "radix_tree iter context",
+                                              ALLOCSET_SMALL_SIZES);
+
 #ifdef RT_SHMEM
    tree->dsa = dsa;
    dp = dsa_allocate0(dsa, sizeof(RT_RADIX_TREE_CONTROL));
@@ -2038,7 +2047,7 @@ RT_BEGIN_ITERATE(RT_RADIX_TREE * tree)
    RT_ITER    *iter;
    RT_CHILD_PTR root;
 
-   iter = (RT_ITER *) MemoryContextAllocZero(tree->context,
+   iter = (RT_ITER *) MemoryContextAllocZero(tree->iter_context,
                                              sizeof(RT_ITER));
    iter->tree = tree;
 
index 32c6c477b7256a96471230fda43d418d05a1afea..0a3a58722de8565c8fc93b5cbdfa7e02fa3ab5d0 100644 (file)
@@ -116,7 +116,8 @@ test_create(PG_FUNCTION_ARGS)
        dsa_pin_mapping(TidStoreGetDSA(tidstore));
    }
    else
-       tidstore = TidStoreCreateLocal(tidstore_max_size);
+       /* VACUUM uses insert only, so we test the other option. */
+       tidstore = TidStoreCreateLocal(tidstore_max_size, false);
 
    tidstore_empty_size = TidStoreMemoryUsage(tidstore);