Skip to content

Remove allocs from io.ReadAll (hard cases)#606

Open
SuperSandro2000 wants to merge 3 commits intomasterfrom
remove-io-ReadAll
Open

Remove allocs from io.ReadAll (hard cases)#606
SuperSandro2000 wants to merge 3 commits intomasterfrom
remove-io-ReadAll

Conversation

@SuperSandro2000
Copy link
Member

@SuperSandro2000 SuperSandro2000 commented Oct 17, 2025

Lets not merge this until Stefan gave a review.

@SuperSandro2000 SuperSandro2000 changed the title Remove io read all Remove allocs from io.ReadAll Oct 17, 2025
@SuperSandro2000 SuperSandro2000 force-pushed the remove-io-ReadAll branch 2 times, most recently from 34e4642 to 948d327 Compare October 22, 2025 12:32
@SuperSandro2000 SuperSandro2000 changed the title Remove allocs from io.ReadAll Remove allocs from io.ReadAll (hard cases) Oct 22, 2025
@SuperSandro2000 SuperSandro2000 marked this pull request as ready for review October 22, 2025 12:33
Copy link
Contributor

@majewsky majewsky left a comment

Choose a reason for hiding this comment

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

I don't like that we're just ignoring most of the errors from Close(). I would like to have helper functions ReadAllAndClose(io.ReadCloser) ([]byte, error) and CopyAllAndClose(io.Writer, io.ReadCloser) error instead.

parsedReport, err := trivy.UnmarshalReportFromJSON(payload.Contents)
unmodifiedReport := &bytes.Buffer{}
parsedReport, err := trivy.UnmarshalReportFromJSON(io.TeeReader(payload.Contents, unmodifiedReport))
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

TeeReader means that we will not be able to save allocations on this part, which as I understand is the most critical part for actually reducing memory usage in the janitor.

In the original, retaining the unmodified report in payload.Contents allowed skipping MarshalJSON if no modifications are required. We can trade this CPU optimization for a RAM optimization by instead always marshalling, and not holding unmodifiedReport. parsedReport is able to faithfully reserialize the original report, so no information would be lost here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, that was a consideration I was making when doing that change and I was not sure if the CPU cost outweighs the memory but probably yet.

Copy link
Member Author

Choose a reason for hiding this comment

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

Before:

 ➜ go test ./internal/keppel/ -bench=BenchmarkEnrichReport -benchmem
goos: linux
goarch: amd64
pkg: github.com/sapcc/keppel/internal/keppel
cpu: Intel(R) Xeon(R) Platinum 8260 CPU @ 2.40GHz
BenchmarkEnrichReport-8              130           9156652 ns/op         1414337 B/op        814 allocs/op
PASS
ok      github.com/sapcc/keppel/internal/keppel 1.216s

After:

 ➜ go test ./internal/keppel/ -bench=BenchmarkEnrichReport -benchmem
goos: linux
goarch: amd64
pkg: github.com/sapcc/keppel/internal/keppel
cpu: Intel(R) Xeon(R) Platinum 8260 CPU @ 2.40GHz
BenchmarkEnrichReport-8              117          10143171 ns/op         1161177 B/op        832 allocs/op
PASS
ok      github.com/sapcc/keppel/internal/keppel 1.218s

Comment on lines +26 to +29
type trivyTestReport struct {
payload trivy.ReportPayload
buf []byte
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Just flagging that I don't like how this is modeled, without yet offering a specific suggestion immediately. Code using this type looks unnecessarily convoluted.

@SuperSandro2000 SuperSandro2000 force-pushed the remove-io-ReadAll branch 4 times, most recently from 148b6e5 to 62e6d3e Compare November 4, 2025 17:17
@github-actions
Copy link

Merging this branch changes the coverage (7 decrease, 1 increase)

Impacted Packages Coverage Δ 🤖
github.com/sapcc/keppel/internal/api/keppel 82.45% (+0.03%) 👍
github.com/sapcc/keppel/internal/api/peer 78.86% (-0.80%) 👎
github.com/sapcc/keppel/internal/api/registry 85.31% (-0.39%) 👎
github.com/sapcc/keppel/internal/client 42.64% (-1.58%) 👎
github.com/sapcc/keppel/internal/client/peer 73.33% (-4.05%) 👎
github.com/sapcc/keppel/internal/drivers/filesystem 0.00% (ø)
github.com/sapcc/keppel/internal/drivers/openstack 0.00% (ø)
github.com/sapcc/keppel/internal/drivers/trivial 0.00% (ø)
github.com/sapcc/keppel/internal/keppel 83.89% (ø)
github.com/sapcc/keppel/internal/processor 83.21% (-0.04%) 👎
github.com/sapcc/keppel/internal/tasks 82.05% (-0.01%) 👎
github.com/sapcc/keppel/internal/test 86.50% (-0.53%) 👎

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/sapcc/keppel/internal/api/keppel/manifests.go 79.88% (+0.12%) 1690 (+10) 1350 (+10) 340 👍
github.com/sapcc/keppel/internal/api/peer/delegatedpull.go 66.67% (-1.75%) 240 (+50) 160 (+30) 80 (+20) 👎
github.com/sapcc/keppel/internal/api/registry/manifests.go 83.82% (-1.98%) 1730 (+40) 1450 280 (+40) 👎
github.com/sapcc/keppel/internal/client/download.go 76.19% (+2.12%) 105 (-30) 80 (-20) 25 (-10) 👍
github.com/sapcc/keppel/internal/client/peer/client.go 81.25% (+1.25%) 160 (-15) 130 (-10) 30 (-5) 👍
github.com/sapcc/keppel/internal/client/peer/requests.go 68.97% (-6.54%) 290 (+45) 200 (+15) 90 (+30) 👎
github.com/sapcc/keppel/internal/client/validate.go 0.00% (ø) 325 (+20) 0 325 (+20)
github.com/sapcc/keppel/internal/drivers/filesystem/storage.go 0.00% (ø) 0 0 0
github.com/sapcc/keppel/internal/drivers/openstack/inbound_cache_swift.go 0.00% (ø) 0 0 0
github.com/sapcc/keppel/internal/drivers/openstack/swift.go 0.00% (ø) 0 0 0
github.com/sapcc/keppel/internal/drivers/trivial/inbound_cache.go 0.00% (ø) 0 0 0
github.com/sapcc/keppel/internal/drivers/trivial/storage.go 0.00% (ø) 0 0 0
github.com/sapcc/keppel/internal/keppel/inbound_cache_driver.go 80.00% (ø) 50 40 10
github.com/sapcc/keppel/internal/keppel/storage_driver.go 80.00% (ø) 100 80 20
github.com/sapcc/keppel/internal/processor/manifests.go 83.90% (-0.10%) 2050 (+50) 1720 (+40) 330 (+10) 👎
github.com/sapcc/keppel/internal/tasks/manifests.go 82.53% (-0.04%) 3320 (+50) 2740 (+40) 580 (+10) 👎
github.com/sapcc/keppel/internal/test/driver_inbound_cache.go 93.75% (-6.25%) 80 (+15) 75 (+10) 5 (+5) 👎
github.com/sapcc/keppel/internal/test/helper_validate.go 65.79% (-0.88%) 380 (+35) 250 (+20) 130 (+15) 👎

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/sapcc/keppel/internal/api/keppel/manifests_test.go
  • github.com/sapcc/keppel/internal/api/keppel/repos_test.go
  • github.com/sapcc/keppel/internal/tasks/account_management_test.go
  • github.com/sapcc/keppel/internal/tasks/manifests_test.go
  • github.com/sapcc/keppel/internal/tasks/storage_test.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants