Skip to content

Commit 7261656

Browse files
authored
Explicitly throw when sync iceberg conversion fails (#2886)
## Description sync iceberg conversion happens when enabled with session config, or uniform iceberg is turned on for the first time. This explicitly throws when sync iceberg conversion fails so user knows conversion status. ## How was this patch tested? UT
1 parent 9bae749 commit 7261656

File tree

4 files changed

+57
-16
lines changed

4 files changed

+57
-16
lines changed

iceberg/src/main/scala/org/apache/spark/sql/delta/icebergShaded/IcebergConverter.scala

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import scala.collection.JavaConverters._
2323
import scala.util.control.Breaks._
2424
import scala.util.control.NonFatal
2525

26-
import org.apache.spark.sql.delta.{DeltaFileNotFoundException, DeltaFileProviderUtils, OptimisticTransactionImpl, Snapshot, UniversalFormat, UniversalFormatConverter}
26+
import org.apache.spark.sql.delta.{DeltaErrors, DeltaFileNotFoundException, DeltaFileProviderUtils, OptimisticTransactionImpl, Snapshot, UniversalFormat, UniversalFormatConverter}
2727
import org.apache.spark.sql.delta.actions.{Action, AddFile, CommitInfo, RemoveFile}
2828
import org.apache.spark.sql.delta.hooks.IcebergConverterHook
2929
import org.apache.spark.sql.delta.metering.DeltaLogging
@@ -169,10 +169,21 @@ class IcebergConverter(spark: SparkSession)
169169
*/
170170
override def convertSnapshot(
171171
snapshotToConvert: Snapshot, catalogTable: CatalogTable): Option[(Long, Long)] = {
172-
if (!UniversalFormat.icebergEnabled(snapshotToConvert.metadata)) {
173-
return None
172+
try {
173+
convertSnapshot(snapshotToConvert, None, catalogTable)
174+
} catch {
175+
case NonFatal(e) =>
176+
logError(s"Error when converting to Iceberg metadata", e)
177+
recordDeltaEvent(
178+
snapshotToConvert.deltaLog,
179+
"delta.iceberg.conversion.error",
180+
data = Map(
181+
"exception" -> ExceptionUtils.getMessage(e),
182+
"stackTrace" -> ExceptionUtils.getStackTrace(e)
183+
)
184+
)
185+
throw e
174186
}
175-
convertSnapshot(snapshotToConvert, None, catalogTable)
176187
}
177188

178189
/**
@@ -185,22 +196,27 @@ class IcebergConverter(spark: SparkSession)
185196
*/
186197
override def convertSnapshot(
187198
snapshotToConvert: Snapshot, txn: OptimisticTransactionImpl): Option[(Long, Long)] = {
188-
if (!UniversalFormat.icebergEnabled(snapshotToConvert.metadata)) {
189-
return None
190-
}
191-
txn.catalogTable match {
192-
case Some(table) => convertSnapshot(snapshotToConvert, Some(txn), table)
193-
case _ =>
194-
logWarning(s"CatalogTable for table ${snapshotToConvert.deltaLog.tableId} " +
195-
s"is empty in txn. Skip iceberg conversion.")
199+
try {
200+
txn.catalogTable match {
201+
case Some(table) => convertSnapshot(snapshotToConvert, Some(txn), table)
202+
case _ =>
203+
val msg = s"CatalogTable for table ${snapshotToConvert.deltaLog.tableId} " +
204+
s"is empty in txn. Skip iceberg conversion."
205+
throw DeltaErrors.universalFormatConversionFailedException(
206+
snapshotToConvert.version, "iceberg", msg)
207+
}
208+
} catch {
209+
case NonFatal(e) =>
210+
logError(s"Error when converting to Iceberg metadata", e)
196211
recordDeltaEvent(
197-
snapshotToConvert.deltaLog,
198-
"delta.iceberg.conversion.skipped.emptyCatalogTable",
212+
txn.deltaLog,
213+
"delta.iceberg.conversion.error",
199214
data = Map(
200-
"version" -> snapshotToConvert.version
215+
"exception" -> ExceptionUtils.getMessage(e),
216+
"stackTrace" -> ExceptionUtils.getStackTrace(e)
201217
)
202218
)
203-
None
219+
throw e
204220
}
205221
}
206222

spark/src/main/resources/error/delta-error-classes.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2320,6 +2320,12 @@
23202320
],
23212321
"sqlState" : "XXKDS"
23222322
},
2323+
"DELTA_UNIVERSAL_FORMAT_CONVERSION_FAILED" : {
2324+
"message" : [
2325+
"Failed to convert the table version <version> to the universal format <format>. <message>"
2326+
],
2327+
"sqlState" : "KD00E"
2328+
},
23232329
"DELTA_UNIVERSAL_FORMAT_VIOLATION" : {
23242330
"message" : [
23252331
"The validation of Universal Format (<format>) has failed: <violation>"

spark/src/main/scala/org/apache/spark/sql/delta/DeltaErrors.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,6 +3213,16 @@ trait DeltaErrorsBase
32133213
)
32143214
}
32153215

3216+
def universalFormatConversionFailedException(
3217+
failedOnCommitVersion: Long,
3218+
format: String,
3219+
errorMessage: String): Throwable = {
3220+
new DeltaRuntimeException(
3221+
errorClass = "DELTA_UNIVERSAL_FORMAT_CONVERSION_FAILED",
3222+
messageParameters = Array(s"$failedOnCommitVersion", format, errorMessage)
3223+
)
3224+
}
3225+
32163226
def invalidAutoCompactType(value: String): Throwable = {
32173227
new DeltaIllegalArgumentException(
32183228
errorClass = "DELTA_INVALID_AUTO_COMPACT_TYPE",

spark/src/main/scala/org/apache/spark/sql/delta/hooks/IcebergConverterHook.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
package org.apache.spark.sql.delta.hooks
1818

1919
import org.apache.spark.sql.delta.{OptimisticTransactionImpl, Snapshot, UniversalFormat}
20+
import org.apache.spark.sql.delta.DeltaErrors
2021
import org.apache.spark.sql.delta.actions.{Action, Metadata}
2122
import org.apache.spark.sql.delta.metering.DeltaLogging
2223
import org.apache.spark.sql.delta.sources.DeltaSQLConf.DELTA_UNIFORM_ICEBERG_SYNC_CONVERT_ENABLED
24+
import org.apache.commons.lang3.exception.ExceptionUtils
2325

2426
import org.apache.spark.sql.SparkSession
2527

@@ -52,4 +54,11 @@ object IcebergConverterHook extends PostCommitHook with DeltaLogging {
5254
converter.enqueueSnapshotForConversion(postCommitSnapshot, txn)
5355
}
5456
}
57+
58+
// Always throw when sync Iceberg conversion fails. Async conversion exception
59+
// is handled in the async thread.
60+
override def handleError(spark: SparkSession, error: Throwable, version: Long): Unit = {
61+
throw DeltaErrors.universalFormatConversionFailedException(
62+
version, "iceberg", ExceptionUtils.getMessage(error))
63+
}
5564
}

0 commit comments

Comments
 (0)