You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by et...@apache.org on 2026/04/14 07:16:30 UTC
(iceberg) branch main updated: ADLS: Throw NotFoundException for inexistent input file (#15806)
This is an automated email from the ASF dual-hosted git repository.
etudenhoefner pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/main by this push:
new 8808f77616 ADLS: Throw NotFoundException for inexistent input file (#15806)
8808f77616 is described below
commit 8808f7761637415f933b97c386f5646f3356896f
Author: Marius Grama <fi...@gmail.com>
AuthorDate: Tue Apr 14 09:16:23 2026 +0200
ADLS: Throw NotFoundException for inexistent input file (#15806)
Signal to the TableOperations that there is no retry needed
for files which do not exist.
---
.../iceberg/azure/adlsv2/TestADLSFileIO.java | 20 ++++++++++++++++++
.../iceberg/azure/adlsv2/TestADLSInputStream.java | 22 ++++++++++++++------
.../apache/iceberg/azure/adlsv2/ADLSInputFile.java | 2 +-
.../iceberg/azure/adlsv2/ADLSInputStream.java | 24 ++++++++++++++++++++++
.../iceberg/azure/adlsv2/TestADLSInputStream.java | 8 +++++++-
5 files changed, 68 insertions(+), 8 deletions(-)
diff --git a/azure/src/integration/java/org/apache/iceberg/azure/adlsv2/TestADLSFileIO.java b/azure/src/integration/java/org/apache/iceberg/azure/adlsv2/TestADLSFileIO.java
index 5e343782ab..621813a255 100644
--- a/azure/src/integration/java/org/apache/iceberg/azure/adlsv2/TestADLSFileIO.java
+++ b/azure/src/integration/java/org/apache/iceberg/azure/adlsv2/TestADLSFileIO.java
@@ -20,6 +20,7 @@ package org.apache.iceberg.azure.adlsv2;
import static org.apache.iceberg.azure.AzureProperties.ADLS_SAS_TOKEN_PREFIX;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
@@ -31,6 +32,7 @@ import static org.mockito.Mockito.when;
import com.azure.core.http.rest.PagedIterable;
import com.azure.core.http.rest.Response;
+import com.azure.storage.blob.models.BlobStorageException;
import com.azure.storage.file.datalake.DataLakeFileClient;
import com.azure.storage.file.datalake.DataLakeFileSystemClient;
import com.azure.storage.file.datalake.DataLakeFileSystemClientBuilder;
@@ -42,6 +44,7 @@ import java.time.OffsetDateTime;
import java.util.Iterator;
import org.apache.iceberg.TestHelpers;
import org.apache.iceberg.azure.AzureProperties;
+import org.apache.iceberg.exceptions.NotFoundException;
import org.apache.iceberg.io.FileIO;
import org.apache.iceberg.io.FileInfo;
import org.apache.iceberg.io.InputFile;
@@ -78,6 +81,23 @@ public class TestADLSFileIO extends AzuriteTestBase {
assertThat(fileClient.exists()).isFalse();
}
+ @Test
+ public void readMissingLocation() {
+ String path = "path/to/file";
+ String location = AZURITE_CONTAINER.location(path);
+ ADLSFileIO io = createFileIO();
+ DataLakeFileClient fileClient = AZURITE_CONTAINER.fileClient(path);
+ assertThat(fileClient.exists()).isFalse();
+
+ InputFile inputFile = io.newInputFile(location);
+
+ assertThatThrownBy(inputFile::newStream)
+ .isInstanceOf(NotFoundException.class)
+ .hasCauseInstanceOf(BlobStorageException.class)
+ .hasMessage(
+ "Location does not exist: abfs://container@account.dfs.core.windows.net/path/to/file");
+ }
+
@Test
public void testBulkDeleteFiles() {
String path1 = "path/to/file1";
diff --git a/azure/src/integration/java/org/apache/iceberg/azure/adlsv2/TestADLSInputStream.java b/azure/src/integration/java/org/apache/iceberg/azure/adlsv2/TestADLSInputStream.java
index 8464e57516..1edf48eaec 100644
--- a/azure/src/integration/java/org/apache/iceberg/azure/adlsv2/TestADLSInputStream.java
+++ b/azure/src/integration/java/org/apache/iceberg/azure/adlsv2/TestADLSInputStream.java
@@ -39,6 +39,10 @@ public class TestADLSInputStream extends AzuriteTestBase {
private final Random random = new Random(1);
private final AzureProperties azureProperties = new AzureProperties();
+ private String location() {
+ return AZURITE_CONTAINER.location(FILE_PATH);
+ }
+
private DataLakeFileClient fileClient() {
return AZURITE_CONTAINER.fileClient(FILE_PATH);
}
@@ -55,7 +59,8 @@ public class TestADLSInputStream extends AzuriteTestBase {
setupData(data);
try (SeekableInputStream in =
- new ADLSInputStream(fileClient(), null, azureProperties, MetricsContext.nullMetrics())) {
+ new ADLSInputStream(
+ location(), fileClient(), null, azureProperties, MetricsContext.nullMetrics())) {
int readSize = 1024;
readAndCheck(in, in.getPos(), readSize, data, false);
@@ -90,7 +95,8 @@ public class TestADLSInputStream extends AzuriteTestBase {
setupData(data);
try (SeekableInputStream in =
- new ADLSInputStream(fileClient(), null, azureProperties, MetricsContext.nullMetrics())) {
+ new ADLSInputStream(
+ location(), fileClient(), null, azureProperties, MetricsContext.nullMetrics())) {
assertThat(in.read()).isEqualTo(i0);
assertThat(in.read()).isEqualTo(i1);
}
@@ -131,7 +137,8 @@ public class TestADLSInputStream extends AzuriteTestBase {
setupData(expected);
try (RangeReadable in =
- new ADLSInputStream(fileClient(), null, azureProperties, MetricsContext.nullMetrics())) {
+ new ADLSInputStream(
+ location(), fileClient(), null, azureProperties, MetricsContext.nullMetrics())) {
// first 1k
position = 0;
offset = 0;
@@ -164,7 +171,8 @@ public class TestADLSInputStream extends AzuriteTestBase {
public void testClose() throws Exception {
setupData(randomData(2));
SeekableInputStream closed =
- new ADLSInputStream(fileClient(), null, azureProperties, MetricsContext.nullMetrics());
+ new ADLSInputStream(
+ location(), fileClient(), null, azureProperties, MetricsContext.nullMetrics());
closed.close();
assertThatThrownBy(() -> closed.seek(0))
.isInstanceOf(IllegalStateException.class)
@@ -178,7 +186,8 @@ public class TestADLSInputStream extends AzuriteTestBase {
setupData(data);
try (SeekableInputStream in =
- new ADLSInputStream(fileClient(), null, azureProperties, MetricsContext.nullMetrics())) {
+ new ADLSInputStream(
+ location(), fileClient(), null, azureProperties, MetricsContext.nullMetrics())) {
in.seek(data.length / 2);
byte[] actual = new byte[data.length / 2];
@@ -193,7 +202,8 @@ public class TestADLSInputStream extends AzuriteTestBase {
public void testSeekNegative() throws Exception {
setupData(randomData(2));
SeekableInputStream in =
- new ADLSInputStream(fileClient(), null, azureProperties, MetricsContext.nullMetrics());
+ new ADLSInputStream(
+ location(), fileClient(), null, azureProperties, MetricsContext.nullMetrics());
assertThatThrownBy(() -> in.seek(-3))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Cannot seek: position -3 is negative");
diff --git a/azure/src/main/java/org/apache/iceberg/azure/adlsv2/ADLSInputFile.java b/azure/src/main/java/org/apache/iceberg/azure/adlsv2/ADLSInputFile.java
index 95e57bf04d..5b07534f13 100644
--- a/azure/src/main/java/org/apache/iceberg/azure/adlsv2/ADLSInputFile.java
+++ b/azure/src/main/java/org/apache/iceberg/azure/adlsv2/ADLSInputFile.java
@@ -55,6 +55,6 @@ class ADLSInputFile extends BaseADLSFile implements InputFile {
@Override
public SeekableInputStream newStream() {
- return new ADLSInputStream(fileClient(), fileSize, azureProperties(), metrics());
+ return new ADLSInputStream(location(), fileClient(), fileSize, azureProperties(), metrics());
}
}
diff --git a/azure/src/main/java/org/apache/iceberg/azure/adlsv2/ADLSInputStream.java b/azure/src/main/java/org/apache/iceberg/azure/adlsv2/ADLSInputStream.java
index 55ecade448..b1a2d3abfa 100644
--- a/azure/src/main/java/org/apache/iceberg/azure/adlsv2/ADLSInputStream.java
+++ b/azure/src/main/java/org/apache/iceberg/azure/adlsv2/ADLSInputStream.java
@@ -18,14 +18,18 @@
*/
package org.apache.iceberg.azure.adlsv2;
+import com.azure.storage.blob.models.BlobErrorCode;
+import com.azure.storage.blob.models.BlobStorageException;
import com.azure.storage.file.datalake.DataLakeFileClient;
import com.azure.storage.file.datalake.models.DataLakeFileOpenInputStreamResult;
+import com.azure.storage.file.datalake.models.DataLakeStorageException;
import com.azure.storage.file.datalake.models.FileRange;
import com.azure.storage.file.datalake.options.DataLakeFileInputStreamOptions;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import org.apache.iceberg.azure.AzureProperties;
+import org.apache.iceberg.exceptions.NotFoundException;
import org.apache.iceberg.io.FileIOMetricsContext;
import org.apache.iceberg.io.IOUtil;
import org.apache.iceberg.io.RangeReadable;
@@ -46,6 +50,7 @@ class ADLSInputStream extends SeekableInputStream implements RangeReadable {
private static final int SKIP_SIZE = 1024 * 1024;
private final StackTraceElement[] createStack;
+ private final String location;
private final DataLakeFileClient fileClient;
private Long fileSize;
private final AzureProperties azureProperties;
@@ -59,10 +64,12 @@ class ADLSInputStream extends SeekableInputStream implements RangeReadable {
private final Counter readOperations;
ADLSInputStream(
+ String location,
DataLakeFileClient fileClient,
Long fileSize,
AzureProperties azureProperties,
MetricsContext metrics) {
+ this.location = location;
this.fileClient = fileClient;
this.fileSize = fileSize;
this.azureProperties = azureProperties;
@@ -184,6 +191,7 @@ class ADLSInputStream extends SeekableInputStream implements RangeReadable {
try {
return fileClient.openInputStream(getInputOptions(range));
} catch (RuntimeException e) {
+ throwNotFoundIfNotPresent(e, location);
LOG.error(
"Failed to open input stream for file {}, range {}", fileClient.getFilePath(), range, e);
throw e;
@@ -209,4 +217,20 @@ class ADLSInputStream extends SeekableInputStream implements RangeReadable {
LOG.warn("Unclosed input stream created by:\n\t{}", trace);
}
}
+
+ private static void throwNotFoundIfNotPresent(Throwable throwable, String location) {
+ if (isFileNotFoundException(throwable)) {
+ throw new NotFoundException(throwable, "Location does not exist: %s", location);
+ }
+ }
+
+ private static boolean isFileNotFoundException(Throwable exception) {
+ if (exception instanceof BlobStorageException blobStorageException) {
+ return BlobErrorCode.BLOB_NOT_FOUND.equals(blobStorageException.getErrorCode());
+ }
+ if (exception instanceof DataLakeStorageException dataLakeStorageException) {
+ return "PathNotFound".equals(dataLakeStorageException.getErrorCode());
+ }
+ return false;
+ }
}
diff --git a/azure/src/test/java/org/apache/iceberg/azure/adlsv2/TestADLSInputStream.java b/azure/src/test/java/org/apache/iceberg/azure/adlsv2/TestADLSInputStream.java
index 058bf0372b..e98061846a 100644
--- a/azure/src/test/java/org/apache/iceberg/azure/adlsv2/TestADLSInputStream.java
+++ b/azure/src/test/java/org/apache/iceberg/azure/adlsv2/TestADLSInputStream.java
@@ -46,7 +46,13 @@ class TestADLSInputStream {
InternalDataLakeFileOpenInputStreamResult openInputStreamResult =
new InternalDataLakeFileOpenInputStreamResult(inputStream, mock());
when(fileClient.openInputStream(any())).thenReturn(openInputStreamResult);
- adlsInputStream = new ADLSInputStream(fileClient, 0L, mock(), mock());
+ adlsInputStream =
+ new ADLSInputStream(
+ "abfs://container@account.dfs.core.windows.net/path/to/file",
+ fileClient,
+ 0L,
+ mock(),
+ mock());
}
@Test