Skip to content

Commit e9933ea

Browse files
authored
[7.15] Fix AzureBlobStore#convertStreamToByteBuffer chunking in Windows (elastic#78775)
Today we are using Math.ceil in order to calculate the number of chunks in the request. Since we cast the values to a double... there be dragons. This could cause issues depending on the platform. This commit uses good old integers to compute the number of parts. Backport of elastic#78772
1 parent 7e58aa6 commit e9933ea

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureBlobStore.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,11 @@ public synchronized int read() throws IOException {
548548
// reclaim them (see MonoSendMany). Additionally, that very same operator requests
549549
// 128 elements (that's hardcoded) once it's subscribed (later on, it requests
550550
// by 64 elements), that's why we provide 64kb buffers.
551-
return Flux.range(0, (int) Math.ceil((double) length / (double) chunkSize))
551+
552+
// length is at most 100MB so it's safe to cast back to an integer in this case
553+
final int parts = (int) length / chunkSize;
554+
final long remaining = length % chunkSize;
555+
return Flux.range(0, remaining == 0 ? parts : parts + 1)
552556
.map(i -> i * chunkSize)
553557
.concatMap(pos -> Mono.fromCallable(() -> {
554558
long count = pos + chunkSize > length ? length - pos : chunkSize;

plugins/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureBlobContainerRetriesTests.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,11 @@ public void testWriteBlobWithRetries() throws Exception {
329329
public void testWriteLargeBlob() throws Exception {
330330
final int maxRetries = randomIntBetween(2, 5);
331331

332-
final byte[] data = randomBytes((int) ByteSizeUnit.MB.toBytes(10));
333-
int nbBlocks = (int) Math.ceil((double) data.length / (double) ByteSizeUnit.MB.toBytes(1));
332+
final byte[] data = randomBytes(ByteSizeUnit.MB.toIntBytes(10) + randomIntBetween(0, ByteSizeUnit.MB.toIntBytes(1)));
333+
int nbBlocks = data.length / ByteSizeUnit.MB.toIntBytes(1);
334+
if (data.length % ByteSizeUnit.MB.toIntBytes(1) != 0) {
335+
nbBlocks += 1;
336+
}
334337

335338
final int nbErrors = 2; // we want all requests to fail at least once
336339
final AtomicInteger countDownUploads = new AtomicInteger(nbErrors * nbBlocks);
@@ -378,6 +381,9 @@ public void testWriteLargeBlob() throws Exception {
378381
if (randomBoolean()) {
379382
Streams.readFully(exchange.getRequestBody());
380383
AzureHttpHandler.sendError(exchange, randomFrom(RestStatus.INTERNAL_SERVER_ERROR, RestStatus.SERVICE_UNAVAILABLE));
384+
} else {
385+
long contentLength = Long.parseLong(exchange.getRequestHeaders().getFirst("Content-Length"));
386+
readFromInputStream(exchange.getRequestBody(), randomLongBetween(0, contentLength));
381387
}
382388
exchange.close();
383389
});
@@ -621,4 +627,16 @@ private String getEndpointForServer(HttpServer server, String accountName) {
621627
InetSocketAddress address = server.getAddress();
622628
return "http://" + InetAddresses.toUriString(address.getAddress()) + ":" + address.getPort() + "/" + accountName;
623629
}
630+
631+
private void readFromInputStream(InputStream inputStream, long bytesToRead) {
632+
try {
633+
long totalBytesRead = 0;
634+
while (inputStream.read() != -1 && totalBytesRead < bytesToRead) {
635+
totalBytesRead += 1;
636+
}
637+
assertThat(totalBytesRead, equalTo(bytesToRead));
638+
} catch (IOException e) {
639+
throw new RuntimeException(e);
640+
}
641+
}
624642
}

0 commit comments

Comments
 (0)