This is an automated email from the ASF dual-hosted git repository.

hongze pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-gluten.git


The following commit(s) were added to refs/heads/main by this push:
     new 37dae7d44 [GLUTEN-6849][VL] Call static initializers once in Spark 
local mode / when session is renewed (#6855)
37dae7d44 is described below

commit 37dae7d44b5e49dca37b51153fb28a87b40e2fd4
Author: Hongze Zhang <[email protected]>
AuthorDate: Mon Aug 19 09:49:44 2024 +0800

    [GLUTEN-6849][VL] Call static initializers once in Spark local mode / when 
session is renewed (#6855)
---
 .../backendsapi/velox/VeloxListenerApi.scala       | 163 ++++++++-------------
 .../apache/gluten/utils/SharedLibraryLoader.scala  | 104 +++++++++++++
 .../CHCelebornColumnarBatchSerializer.scala        |   4 +-
 .../org/apache/spark/util/SparkDirectoryUtil.scala |   2 +-
 .../org/apache/spark/util/SparkResourceUtil.scala  |   4 +
 .../scala/org/apache/gluten/GlutenConfig.scala     |   6 +-
 6 files changed, 173 insertions(+), 110 deletions(-)

diff --git 
a/backends-velox/src/main/scala/org/apache/gluten/backendsapi/velox/VeloxListenerApi.scala
 
b/backends-velox/src/main/scala/org/apache/gluten/backendsapi/velox/VeloxListenerApi.scala
index 86925fd1d..2cfc4e9a9 100644
--- 
a/backends-velox/src/main/scala/org/apache/gluten/backendsapi/velox/VeloxListenerApi.scala
+++ 
b/backends-velox/src/main/scala/org/apache/gluten/backendsapi/velox/VeloxListenerApi.scala
@@ -18,7 +18,6 @@ package org.apache.gluten.backendsapi.velox
 
 import org.apache.gluten.GlutenConfig
 import org.apache.gluten.backendsapi.ListenerApi
-import org.apache.gluten.exception.GlutenException
 import org.apache.gluten.execution.datasource.{GlutenOrcWriterInjects, 
GlutenParquetWriterInjects, GlutenRowSplitter}
 import org.apache.gluten.expression.UDFMappings
 import org.apache.gluten.init.NativeBackendInitializer
@@ -27,138 +26,76 @@ import org.apache.gluten.vectorized.{JniLibLoader, 
JniWorkspace}
 
 import org.apache.spark.{SparkConf, SparkContext}
 import org.apache.spark.api.plugin.PluginContext
+import org.apache.spark.internal.Logging
 import 
org.apache.spark.sql.execution.datasources.velox.{VeloxOrcWriterInjects, 
VeloxParquetWriterInjects, VeloxRowSplitter}
 import org.apache.spark.sql.expression.UDFResolver
 import org.apache.spark.sql.internal.{GlutenConfigUtil, StaticSQLConf}
-import org.apache.spark.util.SparkDirectoryUtil
+import org.apache.spark.util.{SparkDirectoryUtil, SparkResourceUtil}
 
 import org.apache.commons.lang3.StringUtils
 
-import scala.sys.process._
+import java.util.concurrent.atomic.AtomicBoolean
 
-class VeloxListenerApi extends ListenerApi {
-  private val ARROW_VERSION = "1500"
+class VeloxListenerApi extends ListenerApi with Logging {
+  import VeloxListenerApi._
 
   override def onDriverStart(sc: SparkContext, pc: PluginContext): Unit = {
     val conf = pc.conf()
-    // sql table cache serializer
+
+    // Sql table cache serializer.
     if (conf.getBoolean(GlutenConfig.COLUMNAR_TABLE_CACHE_ENABLED.key, 
defaultValue = false)) {
       conf.set(
         StaticSQLConf.SPARK_CACHE_SERIALIZER.key,
         "org.apache.spark.sql.execution.ColumnarCachedBatchSerializer")
     }
-    initialize(conf, isDriver = true)
+
+    // Static initializers for driver.
+    if (!driverInitialized.compareAndSet(false, true)) {
+      // Make sure we call the static initializers only once.
+      logInfo(
+        "Skip rerunning static initializers since they are only supposed to 
run once." +
+          " You see this message probably because you are creating a new 
SparkSession.")
+      return
+    }
+
+    SparkDirectoryUtil.init(conf)
+    UDFResolver.resolveUdfConf(conf, isDriver = true)
+    initialize(conf)
   }
 
   override def onDriverShutdown(): Unit = shutdown()
 
   override def onExecutorStart(pc: PluginContext): Unit = {
-    initialize(pc.conf(), isDriver = false)
-  }
-
-  override def onExecutorShutdown(): Unit = shutdown()
+    val conf = pc.conf()
 
-  private def getLibraryLoaderForOS(
-      systemName: String,
-      systemVersion: String,
-      system: String): SharedLibraryLoader = {
-    if (systemName.contains("Ubuntu") && systemVersion.startsWith("20.04")) {
-      new SharedLibraryLoaderUbuntu2004
-    } else if (systemName.contains("Ubuntu") && 
systemVersion.startsWith("22.04")) {
-      new SharedLibraryLoaderUbuntu2204
-    } else if (systemName.contains("CentOS") && systemVersion.startsWith("9")) 
{
-      new SharedLibraryLoaderCentos9
-    } else if (systemName.contains("CentOS") && systemVersion.startsWith("8")) 
{
-      new SharedLibraryLoaderCentos8
-    } else if (systemName.contains("CentOS") && systemVersion.startsWith("7")) 
{
-      new SharedLibraryLoaderCentos7
-    } else if (systemName.contains("Alibaba Cloud Linux") && 
systemVersion.startsWith("3")) {
-      new SharedLibraryLoaderCentos8
-    } else if (systemName.contains("Alibaba Cloud Linux") && 
systemVersion.startsWith("2")) {
-      new SharedLibraryLoaderCentos7
-    } else if (systemName.contains("Anolis") && systemVersion.startsWith("8")) 
{
-      new SharedLibraryLoaderCentos8
-    } else if (systemName.contains("Anolis") && systemVersion.startsWith("7")) 
{
-      new SharedLibraryLoaderCentos7
-    } else if (system.contains("tencentos") && system.contains("2.4")) {
-      new SharedLibraryLoaderCentos7
-    } else if (system.contains("tencentos") && system.contains("3.2")) {
-      new SharedLibraryLoaderCentos8
-    } else if (systemName.contains("Red Hat") && 
systemVersion.startsWith("9")) {
-      new SharedLibraryLoaderCentos9
-    } else if (systemName.contains("Red Hat") && 
systemVersion.startsWith("8")) {
-      new SharedLibraryLoaderCentos8
-    } else if (systemName.contains("Red Hat") && 
systemVersion.startsWith("7")) {
-      new SharedLibraryLoaderCentos7
-    } else if (systemName.contains("Debian") && 
systemVersion.startsWith("11")) {
-      new SharedLibraryLoaderDebian11
-    } else if (systemName.contains("Debian") && 
systemVersion.startsWith("12")) {
-      new SharedLibraryLoaderDebian12
-    } else {
-      throw new GlutenException(
-        s"Found unsupported OS($systemName, $systemVersion)! Currently, 
Gluten's Velox backend" +
-          " only supports Ubuntu 20.04/22.04, CentOS 7/8, " +
-          "Alibaba Cloud Linux 2/3 & Anolis 7/8, tencentos 2.4/3.2, RedHat 
7/8, " +
-          "Debian 11/12.")
+    // Static initializers for executor.
+    if (!executorInitialized.compareAndSet(false, true)) {
+      // Make sure we call the static initializers only once.
+      logInfo(
+        "Skip rerunning static initializers since they are only supposed to 
run once." +
+          " You see this message probably because you are creating a new 
SparkSession.")
+      return
     }
-  }
-
-  private def loadLibFromJar(load: JniLibLoader, conf: SparkConf): Unit = {
-    val systemName = conf.getOption(GlutenConfig.GLUTEN_LOAD_LIB_OS)
-    val loader = if (systemName.isDefined) {
-      val systemVersion = 
conf.getOption(GlutenConfig.GLUTEN_LOAD_LIB_OS_VERSION)
-      if (systemVersion.isEmpty) {
-        throw new GlutenException(
-          s"${GlutenConfig.GLUTEN_LOAD_LIB_OS_VERSION} must be specified when 
specifies the " +
-            s"${GlutenConfig.GLUTEN_LOAD_LIB_OS}")
-      }
-      getLibraryLoaderForOS(systemName.get, systemVersion.get, "")
-    } else {
-      val system = "cat /etc/os-release".!!
-      val systemNamePattern = "^NAME=\"?(.*)\"?".r
-      val systemVersionPattern = "^VERSION=\"?(.*)\"?".r
-      val systemInfoLines = system.stripMargin.split("\n")
-      val systemNamePattern(systemName) =
-        systemInfoLines.find(_.startsWith("NAME=")).getOrElse("")
-      val systemVersionPattern(systemVersion) =
-        systemInfoLines.find(_.startsWith("VERSION=")).getOrElse("")
-      if (systemName.isEmpty || systemVersion.isEmpty) {
-        throw new GlutenException("Failed to get OS name and version info.")
-      }
-      getLibraryLoaderForOS(systemName, systemVersion, system)
+    if (inLocalMode(conf)) {
+      // Don't do static initializations from executor side in local mode.
+      // Driver already did that.
+      logInfo(
+        "Gluten is running with Spark local mode. Skip running static 
initializer for executor.")
+      return
     }
-    loader.loadLib(load)
-  }
 
-  private def loadLibWithLinux(conf: SparkConf, loader: JniLibLoader): Unit = {
-    if (
-      conf.getBoolean(
-        GlutenConfig.GLUTEN_LOAD_LIB_FROM_JAR,
-        GlutenConfig.GLUTEN_LOAD_LIB_FROM_JAR_DEFAULT)
-    ) {
-      loadLibFromJar(loader, conf)
-    }
+    SparkDirectoryUtil.init(conf)
+    UDFResolver.resolveUdfConf(conf, isDriver = false)
+    initialize(conf)
   }
 
-  private def loadLibWithMacOS(loader: JniLibLoader): Unit = {
-    // Placeholder for loading shared libs on MacOS if user needs.
-  }
+  override def onExecutorShutdown(): Unit = shutdown()
 
-  private def initialize(conf: SparkConf, isDriver: Boolean): Unit = {
-    SparkDirectoryUtil.init(conf)
-    UDFResolver.resolveUdfConf(conf, isDriver = isDriver)
+  private def initialize(conf: SparkConf): Unit = {
     if (conf.getBoolean(GlutenConfig.GLUTEN_DEBUG_KEEP_JNI_WORKSPACE, 
defaultValue = false)) {
       val debugDir = conf.get(GlutenConfig.GLUTEN_DEBUG_KEEP_JNI_WORKSPACE_DIR)
       JniWorkspace.enableDebug(debugDir)
     }
-    val loader = JniWorkspace.getDefault.libLoader
-
-    val osName = System.getProperty("os.name")
-    if (osName.startsWith("Mac OS X") || osName.startsWith("macOS")) {
-      loadLibWithMacOS(loader)
-    } else {
-      loadLibWithLinux(conf, loader)
-    }
 
     // Set the system properties.
     // Use appending policy for children with the same name in a arrow struct 
vector.
@@ -167,6 +104,13 @@ class VeloxListenerApi extends ListenerApi {
     // Load supported hive/python/scala udfs
     UDFMappings.loadFromSparkConf(conf)
 
+    // Initial library loader.
+    val loader = JniWorkspace.getDefault.libLoader
+
+    // Load shared native libraries the backend libraries depend on.
+    SharedLibraryLoader.load(conf, loader)
+
+    // Load backend libraries.
     val libPath = conf.get(GlutenConfig.GLUTEN_LIB_PATH, StringUtils.EMPTY)
     if (StringUtils.isNotBlank(libPath)) { // Path based load. Ignore all 
other loadees.
       JniLibLoader.loadFromPath(libPath, false)
@@ -176,11 +120,11 @@ class VeloxListenerApi extends ListenerApi {
       loader.mapAndLoad(VeloxBackend.BACKEND_NAME, false)
     }
 
+    // Initial native backend with configurations.
     val parsed = GlutenConfigUtil.parseConfig(conf.getAll.toMap)
     NativeBackendInitializer.initializeBackend(parsed)
 
-    // inject backend-specific implementations to override spark classes
-    // FIXME: The following set instances twice in local mode?
+    // Inject backend-specific implementations to override spark classes.
     GlutenParquetWriterInjects.setInstance(new VeloxParquetWriterInjects())
     GlutenOrcWriterInjects.setInstance(new VeloxOrcWriterInjects())
     GlutenRowSplitter.setInstance(new VeloxRowSplitter())
@@ -191,4 +135,13 @@ class VeloxListenerApi extends ListenerApi {
   }
 }
 
-object VeloxListenerApi {}
+object VeloxListenerApi {
+  // TODO: Implement graceful shutdown and remove these flags.
+  //  As spark conf may change when active Spark session is recreated.
+  private val driverInitialized: AtomicBoolean = new AtomicBoolean(false)
+  private val executorInitialized: AtomicBoolean = new AtomicBoolean(false)
+
+  private def inLocalMode(conf: SparkConf): Boolean = {
+    SparkResourceUtil.isLocalMaster(conf)
+  }
+}
diff --git 
a/backends-velox/src/main/scala/org/apache/gluten/utils/SharedLibraryLoader.scala
 
b/backends-velox/src/main/scala/org/apache/gluten/utils/SharedLibraryLoader.scala
index 137da83c0..1f3ca30de 100755
--- 
a/backends-velox/src/main/scala/org/apache/gluten/utils/SharedLibraryLoader.scala
+++ 
b/backends-velox/src/main/scala/org/apache/gluten/utils/SharedLibraryLoader.scala
@@ -16,8 +16,112 @@
  */
 package org.apache.gluten.utils
 
+import org.apache.gluten.GlutenConfig
+import org.apache.gluten.exception.GlutenException
 import org.apache.gluten.vectorized.JniLibLoader
 
+import org.apache.spark.SparkConf
+
+import scala.sys.process._
+
 trait SharedLibraryLoader {
   def loadLib(loader: JniLibLoader): Unit
 }
+
+object SharedLibraryLoader {
+  def load(conf: SparkConf, jni: JniLibLoader): Unit = {
+    val shouldLoad = conf.getBoolean(
+      GlutenConfig.GLUTEN_LOAD_LIB_FROM_JAR,
+      GlutenConfig.GLUTEN_LOAD_LIB_FROM_JAR_DEFAULT)
+    if (!shouldLoad) {
+      return
+    }
+    val osName = System.getProperty("os.name")
+    if (osName.startsWith("Mac OS X") || osName.startsWith("macOS")) {
+      loadLibWithMacOS(jni)
+    } else {
+      loadLibWithLinux(conf, jni)
+    }
+  }
+
+  private def loadLibWithLinux(conf: SparkConf, jni: JniLibLoader): Unit = {
+    val loader = find(conf)
+    loader.loadLib(jni)
+  }
+
+  private def loadLibWithMacOS(jni: JniLibLoader): Unit = {
+    // Placeholder for loading shared libs on MacOS if user needs.
+  }
+
+  private def find(conf: SparkConf): SharedLibraryLoader = {
+    val systemName = conf.getOption(GlutenConfig.GLUTEN_LOAD_LIB_OS)
+    val loader = if (systemName.isDefined) {
+      val systemVersion = 
conf.getOption(GlutenConfig.GLUTEN_LOAD_LIB_OS_VERSION)
+      if (systemVersion.isEmpty) {
+        throw new GlutenException(
+          s"${GlutenConfig.GLUTEN_LOAD_LIB_OS_VERSION} must be specified when 
specifies the " +
+            s"${GlutenConfig.GLUTEN_LOAD_LIB_OS}")
+      }
+      getForOS(systemName.get, systemVersion.get, "")
+    } else {
+      val system = "cat /etc/os-release".!!
+      val systemNamePattern = "^NAME=\"?(.*)\"?".r
+      val systemVersionPattern = "^VERSION=\"?(.*)\"?".r
+      val systemInfoLines = system.stripMargin.split("\n")
+      val systemNamePattern(systemName) =
+        systemInfoLines.find(_.startsWith("NAME=")).getOrElse("")
+      val systemVersionPattern(systemVersion) =
+        systemInfoLines.find(_.startsWith("VERSION=")).getOrElse("")
+      if (systemName.isEmpty || systemVersion.isEmpty) {
+        throw new GlutenException("Failed to get OS name and version info.")
+      }
+      getForOS(systemName, systemVersion, system)
+    }
+    loader
+  }
+
+  private def getForOS(
+      systemName: String,
+      systemVersion: String,
+      system: String): SharedLibraryLoader = {
+    if (systemName.contains("Ubuntu") && systemVersion.startsWith("20.04")) {
+      new SharedLibraryLoaderUbuntu2004
+    } else if (systemName.contains("Ubuntu") && 
systemVersion.startsWith("22.04")) {
+      new SharedLibraryLoaderUbuntu2204
+    } else if (systemName.contains("CentOS") && systemVersion.startsWith("9")) 
{
+      new SharedLibraryLoaderCentos9
+    } else if (systemName.contains("CentOS") && systemVersion.startsWith("8")) 
{
+      new SharedLibraryLoaderCentos8
+    } else if (systemName.contains("CentOS") && systemVersion.startsWith("7")) 
{
+      new SharedLibraryLoaderCentos7
+    } else if (systemName.contains("Alibaba Cloud Linux") && 
systemVersion.startsWith("3")) {
+      new SharedLibraryLoaderCentos8
+    } else if (systemName.contains("Alibaba Cloud Linux") && 
systemVersion.startsWith("2")) {
+      new SharedLibraryLoaderCentos7
+    } else if (systemName.contains("Anolis") && systemVersion.startsWith("8")) 
{
+      new SharedLibraryLoaderCentos8
+    } else if (systemName.contains("Anolis") && systemVersion.startsWith("7")) 
{
+      new SharedLibraryLoaderCentos7
+    } else if (system.contains("tencentos") && system.contains("2.4")) {
+      new SharedLibraryLoaderCentos7
+    } else if (system.contains("tencentos") && system.contains("3.2")) {
+      new SharedLibraryLoaderCentos8
+    } else if (systemName.contains("Red Hat") && 
systemVersion.startsWith("9")) {
+      new SharedLibraryLoaderCentos9
+    } else if (systemName.contains("Red Hat") && 
systemVersion.startsWith("8")) {
+      new SharedLibraryLoaderCentos8
+    } else if (systemName.contains("Red Hat") && 
systemVersion.startsWith("7")) {
+      new SharedLibraryLoaderCentos7
+    } else if (systemName.contains("Debian") && 
systemVersion.startsWith("11")) {
+      new SharedLibraryLoaderDebian11
+    } else if (systemName.contains("Debian") && 
systemVersion.startsWith("12")) {
+      new SharedLibraryLoaderDebian12
+    } else {
+      throw new GlutenException(
+        s"Found unsupported OS($systemName, $systemVersion)! Currently, 
Gluten's Velox backend" +
+          " only supports Ubuntu 20.04/22.04, CentOS 7/8, " +
+          "Alibaba Cloud Linux 2/3 & Anolis 7/8, tencentos 2.4/3.2, RedHat 
7/8, " +
+          "Debian 11/12.")
+    }
+  }
+}
diff --git 
a/gluten-celeborn/clickhouse/src/main/scala/org/apache/spark/shuffle/CHCelebornColumnarBatchSerializer.scala
 
b/gluten-celeborn/clickhouse/src/main/scala/org/apache/spark/shuffle/CHCelebornColumnarBatchSerializer.scala
index 5072ce6a1..3b8e92bfe 100644
--- 
a/gluten-celeborn/clickhouse/src/main/scala/org/apache/spark/shuffle/CHCelebornColumnarBatchSerializer.scala
+++ 
b/gluten-celeborn/clickhouse/src/main/scala/org/apache/spark/shuffle/CHCelebornColumnarBatchSerializer.scala
@@ -62,7 +62,9 @@ private class CHCelebornColumnarBatchSerializerInstance(
   private lazy val compressionCodec = 
GlutenShuffleUtils.getCompressionCodec(conf)
   private lazy val capitalizedCompressionCodec = 
compressionCodec.toUpperCase(Locale.ROOT)
   private lazy val compressionLevel =
-    GlutenShuffleUtils.getCompressionLevel(conf, compressionCodec,
+    GlutenShuffleUtils.getCompressionLevel(
+      conf,
+      compressionCodec,
       GlutenConfig.getConf.columnarShuffleCodecBackend.orNull)
 
   override def deserializeStream(in: InputStream): DeserializationStream = {
diff --git 
a/gluten-core/src/main/scala/org/apache/spark/util/SparkDirectoryUtil.scala 
b/gluten-core/src/main/scala/org/apache/spark/util/SparkDirectoryUtil.scala
index fbc59edfd..833575178 100644
--- a/gluten-core/src/main/scala/org/apache/spark/util/SparkDirectoryUtil.scala
+++ b/gluten-core/src/main/scala/org/apache/spark/util/SparkDirectoryUtil.scala
@@ -79,7 +79,7 @@ object SparkDirectoryUtil extends Logging {
       return
     }
     if (INSTANCE.roots.toSet != roots.toSet) {
-      logWarning(
+      throw new IllegalArgumentException(
         s"Reinitialize SparkDirectoryUtil with different root dirs: old: 
${INSTANCE.ROOTS
             .mkString("Array(", ", ", ")")}, new: ${roots.mkString("Array(", 
", ", ")")}"
       )
diff --git 
a/gluten-core/src/main/scala/org/apache/spark/util/SparkResourceUtil.scala 
b/gluten-core/src/main/scala/org/apache/spark/util/SparkResourceUtil.scala
index b16d43de5..f8c791fe1 100644
--- a/gluten-core/src/main/scala/org/apache/spark/util/SparkResourceUtil.scala
+++ b/gluten-core/src/main/scala/org/apache/spark/util/SparkResourceUtil.scala
@@ -76,4 +76,8 @@ object SparkResourceUtil extends Logging {
     val taskCores = conf.getInt("spark.task.cpus", 1)
     executorCores / taskCores
   }
+
+  def isLocalMaster(conf: SparkConf): Boolean = {
+    Utils.isLocalMaster(conf)
+  }
 }
diff --git a/shims/common/src/main/scala/org/apache/gluten/GlutenConfig.scala 
b/shims/common/src/main/scala/org/apache/gluten/GlutenConfig.scala
index 0146c3604..88491f6bf 100644
--- a/shims/common/src/main/scala/org/apache/gluten/GlutenConfig.scala
+++ b/shims/common/src/main/scala/org/apache/gluten/GlutenConfig.scala
@@ -540,14 +540,14 @@ object GlutenConfig {
   val GLUTEN_OFFHEAP_ENABLED = "spark.memory.offHeap.enabled"
 
   // For Soft Affinity Scheduling
-  // Enable Soft Affinity Scheduling, defalut value is false
+  // Enable Soft Affinity Scheduling, default value is false
   val GLUTEN_SOFT_AFFINITY_ENABLED = "spark.gluten.soft-affinity.enabled"
   val GLUTEN_SOFT_AFFINITY_ENABLED_DEFAULT_VALUE = false
-  // Calculate the number of the replcations for scheduling to the target 
executors per file
+  // Calculate the number of the replications for scheduling to the target 
executors per file
   val GLUTEN_SOFT_AFFINITY_REPLICATIONS_NUM = 
"spark.gluten.soft-affinity.replications.num"
   val GLUTEN_SOFT_AFFINITY_REPLICATIONS_NUM_DEFAULT_VALUE = 2
   // For on HDFS, if there are already target hosts,
-  // and then prefer to use the orginal target hosts to schedule
+  // and then prefer to use the original target hosts to schedule
   val GLUTEN_SOFT_AFFINITY_MIN_TARGET_HOSTS = 
"spark.gluten.soft-affinity.min.target-hosts"
   val GLUTEN_SOFT_AFFINITY_MIN_TARGET_HOSTS_DEFAULT_VALUE = 1
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to