Skip to content

Commit 8e4b332

Browse files
committed
Optimize allocations in bringetbitmap
The bringetbitmap function allocates memory for various purposes, which may be quite expensive, depending on the number of scan keys. Instead of allocating them separately, allocate one bit chunk of memory an carve it into smaller pieces as needed - all the pieces have the same lifespan, and it saves quite a bit of CPU and memory overhead. Author: Tomas Vondra <tomas.vondra@postgresql.org> Reviewed-by: Alvaro Herrera <alvherre@alvh.no-ip.org> Reviewed-by: Mark Dilger <hornschnorter@gmail.com> Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com> Reviewed-by: Masahiko Sawada <masahiko.sawada@enterprisedb.com> Reviewed-by: John Naylor <john.naylor@enterprisedb.com> Discussion: https://postgr.es/m/c1138ead-7668-f0e1-0638-c3be3237e812@2ndquadrant.com
1 parent 72ccf55 commit 8e4b332

File tree

1 file changed

+47
-13
lines changed

1 file changed

+47
-13
lines changed

src/backend/access/brin/brin.c

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
373373
int *nkeys,
374374
*nnullkeys;
375375
int keyno;
376+
char *ptr;
377+
Size len;
378+
char *tmp PG_USED_FOR_ASSERTS_ONLY;
376379

377380
opaque = (BrinOpaque *) scan->opaque;
378381
bdesc = opaque->bo_bdesc;
@@ -403,15 +406,52 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
403406
* We keep null and regular keys separate, so that we can pass just the
404407
* regular keys to the consistent function easily.
405408
*
409+
* To reduce the allocation overhead, we allocate one big chunk and then
410+
* carve it into smaller arrays ourselves. All the pieces have exactly the
411+
* same lifetime, so that's OK.
412+
*
406413
* XXX The widest index can have 32 attributes, so the amount of wasted
407414
* memory is negligible. We could invent a more compact approach (with
408415
* just space for used attributes) but that would make the matching more
409416
* complex so it's not a good trade-off.
410417
*/
411-
keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts);
412-
nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts);
413-
nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts);
414-
nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts);
418+
len =
419+
MAXALIGN(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts) + /* regular keys */
420+
MAXALIGN(sizeof(ScanKey) * scan->numberOfKeys) * bdesc->bd_tupdesc->natts +
421+
MAXALIGN(sizeof(int) * bdesc->bd_tupdesc->natts) +
422+
MAXALIGN(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts) + /* NULL keys */
423+
MAXALIGN(sizeof(ScanKey) * scan->numberOfKeys) * bdesc->bd_tupdesc->natts +
424+
MAXALIGN(sizeof(int) * bdesc->bd_tupdesc->natts);
425+
426+
ptr = palloc(len);
427+
tmp = ptr;
428+
429+
keys = (ScanKey **) ptr;
430+
ptr += MAXALIGN(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts);
431+
432+
nullkeys = (ScanKey **) ptr;
433+
ptr += MAXALIGN(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts);
434+
435+
nkeys = (int *) ptr;
436+
ptr += MAXALIGN(sizeof(int) * bdesc->bd_tupdesc->natts);
437+
438+
nnullkeys = (int *) ptr;
439+
ptr += MAXALIGN(sizeof(int) * bdesc->bd_tupdesc->natts);
440+
441+
for (int i = 0; i < bdesc->bd_tupdesc->natts; i++)
442+
{
443+
keys[i] = (ScanKey *) ptr;
444+
ptr += MAXALIGN(sizeof(ScanKey) * scan->numberOfKeys);
445+
446+
nullkeys[i] = (ScanKey *) ptr;
447+
ptr += MAXALIGN(sizeof(ScanKey) * scan->numberOfKeys);
448+
}
449+
450+
Assert(tmp + len == ptr);
451+
452+
/* zero the number of keys */
453+
memset(nkeys, 0, sizeof(int) * bdesc->bd_tupdesc->natts);
454+
memset(nnullkeys, 0, sizeof(int) * bdesc->bd_tupdesc->natts);
415455

416456
/* Preprocess the scan keys - split them into per-attribute arrays. */
417457
for (keyno = 0; keyno < scan->numberOfKeys; keyno++)
@@ -443,9 +483,9 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
443483
{
444484
FmgrInfo *tmp;
445485

446-
/* No key/null arrays for this attribute. */
447-
Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0));
448-
Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0));
486+
/* First time we see this attribute, so no key/null keys. */
487+
Assert(nkeys[keyattno - 1] == 0);
488+
Assert(nnullkeys[keyattno - 1] == 0);
449489

450490
tmp = index_getprocinfo(idxRel, keyattno,
451491
BRIN_PROCNUM_CONSISTENT);
@@ -456,17 +496,11 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
456496
/* Add key to the proper per-attribute array. */
457497
if (key->sk_flags & SK_ISNULL)
458498
{
459-
if (!nullkeys[keyattno - 1])
460-
nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys);
461-
462499
nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key;
463500
nnullkeys[keyattno - 1]++;
464501
}
465502
else
466503
{
467-
if (!keys[keyattno - 1])
468-
keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys);
469-
470504
keys[keyattno - 1][nkeys[keyattno - 1]] = key;
471505
nkeys[keyattno - 1]++;
472506
}

0 commit comments

Comments
 (0)