Skip to content

feat(kernel range reader): Add buffer pooling support for large reads on regional buckets#4850

Closed
abhishek10004 wants to merge 2 commits into
masterfrom
abhishek/sync_pool_changes
Closed

feat(kernel range reader): Add buffer pooling support for large reads on regional buckets#4850
abhishek10004 wants to merge 2 commits into
masterfrom
abhishek/sync_pool_changes

Conversation

@abhishek10004

Copy link
Copy Markdown
Collaborator

Description

Description

This PR introduces buffer pooling for large and vectored read operations to optimize memory usage and reduce garbage collection overhead. By reusing allocated buffers via a sync pool, we minimize memory churn during sequential and large file reads.

Note

Buffer pooling support for larger reads is only supported for regional buckets when kernel reader is enabled.

Key Changes

  • Buffer Pooling & Lifecycle Management (internal/fs/fs.go)

    • Integrated readBufferPool into read operations to dynamically allocate and recycle byte buffers for read requests (supported only for regional buckets with kernel reader enabled).
    • Implemented immediate buffer reclamation: unused buffers or zero-copy hits return their buffers to the pool right away.
    • Added callback handling to ensure borrowed buffers are properly returned to the pool after the caller finishes consuming the read data.
  • Buffer Limiting Utility (internal/util/util.go)

    • Added a zero-allocation helper function LimitBuffers(buffers [][]byte, limit int) [][]byte.
    • Reslices multi-buffer slices in-place to cap total data size without allocating new slice headers or arrays.
  • Testing (internal/fs/large_read_regional_test.go, internal/util/util_test.go)

    • Added unit tests for LimitBuffers covering boundary conditions, multiple buffer spans, and edge cases.
    • Introduced regional large read test suite (large_read_regional_test.go) verifying successful vectored reads on regional buckets and confirming proper fallback/error behavior (ENOTSUP) for zonal buckets or when kernel reader support is disabled.

Link to the issue in case of a bug fix.

b/530765312

Testing details

  1. Manual - Done
  2. Unit tests - Done
  3. Integration tests - NA

Any backward incompatible change? If so, please explain.

@abhishek10004 abhishek10004 requested a review from a team as a code owner July 7, 2026 08:54
@abhishek10004 abhishek10004 added the execute-integration-tests Run only integration tests label Jul 7, 2026
@github-actions github-actions Bot added the remind-reviewers Auto remind reviewers in attention set for review post 24hrs of inactivity on PR. label Jul 7, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request optimizes memory management for large and vectored read operations by implementing a buffer pooling mechanism. By reusing buffers via a sync.Pool, the system minimizes memory allocations and garbage collection pressure during file read operations. This feature is specifically targeted at regional buckets utilizing the kernel reader, with fallback mechanisms and proper error handling for unsupported configurations.

Highlights

  • Buffer Pooling Integration: Introduced a sync.Pool for managing read buffers in regional buckets when the kernel reader is enabled, significantly reducing memory churn and garbage collection overhead.
  • Buffer Lifecycle Management: Implemented robust buffer reclamation logic, ensuring that borrowed buffers are returned to the pool immediately after use or via callback handling.
  • Zero-Allocation Utility: Added a new utility function, LimitBuffers, which performs in-place reslicing of multi-buffer slices to cap data size without additional allocations.
  • Enhanced Test Coverage: Added a dedicated test suite for regional large reads and comprehensive unit tests for the new buffer limiting utility.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a sync.Pool of 1 MiB buffers to optimize read operations when using the kernel reader on regional buckets, along with a helper function LimitBuffers to reslice buffers in-place. The review feedback focuses on optimizing the pool usage to achieve zero-allocation pooling by storing pointers to fixed-size arrays instead of slice headers, ensuring buffers are returned to the pool on errors to prevent memory leaks, and downgrading an error log to debug level to avoid log flooding.

Comment thread internal/fs/fs.go
Comment thread internal/fs/fs.go
Comment thread internal/fs/fs.go
Comment thread internal/fs/fs.go
Comment on lines +3141 to +3144
logger.Errorf("ReadFile: buffer pool allocation is only supported for regional buckets with"+
" kernel reader enabled (EnableKernelReader: %v, IsRapid: %v)",
fs.newConfig.FileSystem.EnableKernelReader,
fh.Inode().Bucket().BucketType().IsRapid())

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.

medium

Logging this condition as an Errorf on every read request where op.Dst == nil can lead to excessive logging and severely degrade performance under high read workloads on zonal buckets or when the kernel reader is disabled. Since this is a normal fallback/unsupported path returning ENOTSUP, it should be logged at Debugf level or omitted entirely to avoid log flooding.

			logger.Debugf("ReadFile: buffer pool allocation is only supported for regional buckets with kernel reader enabled (EnableKernelReader: %v, IsRapid: %v)",
				fs.newConfig.FileSystem.EnableKernelReader,
				fh.Inode().Bucket().BucketType().IsRapid())

@abhishek10004 abhishek10004 force-pushed the abhishek/sync_pool_changes branch from e8dda77 to e54d532 Compare July 7, 2026 09:21
Comment thread internal/fs/fs.go
op.Data = resp.Data
op.Callback = resp.Callback
if useReadBufferPool {
if len(resp.Data) > 0 {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why all this logic. why can't the read create buffers based on the need.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'm not very clear on the ask here.

IIUC, you're asking why do we have this buffer pool here instead of creating the buffers in kernel range reader. There are a couple of reasons for that.

  1. If we have to read from inode (in case there are local changes), then we need to allocate buffers for that which would be outside the kernel range reader implementation.
  2. In future, if we extend this read capability to other read paths as well, having the buffer pool at this layer would readily allow us to do that.

If you're asking about the additional handling on the returned response: Yes, I'm doing additional handling here (since currently kernel range reader does not allocate buffers on its own or sets any callback) but that is being done for future proofing the code. The ReadResponse struct says readers can return data directly from their internal buffers via Data field or can set a callback. We're not doing that currently but I've added the logic so that in case something changes in the readers (let's say we can get buffers from upper layers etc.), it would be handled automatically here without any additional changes.

Let me know if you meant something else.

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.14286% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.69%. Comparing base (2afb683) to head (c12362a).

Files with missing lines Patch % Lines
internal/fs/fs.go 81.63% 6 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4850      +/-   ##
==========================================
+ Coverage   83.67%   83.69%   +0.02%     
==========================================
  Files         170      170              
  Lines       20948    21006      +58     
==========================================
+ Hits        17528    17582      +54     
- Misses       2763     2766       +3     
- Partials      657      658       +1     
Flag Coverage Δ
unittests 83.69% <87.14%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

Hi @raj-prince, your feedback is needed to move this pull request forward. This automated reminder was triggered because there has been no activity for over 24 hours. Please provide your input when you have a moment. Thank you!

Comment thread internal/fs/fs.go
fs.newConfig.FileSystem.EnableKernelReader,
fh.Inode().Bucket().BucketType().IsRapid())
fh.Inode().Unlock()
return syscall.ENOTSUP

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just to confirm, customer will never face this scenario. Given we are enabling the MaxRead only in case of regional bucket & kernel reader.

@abhishek10004

abhishek10004 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

Closing this PR as we're moving towards lazy allocation based approach for the buffers - #4852

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

Labels

execute-integration-tests Run only integration tests remind-reviewers Auto remind reviewers in attention set for review post 24hrs of inactivity on PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants