Skip to content

postgres: do callback hell instead of giant slices - #2002

Merged
github-actions[bot] merged 4 commits into
quay:mainfrom
hdonnay:hack/pgx-callback-hell
Sep 4, 2026
Merged

postgres: do callback hell instead of giant slices#2002
github-actions[bot] merged 4 commits into
quay:mainfrom
hdonnay:hack/pgx-callback-hell

Conversation

@hdonnay

@hdonnay hdonnay commented Aug 28, 2026

Copy link
Copy Markdown
Member

This set of changes makes the vulnerability update flow operate in more-or-less bounded amounts of memory independent of the number of vulnerability objects handled.

This is done by using a chain of batches where the next one is populated by callbacks triggered when submitting the previous batch. This is a little tricky, but manages to be less code than the previous approach.

@hdonnay
hdonnay force-pushed the hack/pgx-callback-hell branch 5 times, most recently from e74cee1 to 7b0f823 Compare September 1, 2026 19:18
@hdonnay
hdonnay marked this pull request as ready for review September 1, 2026 19:24
@hdonnay
hdonnay requested review from a team as code owners September 1, 2026 19:24
@hdonnay hdonnay added this to the Performance milestone Sep 1, 2026
batch.QueuedQueries = batch.QueuedQueries[:0]
err = errors.Join(
tx.SendBatch(ctx, &insertBatch).Close(),
conn.SendBatch(ctx, &aliasBatch).Close(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this batching might introduce deadlocking but I was not able to recreate it in the wild, I think the conditions would have to be:

  • Two in-flight alias batches
  • Flipped namespace orders (CVE, GHSA and GHSA, CVE)
  • Namespace rows are not committed.

This seems very unlikely in the wild but maybe will be more likely the more ecosystems start saving aliases 🤷

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that will happen because the read-write pair can happen in any order, as long as they're ordered for the connection.

clear(batch.QueuedQueries)
batch.QueuedQueries = batch.QueuedQueries[:0]
err = errors.Join(
tx.SendBatch(ctx, &insertBatch).Close(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check if insertBatch's tx.SendBatch errors before continuing with the aliasBatch's conn.SendBatch? Seems like FK error would come into play if the vuln batch fails mid-stream but we still try to insert the aliases

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking is that because the batches are populated in the callbacks, we might as well try to flush the remaining ones. I'll add a guard against the vulnID not getting populated.

I think the alias rows being free-floating for a while is fine.

@hdonnay
hdonnay force-pushed the hack/pgx-callback-hell branch from 7b0f823 to 0e628c8 Compare September 3, 2026 19:06
@hdonnay
hdonnay requested a review from crozzy September 3, 2026 19:07

@BradLugo BradLugo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not totally convinced this is better than #2001. Couple of things:

  1. I don't love the new connection pool. If the implementation turns out to be better, then we can live with it.

  2. The benchmarks seem slightly worse:

    Benchmark results │ base │ pr2001 │ pr2002 │ │ sec/op │ sec/op vs base │ sec/op vs base │ UpdateVulnerabilities/100Vulnerabilities-24 75.28m ± 12% 74.11m ± 9% ~ (p=0.796 n=10) 80.31m ± 12% ~ (p=0.143 n=10) UpdateVulnerabilities/500Vulnerabilities-24 109.6m ± 7% 111.9m ± 7% ~ (p=0.052 n=10) 137.4m ± 11% +25.42% (p=0.000 n=10) UpdateVulnerabilities/1200Vulnerabilities-24 171.5m ± 5% 198.4m ± 25% +15.67% (p=0.029 n=10) 278.7m ± 6% +62.51% (p=0.000 n=10) UpdateVulnerabilities/50000Vulnerabilities-24 5.311 ± 5% 7.761 ± 3% +46.13% (p=0.000 n=10) 10.501 ± 2% +97.72% (p=0.000 n=10) UpdateVulnerabilities/75000Vulnerabilities-24 8.157 ± 2% 13.804 ± 2% +69.23% (p=0.000 n=10) 15.876 ± 3% +94.63% (p=0.000 n=10) UpdateVulnerabilities/100000Vulnerabilities-24 10.83 ± 2% 18.66 ± 1% +72.22% (p=0.000 n=10) 20.90 ± 5% +92.91% (p=0.000 n=10) geomean 934.0m 1.219 +30.56% 1.485 +58.98%
                                             │      base      │                pr2001                 │                pr2002                 │
                                             │  heapGrowth-B  │ heapGrowth-B   vs base                │ heapGrowth-B   vs base                │
    

    UpdateVulnerabilities/100Vulnerabilities-24 390.8Ki ± 10% 389.0Ki ± 7% ~ (p=1.000 n=10) 626.6Ki ± 7% +60.37% (p=0.000 n=10)
    UpdateVulnerabilities/500Vulnerabilities-24 1.524Mi ± 8% 1.550Mi ± 7% ~ (p=0.143 n=10) 2.389Mi ± 2% +56.81% (p=0.000 n=10)
    UpdateVulnerabilities/1200Vulnerabilities-24 1.638Mi ± 12% 1.678Mi ± 6% ~ (p=0.796 n=10) 2.500Mi ± 6% +52.65% (p=0.000 n=10)
    UpdateVulnerabilities/50000Vulnerabilities-24 37.739Mi ± 12% 1.914Mi ± 17% -94.93% (p=0.000 n=10) 2.631Mi ± 7% -93.03% (p=0.000 n=10)
    UpdateVulnerabilities/75000Vulnerabilities-24 48.987Mi ± 6% 2.009Mi ± 8% -95.90% (p=0.000 n=10) 2.633Mi ± 11% -94.62% (p=0.000 n=10)
    UpdateVulnerabilities/100000Vulnerabilities-24 67.325Mi ± 28% 2.105Mi ± 10% -96.87% (p=0.000 n=10) 3.018Mi ± 5% -95.52% (p=0.000 n=10)
    geomean 7.009Mi 1.414Mi -79.83% 2.060Mi -70.61%

                                             │     base     │                pr2001                │                 pr2002                 │
                                             │     B/op     │     B/op      vs base                │     B/op       vs base                 │
    

    UpdateVulnerabilities/100Vulnerabilities-24 658.7Ki ± 0% 784.3Ki ± 0% +19.07% (p=0.000 n=10) 1460.1Ki ± 0% +121.67% (p=0.000 n=10)
    UpdateVulnerabilities/500Vulnerabilities-24 3.290Mi ± 0% 3.781Mi ± 0% +14.93% (p=0.000 n=10) 6.824Mi ± 0% +107.43% (p=0.000 n=10)
    UpdateVulnerabilities/1200Vulnerabilities-24 8.034Mi ± 0% 8.421Mi ± 0% +4.81% (p=0.000 n=10) 16.258Mi ± 0% +102.36% (p=0.000 n=10)
    UpdateVulnerabilities/50000Vulnerabilities-24 361.3Mi ± 0% 328.0Mi ± 0% -9.21% (p=0.000 n=10) 673.6Mi ± 0% +86.44% (p=0.000 n=10)
    UpdateVulnerabilities/75000Vulnerabilities-24 552.2Mi ± 0% 491.7Mi ± 0% -10.94% (p=0.000 n=10) 1010.3Mi ± 0% +82.97% (p=0.000 n=10)
    UpdateVulnerabilities/100000Vulnerabilities-24 722.3Mi ± 0% 655.5Mi ± 0% -9.26% (p=0.000 n=10) 1347.0Mi ± 0% +86.47% (p=0.000 n=10)
    geomean 36.72Mi 37.03Mi +0.85% 72.48Mi +97.41%

                                             │    base     │               pr2001                │                pr2002                 │
                                             │  allocs/op  │  allocs/op   vs base                │  allocs/op    vs base                 │
    

    UpdateVulnerabilities/100Vulnerabilities-24 5.466k ± 0% 7.881k ± 0% +44.18% (p=0.000 n=10) 18.212k ± 0% +233.19% (p=0.000 n=10)
    UpdateVulnerabilities/500Vulnerabilities-24 25.93k ± 0% 37.94k ± 0% +46.36% (p=0.000 n=10) 93.40k ± 0% +260.25% (p=0.000 n=10)
    UpdateVulnerabilities/1200Vulnerabilities-24 61.72k ± 0% 90.75k ± 0% +47.04% (p=0.000 n=10) 227.25k ± 0% +268.22% (p=0.000 n=10)
    UpdateVulnerabilities/50000Vulnerabilities-24 2.554M ± 0% 3.766M ± 0% +47.45% (p=0.000 n=10) 9.556M ± 0% +274.14% (p=0.000 n=10)
    UpdateVulnerabilities/75000Vulnerabilities-24 3.831M ± 0% 5.649M ± 0% +47.45% (p=0.000 n=10) 14.336M ± 0% +274.18% (p=0.000 n=10)
    UpdateVulnerabilities/100000Vulnerabilities-24 5.108M ± 0% 7.532M ± 0% +47.46% (p=0.000 n=10) 19.115M ± 0% +274.24% (p=0.000 n=10)
    geomean 275.5k 404.0k +46.65% 1.002M +263.73%

That being said, the main memory issue is addressed, so I'm not very inclined to block this merge. I have a couple of other side comments/nits, but I'll defer to @crozzy for the final approval.

Comment thread datastore/postgres/updatevulnerabilities.go Outdated
Comment thread datastore/postgres/updatevulnerabilities.go
@hdonnay
hdonnay force-pushed the hack/pgx-callback-hell branch from 0e628c8 to a5a2b0c Compare September 4, 2026 15:11
@hdonnay
hdonnay requested a review from BradLugo September 4, 2026 17:52

@crozzy crozzy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a decent improvement

BradLugo and others added 4 commits September 4, 2026 16:21
Exercise UpdateVulnerabilities with enough alias-carrying
vulnerabilities to cross batch-flush boundaries and verify the link
tables directly. The benchmark reports peak live heap alongside the
usual metrics, since allocation lifetime is invisible to B/op.

Signed-off-by: Brad Lugo <blugo@redhat.com>
Signed-off-by: Hank Donnay <hdonnay@redhat.com>
Change-Id: Id51fc15a093d90e78733e31182a631e86a6a6964
The chunked link statements are INSERT..SELECTs that must see alias
rows committed by concurrent updaters after the transaction began, so
pin read committed instead of inheriting
default_transaction_isolation.

Signed-off-by: Brad Lugo <blugo@redhat.com>
Signed-off-by: Hank Donnay <hdonnay@redhat.com>
Change-Id: I462ca8ea288011295a2b3cb92ce8ae636a6a6964
Signed-off-by: Hank Donnay <hdonnay@redhat.com>
Change-Id: I85a31f5796751b32e698b7b0108461146a6a6964
Signed-off-by: Hank Donnay <hdonnay@redhat.com>
Change-Id: I7b0aef57f26107254a546add7442b9556a6a6964
@hdonnay
hdonnay force-pushed the hack/pgx-callback-hell branch from a5a2b0c to 5b55a27 Compare September 4, 2026 21:21
@hdonnay

hdonnay commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

/fast-forward

@github-actions
github-actions Bot merged commit 5b55a27 into quay:main Sep 4, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants