Repository: ignite
Updated Branches:
  refs/heads/ignite-3929-1 [created] c9e665e22


IGNITE-3929: wip.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/df3ad76f
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/df3ad76f
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/df3ad76f

Branch: refs/heads/ignite-3929-1
Commit: df3ad76f3f105fbda34ae5bb79463ab41c46fe85
Parents: 857cdcd
Author: iveselovskiy <iveselovs...@gridgain.com>
Authored: Mon Sep 19 21:27:55 2016 +0300
Committer: iveselovskiy <iveselovs...@gridgain.com>
Committed: Mon Sep 19 21:27:55 2016 +0300

----------------------------------------------------------------------
 .../processors/hadoop/HadoopSnappyTest.java     |   6 +-
 .../processors/hadoop/HadoopClassLoader.java    | 225 +++++++++++++++----
 .../hadoop/HadoopClassLoaderUtils.java          |   2 +-
 .../internal/processors/hadoop/LoadHelper.java  |  42 ++++
 .../ignite/internal/processors/hadoop/XXX.java  |   7 +
 5 files changed, 234 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/df3ad76f/modules/hadoop-impl/src/test/java/org/apache/ignite/internal/processors/hadoop/HadoopSnappyTest.java
----------------------------------------------------------------------
diff --git 
a/modules/hadoop-impl/src/test/java/org/apache/ignite/internal/processors/hadoop/HadoopSnappyTest.java
 
b/modules/hadoop-impl/src/test/java/org/apache/ignite/internal/processors/hadoop/HadoopSnappyTest.java
index b4e3dc2..0b86c50 100644
--- 
a/modules/hadoop-impl/src/test/java/org/apache/ignite/internal/processors/hadoop/HadoopSnappyTest.java
+++ 
b/modules/hadoop-impl/src/test/java/org/apache/ignite/internal/processors/hadoop/HadoopSnappyTest.java
@@ -45,10 +45,10 @@ public class HadoopSnappyTest extends 
GridCommonAbstractTest {
      */
     public void testSnappy() throws Throwable {
         // Run Snappy test in default class loader:
-        checkSnappy();
+        //checkSnappy();
 
         // Run the same in several more class loaders simulating jobs and 
tasks:
-        for (int i = 0; i < 2; i++) {
+        for (int i = 0; i < 3; i++) {
             ClassLoader hadoopClsLdr = new HadoopClassLoader(null, "cl-" + i, 
null);
 
             Class<?> cls = 
(Class)Class.forName(HadoopSnappyTest.class.getName(), true, hadoopClsLdr);
@@ -57,6 +57,8 @@ public class HadoopSnappyTest extends GridCommonAbstractTest {
 
             U.invoke(cls, null, "checkSnappy");
         }
+
+        //checkSnappy();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/df3ad76f/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoader.java
----------------------------------------------------------------------
diff --git 
a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoader.java
 
b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoader.java
index 30a6e72..c6d2296 100644
--- 
a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoader.java
+++ 
b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoader.java
@@ -17,7 +17,10 @@
 
 package org.apache.ignite.internal.processors.hadoop;
 
+import java.util.Collections;
+import java.util.List;
 import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.util.ClassCache;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -61,8 +64,7 @@ public class HadoopClassLoader extends URLClassLoader 
implements ClassCache {
     public static final String CLS_DAEMON_REPLACE = 
"org.apache.ignite.internal.processors.hadoop.v2.HadoopDaemon";
 
     /** Hadoop class name: ShutdownHookManager replacement. */
-    public static final String CLS_SHUTDOWN_HOOK_MANAGER_REPLACE =
-        
"org.apache.ignite.internal.processors.hadoop.v2.HadoopShutdownHookManager";
+    public static final String CLS_SHUTDOWN_HOOK_MANAGER_REPLACE = 
"org.apache.ignite.internal.processors.hadoop.v2.HadoopShutdownHookManager";
 
     /** Name of libhadoop library. */
     private static final String LIBHADOOP = "hadoop.";
@@ -83,14 +85,14 @@ public class HadoopClassLoader extends URLClassLoader 
implements ClassCache {
     private final ConcurrentMap<String, Class> cacheMap = new 
ConcurrentHashMap<>();
 
     /** Diagnostic name of this class loader. */
-    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
-    private final String name;
+    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final 
String name;
 
     /** Native library names. */
-    private final String[] libNames;
+    private String[] loadedLibNames;
 
     /**
      * Gets name for Job class loader. The name is specific for local node id.
+     *
      * @param locNodeId The local node id.
      * @return The class loader name.
      */
@@ -100,6 +102,7 @@ public class HadoopClassLoader extends URLClassLoader 
implements ClassCache {
 
     /**
      * Gets name for the task class loader. Task class loader
+     *
      * @param info The task info.
      * @param prefix Get only prefix (without task type and number)
      * @return The class loader name.
@@ -122,70 +125,202 @@ public class HadoopClassLoader extends URLClassLoader 
implements ClassCache {
         super(addHadoopUrls(urls), APP_CLS_LDR);
 
         assert !(getParent() instanceof HadoopClassLoader);
+        assert getClass().getClassLoader() == APP_CLS_LDR; // by definition, 
app cls loader created in such way.
 
         this.name = name;
-        this.libNames = libNames;
 
-        initializeNativeLibraries();
+        // TODO: for POC:
+        if (libNames == null)
+            libNames = new String[] { "hadoop" };
+
+        setNativeLibrariesToBeInjectedIfNeeded(this, libNames);
     }
 
+    //    /**
+    //     * Workaround to load native Hadoop libraries. Java doesn't allow 
native libraries to be loaded from different
+    //     * classloaders. But we load Hadoop classes many times and one of 
these classes - {@code NativeCodeLoader} - tries
+
+    //     * to load the same native library over and over again.
+    //     * <p>
+    //     * To fix the problem, we force native library load in parent class 
loader and then "link" handle to this native
+    //     * library to our class loader. As a result, our class loader will 
think that the library is already loaded and will
+    //     * be able to link native methods.
+    //     *
+    //     * @see <a 
href="http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html#library_version";>
+    //     *     JNI specification</a>
+    //     */
+    //    private void initializeNativeLibraries() {
+    //        try {
+    //            // This must trigger native library load.
+    //            // TODO: Do not delegate to APP LDR
+    //            Class.forName(CLS_NATIVE_CODE_LOADER, true, this);
+    //
+    //            final Vector<Object> curVector = U.field(this, 
"nativeLibraries");
+    //
+    //            // TODO: Do not delegate to APP LDR
+    //            ClassLoader ldr = APP_CLS_LDR;
+    //
+    //            while (ldr != null) {
+    //                Vector vector = U.field(ldr, "nativeLibraries");
+    //
+    //                for (Object lib : vector) {
+    //                    String name = U.field(lib, "name");
+    //
+    //                    boolean add = name.contains(LIBHADOOP);
+    //
+    //                    if (!add && libNames != null) {
+    //                        for (String libName : libNames) {
+    //                            if (libName != null && 
name.contains(libName)) {
+    //                                add = true;
+    //
+    //                                break;
+    //                            }
+    //                        }
+    //                    }
+    //
+    //                    if (add) {
+    //                        curVector.add(lib);
+    //
+    //                        return;
+    //                    }
+    //                }
+    //
+    //                ldr = ldr.getParent();
+    //            }
+    //        }
+    //        catch (Exception e) {
+    //            U.quietAndWarn(null, "Failed to initialize Hadoop native 
library " +
+    //                "(native Hadoop methods might not work properly): " + e);
+    //        }
+    //    }
+
+    /** */
+    private static volatile Collection<Object> nativeLibrariesToBeInjected;
+
     /**
-     * Workaround to load native Hadoop libraries. Java doesn't allow native 
libraries to be loaded from different
-     * classloaders. But we load Hadoop classes many times and one of these 
classes - {@code NativeCodeLoader} - tries
-     * to load the same native library over and over again.
-     * <p>
-     * To fix the problem, we force native library load in parent class loader 
and then "link" handle to this native
-     * library to our class loader. As a result, our class loader will think 
that the library is already loaded and will
-     * be able to link native methods.
-     *
-     * @see <a 
href="http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html#library_version";>
-     *     JNI specification</a>
+     * This method will be invoked for each created instance of 
HadoopClassLoader, but the list of native libraries will
+     * be loaded only once.
      */
-    private void initializeNativeLibraries() {
-        try {
-            // This must trigger native library load.
-            // TODO: Do not delegate to APP LDR
-            Class.forName(CLS_NATIVE_CODE_LOADER, true, APP_CLS_LDR);
+    private static void 
setNativeLibrariesToBeInjectedIfNeeded(HadoopClassLoader instance, String[] 
libs) {
+        if (libs == null)
+            return;
+
+        boolean created = false;
+
+        // 1. If needed, init the native lib data collection:
+        if (nativeLibrariesToBeInjected == null) {
+            synchronized (HadoopClassLoader.class) {
+                if (nativeLibrariesToBeInjected == null) {
+                    instance.runLoadingCode(libs);
+
+                    nativeLibrariesToBeInjected = 
instance.collectNativeLibraries();
+
+                    created = true;
+                }
+            }
+        }
 
+        assert nativeLibrariesToBeInjected != null;
+
+        // 2. Inject libraries:
+        if (!created)
+            // This is an instance that did not load the libs:
+            instance.injectNatives();
+    }
+
+    /**
+     * Injects previously
+     */
+    private void injectNatives() {
+        try {
+            // 2. Init this instance with the natives:
             final Vector<Object> curVector = U.field(this, "nativeLibraries");
 
-            // TODO: Do not delegate to APP LDR
-            ClassLoader ldr = APP_CLS_LDR;
+            curVector.addAll(nativeLibrariesToBeInjected);
+        }
+        catch (Exception e) {
+            U.quietAndWarn(null, "Failed to initialize Hadoop native library " 
+
+                 "(native Hadoop methods might not work properly): " + e);
+        }
+    }
 
-            while (ldr != null) {
-                Vector vector = U.field(ldr, "nativeLibraries");
+    /**
+     *
+     * @return
+     */
+    private Collection<Object> collectNativeLibraries() {
+        List<Object> target = new ArrayList<>();
 
-                for (Object lib : vector) {
-                    String name = U.field(lib, "name");
+        ClassLoader ldr = this;
 
-                    boolean add = name.contains(LIBHADOOP);
+        while (ldr != null) {
+            collectNativeLibrariesFromLoader(ldr, target);
 
-                    if (!add && libNames != null) {
-                        for (String libName : libNames) {
-                            if (libName != null && name.contains(libName)) {
-                                add = true;
+            ldr = ldr.getParent();
+        }
 
-                                break;
-                            }
-                        }
-                    }
+        return Collections.unmodifiableList(target);
+    }
 
-                    if (add) {
-                        curVector.add(lib);
+    /**
+     * Run default or user code to force native libs loading:
+     */
+    private void runLoadingCode(String[] libs) {
+        try {
+            // TODO: "XXX" is a special class loaded by Hadoop class loader 
(simulating Hadoop class).
+            // NB: this sample class must *not* cause loading of any natives.
+            Class<?> sampleCls = this.loadClass(XXX.class.getName(), true);
 
-                        return;
-                    }
-                }
+            assert sampleCls != null;
+            assert sampleCls.getClassLoader() == this;
+
+            Collection<String> loadedLibs = new ArrayList<>();
 
-                ldr = ldr.getParent();
+            for (String lib: libs) {
+                boolean ok = LoadHelper.tryLoad(sampleCls, lib);
+
+                if (ok)
+                    loadedLibs.add(lib);
             }
+
+            loadedLibNames = loadedLibs.toArray(new String[loadedLibs.size()]);
         }
         catch (Exception e) {
-            U.quietAndWarn(null, "Failed to initialize Hadoop native library " 
+
-                "(native Hadoop methods might not work properly): " + e);
+            throw new IgniteException(e);
+        }
+
+    }
+
+    /**
+     *
+     * @param ldr
+     * @param target
+     */
+    private void collectNativeLibrariesFromLoader(ClassLoader ldr, 
Collection<Object> target) {
+        final Vector vector = U.field(ldr, "nativeLibraries");
+
+        for (Object lib : vector) {
+            String name = U.field(lib, "name");
+
+            // TODO: LIBHADOOP should be added implicitly into "libNames"
+            boolean addLib = false; //name.contains(LIBHADOOP);
+
+            if (loadedLibNames != null) {
+                for (String libName : loadedLibNames) {
+                    if (libName != null && name.contains(libName)) {
+                        addLib = true;
+
+                        break;
+                    }
+                }
+            }
+
+            if (addLib)
+                target.add(lib);
         }
     }
 
+
     /** {@inheritDoc} */
     @Override protected Class<?> loadClass(String name, boolean resolve) 
throws ClassNotFoundException {
         try {

http://git-wip-us.apache.org/repos/asf/ignite/blob/df3ad76f/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoaderUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoaderUtils.java
 
b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoaderUtils.java
index 3415d6a..aeef031 100644
--- 
a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoaderUtils.java
+++ 
b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/HadoopClassLoaderUtils.java
@@ -90,7 +90,7 @@ public class HadoopClassLoaderUtils {
      * @return {@code true} If this is Hadoop class.
      */
     public static boolean isHadoop(String cls) {
-        return cls.startsWith("org.apache.hadoop.");
+        return cls.startsWith("org.apache.hadoop.") || 
cls.equals(XXX.class.getName());
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/df3ad76f/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/LoadHelper.java
----------------------------------------------------------------------
diff --git 
a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/LoadHelper.java
 
b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/LoadHelper.java
new file mode 100644
index 0000000..a795085
--- /dev/null
+++ 
b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/LoadHelper.java
@@ -0,0 +1,42 @@
+package org.apache.ignite.internal.processors.hadoop;
+
+import java.lang.reflect.Method;
+
+/**
+ * Should be loaded with the
+ */
+public class LoadHelper {
+
+    private static Method method;
+
+    static {
+        try {
+            method = ClassLoader.class.getDeclaredMethod("loadLibrary",
+                new Class[] {Class.class, String.class, boolean.class});
+
+            method.setAccessible(true);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Utility method that loads given class by name with the given "caller" 
class.
+     *
+     * @return 'true' on success.
+     */
+    public static boolean tryLoad(Class caller, String libName) {
+        try {
+            method.invoke(null, new Object[] {caller/*caller class*/, libName 
/*lib*/ , false/*isAbsolute*/ });
+
+            return true;
+        }
+        catch (Throwable t) {
+            // TODO:
+            t.printStackTrace();
+
+            return false;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/df3ad76f/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/XXX.java
----------------------------------------------------------------------
diff --git 
a/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/XXX.java
 
b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/XXX.java
new file mode 100644
index 0000000..b230636
--- /dev/null
+++ 
b/modules/hadoop/src/main/java/org/apache/ignite/internal/processors/hadoop/XXX.java
@@ -0,0 +1,7 @@
+package org.apache.ignite.internal.processors.hadoop;
+
+/**
+ * Created by ivan on 19.09.16.
+ */
+public class XXX {
+}

Reply via email to