LCOV - differential code coverage report
Current view: top level - src/test/modules/test_tidstore - test_tidstore.c (source / functions) Coverage Total Hit UNC GNC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 93.9 % 115 108 7 108
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 13 13 13
Baseline: 16@8cea358b128 Branches: 62.1 % 66 41 25 41
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 93.9 % 115 108 7 108
Function coverage date bins:
[..60] days: 100.0 % 13 13 13
Branch coverage date bins:
[..60] days: 62.1 % 66 41 25 41

 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, 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 "funcapi.h"
                                 22                 :                : #include "storage/block.h"
                                 23                 :                : #include "storage/itemptr.h"
                                 24                 :                : #include "storage/lwlock.h"
                                 25                 :                : #include "utils/array.h"
                                 26                 :                : #include "utils/memutils.h"
                                 27                 :                : 
   24 msawada@postgresql.o       28                 :GNC           1 : PG_MODULE_MAGIC;
                                 29                 :                : 
                                 30                 :              2 : PG_FUNCTION_INFO_V1(test_create);
                                 31                 :              2 : PG_FUNCTION_INFO_V1(do_set_block_offsets);
                                 32                 :              2 : PG_FUNCTION_INFO_V1(check_set_block_offsets);
                                 33                 :              2 : PG_FUNCTION_INFO_V1(test_is_full);
                                 34                 :              2 : PG_FUNCTION_INFO_V1(test_destroy);
                                 35                 :                : 
                                 36                 :                : static TidStore *tidstore = NULL;
                                 37                 :                : static size_t tidstore_empty_size;
                                 38                 :                : 
                                 39                 :                : /* array for verification of some tests */
                                 40                 :                : typedef struct ItemArray
                                 41                 :                : {
                                 42                 :                :     ItemPointerData *insert_tids;
                                 43                 :                :     ItemPointerData *lookup_tids;
                                 44                 :                :     ItemPointerData *iter_tids;
                                 45                 :                :     int         max_tids;
                                 46                 :                :     int         num_tids;
                                 47                 :                : } ItemArray;
                                 48                 :                : 
                                 49                 :                : static ItemArray items;
                                 50                 :                : 
                                 51                 :                : /* comparator routine for ItemPointer */
                                 52                 :                : static int
                                 53                 :         208070 : itemptr_cmp(const void *left, const void *right)
                                 54                 :                : {
                                 55                 :                :     BlockNumber lblk,
                                 56                 :                :                 rblk;
                                 57                 :                :     OffsetNumber loff,
                                 58                 :                :                 roff;
                                 59                 :                : 
                                 60                 :         208070 :     lblk = ItemPointerGetBlockNumber((ItemPointer) left);
                                 61                 :         208070 :     rblk = ItemPointerGetBlockNumber((ItemPointer) right);
                                 62                 :                : 
                                 63         [ +  + ]:         208070 :     if (lblk < rblk)
                                 64                 :          64084 :         return -1;
                                 65         [ +  + ]:         143986 :     if (lblk > rblk)
                                 66                 :          64510 :         return 1;
                                 67                 :                : 
                                 68                 :          79476 :     loff = ItemPointerGetOffsetNumber((ItemPointer) left);
                                 69                 :          79476 :     roff = ItemPointerGetOffsetNumber((ItemPointer) right);
                                 70                 :                : 
                                 71         [ +  + ]:          79476 :     if (loff < roff)
                                 72                 :          35130 :         return -1;
                                 73         [ +  + ]:          44346 :     if (loff > roff)
                                 74                 :          13842 :         return 1;
                                 75                 :                : 
                                 76                 :          30504 :     return 0;
                                 77                 :                : }
                                 78                 :                : 
                                 79                 :                : /*
                                 80                 :                :  * Create a TidStore. If shared is false, the tidstore is created
                                 81                 :                :  * on TopMemoryContext, otherwise on DSA. Although the tidstore
                                 82                 :                :  * is created on DSA, only the same process can subsequently use
                                 83                 :                :  * the tidstore. The tidstore handle is not shared anywhere.
                                 84                 :                : */
                                 85                 :                : Datum
                                 86                 :              2 : test_create(PG_FUNCTION_ARGS)
                                 87                 :                : {
                                 88                 :              2 :     bool        shared = PG_GETARG_BOOL(0);
                                 89                 :                :     MemoryContext old_ctx;
                                 90                 :                : 
                                 91                 :                :     /* doesn't really matter, since it's just a hint */
                                 92                 :              2 :     size_t      tidstore_max_size = 2 * 1024 * 1024;
                                 93                 :              2 :     size_t      array_init_size = 1024;
                                 94                 :                : 
                                 95         [ -  + ]:              2 :     Assert(tidstore == NULL);
                                 96                 :                : 
                                 97                 :                :     /*
                                 98                 :                :      * Create the TidStore on TopMemoryContext so that the same process use it
                                 99                 :                :      * for subsequent tests.
                                100                 :                :      */
                                101                 :              2 :     old_ctx = MemoryContextSwitchTo(TopMemoryContext);
                                102                 :                : 
                                103         [ +  + ]:              2 :     if (shared)
                                104                 :                :     {
                                105                 :                :         int         tranche_id;
                                106                 :                : 
                                107                 :              1 :         tranche_id = LWLockNewTrancheId();
                                108                 :              1 :         LWLockRegisterTranche(tranche_id, "test_tidstore");
                                109                 :                : 
   17                           110                 :              1 :         tidstore = TidStoreCreateShared(tidstore_max_size, tranche_id);
                                111                 :                : 
                                112                 :                :         /*
                                113                 :                :          * Remain attached until end of backend or explicitly detached so that
                                114                 :                :          * the same process use the tidstore for subsequent tests.
                                115                 :                :          */
                                116                 :              1 :         dsa_pin_mapping(TidStoreGetDSA(tidstore));
                                117                 :                :     }
                                118                 :                :     else
                                119                 :                :         /* VACUUM uses insert only, so we test the other option. */
    7 john.naylor@postgres      120                 :              1 :         tidstore = TidStoreCreateLocal(tidstore_max_size, false);
                                121                 :                : 
   24 msawada@postgresql.o      122                 :              2 :     tidstore_empty_size = TidStoreMemoryUsage(tidstore);
                                123                 :                : 
                                124                 :              2 :     items.num_tids = 0;
                                125                 :              2 :     items.max_tids = array_init_size / sizeof(ItemPointerData);
                                126                 :              2 :     items.insert_tids = (ItemPointerData *) palloc0(array_init_size);
                                127                 :              2 :     items.lookup_tids = (ItemPointerData *) palloc0(array_init_size);
                                128                 :              2 :     items.iter_tids = (ItemPointerData *) palloc0(array_init_size);
                                129                 :                : 
                                130                 :              2 :     MemoryContextSwitchTo(old_ctx);
                                131                 :                : 
                                132                 :              2 :     PG_RETURN_VOID();
                                133                 :                : }
                                134                 :                : 
                                135                 :                : static void
                                136                 :           1112 : sanity_check_array(ArrayType *ta)
                                137                 :                : {
                                138   [ -  +  -  - ]:           1112 :     if (ARR_HASNULL(ta) && array_contains_nulls(ta))
   24 msawada@postgresql.o      139         [ #  # ]:UNC           0 :         ereport(ERROR,
                                140                 :                :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                                141                 :                :                  errmsg("array must not contain nulls")));
                                142                 :                : 
   24 msawada@postgresql.o      143         [ -  + ]:GNC        1112 :     if (ARR_NDIM(ta) > 1)
   24 msawada@postgresql.o      144         [ #  # ]:UNC           0 :         ereport(ERROR,
                                145                 :                :                 (errcode(ERRCODE_DATA_EXCEPTION),
                                146                 :                :                  errmsg("argument must be empty or one-dimensional array")));
   24 msawada@postgresql.o      147                 :GNC        1112 : }
                                148                 :                : 
                                149                 :                : /* Set the given block and offsets pairs */
                                150                 :                : Datum
                                151                 :           1112 : do_set_block_offsets(PG_FUNCTION_ARGS)
                                152                 :                : {
                                153                 :           1112 :     BlockNumber blkno = PG_GETARG_INT64(0);
                                154                 :           1112 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P_COPY(1);
                                155                 :                :     OffsetNumber *offs;
                                156                 :                :     int         noffs;
                                157                 :                : 
                                158                 :           1112 :     sanity_check_array(ta);
                                159                 :                : 
                                160                 :           1112 :     noffs = ArrayGetNItems(ARR_NDIM(ta), ARR_DIMS(ta));
                                161         [ -  + ]:           1112 :     offs = ((OffsetNumber *) ARR_DATA_PTR(ta));
                                162                 :                : 
                                163                 :                :     /* Set TIDs in the store */
                                164                 :           1112 :     TidStoreLockExclusive(tidstore);
                                165                 :           1112 :     TidStoreSetBlockOffsets(tidstore, blkno, offs, noffs);
                                166                 :           1111 :     TidStoreUnlock(tidstore);
                                167                 :                : 
                                168                 :                :     /* Set TIDs in verification array */
                                169         [ +  + ]:          16363 :     for (int i = 0; i < noffs; i++)
                                170                 :                :     {
                                171                 :                :         ItemPointer tid;
                                172                 :          15252 :         int         idx = items.num_tids + i;
                                173                 :                : 
                                174                 :                :         /* Enlarge the TID arrays if necessary */
                                175         [ +  + ]:          15252 :         if (idx >= items.max_tids)
                                176                 :                :         {
                                177                 :             12 :             items.max_tids *= 2;
                                178                 :             12 :             items.insert_tids = repalloc(items.insert_tids, sizeof(ItemPointerData) * items.max_tids);
                                179                 :             12 :             items.lookup_tids = repalloc(items.lookup_tids, sizeof(ItemPointerData) * items.max_tids);
                                180                 :             12 :             items.iter_tids = repalloc(items.iter_tids, sizeof(ItemPointerData) * items.max_tids);
                                181                 :                :         }
                                182                 :                : 
                                183                 :          15252 :         tid = &(items.insert_tids[idx]);
                                184                 :          15252 :         ItemPointerSet(tid, blkno, offs[i]);
                                185                 :                :     }
                                186                 :                : 
                                187                 :                :     /* Update statistics */
                                188                 :           1111 :     items.num_tids += noffs;
                                189                 :                : 
                                190                 :           1111 :     PG_RETURN_INT64(blkno);
                                191                 :                : }
                                192                 :                : 
                                193                 :                : /*
                                194                 :                :  * Verify TIDs in store against the array.
                                195                 :                :  */
                                196                 :                : Datum
                                197                 :              3 : check_set_block_offsets(PG_FUNCTION_ARGS)
                                198                 :                : {
                                199                 :                :     TidStoreIter *iter;
                                200                 :                :     TidStoreIterResult *iter_result;
                                201                 :              3 :     int         num_iter_tids = 0;
                                202                 :              3 :     int         num_lookup_tids = 0;
   16 dgustafsson@postgres      203                 :              3 :     BlockNumber prevblkno = 0;
                                204                 :                : 
                                205                 :                :     /* lookup each member in the verification array */
   24 msawada@postgresql.o      206         [ +  + ]:          15255 :     for (int i = 0; i < items.num_tids; i++)
                                207         [ -  + ]:          15252 :         if (!TidStoreIsMember(tidstore, &items.insert_tids[i]))
   24 msawada@postgresql.o      208         [ #  # ]:UNC           0 :             elog(ERROR, "missing TID with block %u, offset %u",
                                209                 :                :                  ItemPointerGetBlockNumber(&items.insert_tids[i]),
                                210                 :                :                  ItemPointerGetOffsetNumber(&items.insert_tids[i]));
                                211                 :                : 
                                212                 :                :     /*
                                213                 :                :      * Lookup all possible TIDs for each distinct block in the verification
                                214                 :                :      * array and save successful lookups in the lookup array.
                                215                 :                :      */
                                216                 :                : 
   24 msawada@postgresql.o      217         [ +  + ]:GNC       15255 :     for (int i = 0; i < items.num_tids; i++)
                                218                 :                :     {
                                219                 :          15252 :         BlockNumber blkno = ItemPointerGetBlockNumber(&items.insert_tids[i]);
                                220                 :                : 
                                221   [ +  +  +  + ]:          15252 :         if (i > 0 && blkno == prevblkno)
                                222                 :          14141 :             continue;
                                223                 :                : 
                                224         [ +  + ]:        2275328 :         for (OffsetNumber offset = FirstOffsetNumber; offset < MaxOffsetNumber; offset++)
                                225                 :                :         {
                                226                 :                :             ItemPointerData tid;
                                227                 :                : 
                                228                 :        2274217 :             ItemPointerSet(&tid, blkno, offset);
                                229                 :                : 
                                230                 :        2274217 :             TidStoreLockShare(tidstore);
                                231         [ +  + ]:        2274217 :             if (TidStoreIsMember(tidstore, &tid))
                                232                 :          15252 :                 ItemPointerSet(&items.lookup_tids[num_lookup_tids++], blkno, offset);
                                233                 :        2274217 :             TidStoreUnlock(tidstore);
                                234                 :                :         }
                                235                 :                : 
                                236                 :           1111 :         prevblkno = blkno;
                                237                 :                :     }
                                238                 :                : 
                                239                 :                :     /* Collect TIDs stored in the tidstore, in order */
                                240                 :                : 
                                241                 :              3 :     TidStoreLockShare(tidstore);
                                242                 :              3 :     iter = TidStoreBeginIterate(tidstore);
                                243         [ +  + ]:           1114 :     while ((iter_result = TidStoreIterateNext(iter)) != NULL)
                                244                 :                :     {
                                245         [ +  + ]:          16363 :         for (int i = 0; i < iter_result->num_offsets; i++)
                                246                 :          15252 :             ItemPointerSet(&(items.iter_tids[num_iter_tids++]), iter_result->blkno,
                                247                 :          15252 :                            iter_result->offsets[i]);
                                248                 :                :     }
                                249                 :              3 :     TidStoreEndIterate(iter);
                                250                 :              3 :     TidStoreUnlock(tidstore);
                                251                 :                : 
                                252                 :                :     /*
                                253                 :                :      * Sort verification and lookup arrays and test that all arrays are the
                                254                 :                :      * same.
                                255                 :                :      */
                                256                 :                : 
                                257         [ -  + ]:              3 :     if (num_lookup_tids != items.num_tids)
   24 msawada@postgresql.o      258         [ #  # ]:UNC           0 :         elog(ERROR, "should have %d TIDs, have %d", items.num_tids, num_lookup_tids);
   24 msawada@postgresql.o      259         [ -  + ]:GNC           3 :     if (num_iter_tids != items.num_tids)
   24 msawada@postgresql.o      260         [ #  # ]:UNC           0 :         elog(ERROR, "should have %d TIDs, have %d", items.num_tids, num_iter_tids);
                                261                 :                : 
   24 msawada@postgresql.o      262                 :GNC           3 :     qsort(items.insert_tids, items.num_tids, sizeof(ItemPointerData), itemptr_cmp);
                                263                 :              3 :     qsort(items.lookup_tids, items.num_tids, sizeof(ItemPointerData), itemptr_cmp);
                                264         [ +  + ]:          15255 :     for (int i = 0; i < items.num_tids; i++)
                                265                 :                :     {
                                266         [ -  + ]:          15252 :         if (itemptr_cmp((const void *) &items.insert_tids[i], (const void *) &items.iter_tids[i]) != 0)
   24 msawada@postgresql.o      267         [ #  # ]:UNC           0 :             elog(ERROR, "TID iter array doesn't match verification array, got (%u,%u) expected (%u,%u)",
                                268                 :                :                  ItemPointerGetBlockNumber(&items.iter_tids[i]),
                                269                 :                :                  ItemPointerGetOffsetNumber(&items.iter_tids[i]),
                                270                 :                :                  ItemPointerGetBlockNumber(&items.insert_tids[i]),
                                271                 :                :                  ItemPointerGetOffsetNumber(&items.insert_tids[i]));
   24 msawada@postgresql.o      272         [ -  + ]:GNC       15252 :         if (itemptr_cmp((const void *) &items.insert_tids[i], (const void *) &items.lookup_tids[i]) != 0)
   24 msawada@postgresql.o      273         [ #  # ]:UNC           0 :             elog(ERROR, "TID lookup array doesn't match verification array, got (%u,%u) expected (%u,%u)",
                                274                 :                :                  ItemPointerGetBlockNumber(&items.lookup_tids[i]),
                                275                 :                :                  ItemPointerGetOffsetNumber(&items.lookup_tids[i]),
                                276                 :                :                  ItemPointerGetBlockNumber(&items.insert_tids[i]),
                                277                 :                :                  ItemPointerGetOffsetNumber(&items.insert_tids[i]));
                                278                 :                :     }
                                279                 :                : 
   24 msawada@postgresql.o      280                 :GNC           3 :     PG_RETURN_VOID();
                                281                 :                : }
                                282                 :                : 
                                283                 :                : /*
                                284                 :                :  * In real world use, we care if the memory usage is greater than
                                285                 :                :  * some configured limit. Here we just want to verify that
                                286                 :                :  * TidStoreMemoryUsage is not broken.
                                287                 :                :  */
                                288                 :                : Datum
                                289                 :              2 : test_is_full(PG_FUNCTION_ARGS)
                                290                 :                : {
                                291                 :                :     bool        is_full;
                                292                 :                : 
                                293                 :              2 :     is_full = (TidStoreMemoryUsage(tidstore) > tidstore_empty_size);
                                294                 :                : 
                                295                 :              2 :     PG_RETURN_BOOL(is_full);
                                296                 :                : }
                                297                 :                : 
                                298                 :                : /* Free the tidstore */
                                299                 :                : Datum
                                300                 :              2 : test_destroy(PG_FUNCTION_ARGS)
                                301                 :                : {
                                302                 :              2 :     TidStoreDestroy(tidstore);
                                303                 :              2 :     tidstore = NULL;
                                304                 :              2 :     items.num_tids = 0;
                                305                 :              2 :     pfree(items.insert_tids);
                                306                 :              2 :     pfree(items.lookup_tids);
                                307                 :              2 :     pfree(items.iter_tids);
                                308                 :                : 
                                309                 :              2 :     PG_RETURN_VOID();
                                310                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622