Skip to content

Commit bca0c8d

Browse files
Fix Bug in Azure Repo Exception Handling (#47968) (#48031) (#48047)
We were incorrectly handling `IOExceptions` thrown by the `InputStream` side of the upload operation, resulting in a `ClassCastException` as we expected to never get `IOException` from the Azure SDK code but we do in practice. This PR also sets an assertion on `markSupported` for the streams used by the SDK as adding the test for this scenario revealed that the SDK client would retry uploads for non-mark-supporting streams on `IOException` in the `InputStream`.
1 parent 90b9052 commit bca0c8d

File tree

4 files changed

+18
-20
lines changed

4 files changed

+18
-20
lines changed

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public boolean blobExists(String blobName) {
5353
logger.trace("blobExists({})", blobName);
5454
try {
5555
return blobStore.blobExists(buildKey(blobName));
56-
} catch (URISyntaxException | StorageException e) {
56+
} catch (URISyntaxException | StorageException | IOException e) {
5757
logger.warn("can not access [{}] in container {{}}: {}", blobName, blobStore, e.getMessage());
5858
}
5959
return false;
@@ -88,7 +88,6 @@ public InputStream readBlob(String blobName) throws IOException {
8888
@Override
8989
public void writeBlob(String blobName, InputStream inputStream, long blobSize, boolean failIfAlreadyExists) throws IOException {
9090
logger.trace("writeBlob({}, stream, {})", buildKey(blobName), blobSize);
91-
9291
try {
9392
blobStore.writeBlob(buildKey(blobName), inputStream, blobSize, failIfAlreadyExists);
9493
} catch (URISyntaxException|StorageException e) {

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

+5-7
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,20 @@
2020
package org.elasticsearch.repositories.azure;
2121

2222
import com.microsoft.azure.storage.LocationMode;
23-
2423
import com.microsoft.azure.storage.StorageException;
2524
import org.elasticsearch.cluster.metadata.RepositoryMetaData;
2625
import org.elasticsearch.common.blobstore.BlobContainer;
2726
import org.elasticsearch.common.blobstore.BlobMetaData;
2827
import org.elasticsearch.common.blobstore.BlobPath;
2928
import org.elasticsearch.common.blobstore.BlobStore;
3029
import org.elasticsearch.common.component.AbstractComponent;
30+
3131
import java.io.IOException;
3232
import java.io.InputStream;
3333
import java.net.URISyntaxException;
34-
import java.nio.file.FileAlreadyExistsException;
3534
import java.util.Map;
3635

3736
import static java.util.Collections.emptyMap;
38-
3937
import static org.elasticsearch.repositories.azure.AzureRepository.Repository;
4038

4139
public class AzureBlobStore extends AbstractComponent implements BlobStore {
@@ -94,11 +92,11 @@ public void delete(BlobPath path) throws IOException {
9492
public void close() {
9593
}
9694

97-
public boolean blobExists(String blob) throws URISyntaxException, StorageException {
95+
public boolean blobExists(String blob) throws URISyntaxException, StorageException, IOException {
9896
return service.blobExists(clientName, container, blob);
9997
}
10098

101-
public void deleteBlob(String blob) throws URISyntaxException, StorageException {
99+
public void deleteBlob(String blob) throws URISyntaxException, StorageException, IOException {
102100
service.deleteBlob(clientName, container, blob);
103101
}
104102

@@ -107,12 +105,12 @@ public InputStream getInputStream(String blob) throws URISyntaxException, Storag
107105
}
108106

109107
public Map<String, BlobMetaData> listBlobsByPrefix(String keyPath, String prefix)
110-
throws URISyntaxException, StorageException {
108+
throws URISyntaxException, StorageException, IOException {
111109
return service.listBlobsByPrefix(clientName, container, keyPath, prefix);
112110
}
113111

114112
public void writeBlob(String blobName, InputStream inputStream, long blobSize, boolean failIfAlreadyExists)
115-
throws URISyntaxException, StorageException, FileAlreadyExistsException {
113+
throws URISyntaxException, StorageException, IOException {
116114
service.writeBlob(this.clientName, container, blobName, inputStream, blobSize, failIfAlreadyExists);
117115
}
118116
}

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ public InputStream getInputStream(String account, String container, String blob)
206206
}
207207

208208
public Map<String, BlobMetaData> listBlobsByPrefix(String account, String container, String keyPath, String prefix)
209-
throws URISyntaxException, StorageException {
209+
throws URISyntaxException, StorageException, IOException {
210210
// NOTE: this should be here: if (prefix == null) prefix = "";
211211
// however, this is really inefficient since deleteBlobsByPrefix enumerates everything and
212212
// then does a prefix match on the result; it should just call listBlobsByPrefix with the prefix!
@@ -233,8 +233,9 @@ public Map<String, BlobMetaData> listBlobsByPrefix(String account, String contai
233233
}
234234

235235
public void writeBlob(String account, String container, String blobName, InputStream inputStream, long blobSize,
236-
boolean failIfAlreadyExists)
237-
throws URISyntaxException, StorageException, FileAlreadyExistsException {
236+
boolean failIfAlreadyExists) throws URISyntaxException, StorageException, IOException {
237+
assert inputStream.markSupported()
238+
: "Should not be used with non-mark supporting streams as their retry handling in the SDK is broken";
238239
logger.trace(() -> new ParameterizedMessage("writeBlob({}, stream, {})", blobName, blobSize));
239240
final Tuple<CloudBlobClient, Supplier<OperationContext>> client = client(account);
240241
final CloudBlobContainer blobContainer = client.v1().getContainerReference(container);

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

+8-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.repositories.azure;
2121

2222
import com.microsoft.azure.storage.StorageException;
23+
import org.apache.logging.log4j.core.util.Throwables;
2324
import org.elasticsearch.SpecialPermission;
2425

2526
import java.io.IOException;
@@ -44,7 +45,9 @@ public static <T> T doPrivilegedIOException(PrivilegedExceptionAction<T> operati
4445
try {
4546
return AccessController.doPrivileged(operation);
4647
} catch (PrivilegedActionException e) {
47-
throw (IOException) e.getCause();
48+
Throwables.rethrow(e.getCause());
49+
assert false : "always throws";
50+
return null;
4851
}
4952
}
5053

@@ -53,7 +56,9 @@ public static <T> T doPrivilegedException(PrivilegedExceptionAction<T> operation
5356
try {
5457
return AccessController.doPrivileged(operation);
5558
} catch (PrivilegedActionException e) {
56-
throw (StorageException) e.getCause();
59+
Throwables.rethrow(e.getCause());
60+
assert false : "always throws";
61+
return null;
5762
}
5863
}
5964

@@ -65,12 +70,7 @@ public static void doPrivilegedVoidException(StorageRunnable action) throws Stor
6570
return null;
6671
});
6772
} catch (PrivilegedActionException e) {
68-
Throwable cause = e.getCause();
69-
if (cause instanceof StorageException) {
70-
throw (StorageException) cause;
71-
} else {
72-
throw (URISyntaxException) cause;
73-
}
73+
Throwables.rethrow(e.getCause());
7474
}
7575
}
7676

0 commit comments

Comments
 (0)