Skip to content

Commit e039838

Browse files
authored
Merge branch 'main' into fix/parallel-unit-tests
2 parents 93105d1 + ac0df5a commit e039838

8 files changed

Lines changed: 100 additions & 19 deletions

File tree

delta-lake/common/src/main/delta-33x-41x/scala/com/nvidia/spark/rapids/delta/common/GpuDeltaParquetFileFormatBase2.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ class GpuDeltaParquetFileFormatBase2(
312312
val (rowGroupOffsets, rowGroupNumRows) =
313313
RapidsDeletionVectors.getRowGroupMetadata(chunkedBlocks)
314314
val maybeDvInfo = maybeSerializedDV.map(serializedDV =>
315-
new DeletionVector.DeletionVectorInfo(serializedDV, rowGroupOffsets, rowGroupNumRows))
315+
new DeletionVector.DeletionVectorInfo(serializedDV,
316+
false, rowGroupOffsets, rowGroupNumRows))
316317

317318
val hostBuf = dataBuffer.getDataHostBuffer()
318319
// Duplicate request is ok, and start to use the GPU just after the host
@@ -686,6 +687,7 @@ class GpuDeltaParquetFileFormatBase2(
686687
.map(spillableDvInfo =>
687688
new DeletionVector.DeletionVectorInfo(
688689
spillableDvInfo.serializedBitmap.getDataHostBuffer(),
690+
false,
689691
spillableDvInfo.rowGroupOffsets,
690692
spillableDvInfo.rowGroupNumRows
691693
))
@@ -1193,7 +1195,8 @@ class GpuDeltaParquetFileFormatBase2(
11931195
.zip(batchExtra.perFileEntries)
11941196
.map { case (loaded, entry) =>
11951197
new DeletionVector.DeletionVectorInfo(
1196-
loaded.gpuBitmap.getDataHostBuffer(), entry.rowGroupOffsets, entry.rowGroupNumRows)
1198+
loaded.gpuBitmap.getDataHostBuffer(),
1199+
false, entry.rowGroupOffsets, entry.rowGroupNumRows)
11971200
}.toArray
11981201
// MakeParquetTableWithDVProducer closes the dataBuffer and the bitmaps in dvInfos.
11991202
MakeParquetTableWithDVProducer(useChunkedReader, maxChunkedReaderMemoryUsageSizeBytes,

delta-lake/delta-spark400db173/src/main/scala/com/nvidia/spark/rapids/delta/GpuDeltaParquetFileFormatNativeDV.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,8 @@ case class GpuDeltaParquetFileFormatNativeDV(
321321
val (rowGroupOffsets, rowGroupNumRows) =
322322
RapidsDeletionVectors.getRowGroupMetadata(chunkedBlocks)
323323
val maybeDvInfo = maybeSerializedDV.map(serializedDV =>
324-
new DeletionVector.DeletionVectorInfo(serializedDV, rowGroupOffsets, rowGroupNumRows))
324+
new DeletionVector.DeletionVectorInfo(serializedDV,
325+
false, rowGroupOffsets, rowGroupNumRows))
325326

326327
val hostBuf = dataBuffer.getDataHostBuffer()
327328
// Duplicate request is ok, and start to use the GPU just after the host
@@ -752,6 +753,7 @@ case class GpuDeltaParquetFileFormatNativeDV(
752753
.map(spillableDvInfo =>
753754
new DeletionVector.DeletionVectorInfo(
754755
spillableDvInfo.serializedBitmap.getDataHostBuffer(),
756+
false,
755757
spillableDvInfo.rowGroupOffsets,
756758
spillableDvInfo.rowGroupNumRows
757759
))
@@ -1350,7 +1352,8 @@ case class GpuDeltaParquetFileFormatNativeDV(
13501352
.zip(batchExtra.perFileEntries)
13511353
.map { case (loaded, entry) =>
13521354
new DeletionVector.DeletionVectorInfo(
1353-
loaded.gpuBitmap.getDataHostBuffer(), entry.rowGroupOffsets, entry.rowGroupNumRows)
1355+
loaded.gpuBitmap.getDataHostBuffer(),
1356+
false, entry.rowGroupOffsets, entry.rowGroupNumRows)
13541357
}.toArray
13551358
// MakeParquetTableWithDVProducer closes the dataBuffer and the bitmaps in dvInfos.
13561359
MakeParquetTableWithDVProducer(useChunkedReader, maxChunkedReaderMemoryUsageSizeBytes,

docs/additional-functionality/advanced_configs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Name | Description | Default Value | Applicable at
5050
<a name="memory.gpu.reserve"></a>spark.rapids.memory.gpu.reserve|The amount of GPU memory that should remain unallocated by RMM and left for system use such as memory needed for kernels and kernel launches.|671088640|Startup
5151
<a name="memory.gpu.state.debug"></a>spark.rapids.memory.gpu.state.debug|To better recover from out of memory errors, RMM will track several states for the threads that interact with the GPU. This provides a log of those state transitions to aid in debugging it. STDOUT or STDERR will have the logging go there empty string will disable logging and anything else will be treated as a file to write the logs to.||Startup
5252
<a name="memory.gpu.unspill.enabled"></a>spark.rapids.memory.gpu.unspill.enabled|When a spilled GPU buffer is needed again, should it be unspilled, or only copied back into GPU memory temporarily. Unspilling may be useful for GPU buffers that are needed frequently, for example, broadcast variables; however, it may also increase GPU memory usage|false|Startup
53-
<a name="perfio.gcs.enabled"></a>spark.rapids.perfio.gcs.enabled|Controls the Google Cloud Storage reader for improved performance in certain queries. When true, enables it and throws at startup if google-cloud-storage classes are not on the classpath. When false, disables it unconditionally. When unset (default), enables it opportunistically if google-cloud-storage classes are found, otherwise falls back to the configured GCS connector with a warning. The presence of com.google.cloud:google-cloud-storage on the executor classpath is required.|None|Startup
53+
<a name="perfio.gcs.enabled"></a>spark.rapids.perfio.gcs.enabled|Controls the Google Cloud Storage reader for improved performance in certain queries. When true, enables it. When false, disables it unconditionally. When unset (default), enables it on Google Cloud Dataproc when compatible connector classes are available; outside Dataproc it remains disabled. Explicit enablement fails at startup if the required classes are unavailable.|None|Startup
5454
<a name="perfio.s3.enabled"></a>spark.rapids.perfio.s3.enabled|Controls the AWS S3 reader for improved performance in certain queries. When true, enables it and throws at startup if no compatible HTTP client is on the classpath. When false, disables it unconditionally. When unset (default), enables it opportunistically if a compatible HTTP client is found, otherwise falls back to S3A with a warning. The presence of AWS SDK packages for Netty and/or CRT HTTP clients on the classpath is required. You can use Spark submit option `--packages software.amazon.awssdk:s3:2.22.12,software.amazon.awssdk:aws-crt-client:2.22.12` to achieve this. See https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/crt-based-s3-client.html#crt-based-s3-client-depend|None|Startup
5555
<a name="python.concurrentPythonWorkers"></a>spark.rapids.python.concurrentPythonWorkers|Set the number of Python worker processes that can execute concurrently per GPU. Python worker processes may temporarily block when the number of concurrent Python worker processes started by the same executor exceeds this amount. Allowing too many concurrent tasks on the same GPU may lead to GPU out of memory errors. >0 means enabled, while <=0 means unlimited|0|Runtime
5656
<a name="python.memory.gpu.allocFraction"></a>spark.rapids.python.memory.gpu.allocFraction|The fraction of total GPU memory that should be initially allocated for pooled memory for all the Python workers. It supposes to be less than (1 - $(spark.rapids.memory.gpu.allocFraction)), since the executor will share the GPU with its owning Python workers. Half of the rest will be used if not specified|None|Runtime

jenkins/databricks/init_cudf_udf.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
set -ex
2222

23-
# TODO: https://github.com/NVIDIA/cudf-spark/issues/15386
2423
CUDF_VER=${CUDF_VER:-26.10.0-SNAPSHOT}
2524
CUDA_VER=${CUDA_VER:-12.9}
2625

pom.xml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -987,10 +987,9 @@
987987
<spark.version.classifier>spark${buildver}</spark.version.classifier>
988988
<cuda.version>cuda12</cuda.version>
989989
<jni.classifier>${cuda.version}</jni.classifier>
990-
<!-- TODO: https://github.com/NVIDIA/cudf-spark/issues/15386 -->
991-
<spark-rapids-jni.version>26.08.0-SNAPSHOT</spark-rapids-jni.version>
992-
<spark-rapids-private.version>26.08.0-SNAPSHOT</spark-rapids-private.version>
993-
<spark-rapids-hybrid.version>26.08.0-SNAPSHOT</spark-rapids-hybrid.version>
990+
<spark-rapids-jni.version>26.10.0-SNAPSHOT</spark-rapids-jni.version>
991+
<spark-rapids-private.version>26.10.0-SNAPSHOT</spark-rapids-private.version>
992+
<spark-rapids-hybrid.version>26.10.0-SNAPSHOT</spark-rapids-hybrid.version>
994993
<scala.binary.version>2.12</scala.binary.version>
995994
<scala.recompileMode>incremental</scala.recompileMode>
996995
<scala.version>2.12.21</scala.version>

scala2.13/pom.xml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -987,10 +987,9 @@
987987
<spark.version.classifier>spark${buildver}</spark.version.classifier>
988988
<cuda.version>cuda12</cuda.version>
989989
<jni.classifier>${cuda.version}</jni.classifier>
990-
<!-- TODO: https://github.com/NVIDIA/cudf-spark/issues/15386 -->
991-
<spark-rapids-jni.version>26.08.0-SNAPSHOT</spark-rapids-jni.version>
992-
<spark-rapids-private.version>26.08.0-SNAPSHOT</spark-rapids-private.version>
993-
<spark-rapids-hybrid.version>26.08.0-SNAPSHOT</spark-rapids-hybrid.version>
990+
<spark-rapids-jni.version>26.10.0-SNAPSHOT</spark-rapids-jni.version>
991+
<spark-rapids-private.version>26.10.0-SNAPSHOT</spark-rapids-private.version>
992+
<spark-rapids-hybrid.version>26.10.0-SNAPSHOT</spark-rapids-hybrid.version>
994993
<scala.binary.version>2.13</scala.binary.version>
995994
<scala.recompileMode>incremental</scala.recompileMode>
996995
<scala.version>2.13.18</scala.version>

sql-plugin/src/main/scala/com/nvidia/spark/rapids/shims/OrcShims320untilAllBase.scala

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,46 @@ package com.nvidia.spark.rapids.shims
1919
import java.nio.ByteBuffer
2020

2121
import scala.collection.mutable.ArrayBuffer
22+
import scala.util.control.NonFatal
2223

2324
import com.nvidia.spark.rapids.Arm.withResource
2425
import com.nvidia.spark.rapids.OrcOutputStripe
25-
import com.nvidia.spark.rapids.RapidsPluginImplicits._
2626
import org.apache.hadoop.conf.Configuration
2727
import org.apache.orc.{CompressionCodec, CompressionKind, DataReader, OrcConf, OrcFile, OrcProto, PhysicalWriter, Reader, StripeInformation, TypeDescription}
2828
import org.apache.orc.impl.{BufferChunk, DataReaderProperties, InStream, OrcCodecPool, OutStream, ReaderImpl, SchemaEvolution}
2929
import org.apache.orc.impl.RecordReaderImpl.SargApplier
3030
import org.apache.orc.impl.reader.StripePlanner
3131
import org.apache.orc.impl.writer.StreamOptions
3232

33-
trait OrcShims320untilAllBase {
33+
import org.apache.spark.internal.Logging
34+
35+
trait OrcShims320untilAllBase extends Logging {
3436

3537
// the ORC Reader in non-CDH Spark is closeable
3638
def withReader[T <: Reader, V](r: T)(block: T => V): V = {
3739
try {
3840
block(r)
3941
} finally {
40-
r.safeClose()
42+
closeReader(r)
4143
}
4244
}
4345

4446
// the ORC Reader in non-CDH Spark is closeable
4547
def closeReader(reader: Reader): Unit = {
46-
if(reader != null) {
47-
reader.close()
48+
if (reader != null) {
49+
// Close without being aborted by a pending interrupt from task cancellation, then restore
50+
// the interrupt status for the caller. This matches Spark's SPARK-57958 ORC reader hardening.
51+
val interrupted = Thread.interrupted()
52+
try {
53+
reader.close()
54+
} catch {
55+
case NonFatal(t) =>
56+
logWarning("Failed to close the ORC reader", t)
57+
} finally {
58+
if (interrupted) {
59+
Thread.currentThread().interrupt()
60+
}
61+
}
4862
}
4963
}
5064

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2026, NVIDIA CORPORATION.
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+
17+
package com.nvidia.spark.rapids.shims
18+
19+
import java.io.IOException
20+
21+
import org.apache.orc.Reader
22+
import org.mockito.Mockito.{doAnswer, doThrow, verify}
23+
import org.scalatest.funsuite.AnyFunSuite
24+
import org.scalatestplus.mockito.MockitoSugar
25+
26+
class OrcShimsSuite extends AnyFunSuite with MockitoSugar {
27+
28+
test("closeReader clears and restores interrupt status") {
29+
val reader = mock[Reader]
30+
var closedWithInterruptSet = true
31+
doAnswer { _ =>
32+
closedWithInterruptSet = Thread.currentThread().isInterrupted
33+
null
34+
}.when(reader).close()
35+
36+
Thread.interrupted()
37+
Thread.currentThread().interrupt()
38+
try {
39+
OrcShims.closeReader(reader)
40+
41+
assert(!closedWithInterruptSet)
42+
assert(Thread.currentThread().isInterrupted)
43+
verify(reader).close()
44+
} finally {
45+
Thread.interrupted()
46+
}
47+
}
48+
49+
test("closeReader restores interrupt status after non-fatal close failure") {
50+
val reader = mock[Reader]
51+
doThrow(new IOException("close failed")).when(reader).close()
52+
53+
Thread.interrupted()
54+
Thread.currentThread().interrupt()
55+
try {
56+
OrcShims.closeReader(reader)
57+
58+
assert(Thread.currentThread().isInterrupted)
59+
verify(reader).close()
60+
} finally {
61+
Thread.interrupted()
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)