LCOV - differential code coverage report
Current view: top level - src/test/modules/test_tidstore - test_tidstore.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 93.9 % 132 124 8 1 123 2
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 15 15 1 14
Baseline: lcov-20250906-005545-baseline Branches: 61.8 % 76 47 29 47
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 100.0 % 1 1 1
(30,360] days: 100.0 % 2 2 2
(360..) days: 93.8 % 129 121 8 121
Function coverage date bins:
(360..) days: 100.0 % 15 15 1 14
Branch coverage date bins:
(30,360] days: 50.0 % 4 2 2 2
(360..) days: 62.5 % 72 45 27 45

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*--------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * test_tidstore.c
                                  4                 :                :  *      Test TidStore data structure.
                                  5                 :                :  *
                                  6                 :                :  * Note: all locking in this test module is useless since there is only
                                  7                 :                :  * a single process to use the TidStore. It is meant to be an example of
                                  8                 :                :  * usage.
                                  9                 :                :  *
                                 10                 :                :  * Copyright (c) 2024-2025, PostgreSQL Global Development Group
                                 11                 :                :  *
                                 12                 :                :  * IDENTIFICATION
                                 13                 :                :  *      src/test/modules/test_tidstore/test_tidstore.c
                                 14                 :                :  *
                                 15                 :                :  * -------------------------------------------------------------------------
                                 16                 :                :  */
                                 17                 :                : #include "postgres.h"
                                 18                 :                : 
                                 19                 :                : #include "access/tidstore.h"
                                 20                 :                : #include "fmgr.h"
                                 21                 :                : #include "storage/block.h"
                                 22                 :                : #include "storage/itemptr.h"
                                 23                 :                : #include "storage/lwlock.h"
                                 24                 :                : #include "utils/array.h"
                                 25                 :                : #include "utils/memutils.h"
                                 26                 :                : 
  534 msawada@postgresql.o       27                 :CBC           1 : PG_MODULE_MAGIC;
                                 28                 :                : 
                                 29                 :              2 : PG_FUNCTION_INFO_V1(test_create);
                                 30                 :              2 : PG_FUNCTION_INFO_V1(do_set_block_offsets);
                                 31                 :              2 : PG_FUNCTION_INFO_V1(check_set_block_offsets);
                                 32                 :              2 : PG_FUNCTION_INFO_V1(test_is_full);
                                 33                 :              2 : PG_FUNCTION_INFO_V1(test_destroy);
                                 34                 :                : 
                                 35                 :                : static TidStore *tidstore = NULL;
                                 36                 :                : static size_t tidstore_empty_size;
                                 37                 :                : 
                                 38                 :                : /* array for verification of some tests */
                                 39                 :                : typedef struct ItemArray
                                 40                 :                : {
                                 41                 :                :     ItemPointerData *insert_tids;
                                 42                 :                :     ItemPointerData *lookup_tids;
                                 43                 :                :     ItemPointerData *iter_tids;
                                 44                 :                :     int         max_tids;
                                 45                 :                :     int         num_tids;
                                 46                 :                : } ItemArray;
                                 47                 :                : 
                                 48                 :                : static ItemArray items;
                                 49                 :                : 
                                 50                 :                : /* comparator routine for ItemPointer */
                                 51                 :                : static int
                                 52                 :         208030 : itemptr_cmp(const void *left, const void *right)
                                 53                 :                : {
                                 54                 :                :     BlockNumber lblk,
                                 55                 :                :                 rblk;
                                 56                 :                :     OffsetNumber loff,
                                 57                 :                :                 roff;
                                 58                 :                : 
                                 59                 :         208030 :     lblk = ItemPointerGetBlockNumber((ItemPointer) left);
                                 60                 :         208030 :     rblk = ItemPointerGetBlockNumber((ItemPointer) right);
                                 61                 :                : 
                                 62         [ +  + ]:         208030 :     if (lblk < rblk)
                                 63                 :          64026 :         return -1;
                                 64         [ +  + ]:         144004 :     if (lblk > rblk)
                                 65                 :          64680 :         return 1;
                                 66                 :                : 
                                 67                 :          79324 :     loff = ItemPointerGetOffsetNumber((ItemPointer) left);
                                 68                 :          79324 :     roff = ItemPointerGetOffsetNumber((ItemPointer) right);
                                 69                 :                : 
                                 70         [ +  + ]:          79324 :     if (loff < roff)
                                 71                 :          35152 :         return -1;
                                 72         [ +  + ]:          44172 :     if (loff > roff)
                                 73                 :          13686 :         return 1;
                                 74                 :                : 
                                 75                 :          30486 :     return 0;
                                 76                 :                : }
                                 77                 :                : 
                                 78                 :                : /*
                                 79                 :                :  * Create a TidStore. If shared is false, the tidstore is created
                                 80                 :                :  * on TopMemoryContext, otherwise on DSA. Although the tidstore
                                 81                 :                :  * is created on DSA, only the same process can subsequently use
                                 82                 :                :  * the tidstore. The tidstore handle is not shared anywhere.
                                 83                 :                : */
                                 84                 :                : Datum
                                 85                 :              3 : test_create(PG_FUNCTION_ARGS)
                                 86                 :                : {
                                 87                 :              3 :     bool        shared = PG_GETARG_BOOL(0);
                                 88                 :                :     MemoryContext old_ctx;
                                 89                 :                : 
                                 90                 :                :     /* doesn't really matter, since it's just a hint */
                                 91                 :              3 :     size_t      tidstore_max_size = 2 * 1024 * 1024;
                                 92                 :              3 :     size_t      array_init_size = 1024;
                                 93                 :                : 
                                 94         [ -  + ]:              3 :     Assert(tidstore == NULL);
                                 95                 :                : 
                                 96                 :                :     /*
                                 97                 :                :      * Create the TidStore on TopMemoryContext so that the same process use it
                                 98                 :                :      * for subsequent tests.
                                 99                 :                :      */
                                100                 :              3 :     old_ctx = MemoryContextSwitchTo(TopMemoryContext);
                                101                 :                : 
                                102         [ +  + ]:              3 :     if (shared)
                                103                 :                :     {
                                104                 :                :         int         tranche_id;
                                105                 :                : 
    3 nathan@postgresql.or      106                 :GNC           1 :         tranche_id = LWLockNewTrancheId("test_tidstore");
                                107                 :                : 
  527 msawada@postgresql.o      108                 :CBC           1 :         tidstore = TidStoreCreateShared(tidstore_max_size, tranche_id);
                                109                 :                : 
                                110                 :                :         /*
                                111                 :                :          * Remain attached until end of backend or explicitly detached so that
                                112                 :                :          * the same process use the tidstore for subsequent tests.
                                113                 :                :          */
                                114                 :              1 :         dsa_pin_mapping(TidStoreGetDSA(tidstore));
                                115                 :                :     }
                                116                 :                :     else
                                117                 :                :         /* VACUUM uses insert only, so we test the other option. */
  517 john.naylor@postgres      118                 :              2 :         tidstore = TidStoreCreateLocal(tidstore_max_size, false);
                                119                 :                : 
  534 msawada@postgresql.o      120                 :              3 :     tidstore_empty_size = TidStoreMemoryUsage(tidstore);
                                121                 :                : 
                                122                 :              3 :     items.num_tids = 0;
                                123                 :              3 :     items.max_tids = array_init_size / sizeof(ItemPointerData);
                                124                 :              3 :     items.insert_tids = (ItemPointerData *) palloc0(array_init_size);
                                125                 :              3 :     items.lookup_tids = (ItemPointerData *) palloc0(array_init_size);
                                126                 :              3 :     items.iter_tids = (ItemPointerData *) palloc0(array_init_size);
                                127                 :                : 
                                128                 :              3 :     MemoryContextSwitchTo(old_ctx);
                                129                 :                : 
                                130                 :              3 :     PG_RETURN_VOID();
                                131                 :                : }
                                132                 :                : 
                                133                 :                : static void
                                134                 :           1121 : sanity_check_array(ArrayType *ta)
                                135                 :                : {
                                136   [ -  +  -  - ]:           1121 :     if (ARR_HASNULL(ta) && array_contains_nulls(ta))
  534 msawada@postgresql.o      137         [ #  # ]:UBC           0 :         ereport(ERROR,
                                138                 :                :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                                139                 :                :                  errmsg("array must not contain nulls")));
                                140                 :                : 
  534 msawada@postgresql.o      141         [ -  + ]:CBC        1121 :     if (ARR_NDIM(ta) > 1)
  534 msawada@postgresql.o      142         [ #  # ]:UBC           0 :         ereport(ERROR,
                                143                 :                :                 (errcode(ERRCODE_DATA_EXCEPTION),
                                144                 :                :                  errmsg("argument must be empty or one-dimensional array")));
  534 msawada@postgresql.o      145                 :CBC        1121 : }
                                146                 :                : 
                                147                 :                : static void
  451                           148                 :           1138 : check_tidstore_available(void)
                                149                 :                : {
                                150         [ -  + ]:           1138 :     if (tidstore == NULL)
  451 msawada@postgresql.o      151         [ #  # ]:UBC           0 :         elog(ERROR, "tidstore is not created");
  451 msawada@postgresql.o      152                 :CBC        1138 : }
                                153                 :                : 
                                154                 :                : static void
  499                           155                 :           1120 : purge_from_verification_array(BlockNumber blkno)
                                156                 :                : {
                                157                 :           1120 :     int         dst = 0;
                                158                 :                : 
                                159         [ +  + ]:        3491493 :     for (int src = 0; src < items.num_tids; src++)
                                160         [ +  + ]:        3490373 :         if (ItemPointerGetBlockNumber(&items.insert_tids[src]) != blkno)
                                161                 :        3490349 :             items.insert_tids[dst++] = items.insert_tids[src];
                                162                 :           1120 :     items.num_tids = dst;
                                163                 :           1120 : }
                                164                 :                : 
                                165                 :                : 
                                166                 :                : /* Set the given block and offsets pairs */
                                167                 :                : Datum
  534                           168                 :           1121 : do_set_block_offsets(PG_FUNCTION_ARGS)
                                169                 :                : {
                                170                 :           1121 :     BlockNumber blkno = PG_GETARG_INT64(0);
                                171                 :           1121 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P_COPY(1);
                                172                 :                :     OffsetNumber *offs;
                                173                 :                :     int         noffs;
                                174                 :                : 
  451                           175                 :           1121 :     check_tidstore_available();
  534                           176                 :           1121 :     sanity_check_array(ta);
                                177                 :                : 
                                178                 :           1121 :     noffs = ArrayGetNItems(ARR_NDIM(ta), ARR_DIMS(ta));
                                179         [ -  + ]:           1121 :     offs = ((OffsetNumber *) ARR_DATA_PTR(ta));
                                180                 :                : 
                                181                 :                :     /* Set TIDs in the store */
                                182                 :           1121 :     TidStoreLockExclusive(tidstore);
                                183                 :           1121 :     TidStoreSetBlockOffsets(tidstore, blkno, offs, noffs);
                                184                 :           1120 :     TidStoreUnlock(tidstore);
                                185                 :                : 
                                186                 :                :     /* Remove the existing items of blkno from the verification array */
  499                           187                 :           1120 :     purge_from_verification_array(blkno);
                                188                 :                : 
                                189                 :                :     /* Set TIDs in verification array */
  534                           190         [ +  + ]:          16363 :     for (int i = 0; i < noffs; i++)
                                191                 :                :     {
                                192                 :                :         ItemPointer tid;
                                193                 :          15243 :         int         idx = items.num_tids + i;
                                194                 :                : 
                                195                 :                :         /* Enlarge the TID arrays if necessary */
                                196         [ +  + ]:          15243 :         if (idx >= items.max_tids)
                                197                 :                :         {
                                198                 :             12 :             items.max_tids *= 2;
                                199                 :             12 :             items.insert_tids = repalloc(items.insert_tids, sizeof(ItemPointerData) * items.max_tids);
                                200                 :             12 :             items.lookup_tids = repalloc(items.lookup_tids, sizeof(ItemPointerData) * items.max_tids);
                                201                 :             12 :             items.iter_tids = repalloc(items.iter_tids, sizeof(ItemPointerData) * items.max_tids);
                                202                 :                :         }
                                203                 :                : 
                                204                 :          15243 :         tid = &(items.insert_tids[idx]);
                                205                 :          15243 :         ItemPointerSet(tid, blkno, offs[i]);
                                206                 :                :     }
                                207                 :                : 
                                208                 :                :     /* Update statistics */
                                209                 :           1120 :     items.num_tids += noffs;
                                210                 :                : 
                                211                 :           1120 :     PG_RETURN_INT64(blkno);
                                212                 :                : }
                                213                 :                : 
                                214                 :                : /*
                                215                 :                :  * Verify TIDs in store against the array.
                                216                 :                :  */
                                217                 :                : Datum
                                218                 :             12 : check_set_block_offsets(PG_FUNCTION_ARGS)
                                219                 :                : {
                                220                 :                :     TidStoreIter *iter;
                                221                 :                :     TidStoreIterResult *iter_result;
                                222                 :             12 :     int         num_iter_tids = 0;
                                223                 :             12 :     int         num_lookup_tids = 0;
  526 dgustafsson@postgres      224                 :             12 :     BlockNumber prevblkno = 0;
                                225                 :                : 
  451 msawada@postgresql.o      226                 :             12 :     check_tidstore_available();
                                227                 :                : 
                                228                 :                :     /* lookup each member in the verification array */
  534                           229         [ +  + ]:          15255 :     for (int i = 0; i < items.num_tids; i++)
                                230         [ -  + ]:          15243 :         if (!TidStoreIsMember(tidstore, &items.insert_tids[i]))
  534 msawada@postgresql.o      231         [ #  # ]:UBC           0 :             elog(ERROR, "missing TID with block %u, offset %u",
                                232                 :                :                  ItemPointerGetBlockNumber(&items.insert_tids[i]),
                                233                 :                :                  ItemPointerGetOffsetNumber(&items.insert_tids[i]));
                                234                 :                : 
                                235                 :                :     /*
                                236                 :                :      * Lookup all possible TIDs for each distinct block in the verification
                                237                 :                :      * array and save successful lookups in the lookup array.
                                238                 :                :      */
                                239                 :                : 
  534 msawada@postgresql.o      240         [ +  + ]:CBC       15255 :     for (int i = 0; i < items.num_tids; i++)
                                241                 :                :     {
                                242                 :          15243 :         BlockNumber blkno = ItemPointerGetBlockNumber(&items.insert_tids[i]);
                                243                 :                : 
                                244   [ +  +  +  + ]:          15243 :         if (i > 0 && blkno == prevblkno)
                                245                 :          14123 :             continue;
                                246                 :                : 
                                247         [ +  + ]:        2293760 :         for (OffsetNumber offset = FirstOffsetNumber; offset < MaxOffsetNumber; offset++)
                                248                 :                :         {
                                249                 :                :             ItemPointerData tid;
                                250                 :                : 
                                251                 :        2292640 :             ItemPointerSet(&tid, blkno, offset);
                                252                 :                : 
                                253                 :        2292640 :             TidStoreLockShare(tidstore);
                                254         [ +  + ]:        2292640 :             if (TidStoreIsMember(tidstore, &tid))
                                255                 :          15243 :                 ItemPointerSet(&items.lookup_tids[num_lookup_tids++], blkno, offset);
                                256                 :        2292640 :             TidStoreUnlock(tidstore);
                                257                 :                :         }
                                258                 :                : 
                                259                 :           1120 :         prevblkno = blkno;
                                260                 :                :     }
                                261                 :                : 
                                262                 :                :     /* Collect TIDs stored in the tidstore, in order */
                                263                 :                : 
                                264                 :             12 :     TidStoreLockShare(tidstore);
                                265                 :             12 :     iter = TidStoreBeginIterate(tidstore);
                                266         [ +  + ]:           1132 :     while ((iter_result = TidStoreIterateNext(iter)) != NULL)
                                267                 :                :     {
                                268                 :                :         OffsetNumber offsets[MaxOffsetNumber];
                                269                 :                :         int         num_offsets;
                                270                 :                : 
  409 tmunro@postgresql.or      271                 :           1120 :         num_offsets = TidStoreGetBlockOffsets(iter_result, offsets, lengthof(offsets));
                                272         [ -  + ]:           1120 :         Assert(num_offsets <= lengthof(offsets));
                                273         [ +  + ]:          16363 :         for (int i = 0; i < num_offsets; i++)
  534 msawada@postgresql.o      274                 :          15243 :             ItemPointerSet(&(items.iter_tids[num_iter_tids++]), iter_result->blkno,
  409 tmunro@postgresql.or      275                 :          15243 :                            offsets[i]);
                                276                 :                :     }
  534 msawada@postgresql.o      277                 :             12 :     TidStoreEndIterate(iter);
                                278                 :             12 :     TidStoreUnlock(tidstore);
                                279                 :                : 
                                280                 :                :     /*
                                281                 :                :      * Sort verification and lookup arrays and test that all arrays are the
                                282                 :                :      * same.
                                283                 :                :      */
                                284                 :                : 
                                285         [ -  + ]:             12 :     if (num_lookup_tids != items.num_tids)
  534 msawada@postgresql.o      286         [ #  # ]:UBC           0 :         elog(ERROR, "should have %d TIDs, have %d", items.num_tids, num_lookup_tids);
  534 msawada@postgresql.o      287         [ -  + ]:CBC          12 :     if (num_iter_tids != items.num_tids)
  534 msawada@postgresql.o      288         [ #  # ]:UBC           0 :         elog(ERROR, "should have %d TIDs, have %d", items.num_tids, num_iter_tids);
                                289                 :                : 
  534 msawada@postgresql.o      290                 :CBC          12 :     qsort(items.insert_tids, items.num_tids, sizeof(ItemPointerData), itemptr_cmp);
                                291                 :             12 :     qsort(items.lookup_tids, items.num_tids, sizeof(ItemPointerData), itemptr_cmp);
                                292         [ +  + ]:          15255 :     for (int i = 0; i < items.num_tids; i++)
                                293                 :                :     {
  274 peter@eisentraut.org      294         [ -  + ]:          15243 :         if (itemptr_cmp(&items.insert_tids[i], &items.iter_tids[i]) != 0)
  534 msawada@postgresql.o      295         [ #  # ]:UBC           0 :             elog(ERROR, "TID iter array doesn't match verification array, got (%u,%u) expected (%u,%u)",
                                296                 :                :                  ItemPointerGetBlockNumber(&items.iter_tids[i]),
                                297                 :                :                  ItemPointerGetOffsetNumber(&items.iter_tids[i]),
                                298                 :                :                  ItemPointerGetBlockNumber(&items.insert_tids[i]),
                                299                 :                :                  ItemPointerGetOffsetNumber(&items.insert_tids[i]));
  274 peter@eisentraut.org      300         [ -  + ]:CBC       15243 :         if (itemptr_cmp(&items.insert_tids[i], &items.lookup_tids[i]) != 0)
  534 msawada@postgresql.o      301         [ #  # ]:UBC           0 :             elog(ERROR, "TID lookup array doesn't match verification array, got (%u,%u) expected (%u,%u)",
                                302                 :                :                  ItemPointerGetBlockNumber(&items.lookup_tids[i]),
                                303                 :                :                  ItemPointerGetOffsetNumber(&items.lookup_tids[i]),
                                304                 :                :                  ItemPointerGetBlockNumber(&items.insert_tids[i]),
                                305                 :                :                  ItemPointerGetOffsetNumber(&items.insert_tids[i]));
                                306                 :                :     }
                                307                 :                : 
  534 msawada@postgresql.o      308                 :CBC          12 :     PG_RETURN_VOID();
                                309                 :                : }
                                310                 :                : 
                                311                 :                : /*
                                312                 :                :  * In real world use, we care if the memory usage is greater than
                                313                 :                :  * some configured limit. Here we just want to verify that
                                314                 :                :  * TidStoreMemoryUsage is not broken.
                                315                 :                :  */
                                316                 :                : Datum
                                317                 :              2 : test_is_full(PG_FUNCTION_ARGS)
                                318                 :                : {
                                319                 :                :     bool        is_full;
                                320                 :                : 
  451                           321                 :              2 :     check_tidstore_available();
                                322                 :                : 
  534                           323                 :              2 :     is_full = (TidStoreMemoryUsage(tidstore) > tidstore_empty_size);
                                324                 :                : 
                                325                 :              2 :     PG_RETURN_BOOL(is_full);
                                326                 :                : }
                                327                 :                : 
                                328                 :                : /* Free the tidstore */
                                329                 :                : Datum
                                330                 :              3 : test_destroy(PG_FUNCTION_ARGS)
                                331                 :                : {
  451                           332                 :              3 :     check_tidstore_available();
                                333                 :                : 
  534                           334                 :              3 :     TidStoreDestroy(tidstore);
                                335                 :              3 :     tidstore = NULL;
                                336                 :              3 :     items.num_tids = 0;
                                337                 :              3 :     pfree(items.insert_tids);
                                338                 :              3 :     pfree(items.lookup_tids);
                                339                 :              3 :     pfree(items.iter_tids);
                                340                 :                : 
                                341                 :              3 :     PG_RETURN_VOID();
                                342                 :                : }
        

Generated by: LCOV version 2.4-beta