Fix range download: use real seek instead of read-and-discard (#3044)
* perf(rest): fix range download to use real seek FileStreamingUtil.copyStreams called IOUtils.skipFully(from, start), which reads start bytes through a 2KB scratch buffer. Combined with ArtifactStream not overriding skip(long), a Range request at offset 600MB on an 800MB artifact made the server read+discard 600MB before serving any payload. With 80 concurrent devices this saturated CPU. Fix: - ArtifactStream.skip(long) now delegates to the wrapped stream so a FileInputStream can lseek(2). Non-seekable backends (CipherInputStream for encrypted artifacts, S3 streams) keep their existing behaviour. - FileStreamingUtil.copyStreams uses InputStream.skipNBytes(start) instead of IOUtils.skipFully so the call chain reaches the underlying skip(). JMH (single thread, 600MB offset, 1MB read): 27.21 ms -> 0.034 ms (800x). Real stack (80 parallel curl, 1MB range at 600MB offset): avg 728 ms -> 28 ms (26x), p99 966 ms -> 54 ms. Adds JMH test-scope dep and FileStreamingBenchmark/BufferSizeBenchmark for regression detection. Both gated on -Dperf=true so default test runs stay fast. * perf(rest): drop JMH benchmarks per upstream review Eclipse hawkBit minimizes dependencies. Drop jmh-core / jmh-generator-annprocess test-scope deps (also GPL-2.0 — not EPL-2.0 compatible) and the two JMH benchmarks added with the seek fix. Move the BUFFER_SIZE rationale into an inline comment in FileStreamingUtil so the empirical reasoning behind keeping the 8 KiB constant stays discoverable. The benchmarks may be reintroduced as a separate PR if upstream wants a perf-regression harness later.
This commit is contained in:
@@ -44,6 +44,13 @@ public class ArtifactStream extends InputStream {
|
||||
return inputStream.read(b, off, len);
|
||||
}
|
||||
|
||||
// Delegate so wrappers backed by a seekable stream (e.g. FileInputStream) actually seek
|
||||
// instead of reading bytes through the default InputStream.skip implementation.
|
||||
@Override
|
||||
public long skip(final long n) throws IOException {
|
||||
return inputStream.skip(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
inputStream.close();
|
||||
|
||||
Reference in New Issue
Block a user