Skip to content

Commit c8bbd5b

Browse files
[Kernel] Refactor all user-facing exceptions to be "KernelExceptions" (#3014)
<!-- Thanks for sending a pull request! Here are some tips for you: 1. If this is your first time, please read our contributor guidelines: https://github.com/delta-io/delta/blob/master/CONTRIBUTING.md 2. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP] Your PR title ...'. 3. Be sure to keep the PR description updated to reflect all changes. 4. Please write your PR title to summarize what this PR proposes. 5. If possible, provide a concise example to reproduce the issue for a faster review. 6. If applicable, include the corresponding issue number in the PR title and link it in the body. --> #### Which Delta project/connector is this regarding? <!-- Please add the component selected below to the beginning of the pull request title For example: [Spark] Title of my pull request --> - [ ] Spark - [ ] Standalone - [ ] Flink - [X] Kernel - [ ] Other (fill in here) ## Description In order to provide a unified and user-friendly experience we are making all user-facing exceptions instances of one parent class `KernelException`. This PR also attempts to unify/improve some of these error messsages. ## How was this patch tested? Existing tests should suffice (updated to match the changes here). ## Does this PR introduce _any_ user-facing changes? Yes, changes exception types + messages. (cherry picked from commit c426f03)
1 parent f4555f5 commit c8bbd5b

File tree

22 files changed

+243
-166
lines changed

22 files changed

+243
-166
lines changed

connectors/flink/src/main/scala/io/delta/flink/internal/KernelDeltaLogDelegator.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ package io.delta.standalone.internal
2020

2121
import org.apache.hadoop.conf.Configuration
2222
import org.apache.hadoop.fs.Path
23-
24-
import io.delta.kernel.{Table, TableNotFoundException}
23+
import io.delta.kernel.Table
2524
import io.delta.kernel.defaults.engine.DefaultEngine
25+
import io.delta.kernel.exceptions.TableNotFoundException
2626
import io.delta.kernel.internal.{TableImpl, SnapshotImpl => SnapshotImplKernel}
2727
import io.delta.standalone.VersionLog
2828
import io.delta.standalone.actions.{CommitInfo => CommitInfoJ}

kernel/examples/table-reader/src/main/java/io/delta/kernel/examples/BaseTableReader.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
import org.apache.commons.cli.ParseException;
3737
import org.apache.hadoop.conf.Configuration;
3838

39-
import io.delta.kernel.TableNotFoundException;
4039
import io.delta.kernel.engine.Engine;
40+
import io.delta.kernel.exceptions.TableNotFoundException;
4141
import io.delta.kernel.data.FilteredColumnarBatch;
4242
import io.delta.kernel.data.Row;
4343
import io.delta.kernel.expressions.Predicate;

kernel/examples/table-reader/src/main/java/io/delta/kernel/examples/MultiThreadedTableReader.java

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.delta.kernel.data.FilteredColumnarBatch;
3232
import io.delta.kernel.data.Row;
3333
import io.delta.kernel.examples.utils.RowSerDe;
34+
import io.delta.kernel.exceptions.TableNotFoundException;
3435
import io.delta.kernel.expressions.Predicate;
3536
import io.delta.kernel.types.StructType;
3637
import io.delta.kernel.utils.CloseableIterator;

kernel/examples/table-reader/src/main/java/io/delta/kernel/examples/SingleThreadedTableReader.java

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import io.delta.kernel.data.ColumnarBatch;
2626
import io.delta.kernel.data.FilteredColumnarBatch;
2727
import io.delta.kernel.data.Row;
28+
import io.delta.kernel.exceptions.TableNotFoundException;
2829
import io.delta.kernel.expressions.Predicate;
2930
import io.delta.kernel.types.StructType;
3031
import io.delta.kernel.utils.CloseableIterator;

kernel/kernel-api/src/main/java/io/delta/kernel/Table.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
import io.delta.kernel.annotation.Evolving;
2121
import io.delta.kernel.engine.Engine;
22-
22+
import io.delta.kernel.exceptions.CheckpointAlreadyExistsException;
23+
import io.delta.kernel.exceptions.KernelException;
24+
import io.delta.kernel.exceptions.TableNotFoundException;
2325
import io.delta.kernel.internal.TableImpl;
2426

2527
/**
@@ -84,6 +86,8 @@ Snapshot getLatestSnapshot(Engine engine)
8486
* @param engine {@link Engine} instance to use in Delta Kernel.
8587
* @param versionId snapshot version to retrieve
8688
* @return an instance of {@link Snapshot}
89+
* @throws KernelException if the provided version is less than the first available version
90+
* or greater than the last available version
8791
* @since 3.2.0
8892
*/
8993
Snapshot getSnapshotAsOfVersion(Engine engine, long versionId)
@@ -109,6 +113,8 @@ Snapshot getSnapshotAsOfVersion(Engine engine, long versionId)
109113
* @param millisSinceEpochUTC timestamp to fetch the snapshot for in milliseconds since the
110114
* unix epoch
111115
* @return an instance of {@link Snapshot}
116+
* @throws KernelException if the provided timestamp is before the earliest available version or
117+
* after the latest available version
112118
* @since 3.2.0
113119
*/
114120
Snapshot getSnapshotAsOfTimestamp(Engine engine, long millisSinceEpochUTC)

kernel/kernel-api/src/main/java/io/delta/kernel/CheckpointAlreadyExistsException.java kernel/kernel-api/src/main/java/io/delta/kernel/exceptions/CheckpointAlreadyExistsException.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package io.delta.kernel;
16+
package io.delta.kernel.exceptions;
1717

1818
import static java.lang.String.format;
1919

@@ -26,7 +26,7 @@
2626
* @since 3.2.0
2727
*/
2828
@Evolving
29-
public class CheckpointAlreadyExistsException extends IllegalArgumentException {
29+
public class CheckpointAlreadyExistsException extends KernelException {
3030
public CheckpointAlreadyExistsException(long version) {
3131
super(format("Checkpoint for given version %d already exists in the table", version));
3232
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (2024) The Delta Lake Project Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.delta.kernel.exceptions;
17+
18+
/**
19+
* Thrown when Kernel cannot execute the requested operation due to the operation being invalid
20+
* or unsupported.
21+
*/
22+
public class KernelException extends RuntimeException {
23+
24+
public KernelException() {
25+
super();
26+
}
27+
28+
public KernelException(String message) {
29+
super(message);
30+
}
31+
32+
public KernelException(Throwable cause) {
33+
super(cause);
34+
}
35+
36+
public KernelException(String message, Throwable cause) {
37+
super(message, cause);
38+
}
39+
}

kernel/kernel-api/src/main/java/io/delta/kernel/TableNotFoundException.java kernel/kernel-api/src/main/java/io/delta/kernel/exceptions/TableNotFoundException.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package io.delta.kernel;
17+
package io.delta.kernel.exceptions;
1818

1919
import io.delta.kernel.annotation.Evolving;
2020

@@ -24,22 +24,23 @@
2424
* @since 3.0.0
2525
*/
2626
@Evolving
27-
public class TableNotFoundException
28-
extends Exception {
27+
public class TableNotFoundException extends KernelException {
2928

3029
private final String tablePath;
3130

3231
public TableNotFoundException(String tablePath) {
33-
this.tablePath = tablePath;
32+
this(tablePath, null);
3433
}
3534

3635
public TableNotFoundException(String tablePath, Throwable cause) {
37-
super(cause);
36+
super(String.format("Delta table at path `%s` is not found", tablePath), cause);
3837
this.tablePath = tablePath;
3938
}
4039

41-
@Override
42-
public String getMessage() {
43-
return String.format("Delta table at path `%s` is not found", tablePath);
40+
/**
41+
* @return the provided path where no Delta table was found
42+
*/
43+
public String getTablePath() {
44+
return tablePath;
4445
}
4546
}

kernel/kernel-api/src/main/java/io/delta/kernel/internal/DeltaErrors.java

+77-75
Original file line numberDiff line numberDiff line change
@@ -16,120 +16,122 @@
1616
package io.delta.kernel.internal;
1717

1818
import java.sql.Timestamp;
19-
import java.util.Optional;
2019

21-
import io.delta.kernel.expressions.Expression;
20+
import io.delta.kernel.exceptions.KernelException;
2221

22+
/**
23+
* Contains methods to create user-facing Delta exceptions.
24+
*/
2325
public final class DeltaErrors {
2426
private DeltaErrors() {}
2527

26-
// TODO update to be user-facing exception with future exception framework
27-
// (see delta-io/delta#2231) & document in method docs as needed (Table::getSnapshotAtVersion)
28-
public static RuntimeException nonReconstructableStateException(
29-
String tablePath, long version) {
28+
public static KernelException versionBeforeFirstAvailableCommit(
29+
String tablePath, long versionToLoad, long earliestVersion) {
3030
String message = String.format(
31-
"%s: Unable to reconstruct state at version %s as the transaction log has been " +
32-
"truncated due to manual deletion or the log retention policy and checkpoint " +
33-
"retention policy.",
31+
"%s: Cannot load table version %s as the transaction log has been truncated due to " +
32+
"manual deletion or the log/checkpoint retention policy. The earliest available " +
33+
"version is %s.",
3434
tablePath,
35-
version);
36-
return new RuntimeException(message);
35+
versionToLoad,
36+
earliestVersion);
37+
return new KernelException(message);
3738
}
3839

39-
// TODO update to be user-facing exception with future exception framework
40-
// (see delta-io/delta#2231) & document in method docs as needed (Table::getSnapshotAtVersion)
41-
public static RuntimeException nonExistentVersionException(
40+
public static KernelException versionAfterLatestCommit(
4241
String tablePath, long versionToLoad, long latestVersion) {
4342
String message = String.format(
44-
"%s: Trying to load a non-existent version %s. The latest version available is %s",
43+
"%s: Cannot load table version %s as it does not exist. " +
44+
"The latest available version is %s.",
4545
tablePath,
4646
versionToLoad,
4747
latestVersion);
48-
return new RuntimeException(message);
48+
return new KernelException(message);
4949
}
5050

51-
// TODO update to be user-facing exception with future exception framework
52-
// (see delta-io/delta#2231) & document in method docs as needed
53-
// (Table::getSnapshotAtTimestamp)
54-
public static RuntimeException timestampEarlierThanTableFirstCommitException(
55-
String tablePath, long providedTimestamp, long commitTimestamp) {
51+
public static KernelException timestampBeforeFirstAvailableCommit(
52+
String tablePath,
53+
long providedTimestamp,
54+
long earliestCommitTimestamp,
55+
long earliestCommitVersion) {
5656
String message = String.format(
57-
"%s: The provided timestamp %s ms (%s) is before the earliest version available. " +
58-
"Please use a timestamp greater than or equal to %s ms (%s)",
57+
"%s: The provided timestamp %s ms (%s) is before the earliest available version %s. " +
58+
"Please use a timestamp greater than or equal to %s ms (%s).",
5959
tablePath,
6060
providedTimestamp,
6161
formatTimestamp(providedTimestamp),
62-
commitTimestamp,
63-
formatTimestamp(commitTimestamp));
64-
return new RuntimeException(message);
62+
earliestCommitVersion,
63+
earliestCommitTimestamp,
64+
formatTimestamp(earliestCommitTimestamp));
65+
return new KernelException(message);
6566
}
6667

67-
// TODO update to be user-facing exception with future exception framework
68-
// (see delta-io/delta#2231) & document in method docs as needed
69-
// (Table::getSnapshotAtTimestamp)
70-
public static RuntimeException timestampLaterThanTableLastCommit(
71-
String tablePath, long providedTimestamp, long commitTimestamp, long commitVersion) {
72-
String commitTimestampStr = formatTimestamp(commitTimestamp);
68+
public static KernelException timestampAfterLatestCommit(
69+
String tablePath,
70+
long providedTimestamp,
71+
long latestCommitTimestamp,
72+
long latestCommitVersion) {
7373
String message = String.format(
74-
"%s: The provided timestamp %s ms (%s) is after the latest commit with " +
75-
"timestamp %s ms (%s). If you wish to query this version of the table please " +
76-
"either provide the version %s or use the exact timestamp of the last " +
77-
"commit %s ms (%s)",
74+
"%s: The provided timestamp %s ms (%s) is after the latest available version %s. " +
75+
"Please use a timestamp less than or equal to %s ms (%s).",
7876
tablePath,
7977
providedTimestamp,
8078
formatTimestamp(providedTimestamp),
81-
commitTimestamp,
82-
commitTimestampStr,
83-
commitVersion,
84-
commitTimestamp,
85-
commitTimestampStr);
86-
return new RuntimeException(message);
79+
latestCommitVersion,
80+
latestCommitTimestamp,
81+
formatTimestamp(latestCommitTimestamp));
82+
return new KernelException(message);
8783
}
8884

89-
// TODO: Change the exception to proper type as part of the exception framework
90-
// (see delta-io/delta#2231)
91-
/**
92-
* Exception thrown when the expression evaluator doesn't support the given expression.
93-
* @param expression
94-
* @param reason Optional additional reason for why the expression is not supported.
95-
* @return
96-
*/
97-
public static UnsupportedOperationException unsupportedExpression(
98-
Expression expression,
99-
Optional<String> reason) {
85+
/* ------------------------ PROTOCOL EXCEPTIONS ----------------------------- */
86+
87+
public static KernelException unsupportedReaderProtocol(
88+
String tablePath, int tableReaderVersion) {
10089
String message = String.format(
101-
"Expression evaluator doesn't support the expression: %s.%s",
102-
expression,
103-
reason.map(r -> " Reason: " + r).orElse(""));
104-
return new UnsupportedOperationException(message);
90+
"Unsupported Delta protocol reader version: table `%s` requires reader version %s " +
91+
"which is unsupported by this version of Delta Kernel.",
92+
tablePath,
93+
tableReaderVersion);
94+
return new KernelException(message);
10595
}
10696

107-
public static UnsupportedOperationException unsupportedReaderProtocol(int readVersion) {
108-
throw new UnsupportedOperationException(
109-
"Unsupported reader protocol version: " + readVersion);
97+
public static KernelException unsupportedReaderFeature(
98+
String tablePath, String readerFeature) {
99+
String message = String.format(
100+
"Unsupported Delta reader feature: table `%s` requires reader table feature \"%s\" " +
101+
"which is unsupported by this version of Delta Kernel.",
102+
tablePath,
103+
readerFeature);
104+
return new KernelException(message);
110105
}
111106

112-
public static UnsupportedOperationException unsupportedReadFeature(
113-
int readProtocolVersion,
114-
String readFeature) {
115-
throw new UnsupportedOperationException(String.format(
116-
"Unsupported reader protocol version: %s with feature: %s",
117-
readProtocolVersion, readFeature));
107+
public static KernelException unsupportedWriterProtocol(
108+
String tablePath, int tableWriterVersion) {
109+
String message = String.format(
110+
"Unsupported Delta protocol writer version: table `%s` requires writer version %s " +
111+
"which is unsupported by this version of Delta Kernel.",
112+
tablePath,
113+
tableWriterVersion);
114+
return new KernelException(message);
118115
}
119116

120-
public static UnsupportedOperationException unsupportedWriterProtocol(int writeVersion) {
121-
throw new UnsupportedOperationException(
122-
"Unsupported writer protocol version: " + writeVersion);
117+
public static KernelException unsupportedWriterFeature(
118+
String tablePath, String writerFeature) {
119+
String message = String.format(
120+
"Unsupported Delta writer feature: table `%s` requires writer table feature \"%s\" " +
121+
"which is unsupported by this version of Delta Kernel.",
122+
tablePath,
123+
writerFeature);
124+
return new KernelException(message);
123125
}
124126

125-
public static UnsupportedOperationException unsupportedWriteFeature(
126-
int writeProtocolVersion,
127-
String writeFeature) {
128-
throw new UnsupportedOperationException(String.format(
129-
"Unsupported writer protocol version: %s with feature: %s",
130-
writeProtocolVersion, writeFeature));
127+
public static KernelException columnInvariantsNotSupported() {
128+
String message = "This version of Delta Kernel does not support writing to tables with " +
129+
"column invariants present.";
130+
return new KernelException(message);
131131
}
132132

133+
/* ------------------------ HELPER METHODS ----------------------------- */
134+
133135
private static String formatTimestamp(long millisSinceEpochUTC) {
134136
return new Timestamp(millisSinceEpochUTC).toInstant().toString();
135137
}

0 commit comments

Comments
 (0)