Skip to content

feat(gax): add RewindableStreamBuffer for single-chunk rewinds and seeks - #14224

Draft
whowes wants to merge 5 commits into
whowes/resumable-upload-statusfrom
whowes/rewindable-stream-buffer
Draft

feat(gax): add RewindableStreamBuffer for single-chunk rewinds and seeks#14224
whowes wants to merge 5 commits into
whowes/resumable-upload-statusfrom
whowes/rewindable-stream-buffer

Conversation

@whowes

@whowes whowes commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Work in progress - not yet ready for review

@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 RewindableStreamBuffer, a new stream buffer supporting single-chunk rewind and seeking over an InputStream for resumable uploads, along with its corresponding unit tests. The feedback suggests adding a precondition check in readChunk to ensure the requested targetOffset matches the actual streamPosition to prevent potential data corruption. Additionally, it is recommended to remove the unused chunkSize field and constructor parameter from both the class and its tests.

Comment on lines +84 to +87

if (endOfStream) {
return ByteString.EMPTY;
}

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.

high

If targetOffset does not match streamPosition when reading a new chunk from the stream, it means we are attempting to read from an incorrect position in the underlying stream (either because we skipped bytes without seeking, or because we are trying to read an invalid offset). Without this check, the buffer would silently read incorrect data from the stream and associate it with the wrong offset, leading to silent data corruption.

Adding a precondition check ensures that the caller's requested offset matches the actual stream position before reading.

    checkArgument(
        targetOffset == streamPosition,
        "targetOffset (%s) must match streamPosition (%s) when reading from the stream",
        targetOffset,
        streamPosition);

    if (endOfStream) {
      return ByteString.EMPTY;
    }

Comment on lines +52 to +64
private final InputStream source;
private final int chunkSize;

private byte @Nullable [] currentChunkData;
private long currentChunkStartOffset = 0L;
private long streamPosition = 0L;
private boolean endOfStream = false;

public RewindableStreamBuffer(InputStream source, int chunkSize) {
this.source = checkNotNull(source);
checkArgument(chunkSize > 0, "chunkSize must be > 0");
this.chunkSize = chunkSize;
}

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

The chunkSize field and constructor parameter are completely unused in this class. To simplify the API and avoid dead code, we should remove them.

  private final InputStream source;

  private byte @Nullable [] currentChunkData;
  private long currentChunkStartOffset = 0L;
  private long streamPosition = 0L;
  private boolean endOfStream = false;

  public RewindableStreamBuffer(InputStream source) {
    this.source = checkNotNull(source);
  }

import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;

class RewindableStreamBufferTest {

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

If the unused chunkSize parameter is removed from the RewindableStreamBuffer constructor, please update all constructor calls in this test file to omit the second argument (e.g., new RewindableStreamBuffer(stream)), and remove the testInvalidChunkSize test case.

@whowes
whowes force-pushed the whowes/rewindable-stream-buffer branch from e73249a to 5407505 Compare September 1, 2026 06:29
@whowes
whowes force-pushed the whowes/resumable-upload-status branch 2 times, most recently from 4b3b68b to ddfd13c Compare September 1, 2026 06:39
@whowes
whowes force-pushed the whowes/rewindable-stream-buffer branch 3 times, most recently from 3d41927 to 4ba5af0 Compare September 1, 2026 20:00
@whowes
whowes force-pushed the whowes/resumable-upload-status branch from ddfd13c to 3c74cf4 Compare September 1, 2026 20:00
@sonarqubecloud

sonarqubecloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

❌ The last analysis has failed.

See analysis details on SonarQube Cloud

@whowes
whowes force-pushed the whowes/resumable-upload-status branch from 3c74cf4 to fec6fbb Compare September 1, 2026 20:22
@whowes
whowes force-pushed the whowes/rewindable-stream-buffer branch from 4ba5af0 to 575e38e Compare September 1, 2026 20:22
@whowes
whowes force-pushed the whowes/rewindable-stream-buffer branch from 575e38e to 6e8ee1a Compare September 1, 2026 20:33
@whowes
whowes force-pushed the whowes/resumable-upload-status branch from fec6fbb to 42d7132 Compare September 1, 2026 20:33
@whowes
whowes force-pushed the whowes/rewindable-stream-buffer branch from 6e8ee1a to be5a011 Compare September 1, 2026 22:36
@whowes
whowes force-pushed the whowes/resumable-upload-status branch from 42d7132 to f92d57e Compare September 1, 2026 23:03
@whowes
whowes force-pushed the whowes/rewindable-stream-buffer branch from be5a011 to 849f448 Compare September 1, 2026 23:03
@whowes
whowes force-pushed the whowes/rewindable-stream-buffer branch from 849f448 to 1fac6c2 Compare September 1, 2026 23:06
@sonarqubecloud

sonarqubecloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

@sonarqubecloud

sonarqubecloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed for 'gapic-generator-java-root'

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@whowes
whowes force-pushed the whowes/resumable-upload-status branch 2 times, most recently from cf08aec to 87b9732 Compare September 2, 2026 01:01
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.

1 participant