diff --git a/gazelle-dist/pom.xml b/gazelle-dist/pom.xml
index 48f11c15f..e4e3ed484 100644
--- a/gazelle-dist/pom.xml
+++ b/gazelle-dist/pom.xml
@@ -55,6 +55,36 @@
+
+ spark-3.2.1
+
+
+ com.intel.oap
+ spark-sql-columnar-shims-spark32
+ ${project.version}
+
+
+ com.intel.oap
+ spark-sql-columnar-shims-spark321
+ ${project.version}
+
+
+
+
+ spark-3.2.2
+
+
+ com.intel.oap
+ spark-sql-columnar-shims-spark32
+ ${project.version}
+
+
+ com.intel.oap
+ spark-sql-columnar-shims-spark322
+ ${project.version}
+
+
+
diff --git a/native-sql-engine/core/pom.xml b/native-sql-engine/core/pom.xml
index a5dd253bf..a4548f3b6 100644
--- a/native-sql-engine/core/pom.xml
+++ b/native-sql-engine/core/pom.xml
@@ -78,6 +78,40 @@
+
+ spark-3.2.1
+
+
+ com.intel.oap
+ spark-sql-columnar-shims-spark32
+ ${project.version}
+ provided
+
+
+ com.intel.oap
+ spark-sql-columnar-shims-spark321
+ ${project.version}
+ provided
+
+
+
+
+ spark-3.2.2
+
+
+ com.intel.oap
+ spark-sql-columnar-shims-spark32
+ ${project.version}
+ provided
+
+
+ com.intel.oap
+ spark-sql-columnar-shims-spark322
+ ${project.version}
+ provided
+
+
+
diff --git a/native-sql-engine/core/src/main/java/com/intel/oap/vectorized/JniUtils.java b/native-sql-engine/core/src/main/java/com/intel/oap/vectorized/JniUtils.java
index 4579be179..0ca1e0dab 100644
--- a/native-sql-engine/core/src/main/java/com/intel/oap/vectorized/JniUtils.java
+++ b/native-sql-engine/core/src/main/java/com/intel/oap/vectorized/JniUtils.java
@@ -17,11 +17,19 @@
package com.intel.oap.vectorized;
+import org.apache.spark.util.GazelleShutdownManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.Function0;
+import scala.runtime.BoxedUnit;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
@@ -30,9 +38,15 @@
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
+import java.util.LinkedHashSet;
import java.util.Objects;
+import java.util.Vector;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -53,6 +67,23 @@ public class JniUtils {
private static List codegenJarsLoadedCache = new ArrayList<>();
private static volatile JniUtils INSTANCE;
private static String tmp_dir;
+ private static final Logger LOG =
+ LoggerFactory.getLogger(JniUtils.class);
+
+ public static Set LOADED_LIBRARY_PATHS = new HashSet<>();
+ public static Set REQUIRE_UNLOAD_LIBRARY_PATHS = new LinkedHashSet<>();
+
+ static {
+ GazelleShutdownManager.registerUnloadLibShutdownHook(new Function0() {
+ @Override
+ public BoxedUnit apply() {
+ List loaded = new ArrayList<>(REQUIRE_UNLOAD_LIBRARY_PATHS);
+ Collections.reverse(loaded); // use reversed order to unload
+ loaded.forEach(JniUtils::unloadFromPath);
+ return BoxedUnit.UNIT;
+ }
+ });
+ }
public static JniUtils getInstance() throws IOException {
String tmp_dir = System.getProperty("java.io.tmpdir");
@@ -118,6 +149,19 @@ public void setJars(List list_jars) throws IOException, IllegalAccessExc
}
}
+ private static synchronized void loadFromPath0(String libPath, boolean requireUnload) {
+ if (LOADED_LIBRARY_PATHS.contains(libPath)) {
+ LOG.debug("Library in path {} has already been loaded, skipping", libPath);
+ } else {
+ System.load(libPath);
+ LOADED_LIBRARY_PATHS.add(libPath);
+ LOG.info("Library {} has been loaded using path-loading method", libPath);
+ }
+ if (requireUnload) {
+ REQUIRE_UNLOAD_LIBRARY_PATHS.add(libPath);
+ }
+ }
+
static void loadLibraryFromJar(String tmp_dir) throws IOException, IllegalAccessException {
synchronized (JniUtils.class) {
if (tmp_dir == null) {
@@ -127,15 +171,18 @@ static void loadLibraryFromJar(String tmp_dir) throws IOException, IllegalAccess
Path arrowMiddleLink = createSoftLink(arrowlibraryFile, ARROW_PARENT_LIBRARY_NAME);
Path arrowShortLink = createSoftLink(new File(arrowMiddleLink.toString()), ARROW_PARENT_LIBRARY_SHORT);
System.load(arrowShortLink.toAbsolutePath().toString());
+ loadFromPath0(arrowShortLink.toAbsolutePath().toString(), true);
final File gandivalibraryFile = moveFileFromJarToTemp(tmp_dir, GANDIVA_LIBRARY_NAME);
Path gandivaMiddleLink = createSoftLink(gandivalibraryFile, GANDIVA_PARENT_LIBRARY_NAME);
Path gandivaShortLink = createSoftLink(new File(gandivaMiddleLink.toString()), GANDIVA_PARENT_LIBRARY_SHORT);
System.load(gandivaShortLink.toAbsolutePath().toString());
+ loadFromPath0(gandivaShortLink.toAbsolutePath().toString(), true);
final String libraryToLoad = System.mapLibraryName(LIBRARY_NAME);
final File libraryFile = moveFileFromJarToTemp(tmp_dir, libraryToLoad);
System.load(libraryFile.getAbsolutePath());
+ loadFromPath0(libraryFile.getAbsolutePath(), true);
}
}
@@ -282,4 +329,41 @@ public static void copyResourcesToDirectory(URLConnection urlConnection,
}
}
}
+
+ public static synchronized void unloadFromPath(String libPath) {
+ if (!LOADED_LIBRARY_PATHS.remove(libPath)) {
+ throw new IllegalStateException("Library not exist: " + libPath);
+ }
+
+ REQUIRE_UNLOAD_LIBRARY_PATHS.remove(libPath);
+
+ try {
+ while (Files.isSymbolicLink(Paths.get(libPath))) {
+ libPath = Files.readSymbolicLink(Paths.get(libPath)).toString();
+ }
+
+ ClassLoader classLoader = JniUtils.class.getClassLoader();
+ Field field = ClassLoader.class.getDeclaredField("nativeLibraries");
+ field.setAccessible(true);
+ Vector