Small improvements for allocation logic in ginHeapTupleFastCollect().
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 19 Dec 2018 16:41:36 +0000 (11:41 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 19 Dec 2018 16:41:36 +0000 (11:41 -0500)
Avoid repetitive calls to repalloc() when the required size of the
collector array grows more than 2x in one call.  Also ensure that the
array size is a power of 2 (since palloc will probably consume a power
of 2 anyway) and doesn't start out very small (which'd likely just lead
to extra repallocs).

David Rowley, tweaked a bit by me

Discussion: https://postgr.es/m/CAKJS1f8vn-iSBE8PKeVHrnhvyjRNYCxguPFFY08QLYmjWG9hPQ@mail.gmail.com

src/backend/access/gin/ginfast.c

index ca2a32bd257c4f49a1afac83a2cc8dbdcaee3e50..a800659b9230ade10efb15f19a826c4311b08976 100644 (file)
@@ -486,18 +486,41 @@ ginHeapTupleFastCollect(GinState *ginstate,
    entries = ginExtractEntries(ginstate, attnum, value, isNull,
                                &nentries, &categories);
 
+   /*
+    * Protect against integer overflow in allocation calculations
+    */
+   if (nentries < 0 ||
+       collector->ntuples + nentries > MaxAllocSize / sizeof(IndexTuple))
+       elog(ERROR, "too many entries for GIN index");
+
    /*
     * Allocate/reallocate memory for storing collected tuples
     */
    if (collector->tuples == NULL)
    {
-       collector->lentuples = nentries * ginstate->origTupdesc->natts;
+       /*
+        * Determine the number of elements to allocate in the tuples array
+        * initially.  Make it a power of 2 to avoid wasting memory when
+        * resizing (since palloc likes powers of 2).
+        */
+       collector->lentuples = 16;
+       while (collector->lentuples < nentries)
+           collector->lentuples *= 2;
+
        collector->tuples = (IndexTuple *) palloc(sizeof(IndexTuple) * collector->lentuples);
    }
-
-   while (collector->ntuples + nentries > collector->lentuples)
+   else if (collector->lentuples < collector->ntuples + nentries)
    {
-       collector->lentuples *= 2;
+       /*
+        * Advance lentuples to the next suitable power of 2.  This won't
+        * overflow, though we could get to a value that exceeds
+        * MaxAllocSize/sizeof(IndexTuple), causing an error in repalloc.
+        */
+       do
+       {
+           collector->lentuples *= 2;
+       } while (collector->lentuples < collector->ntuples + nentries);
+
        collector->tuples = (IndexTuple *) repalloc(collector->tuples,
                                                    sizeof(IndexTuple) * collector->lentuples);
    }