LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginbulk.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: 806555e3000d0b0e0c536c1dc65548128d457d86 vs 1d325ad99cb2dec0e8b45ba36909ee0a497d2a57 Lines: 92.2 % 102 94 8 2 92 3
Current Date: 2025-12-17 08:58:58 +0900 Functions: 90.0 % 10 9 1 2 7
Baseline: lcov-20251217-005640-baseline Branches: 63.0 % 46 29 17 29
Baseline Date: 2025-12-16 12:57:12 -0800 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 100.0 % 2 2 2
(360..) days: 92.0 % 100 92 8 92
Function coverage date bins:
(360..) days: 90.0 % 10 9 1 2 7
Branch coverage date bins:
(360..) days: 63.0 % 46 29 17 29

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * ginbulk.c
                                  4                 :                :  *    routines for fast build of inverted index
                                  5                 :                :  *
                                  6                 :                :  *
                                  7                 :                :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
                                  8                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *          src/backend/access/gin/ginbulk.c
                                 12                 :                :  *-------------------------------------------------------------------------
                                 13                 :                :  */
                                 14                 :                : 
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include <limits.h>
                                 18                 :                : 
                                 19                 :                : #include "access/gin_private.h"
                                 20                 :                : #include "utils/datum.h"
                                 21                 :                : #include "utils/memutils.h"
                                 22                 :                : 
                                 23                 :                : 
                                 24                 :                : #define DEF_NENTRY  2048        /* GinEntryAccumulator allocation quantum */
                                 25                 :                : #define DEF_NPTR    5           /* ItemPointer initial allocation quantum */
                                 26                 :                : 
                                 27                 :                : 
                                 28                 :                : /* Combiner function for rbtree.c */
                                 29                 :                : static void
 2598 tgl@sss.pgh.pa.us          30                 :CBC     1248590 : ginCombineData(RBTNode *existing, const RBTNode *newdata, void *arg)
                                 31                 :                : {
 5458                            32                 :        1248590 :     GinEntryAccumulator *eo = (GinEntryAccumulator *) existing;
                                 33                 :        1248590 :     const GinEntryAccumulator *en = (const GinEntryAccumulator *) newdata;
 5773 bruce@momjian.us           34                 :        1248590 :     BuildAccumulator *accum = (BuildAccumulator *) arg;
                                 35                 :                : 
                                 36                 :                :     /*
                                 37                 :                :      * Note this code assumes that newdata contains only one itempointer.
                                 38                 :                :      */
 5458 tgl@sss.pgh.pa.us          39         [ +  + ]:        1248590 :     if (eo->count >= eo->maxcount)
                                 40                 :                :     {
 3759 teodor@sigaev.ru           41         [ -  + ]:          44256 :         if (eo->maxcount > INT_MAX)
 3759 teodor@sigaev.ru           42         [ #  # ]:UBC           0 :             ereport(ERROR,
                                 43                 :                :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                 44                 :                :                      errmsg("posting list is too long"),
                                 45                 :                :                      errhint("Reduce \"maintenance_work_mem\".")));
                                 46                 :                : 
 5788 teodor@sigaev.ru           47                 :CBC       44256 :         accum->allocatedMemory -= GetMemoryChunkSpace(eo->list);
 5458 tgl@sss.pgh.pa.us          48                 :          44256 :         eo->maxcount *= 2;
                                 49                 :          44256 :         eo->list = (ItemPointerData *)
 3759 teodor@sigaev.ru           50                 :          44256 :             repalloc_huge(eo->list, sizeof(ItemPointerData) * eo->maxcount);
 5788                            51                 :          44256 :         accum->allocatedMemory += GetMemoryChunkSpace(eo->list);
                                 52                 :                :     }
                                 53                 :                : 
                                 54                 :                :     /* If item pointers are not ordered, they will need to be sorted later */
 3045 peter_e@gmx.net            55         [ +  - ]:        1248590 :     if (eo->shouldSort == false)
                                 56                 :                :     {
                                 57                 :                :         int         res;
                                 58                 :                : 
 5458 tgl@sss.pgh.pa.us          59                 :        1248590 :         res = ginCompareItemPointers(eo->list + eo->count - 1, en->list);
 7014 bruce@momjian.us           60         [ -  + ]:        1248590 :         Assert(res != 0);
                                 61                 :                : 
                                 62         [ -  + ]:        1248590 :         if (res > 0)
 3045 peter_e@gmx.net            63                 :UBC           0 :             eo->shouldSort = true;
                                 64                 :                :     }
                                 65                 :                : 
 5458 tgl@sss.pgh.pa.us          66                 :CBC     1248590 :     eo->list[eo->count] = en->list[0];
                                 67                 :        1248590 :     eo->count++;
 5788 teodor@sigaev.ru           68                 :        1248590 : }
                                 69                 :                : 
                                 70                 :                : /* Comparator function for rbtree.c */
                                 71                 :                : static int
 2598 tgl@sss.pgh.pa.us          72                 :       14468116 : cmpEntryAccumulator(const RBTNode *a, const RBTNode *b, void *arg)
                                 73                 :                : {
 5458                            74                 :       14468116 :     const GinEntryAccumulator *ea = (const GinEntryAccumulator *) a;
                                 75                 :       14468116 :     const GinEntryAccumulator *eb = (const GinEntryAccumulator *) b;
 5773 bruce@momjian.us           76                 :       14468116 :     BuildAccumulator *accum = (BuildAccumulator *) arg;
                                 77                 :                : 
 5458 tgl@sss.pgh.pa.us          78                 :       28936232 :     return ginCompareAttEntries(accum->ginstate,
                                 79                 :       14468116 :                                 ea->attnum, ea->key, ea->category,
                                 80                 :       14468116 :                                 eb->attnum, eb->key, eb->category);
                                 81                 :                : }
                                 82                 :                : 
                                 83                 :                : /* Allocator function for rbtree.c */
                                 84                 :                : static RBTNode *
 5617                            85                 :         259322 : ginAllocEntryAccumulator(void *arg)
                                 86                 :                : {
                                 87                 :         259322 :     BuildAccumulator *accum = (BuildAccumulator *) arg;
                                 88                 :                :     GinEntryAccumulator *ea;
                                 89                 :                : 
                                 90                 :                :     /*
                                 91                 :                :      * Allocate memory by rather big chunks to decrease overhead.  We have no
                                 92                 :                :      * need to reclaim RBTNodes individually, so this costs nothing.
                                 93                 :                :      */
 5458                            94   [ +  +  +  + ]:         259322 :     if (accum->entryallocator == NULL || accum->eas_used >= DEF_NENTRY)
                                 95                 :                :     {
    7 michael@paquier.xyz        96                 :GNC         289 :         accum->entryallocator = palloc_array(GinEntryAccumulator, DEF_NENTRY);
 5617 tgl@sss.pgh.pa.us          97                 :CBC         289 :         accum->allocatedMemory += GetMemoryChunkSpace(accum->entryallocator);
 5458                            98                 :            289 :         accum->eas_used = 0;
                                 99                 :                :     }
                                100                 :                : 
                                101                 :                :     /* Allocate new RBTNode from current chunk */
                                102                 :         259322 :     ea = accum->entryallocator + accum->eas_used;
                                103                 :         259322 :     accum->eas_used++;
                                104                 :                : 
 2598                           105                 :         259322 :     return (RBTNode *) ea;
                                106                 :                : }
                                107                 :                : 
                                108                 :                : void
 5788 teodor@sigaev.ru          109                 :            217 : ginInitBA(BuildAccumulator *accum)
                                110                 :                : {
                                111                 :                :     /* accum->ginstate is intentionally not set here */
                                112                 :            217 :     accum->allocatedMemory = 0;
                                113                 :            217 :     accum->entryallocator = NULL;
 5458 tgl@sss.pgh.pa.us         114                 :            217 :     accum->eas_used = 0;
 2598                           115                 :            217 :     accum->tree = rbt_create(sizeof(GinEntryAccumulator),
                                116                 :                :                              cmpEntryAccumulator,
                                117                 :                :                              ginCombineData,
                                118                 :                :                              ginAllocEntryAccumulator,
                                119                 :                :                              NULL,  /* no freefunc needed */
                                120                 :                :                              accum);
 7169 teodor@sigaev.ru          121                 :            217 : }
                                122                 :                : 
                                123                 :                : /*
                                124                 :                :  * This is basically the same as datumCopy(), but extended to count
                                125                 :                :  * palloc'd space in accum->allocatedMemory.
                                126                 :                :  */
                                127                 :                : static Datum
 6368 tgl@sss.pgh.pa.us         128                 :         259249 : getDatumCopy(BuildAccumulator *accum, OffsetNumber attnum, Datum value)
                                129                 :                : {
                                130                 :                :     CompactAttribute *att;
                                131                 :                :     Datum       res;
                                132                 :                : 
  362 drowley@postgresql.o      133                 :         259249 :     att = TupleDescCompactAttr(accum->ginstate->origTupdesc, attnum - 1);
 6368 tgl@sss.pgh.pa.us         134         [ +  + ]:         259249 :     if (att->attbyval)
 7094                           135                 :         249838 :         res = value;
                                136                 :                :     else
                                137                 :                :     {
 6368                           138                 :           9411 :         res = datumCopy(value, false, att->attlen);
 6380                           139                 :           9411 :         accum->allocatedMemory += GetMemoryChunkSpace(DatumGetPointer(res));
                                140                 :                :     }
 7094                           141                 :         259249 :     return res;
                                142                 :                : }
                                143                 :                : 
                                144                 :                : /*
                                145                 :                :  * Find/store one entry from indexed value.
                                146                 :                :  */
                                147                 :                : static void
 5458                           148                 :        1507912 : ginInsertBAEntry(BuildAccumulator *accum,
                                149                 :                :                  ItemPointer heapptr, OffsetNumber attnum,
                                150                 :                :                  Datum key, GinNullCategory category)
                                151                 :                : {
                                152                 :                :     GinEntryAccumulator eatmp;
                                153                 :                :     GinEntryAccumulator *ea;
                                154                 :                :     bool        isNew;
                                155                 :                : 
                                156                 :                :     /*
                                157                 :                :      * For the moment, fill only the fields of eatmp that will be looked at by
                                158                 :                :      * cmpEntryAccumulator or ginCombineData.
                                159                 :                :      */
                                160                 :        1507912 :     eatmp.attnum = attnum;
                                161                 :        1507912 :     eatmp.key = key;
                                162                 :        1507912 :     eatmp.category = category;
                                163                 :                :     /* temporarily set up single-entry itempointer list */
                                164                 :        1507912 :     eatmp.list = heapptr;
                                165                 :                : 
 2598                           166                 :        1507912 :     ea = (GinEntryAccumulator *) rbt_insert(accum->tree, (RBTNode *) &eatmp,
                                167                 :                :                                             &isNew);
                                168                 :                : 
 5617                           169         [ +  + ]:        1507912 :     if (isNew)
                                170                 :                :     {
                                171                 :                :         /*
                                172                 :                :          * Finish initializing new tree entry, including making permanent
                                173                 :                :          * copies of the datum (if it's not null) and itempointer.
                                174                 :                :          */
 5458                           175         [ +  + ]:         259322 :         if (category == GIN_CAT_NORM_KEY)
                                176                 :         259249 :             ea->key = getDatumCopy(accum, attnum, key);
                                177                 :         259322 :         ea->maxcount = DEF_NPTR;
                                178                 :         259322 :         ea->count = 1;
 3045 peter_e@gmx.net           179                 :         259322 :         ea->shouldSort = false;
    7 michael@paquier.xyz       180                 :GNC      259322 :         ea->list = palloc_array(ItemPointerData, DEF_NPTR);
 5617 tgl@sss.pgh.pa.us         181                 :CBC      259322 :         ea->list[0] = *heapptr;
                                182                 :         259322 :         accum->allocatedMemory += GetMemoryChunkSpace(ea->list);
                                183                 :                :     }
                                184                 :                :     else
                                185                 :                :     {
                                186                 :                :         /*
                                187                 :                :          * ginCombineData did everything needed.
                                188                 :                :          */
                                189                 :                :     }
 7099 teodor@sigaev.ru          190                 :        1507912 : }
                                191                 :                : 
                                192                 :                : /*
                                193                 :                :  * Insert the entries for one heap pointer.
                                194                 :                :  *
                                195                 :                :  * Since the entries are being inserted into a balanced binary tree, you
                                196                 :                :  * might think that the order of insertion wouldn't be critical, but it turns
                                197                 :                :  * out that inserting the entries in sorted order results in a lot of
                                198                 :                :  * rebalancing operations and is slow.  To prevent this, we attempt to insert
                                199                 :                :  * the nodes in an order that will produce a nearly-balanced tree if the input
                                200                 :                :  * is in fact sorted.
                                201                 :                :  *
                                202                 :                :  * We do this as follows.  First, we imagine that we have an array whose size
                                203                 :                :  * is the smallest power of two greater than or equal to the actual array
                                204                 :                :  * size.  Second, we insert the middle entry of our virtual array into the
                                205                 :                :  * tree; then, we insert the middles of each half of our virtual array, then
                                206                 :                :  * middles of quarters, etc.
                                207                 :                :  */
                                208                 :                : void
 5458 tgl@sss.pgh.pa.us         209                 :         664005 : ginInsertBAEntries(BuildAccumulator *accum,
                                210                 :                :                    ItemPointer heapptr, OffsetNumber attnum,
                                211                 :                :                    Datum *entries, GinNullCategory *categories,
                                212                 :                :                    int32 nentries)
                                213                 :                : {
                                214                 :         664005 :     uint32      step = nentries;
                                215                 :                : 
                                216         [ -  + ]:         664005 :     if (nentries <= 0)
 7099 teodor@sigaev.ru          217                 :UBC           0 :         return;
                                218                 :                : 
 6112 tgl@sss.pgh.pa.us         219   [ +  -  -  + ]:CBC      664005 :     Assert(ItemPointerIsValid(heapptr) && attnum >= FirstOffsetNumber);
                                220                 :                : 
                                221                 :                :     /*
                                222                 :                :      * step will contain largest power of 2 and <= nentries
                                223                 :                :      */
 5773 bruce@momjian.us          224                 :         664005 :     step |= (step >> 1);
                                225                 :         664005 :     step |= (step >> 2);
                                226                 :         664005 :     step |= (step >> 4);
                                227                 :         664005 :     step |= (step >> 8);
 5788 teodor@sigaev.ru          228                 :         664005 :     step |= (step >> 16);
                                229                 :         664005 :     step >>= 1;
 5773 bruce@momjian.us          230                 :         664005 :     step++;
                                231                 :                : 
                                232         [ +  + ]:        1668371 :     while (step > 0)
                                233                 :                :     {
                                234                 :                :         int         i;
                                235                 :                : 
 5458 tgl@sss.pgh.pa.us         236   [ +  +  +  - ]:        2512278 :         for (i = step - 1; i < nentries && i >= 0; i += step << 1 /* *2 */ )
                                237                 :        1507912 :             ginInsertBAEntry(accum, heapptr, attnum,
                                238                 :        1507912 :                              entries[i], categories[i]);
                                239                 :                : 
 5773 bruce@momjian.us          240                 :        1004366 :         step >>= 1;               /* /2 */
                                241                 :                :     }
                                242                 :                : }
                                243                 :                : 
                                244                 :                : static int
 7014 bruce@momjian.us          245                 :UBC           0 : qsortCompareItemPointers(const void *a, const void *b)
                                246                 :                : {
 5540 tgl@sss.pgh.pa.us         247                 :              0 :     int         res = ginCompareItemPointers((ItemPointer) a, (ItemPointer) b);
                                248                 :                : 
                                249                 :                :     /* Assert that there are no equal item pointers being sorted */
 7014 bruce@momjian.us          250         [ #  # ]:              0 :     Assert(res != 0);
 7169 teodor@sigaev.ru          251                 :              0 :     return res;
                                252                 :                : }
                                253                 :                : 
                                254                 :                : /* Prepare to read out the rbtree contents using ginGetBAEntry */
                                255                 :                : void
 5617 tgl@sss.pgh.pa.us         256                 :CBC         217 : ginBeginBAScan(BuildAccumulator *accum)
                                257                 :                : {
 2598                           258                 :            217 :     rbt_begin_iterate(accum->tree, LeftRightWalk, &accum->tree_walk);
 5617                           259                 :            217 : }
                                260                 :                : 
                                261                 :                : /*
                                262                 :                :  * Get the next entry in sequence from the BuildAccumulator's rbtree.
                                263                 :                :  * This consists of a single key datum and a list (array) of one or more
                                264                 :                :  * heap TIDs in which that key is found.  The list is guaranteed sorted.
                                265                 :                :  */
                                266                 :                : ItemPointerData *
 5458                           267                 :         259539 : ginGetBAEntry(BuildAccumulator *accum,
                                268                 :                :               OffsetNumber *attnum, Datum *key, GinNullCategory *category,
                                269                 :                :               uint32 *n)
                                270                 :                : {
                                271                 :                :     GinEntryAccumulator *entry;
                                272                 :                :     ItemPointerData *list;
                                273                 :                : 
 2598                           274                 :         259539 :     entry = (GinEntryAccumulator *) rbt_iterate(&accum->tree_walk);
                                275                 :                : 
 7014 bruce@momjian.us          276         [ +  + ]:         259539 :     if (entry == NULL)
 5458 tgl@sss.pgh.pa.us         277                 :            217 :         return NULL;            /* no more entries */
                                278                 :                : 
 6368                           279                 :         259322 :     *attnum = entry->attnum;
 5458                           280                 :         259322 :     *key = entry->key;
                                281                 :         259322 :     *category = entry->category;
 7014 bruce@momjian.us          282                 :         259322 :     list = entry->list;
 5458 tgl@sss.pgh.pa.us         283                 :         259322 :     *n = entry->count;
                                284                 :                : 
                                285   [ +  -  -  + ]:         259322 :     Assert(list != NULL && entry->count > 0);
                                286                 :                : 
                                287   [ -  +  -  - ]:         259322 :     if (entry->shouldSort && entry->count > 1)
 5458 tgl@sss.pgh.pa.us         288                 :UBC           0 :         qsort(list, entry->count, sizeof(ItemPointerData),
                                289                 :                :               qsortCompareItemPointers);
                                290                 :                : 
 7169 teodor@sigaev.ru          291                 :CBC      259322 :     return list;
                                292                 :                : }
        

Generated by: LCOV version 2.4-beta