Skip to content

Commit cfef67d

Browse files
benjaminpcopybara-github
authored andcommitted
Fix seeking of empty chunkers.
Empty chunkers are strange in that they emit one empty chunk and then end. This change makes them properly resetable. Previously, reset() on a empty chunker could result in a NullPointerException. Also, it's important to call close() on the underlying data stream even if it's empty. Closes #17797. PiperOrigin-RevId: 517119206 Change-Id: Iff7908d6cd0633aa2a355ea89f8e647a9fefffcd
1 parent 3b475b3 commit cfef67d

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

src/main/java/com/google/devtools/build/lib/remote/Chunker.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,14 @@ public void reset() throws IOException {
159159
public void seek(long toOffset) throws IOException {
160160
// For compressed stream, we need to reinitialize the stream since the offset refers to the
161161
// uncompressed form.
162-
if (initialized && toOffset >= offset && !compressed) {
162+
if (initialized && size > 0 && toOffset >= offset && !compressed) {
163163
ByteStreams.skipFully(data, toOffset - offset);
164164
offset = toOffset;
165165
} else {
166166
reset();
167167
initialize(toOffset);
168168
}
169-
if (data.finished()) {
169+
if (size > 0 && data.finished()) {
170170
close();
171171
}
172172
}
@@ -216,7 +216,7 @@ public Chunk next() throws IOException {
216216
maybeInitialize();
217217

218218
if (size == 0) {
219-
data = null;
219+
close();
220220
return emptyChunk;
221221
}
222222

src/test/java/com/google/devtools/build/lib/remote/ChunkerTest.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,17 @@ public void nextShouldThrowIfNoMoreData() throws IOException {
8484

8585
@Test
8686
public void emptyData() throws Exception {
87-
byte[] data = new byte[0];
88-
Chunker chunker = Chunker.builder().setInput(data).build();
87+
var inp =
88+
new ByteArrayInputStream(new byte[0]) {
89+
private boolean closed;
90+
91+
@Override
92+
public void close() throws IOException {
93+
closed = true;
94+
super.close();
95+
}
96+
};
97+
Chunker chunker = Chunker.builder().setInput(0, inp).build();
8998

9099
assertThat(chunker.hasNext()).isTrue();
91100

@@ -96,6 +105,7 @@ public void emptyData() throws Exception {
96105
assertThat(next.getOffset()).isEqualTo(0);
97106

98107
assertThat(chunker.hasNext()).isFalse();
108+
assertThat(inp.closed).isTrue();
99109

100110
assertThrows(NoSuchElementException.class, () -> chunker.next());
101111
}
@@ -193,6 +203,21 @@ public void seekForwards() throws IOException {
193203
assertThat(chunker.hasNext()).isFalse();
194204
}
195205

206+
@Test
207+
public void seekEmptyData() throws IOException {
208+
var chunker = Chunker.builder().setInput(new byte[0]).build();
209+
for (var i = 0; i < 2; i++) {
210+
chunker.seek(0);
211+
var next = chunker.next();
212+
assertThat(next).isNotNull();
213+
assertThat(next.getData()).isEmpty();
214+
assertThat(next.getOffset()).isEqualTo(0);
215+
216+
assertThat(chunker.hasNext()).isFalse();
217+
assertThrows(NoSuchElementException.class, chunker::next);
218+
}
219+
}
220+
196221
@Test
197222
public void testSingleChunkCompressed() throws IOException {
198223
byte[] data = {72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33};

0 commit comments

Comments
 (0)