Skip to content

Commit c766b5f

Browse files
authored
Fix AzureBlobStore#convertStreamToByteBuffer chunking in Windows (#78772)
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.
1 parent 57a501c commit c766b5f

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-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
@@ -547,7 +547,11 @@ public synchronized int read() throws IOException {
547547
// reclaim them (see MonoSendMany). Additionally, that very same operator requests
548548
// 128 elements (that's hardcoded) once it's subscribed (later on, it requests
549549
// by 64 elements), that's why we provide 64kb buffers.
550-
return Flux.range(0, (int) Math.ceil((double) length / (double) chunkSize))
550+
551+
// length is at most 100MB so it's safe to cast back to an integer in this case
552+
final int parts = (int) length / chunkSize;
553+
final long remaining = length % chunkSize;
554+
return Flux.range(0, remaining == 0 ? parts : parts + 1)
551555
.map(i -> i * chunkSize)
552556
.concatMap(pos -> Mono.fromCallable(() -> {
553557
long count = pos + chunkSize > length ? length - pos : chunkSize;

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

Lines changed: 21 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,17 @@ 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+
int bytesRead;
635+
while ((bytesRead = inputStream.read()) != -1 && totalBytesRead < bytesToRead) {
636+
totalBytesRead += bytesRead;
637+
}
638+
assertThat(totalBytesRead, equalTo(bytesToRead));
639+
} catch (IOException e) {
640+
throw new RuntimeException(e);
641+
}
642+
}
624643
}

0 commit comments

Comments
 (0)