LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginbulk.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 92.2 % 103 95 8 95
Current Date: 2024-04-14 14:21:10 Functions: 90.0 % 10 9 1 9
Baseline: 16@8cea358b128 Branches: 63.0 % 46 29 17 29
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 92.2 % 103 95 8 95
Function coverage date bins:
(240..) days: 90.0 % 10 9 1 9
Branch coverage date bins:
(240..) 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-2024, 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
 1986 tgl@sss.pgh.pa.us          30                 :CBC     1003382 : ginCombineData(RBTNode *existing, const RBTNode *newdata, void *arg)
                                 31                 :                : {
 4846                            32                 :        1003382 :     GinEntryAccumulator *eo = (GinEntryAccumulator *) existing;
                                 33                 :        1003382 :     const GinEntryAccumulator *en = (const GinEntryAccumulator *) newdata;
 5161 bruce@momjian.us           34                 :        1003382 :     BuildAccumulator *accum = (BuildAccumulator *) arg;
                                 35                 :                : 
                                 36                 :                :     /*
                                 37                 :                :      * Note this code assumes that newdata contains only one itempointer.
                                 38                 :                :      */
 4846 tgl@sss.pgh.pa.us          39         [ +  + ]:        1003382 :     if (eo->count >= eo->maxcount)
                                 40                 :                :     {
 3147 teodor@sigaev.ru           41         [ -  + ]:          38580 :         if (eo->maxcount > INT_MAX)
 3147 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                 :                : 
 5176 teodor@sigaev.ru           47                 :CBC       38580 :         accum->allocatedMemory -= GetMemoryChunkSpace(eo->list);
 4846 tgl@sss.pgh.pa.us          48                 :          38580 :         eo->maxcount *= 2;
                                 49                 :          38580 :         eo->list = (ItemPointerData *)
 3147 teodor@sigaev.ru           50                 :          38580 :             repalloc_huge(eo->list, sizeof(ItemPointerData) * eo->maxcount);
 5176                            51                 :          38580 :         accum->allocatedMemory += GetMemoryChunkSpace(eo->list);
                                 52                 :                :     }
                                 53                 :                : 
                                 54                 :                :     /* If item pointers are not ordered, they will need to be sorted later */
 2433 peter_e@gmx.net            55         [ +  - ]:        1003382 :     if (eo->shouldSort == false)
                                 56                 :                :     {
                                 57                 :                :         int         res;
                                 58                 :                : 
 4846 tgl@sss.pgh.pa.us          59                 :        1003382 :         res = ginCompareItemPointers(eo->list + eo->count - 1, en->list);
 6402 bruce@momjian.us           60         [ -  + ]:        1003382 :         Assert(res != 0);
                                 61                 :                : 
                                 62         [ -  + ]:        1003382 :         if (res > 0)
 2433 peter_e@gmx.net            63                 :UBC           0 :             eo->shouldSort = true;
                                 64                 :                :     }
                                 65                 :                : 
 4846 tgl@sss.pgh.pa.us          66                 :CBC     1003382 :     eo->list[eo->count] = en->list[0];
                                 67                 :        1003382 :     eo->count++;
 5176 teodor@sigaev.ru           68                 :        1003382 : }
                                 69                 :                : 
                                 70                 :                : /* Comparator function for rbtree.c */
                                 71                 :                : static int
 1986 tgl@sss.pgh.pa.us          72                 :       12719606 : cmpEntryAccumulator(const RBTNode *a, const RBTNode *b, void *arg)
                                 73                 :                : {
 4846                            74                 :       12719606 :     const GinEntryAccumulator *ea = (const GinEntryAccumulator *) a;
                                 75                 :       12719606 :     const GinEntryAccumulator *eb = (const GinEntryAccumulator *) b;
 5161 bruce@momjian.us           76                 :       12719606 :     BuildAccumulator *accum = (BuildAccumulator *) arg;
                                 77                 :                : 
 4846 tgl@sss.pgh.pa.us          78                 :       25439212 :     return ginCompareAttEntries(accum->ginstate,
                                 79                 :       12719606 :                                 ea->attnum, ea->key, ea->category,
                                 80                 :       12719606 :                                 eb->attnum, eb->key, eb->category);
                                 81                 :                : }
                                 82                 :                : 
                                 83                 :                : /* Allocator function for rbtree.c */
                                 84                 :                : static RBTNode *
 5005                            85                 :         257625 : ginAllocEntryAccumulator(void *arg)
                                 86                 :                : {
                                 87                 :         257625 :     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                 :                :      */
 4846                            94   [ +  +  +  + ]:         257625 :     if (accum->entryallocator == NULL || accum->eas_used >= DEF_NENTRY)
                                 95                 :                :     {
                                 96                 :            248 :         accum->entryallocator = palloc(sizeof(GinEntryAccumulator) * DEF_NENTRY);
 5005                            97                 :            248 :         accum->allocatedMemory += GetMemoryChunkSpace(accum->entryallocator);
 4846                            98                 :            248 :         accum->eas_used = 0;
                                 99                 :                :     }
                                100                 :                : 
                                101                 :                :     /* Allocate new RBTNode from current chunk */
                                102                 :         257625 :     ea = accum->entryallocator + accum->eas_used;
                                103                 :         257625 :     accum->eas_used++;
                                104                 :                : 
 1986                           105                 :         257625 :     return (RBTNode *) ea;
                                106                 :                : }
                                107                 :                : 
                                108                 :                : void
 5176 teodor@sigaev.ru          109                 :            175 : ginInitBA(BuildAccumulator *accum)
                                110                 :                : {
                                111                 :                :     /* accum->ginstate is intentionally not set here */
                                112                 :            175 :     accum->allocatedMemory = 0;
                                113                 :            175 :     accum->entryallocator = NULL;
 4846 tgl@sss.pgh.pa.us         114                 :            175 :     accum->eas_used = 0;
 1986                           115                 :            175 :     accum->tree = rbt_create(sizeof(GinEntryAccumulator),
                                116                 :                :                              cmpEntryAccumulator,
                                117                 :                :                              ginCombineData,
                                118                 :                :                              ginAllocEntryAccumulator,
                                119                 :                :                              NULL,  /* no freefunc needed */
                                120                 :                :                              (void *) accum);
 6557 teodor@sigaev.ru          121                 :            175 : }
                                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
 5756 tgl@sss.pgh.pa.us         128                 :         257550 : getDatumCopy(BuildAccumulator *accum, OffsetNumber attnum, Datum value)
                                129                 :                : {
                                130                 :                :     Form_pg_attribute att;
                                131                 :                :     Datum       res;
                                132                 :                : 
 2429 andres@anarazel.de        133                 :         257550 :     att = TupleDescAttr(accum->ginstate->origTupdesc, attnum - 1);
 5756 tgl@sss.pgh.pa.us         134         [ +  + ]:         257550 :     if (att->attbyval)
 6482                           135                 :         248998 :         res = value;
                                136                 :                :     else
                                137                 :                :     {
 5756                           138                 :           8552 :         res = datumCopy(value, false, att->attlen);
 5768                           139                 :           8552 :         accum->allocatedMemory += GetMemoryChunkSpace(DatumGetPointer(res));
                                140                 :                :     }
 6482                           141                 :         257550 :     return res;
                                142                 :                : }
                                143                 :                : 
                                144                 :                : /*
                                145                 :                :  * Find/store one entry from indexed value.
                                146                 :                :  */
                                147                 :                : static void
 4846                           148                 :        1261007 : 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                 :        1261007 :     eatmp.attnum = attnum;
                                161                 :        1261007 :     eatmp.key = key;
                                162                 :        1261007 :     eatmp.category = category;
                                163                 :                :     /* temporarily set up single-entry itempointer list */
                                164                 :        1261007 :     eatmp.list = heapptr;
                                165                 :                : 
 1986                           166                 :        1261007 :     ea = (GinEntryAccumulator *) rbt_insert(accum->tree, (RBTNode *) &eatmp,
                                167                 :                :                                             &isNew);
                                168                 :                : 
 5005                           169         [ +  + ]:        1261007 :     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                 :                :          */
 4846                           175         [ +  + ]:         257625 :         if (category == GIN_CAT_NORM_KEY)
                                176                 :         257550 :             ea->key = getDatumCopy(accum, attnum, key);
                                177                 :         257625 :         ea->maxcount = DEF_NPTR;
                                178                 :         257625 :         ea->count = 1;
 2433 peter_e@gmx.net           179                 :         257625 :         ea->shouldSort = false;
 5005 tgl@sss.pgh.pa.us         180                 :         257625 :         ea->list =
                                181                 :         257625 :             (ItemPointerData *) palloc(sizeof(ItemPointerData) * DEF_NPTR);
                                182                 :         257625 :         ea->list[0] = *heapptr;
                                183                 :         257625 :         accum->allocatedMemory += GetMemoryChunkSpace(ea->list);
                                184                 :                :     }
                                185                 :                :     else
                                186                 :                :     {
                                187                 :                :         /*
                                188                 :                :          * ginCombineData did everything needed.
                                189                 :                :          */
                                190                 :                :     }
 6487 teodor@sigaev.ru          191                 :        1261007 : }
                                192                 :                : 
                                193                 :                : /*
                                194                 :                :  * Insert the entries for one heap pointer.
                                195                 :                :  *
                                196                 :                :  * Since the entries are being inserted into a balanced binary tree, you
                                197                 :                :  * might think that the order of insertion wouldn't be critical, but it turns
                                198                 :                :  * out that inserting the entries in sorted order results in a lot of
                                199                 :                :  * rebalancing operations and is slow.  To prevent this, we attempt to insert
                                200                 :                :  * the nodes in an order that will produce a nearly-balanced tree if the input
                                201                 :                :  * is in fact sorted.
                                202                 :                :  *
                                203                 :                :  * We do this as follows.  First, we imagine that we have an array whose size
                                204                 :                :  * is the smallest power of two greater than or equal to the actual array
                                205                 :                :  * size.  Second, we insert the middle entry of our virtual array into the
                                206                 :                :  * tree; then, we insert the middles of each half of our virtual array, then
                                207                 :                :  * middles of quarters, etc.
                                208                 :                :  */
                                209                 :                : void
 4846 tgl@sss.pgh.pa.us         210                 :         627056 : ginInsertBAEntries(BuildAccumulator *accum,
                                211                 :                :                    ItemPointer heapptr, OffsetNumber attnum,
                                212                 :                :                    Datum *entries, GinNullCategory *categories,
                                213                 :                :                    int32 nentries)
                                214                 :                : {
                                215                 :         627056 :     uint32      step = nentries;
                                216                 :                : 
                                217         [ -  + ]:         627056 :     if (nentries <= 0)
 6487 teodor@sigaev.ru          218                 :UBC           0 :         return;
                                219                 :                : 
 5500 tgl@sss.pgh.pa.us         220   [ +  -  -  + ]:CBC      627056 :     Assert(ItemPointerIsValid(heapptr) && attnum >= FirstOffsetNumber);
                                221                 :                : 
                                222                 :                :     /*
                                223                 :                :      * step will contain largest power of 2 and <= nentries
                                224                 :                :      */
 5161 bruce@momjian.us          225                 :         627056 :     step |= (step >> 1);
                                226                 :         627056 :     step |= (step >> 2);
                                227                 :         627056 :     step |= (step >> 4);
                                228                 :         627056 :     step |= (step >> 8);
 5176 teodor@sigaev.ru          229                 :         627056 :     step |= (step >> 16);
                                230                 :         627056 :     step >>= 1;
 5161 bruce@momjian.us          231                 :         627056 :     step++;
                                232                 :                : 
                                233         [ +  + ]:        1524626 :     while (step > 0)
                                234                 :                :     {
                                235                 :                :         int         i;
                                236                 :                : 
 4846 tgl@sss.pgh.pa.us         237   [ +  +  +  - ]:        2158577 :         for (i = step - 1; i < nentries && i >= 0; i += step << 1 /* *2 */ )
                                238                 :        1261007 :             ginInsertBAEntry(accum, heapptr, attnum,
                                239                 :        1261007 :                              entries[i], categories[i]);
                                240                 :                : 
 5161 bruce@momjian.us          241                 :         897570 :         step >>= 1;               /* /2 */
                                242                 :                :     }
                                243                 :                : }
                                244                 :                : 
                                245                 :                : static int
 6402 bruce@momjian.us          246                 :UBC           0 : qsortCompareItemPointers(const void *a, const void *b)
                                247                 :                : {
 4928 tgl@sss.pgh.pa.us         248                 :              0 :     int         res = ginCompareItemPointers((ItemPointer) a, (ItemPointer) b);
                                249                 :                : 
                                250                 :                :     /* Assert that there are no equal item pointers being sorted */
 6402 bruce@momjian.us          251         [ #  # ]:              0 :     Assert(res != 0);
 6557 teodor@sigaev.ru          252                 :              0 :     return res;
                                253                 :                : }
                                254                 :                : 
                                255                 :                : /* Prepare to read out the rbtree contents using ginGetBAEntry */
                                256                 :                : void
 5005 tgl@sss.pgh.pa.us         257                 :CBC         175 : ginBeginBAScan(BuildAccumulator *accum)
                                258                 :                : {
 1986                           259                 :            175 :     rbt_begin_iterate(accum->tree, LeftRightWalk, &accum->tree_walk);
 5005                           260                 :            175 : }
                                261                 :                : 
                                262                 :                : /*
                                263                 :                :  * Get the next entry in sequence from the BuildAccumulator's rbtree.
                                264                 :                :  * This consists of a single key datum and a list (array) of one or more
                                265                 :                :  * heap TIDs in which that key is found.  The list is guaranteed sorted.
                                266                 :                :  */
                                267                 :                : ItemPointerData *
 4846                           268                 :         257800 : ginGetBAEntry(BuildAccumulator *accum,
                                269                 :                :               OffsetNumber *attnum, Datum *key, GinNullCategory *category,
                                270                 :                :               uint32 *n)
                                271                 :                : {
                                272                 :                :     GinEntryAccumulator *entry;
                                273                 :                :     ItemPointerData *list;
                                274                 :                : 
 1986                           275                 :         257800 :     entry = (GinEntryAccumulator *) rbt_iterate(&accum->tree_walk);
                                276                 :                : 
 6402 bruce@momjian.us          277         [ +  + ]:         257800 :     if (entry == NULL)
 4846 tgl@sss.pgh.pa.us         278                 :            175 :         return NULL;            /* no more entries */
                                279                 :                : 
 5756                           280                 :         257625 :     *attnum = entry->attnum;
 4846                           281                 :         257625 :     *key = entry->key;
                                282                 :         257625 :     *category = entry->category;
 6402 bruce@momjian.us          283                 :         257625 :     list = entry->list;
 4846 tgl@sss.pgh.pa.us         284                 :         257625 :     *n = entry->count;
                                285                 :                : 
                                286   [ +  -  -  + ]:         257625 :     Assert(list != NULL && entry->count > 0);
                                287                 :                : 
                                288   [ -  +  -  - ]:         257625 :     if (entry->shouldSort && entry->count > 1)
 4846 tgl@sss.pgh.pa.us         289                 :UBC           0 :         qsort(list, entry->count, sizeof(ItemPointerData),
                                290                 :                :               qsortCompareItemPointers);
                                291                 :                : 
 6557 teodor@sigaev.ru          292                 :CBC      257625 :     return list;
                                293                 :                : }
        

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