LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginbulk.c (source / functions) Coverage Total Hit LBC UBC CBC
Current: 603a3335f2b60b2c798da5c627b3bb288b92a7bd vs e395fbd32a07557de4ac98088928c1749d4845d8 Lines: 92.2 % 102 94 6 2 94
Current Date: 2026-07-25 17:13:00 -0400 Functions: 90.0 % 10 9 1 9
Baseline: lcov-20260726-baseline Branches: 63.0 % 46 29 4 13 29
Baseline Date: 2026-07-25 19:16:42 +0200 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 66.7 % 3 2 1 2
(360..) days: 92.9 % 99 92 5 2 92
Function coverage date bins:
(360..) days: 90.0 % 10 9 1 9
Branch coverage date bins:
(360..) days: 63.0 % 46 29 4 13 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-2026, 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
 2819 tgl@sss.pgh.pa.us          30                 :CBC     1427594 : ginCombineData(RBTNode *existing, const RBTNode *newdata, void *arg)
                                 31                 :                : {
 5679                            32                 :        1427594 :     GinEntryAccumulator *eo = (GinEntryAccumulator *) existing;
                                 33                 :        1427594 :     const GinEntryAccumulator *en = (const GinEntryAccumulator *) newdata;
 5994 bruce@momjian.us           34                 :        1427594 :     BuildAccumulator *accum = (BuildAccumulator *) arg;
                                 35                 :                : 
                                 36                 :                :     /*
                                 37                 :                :      * Note this code assumes that newdata contains only one itempointer.
                                 38                 :                :      */
 5679 tgl@sss.pgh.pa.us          39         [ +  + ]:        1427594 :     if (eo->count >= eo->maxcount)
                                 40                 :                :     {
 3980 teodor@sigaev.ru           41         [ -  + ]:          59351 :         if (eo->maxcount > INT_MAX)
 3980 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                 :                : 
 6009 teodor@sigaev.ru           47                 :CBC       59351 :         accum->allocatedMemory -= GetMemoryChunkSpace(eo->list);
 5679 tgl@sss.pgh.pa.us          48                 :          59351 :         eo->maxcount *= 2;
                                 49                 :          59351 :         eo->list = (ItemPointerData *)
 3980 teodor@sigaev.ru           50                 :          59351 :             repalloc_huge(eo->list, sizeof(ItemPointerData) * eo->maxcount);
 6009                            51                 :          59351 :         accum->allocatedMemory += GetMemoryChunkSpace(eo->list);
                                 52                 :                :     }
                                 53                 :                : 
                                 54                 :                :     /* If item pointers are not ordered, they will need to be sorted later */
 3266 peter_e@gmx.net            55         [ +  - ]:        1427594 :     if (eo->shouldSort == false)
                                 56                 :                :     {
                                 57                 :                :         int         res;
                                 58                 :                : 
 5679 tgl@sss.pgh.pa.us          59                 :        1427594 :         res = ginCompareItemPointers(eo->list + eo->count - 1, en->list);
 7235 bruce@momjian.us           60         [ -  + ]:        1427594 :         Assert(res != 0);
                                 61                 :                : 
                                 62         [ -  + ]:        1427594 :         if (res > 0)
 3266 peter_e@gmx.net            63                 :LBC         (2) :             eo->shouldSort = true;
                                 64                 :                :     }
                                 65                 :                : 
 5679 tgl@sss.pgh.pa.us          66                 :CBC     1427594 :     eo->list[eo->count] = en->list[0];
                                 67                 :        1427594 :     eo->count++;
 6009 teodor@sigaev.ru           68                 :        1427594 : }
                                 69                 :                : 
                                 70                 :                : /* Comparator function for rbtree.c */
                                 71                 :                : static int
 2819 tgl@sss.pgh.pa.us          72                 :       18171958 : cmpEntryAccumulator(const RBTNode *a, const RBTNode *b, void *arg)
                                 73                 :                : {
 5679                            74                 :       18171958 :     const GinEntryAccumulator *ea = (const GinEntryAccumulator *) a;
                                 75                 :       18171958 :     const GinEntryAccumulator *eb = (const GinEntryAccumulator *) b;
 5994 bruce@momjian.us           76                 :       18171958 :     BuildAccumulator *accum = (BuildAccumulator *) arg;
                                 77                 :                : 
 5679 tgl@sss.pgh.pa.us          78                 :       36343916 :     return ginCompareAttEntries(accum->ginstate,
                                 79                 :       18171958 :                                 ea->attnum, ea->key, ea->category,
                                 80                 :       18171958 :                                 eb->attnum, eb->key, eb->category);
                                 81                 :                : }
                                 82                 :                : 
                                 83                 :                : /* Allocator function for rbtree.c */
                                 84                 :                : static RBTNode *
 5838                            85                 :         344486 : ginAllocEntryAccumulator(void *arg)
                                 86                 :                : {
                                 87                 :         344486 :     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                 :                :      */
 5679                            94   [ +  +  +  + ]:         344486 :     if (accum->entryallocator == NULL || accum->eas_used >= DEF_NENTRY)
                                 95                 :                :     {
  228 michael@paquier.xyz        96                 :            365 :         accum->entryallocator = palloc_array(GinEntryAccumulator, DEF_NENTRY);
 5838 tgl@sss.pgh.pa.us          97                 :            365 :         accum->allocatedMemory += GetMemoryChunkSpace(accum->entryallocator);
 5679                            98                 :            365 :         accum->eas_used = 0;
                                 99                 :                :     }
                                100                 :                : 
                                101                 :                :     /* Allocate new RBTNode from current chunk */
                                102                 :         344486 :     ea = accum->entryallocator + accum->eas_used;
                                103                 :         344486 :     accum->eas_used++;
                                104                 :                : 
 2819                           105                 :         344486 :     return (RBTNode *) ea;
                                106                 :                : }
                                107                 :                : 
                                108                 :                : void
 6009 teodor@sigaev.ru          109                 :            334 : ginInitBA(BuildAccumulator *accum)
                                110                 :                : {
                                111                 :                :     /* accum->ginstate is intentionally not set here */
                                112                 :            334 :     accum->allocatedMemory = 0;
                                113                 :            334 :     accum->entryallocator = NULL;
 5679 tgl@sss.pgh.pa.us         114                 :            334 :     accum->eas_used = 0;
 2819                           115                 :            334 :     accum->tree = rbt_create(sizeof(GinEntryAccumulator),
                                116                 :                :                              cmpEntryAccumulator,
                                117                 :                :                              ginCombineData,
                                118                 :                :                              ginAllocEntryAccumulator,
                                119                 :                :                              NULL,  /* no freefunc needed */
                                120                 :                :                              accum);
 7390 teodor@sigaev.ru          121                 :            334 : }
                                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
 6589 tgl@sss.pgh.pa.us         128                 :         344378 : getDatumCopy(BuildAccumulator *accum, OffsetNumber attnum, Datum value)
                                129                 :                : {
                                130                 :                :     CompactAttribute *att;
                                131                 :                :     Datum       res;
                                132                 :                : 
  583 drowley@postgresql.o      133                 :         344378 :     att = TupleDescCompactAttr(accum->ginstate->origTupdesc, attnum - 1);
 6589 tgl@sss.pgh.pa.us         134         [ +  + ]:         344378 :     if (att->attbyval)
 7315                           135                 :         323358 :         res = value;
                                136                 :                :     else
                                137                 :                :     {
 6589                           138                 :          21020 :         res = datumCopy(value, false, att->attlen);
 6601                           139                 :          21020 :         accum->allocatedMemory += GetMemoryChunkSpace(DatumGetPointer(res));
                                140                 :                :     }
 7315                           141                 :         344378 :     return res;
                                142                 :                : }
                                143                 :                : 
                                144                 :                : /*
                                145                 :                :  * Find/store one entry from indexed value.
                                146                 :                :  */
                                147                 :                : static void
 5679                           148                 :        1772080 : 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                 :        1772080 :     eatmp.attnum = attnum;
                                161                 :        1772080 :     eatmp.key = key;
                                162                 :        1772080 :     eatmp.category = category;
                                163                 :                :     /* temporarily set up single-entry itempointer list */
                                164                 :        1772080 :     eatmp.list = heapptr;
                                165                 :                : 
 2819                           166                 :        1772080 :     ea = (GinEntryAccumulator *) rbt_insert(accum->tree, (RBTNode *) &eatmp,
                                167                 :                :                                             &isNew);
                                168                 :                : 
 5838                           169         [ +  + ]:        1772080 :     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                 :                :          */
 5679                           175         [ +  + ]:         344486 :         if (category == GIN_CAT_NORM_KEY)
                                176                 :         344378 :             ea->key = getDatumCopy(accum, attnum, key);
                                177                 :         344486 :         ea->maxcount = DEF_NPTR;
                                178                 :         344486 :         ea->count = 1;
 3266 peter_e@gmx.net           179                 :         344486 :         ea->shouldSort = false;
  228 michael@paquier.xyz       180                 :         344486 :         ea->list = palloc_array(ItemPointerData, DEF_NPTR);
 5838 tgl@sss.pgh.pa.us         181                 :         344486 :         ea->list[0] = *heapptr;
                                182                 :         344486 :         accum->allocatedMemory += GetMemoryChunkSpace(ea->list);
                                183                 :                :     }
                                184                 :                :     else
                                185                 :                :     {
                                186                 :                :         /*
                                187                 :                :          * ginCombineData did everything needed.
                                188                 :                :          */
                                189                 :                :     }
 7320 teodor@sigaev.ru          190                 :        1772080 : }
                                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
 5679 tgl@sss.pgh.pa.us         209                 :         742185 : ginInsertBAEntries(BuildAccumulator *accum,
                                210                 :                :                    ItemPointer heapptr, OffsetNumber attnum,
                                211                 :                :                    Datum *entries, GinNullCategory *categories,
                                212                 :                :                    int32 nentries)
                                213                 :                : {
                                214                 :         742185 :     uint32      step = nentries;
                                215                 :                : 
                                216         [ -  + ]:         742185 :     if (nentries <= 0)
 7320 teodor@sigaev.ru          217                 :UBC           0 :         return;
                                218                 :                : 
 6333 tgl@sss.pgh.pa.us         219   [ +  -  -  + ]:CBC      742185 :     Assert(ItemPointerIsValid(heapptr) && attnum >= FirstOffsetNumber);
                                220                 :                : 
                                221                 :                :     /*
                                222                 :                :      * step will contain largest power of 2 and <= nentries
                                223                 :                :      */
 5994 bruce@momjian.us          224                 :         742185 :     step |= (step >> 1);
                                225                 :         742185 :     step |= (step >> 2);
                                226                 :         742185 :     step |= (step >> 4);
                                227                 :         742185 :     step |= (step >> 8);
 6009 teodor@sigaev.ru          228                 :         742185 :     step |= (step >> 16);
                                229                 :         742185 :     step >>= 1;
 5994 bruce@momjian.us          230                 :         742185 :     step++;
                                231                 :                : 
                                232         [ +  + ]:        1905717 :     while (step > 0)
                                233                 :                :     {
                                234                 :                :         int         i;
                                235                 :                : 
 5679 tgl@sss.pgh.pa.us         236   [ +  +  +  - ]:        2935612 :         for (i = step - 1; i < nentries && i >= 0; i += step << 1 /* *2 */ )
                                237                 :        1772080 :             ginInsertBAEntry(accum, heapptr, attnum,
                                238                 :        1772080 :                              entries[i], categories[i]);
                                239                 :                : 
 5994 bruce@momjian.us          240                 :        1163532 :         step >>= 1;               /* /2 */
                                241                 :                :     }
                                242                 :                : }
                                243                 :                : 
                                244                 :                : static int
 7235 bruce@momjian.us          245                 :LBC         (6) : qsortCompareItemPointers(const void *a, const void *b)
                                246                 :                : {
  149 peter@eisentraut.org      247                 :            (6) :     int         res = ginCompareItemPointers((const ItemPointerData *) a, (const ItemPointerData *) b);
                                248                 :                : 
                                249                 :                :     /* Assert that there are no equal item pointers being sorted */
 7235 bruce@momjian.us          250         [ #  # ]:            (6) :     Assert(res != 0);
 7390 teodor@sigaev.ru          251                 :            (6) :     return res;
                                252                 :                : }
                                253                 :                : 
                                254                 :                : /* Prepare to read out the rbtree contents using ginGetBAEntry */
                                255                 :                : void
 5838 tgl@sss.pgh.pa.us         256                 :CBC         283 : ginBeginBAScan(BuildAccumulator *accum)
                                257                 :                : {
 2819                           258                 :            283 :     rbt_begin_iterate(accum->tree, LeftRightWalk, &accum->tree_walk);
 5838                           259                 :            283 : }
                                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 *
 5679                           267                 :         344769 : ginGetBAEntry(BuildAccumulator *accum,
                                268                 :                :               OffsetNumber *attnum, Datum *key, GinNullCategory *category,
                                269                 :                :               uint32 *n)
                                270                 :                : {
                                271                 :                :     GinEntryAccumulator *entry;
                                272                 :                :     ItemPointerData *list;
                                273                 :                : 
 2819                           274                 :         344769 :     entry = (GinEntryAccumulator *) rbt_iterate(&accum->tree_walk);
                                275                 :                : 
 7235 bruce@momjian.us          276         [ +  + ]:         344769 :     if (entry == NULL)
 5679 tgl@sss.pgh.pa.us         277                 :            283 :         return NULL;            /* no more entries */
                                278                 :                : 
 6589                           279                 :         344486 :     *attnum = entry->attnum;
 5679                           280                 :         344486 :     *key = entry->key;
                                281                 :         344486 :     *category = entry->category;
 7235 bruce@momjian.us          282                 :         344486 :     list = entry->list;
 5679 tgl@sss.pgh.pa.us         283                 :         344486 :     *n = entry->count;
                                284                 :                : 
                                285   [ +  -  -  + ]:         344486 :     Assert(list != NULL && entry->count > 0);
                                286                 :                : 
                                287   [ -  +  -  - ]:         344486 :     if (entry->shouldSort && entry->count > 1)
 5679 tgl@sss.pgh.pa.us         288                 :LBC         (2) :         qsort(list, entry->count, sizeof(ItemPointerData),
                                289                 :                :               qsortCompareItemPointers);
                                290                 :                : 
 7390 teodor@sigaev.ru          291                 :CBC      344486 :     return list;
                                292                 :                : }
        

Generated by: LCOV version 2.0-1