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

ayushtkn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tez.git


The following commit(s) were added to refs/heads/master by this push:
     new 61cc636fd TEZ-4727: Add ARM support of the dependent leveldbjni 
(#509). (Ayush Saxena, reviewed by Laszlo Bodor)
61cc636fd is described below

commit 61cc636fdfffe871d3a52d9d739a668b0908995c
Author: Ayush Saxena <[email protected]>
AuthorDate: Tue Jun 23 17:39:02 2026 +0530

    TEZ-4727: Add ARM support of the dependent leveldbjni (#509). (Ayush 
Saxena, reviewed by Laszlo Bodor)
---
 .github/workflows/build.yml                        |  5 +-
 pom.xml                                            | 21 +++++++-
 tez-plugins/tez-aux-services/pom.xml               | 32 +++++++++++-
 .../org/apache/tez/auxservices/ShuffleHandler.java | 59 ++++++++++++++--------
 4 files changed, 92 insertions(+), 25 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index befb80094..7c3870b86 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -36,7 +36,7 @@ jobs:
     strategy:
       matrix:
         java-version: [21, 25]
-        os: [ubuntu-latest, macos-latest]
+        os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest]
     runs-on: ${{ matrix.os }}
     steps:
       - uses: actions/checkout@v6
@@ -48,3 +48,6 @@ jobs:
         run: >
           mvn --batch-mode --no-transfer-progress clean install
           -DskipTests -Dmaven.javadoc.skip=true
+          ${{ runner.os == 'Linux'
+          && runner.arch == 'ARM64'
+          && '-pl !tez-ui' || '' }}
diff --git a/pom.xml b/pom.xml
index bd1a268aa..0aadd69e3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -87,6 +87,8 @@
     <jettison.version>1.5.4</jettison.version>
     <junit.version>4.13.2</junit.version>
     <junit.jupiter.version>5.9.3</junit.jupiter.version>
+    <leveldbjni.group>org.fusesource.leveldbjni</leveldbjni.group>
+    <leveldb.version>0.12</leveldb.version>
     <leveldbjni-all.version>1.8</leveldbjni-all.version>
     <lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
     <metrics-core.version>3.1.0</metrics-core.version>
@@ -938,10 +940,15 @@
         <version>${bouncycastle.version}</version>
       </dependency>
       <dependency>
-        <groupId>org.fusesource.leveldbjni</groupId>
+        <groupId>${leveldbjni.group}</groupId>
         <artifactId>leveldbjni-all</artifactId>
         <version>${leveldbjni-all.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.iq80.leveldb</groupId>
+        <artifactId>leveldb</artifactId>
+        <version>${leveldb.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.xerial.snappy</groupId>
         <artifactId>snappy-java</artifactId>
@@ -1486,6 +1493,18 @@
         </plugins>
       </reporting>
     </profile>
+    <profile>
+      <id>aarch64</id>
+      <properties>
+        <leveldbjni.group>org.openlabtesting.leveldbjni</leveldbjni.group>
+      </properties>
+      <activation>
+        <os>
+          <family>linux</family>
+          <arch>aarch64</arch>
+        </os>
+      </activation>
+    </profile>
   </profiles>
 
   <reporting>
diff --git a/tez-plugins/tez-aux-services/pom.xml 
b/tez-plugins/tez-aux-services/pom.xml
index efa6fb107..dcebb15a5 100644
--- a/tez-plugins/tez-aux-services/pom.xml
+++ b/tez-plugins/tez-aux-services/pom.xml
@@ -49,6 +49,12 @@
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-yarn-server-common</artifactId>
       <scope>provided</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.fusesource.leveldbjni</groupId>
+          <artifactId>leveldbjni-all</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.apache.hadoop</groupId>
@@ -64,6 +70,10 @@
           <groupId>io.netty</groupId>
           <artifactId>*</artifactId>
         </exclusion>
+        <exclusion>
+          <groupId>org.fusesource.leveldbjni</groupId>
+          <artifactId>leveldbjni-all</artifactId>
+        </exclusion>
       </exclusions>
     </dependency>
     <dependency>
@@ -90,6 +100,12 @@
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-mapreduce-client-shuffle</artifactId>
       <scope>provided</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.fusesource.leveldbjni</groupId>
+          <artifactId>leveldbjni-all</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.apache.tez</groupId>
@@ -110,10 +126,14 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>org.fusesource.leveldbjni</groupId>
+      <groupId>${leveldbjni.group}</groupId>
       <artifactId>leveldbjni-all</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.iq80.leveldb</groupId>
+      <artifactId>leveldb</artifactId>
+    </dependency>
     <dependency>
       <groupId>io.netty</groupId>
       <artifactId>netty-all</artifactId>
@@ -146,6 +166,10 @@
           <groupId>io.netty</groupId>
           <artifactId>*</artifactId>
         </exclusion>
+        <exclusion>
+          <groupId>org.fusesource.leveldbjni</groupId>
+          <artifactId>leveldbjni-all</artifactId>
+        </exclusion>
       </exclusions>
     </dependency>
    <dependency>
@@ -159,6 +183,12 @@
      <artifactId>hadoop-yarn-server-tests</artifactId>
      <scope>test</scope>
      <type>test-jar</type>
+     <exclusions>
+       <exclusion>
+         <groupId>org.fusesource.leveldbjni</groupId>
+         <artifactId>leveldbjni-all</artifactId>
+       </exclusion>
+     </exclusions>
    </dependency>
   <dependency>
      <groupId>org.apache.hadoop</groupId>
diff --git 
a/tez-plugins/tez-aux-services/src/main/java/org/apache/tez/auxservices/ShuffleHandler.java
 
b/tez-plugins/tez-aux-services/src/main/java/org/apache/tez/auxservices/ShuffleHandler.java
index 42f3c6834..60aa088be 100644
--- 
a/tez-plugins/tez-aux-services/src/main/java/org/apache/tez/auxservices/ShuffleHandler.java
+++ 
b/tez-plugins/tez-aux-services/src/main/java/org/apache/tez/auxservices/ShuffleHandler.java
@@ -29,8 +29,7 @@ import static 
io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
 import static io.netty.handler.codec.http.HttpResponseStatus.OK;
 import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED;
 import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
-import static org.fusesource.leveldbjni.JniDBFactory.asString;
-import static org.fusesource.leveldbjni.JniDBFactory.bytes;
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -91,7 +90,6 @@ import 
org.apache.hadoop.yarn.server.api.ApplicationTerminationContext;
 import org.apache.hadoop.yarn.server.api.AuxiliaryService;
 import org.apache.hadoop.yarn.server.records.Version;
 import org.apache.hadoop.yarn.server.records.impl.pb.VersionPBImpl;
-import org.apache.hadoop.yarn.server.utils.LeveldbIterator;
 import org.apache.tez.common.security.JobTokenIdentifier;
 import org.apache.tez.common.security.JobTokenSecretManager;
 import org.apache.tez.runtime.library.common.Constants;
@@ -150,10 +148,10 @@ import io.netty.handler.timeout.IdleStateHandler;
 import io.netty.util.CharsetUtil;
 import io.netty.util.concurrent.GlobalEventExecutor;
 
-import org.fusesource.leveldbjni.JniDBFactory;
-import org.fusesource.leveldbjni.internal.NativeDB;
 import org.iq80.leveldb.DB;
 import org.iq80.leveldb.DBException;
+import org.iq80.leveldb.DBFactory;
+import org.iq80.leveldb.DBIterator;
 import org.iq80.leveldb.Logger;
 import org.iq80.leveldb.Options;
 import org.slf4j.LoggerFactory;
@@ -211,6 +209,7 @@ public class ShuffleHandler extends AuxiliaryService {
   private JobTokenSecretManager secretManager;
 
   private DB stateDb = null;
+  private static final DBFactory DB_FACTORY = createDBFactory();
 
   public static final String TEZ_SHUFFLE_SERVICEID =
       "tez_shuffle";
@@ -644,6 +643,7 @@ public class ShuffleHandler extends AuxiliaryService {
     destroyPipeline();
     if (stateDb != null) {
       stateDb.close();
+      stateDb = null;
     }
     super.serviceStop();
   }
@@ -672,9 +672,9 @@ public class ShuffleHandler extends AuxiliaryService {
     if (recoveryRoot != null) {
       startStore(recoveryRoot);
       Pattern jobPattern = Pattern.compile(JobID.JOBID_REGEX);
-      LeveldbIterator iter = null;
+      DBIterator iter = null;
       try {
-        iter = new LeveldbIterator(stateDb);
+        iter = stateDb.iterator();
         iter.seek(bytes(JobID.JOB));
         while (iter.hasNext()) {
           Map.Entry<byte[],byte[]> entry = iter.next();
@@ -696,26 +696,20 @@ public class ShuffleHandler extends AuxiliaryService {
 
   private void startStore(Path recoveryRoot) throws IOException {
     Options options = new Options();
-    options.createIfMissing(false);
     options.logger(new LevelDBLogger());
     Path dbPath = new Path(recoveryRoot, STATE_DB_NAME);
     LOG.info("Using state database at " + dbPath + " for recovery");
     File dbfile = new File(dbPath.toString());
+    boolean dbExists = dbfile.exists();
+    options.createIfMissing(!dbExists);
     try {
-      stateDb = JniDBFactory.factory.open(dbfile, options);
-    } catch (NativeDB.DBException e) {
-      if (e.isNotFound() || e.getMessage().contains(" does not exist ")) {
-        LOG.info("Creating state database at " + dbfile);
-        options.createIfMissing(true);
-        try {
-          stateDb = JniDBFactory.factory.open(dbfile, options);
-          storeVersion();
-        } catch (DBException dbExc) {
-          throw new IOException("Unable to create state store", dbExc);
-        }
-      } else {
-        throw e;
-      }
+      stateDb = DB_FACTORY.open(dbfile, options);
+    } catch (Exception e) {
+      throw new IOException("Unable to open state store", e);
+    }
+    if (!dbExists) {
+      LOG.info("Created state database at " + dbfile);
+      storeVersion();
     }
     checkVersion();
   }
@@ -844,6 +838,27 @@ public class ShuffleHandler extends AuxiliaryService {
     }
   }
 
+  private static DBFactory createDBFactory() {
+    // Try native JNI LevelDB first (fastest), fall back to pure-Java iq80
+    try {
+      DBFactory jniFactory = org.fusesource.leveldbjni.JniDBFactory.factory;
+      LOG.info("Using JNI LevelDB factory");
+      return jniFactory;
+    } catch (Throwable t) {
+      LOG.info("Native LevelDB JNI library not available ({}), "
+          + "falling back to pure-Java implementation", t.getMessage());
+      return new org.iq80.leveldb.impl.Iq80DBFactory();
+    }
+  }
+
+  private static byte[] bytes(String value) {
+    return value.getBytes(UTF_8);
+  }
+
+  private static String asString(byte[] value) {
+    return new String(value, UTF_8);
+  }
+
   private static class LevelDBLogger implements Logger {
     private static final org.slf4j.Logger LOG = 
LoggerFactory.getLogger(LevelDBLogger.class);
 

Reply via email to