[AURON #2118] make native environment initialization retriable after failure (#2151)
# Which issue does this PR close?
Closes #2118
# Rationale for this change
avoid initialize in static block, make native environment initialization
retriable after failure
# What changes are included in this PR?
# Are there any user-facing changes?
# How was this patch tested?
diff --git a/auron-core/src/main/java/org/apache/auron/jni/AuronCallNativeWrapper.java b/auron-core/src/main/java/org/apache/auron/jni/AuronCallNativeWrapper.java
index 661d807..3fbcdc6 100644
--- a/auron-core/src/main/java/org/apache/auron/jni/AuronCallNativeWrapper.java
+++ b/auron-core/src/main/java/org/apache/auron/jni/AuronCallNativeWrapper.java
@@ -53,27 +53,7 @@
private Schema arrowSchema;
private long nativeRuntimePtr;
private Consumer<VectorSchemaRoot> batchConsumer;
-
- // initialize native environment
- static {
- LOG.info("Initializing native environment (batchSize="
- + AuronAdaptor.getInstance().getAuronConfiguration().get(AuronConfiguration.BATCH_SIZE) + ", "
- + "memoryFraction="
- + AuronAdaptor.getInstance().getAuronConfiguration().get(AuronConfiguration.MEMORY_FRACTION) + ")");
-
- // arrow configuration
- System.setProperty("arrow.struct.conflict.policy", "CONFLICT_APPEND");
-
- // preload JNI bridge classes
- try {
- Class.forName("org.apache.auron.jni.JniBridge");
- } catch (ClassNotFoundException e) {
- throw new RuntimeException("Cannot load JniBridge class", e);
- }
-
- AuronAdaptor.getInstance().loadAuronLib();
- Runtime.getRuntime().addShutdownHook(new Thread(JniBridge::onExit));
- }
+ private static volatile boolean initialized = false;
public AuronCallNativeWrapper(
BufferAllocator arrowAllocator,
@@ -90,6 +70,7 @@
this.stageId = stageId;
this.taskId = taskId;
+ init();
LOG.warn("Start executing native plan");
this.nativeRuntimePtr = JniBridge.callNative(
nativeMemory,
@@ -97,6 +78,41 @@
this);
}
+ private static void init() {
+ if (!initialized) {
+ synchronized (AuronCallNativeWrapper.class) {
+ if (!initialized) {
+ // Retry-safe: on failure `initialized` stays false so the next call retries.
+ // Every step below must be idempotent, or must not run on the failure path.
+ // In particular, loadAuronLib() must throw before System.load — a retried
+ // System.load would load the native library twice.
+ // initialize native environment
+ LOG.info("Initializing native environment (batchSize="
+ + AuronAdaptor.getInstance().getAuronConfiguration().get(AuronConfiguration.BATCH_SIZE)
+ + ", "
+ + "memoryFraction="
+ + AuronAdaptor.getInstance().getAuronConfiguration().get(AuronConfiguration.MEMORY_FRACTION)
+ + ")");
+
+ // arrow configuration
+ System.setProperty("arrow.struct.conflict.policy", "CONFLICT_APPEND");
+
+ // preload JNI bridge classes
+ try {
+ Class.forName("org.apache.auron.jni.JniBridge");
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Cannot load JniBridge class", e);
+ }
+
+ AuronAdaptor.getInstance().loadAuronLib();
+ Runtime.getRuntime().addShutdownHook(new Thread(JniBridge::onExit));
+
+ initialized = true;
+ }
+ }
+ }
+ }
+
/**
* Loads and processes the next batch of data from the native plan.
* <p>