adequate
adequate
adequate
adequate
 

JPPF
 Home   About   Download   Documentation   Forums 
May 25, 2013, 02:48:57 AM *
Welcome,
Please login or register.

Login with username, password and session length
Advanced search  
News: Registered users, your contribution is requested! Please participate in our JDK support poll
New users, please read this message. Thank you!
  Home Help Search Login Register  
Pages: [1]   Go Down

Author Topic: RFE: Extends JPPFClassLoader for downloading whole JARs  (Read 1486 times)

jandam

  • JPPF Master
  • ***
  • Posts: 38
RFE: Extends JPPFClassLoader for downloading whole JARs
« on: June 12, 2011, 01:22:47 PM »

First initialization of my application takes more that 2 minutes (not optimized, need ~10 JARs - tons of classes + resource files)
It can improve startup time on slow networks with huge latencies. And decrease communication traffic between JPPF components.

JARs can be stored in temp directory and deleted on JPPFNode shutdown. Now class files and resources are cached in JPPFClassLoader by JPPFClient.ID.
I suggest extends JPPFClient and JPPFJob with new methods.

JPPFClient:addClassLoaderURL(URL)
JPPFJob:addClassLoaderURL(URL)

addClassLoaderURL - computes unique hashCode for URL (eg SHA-256 from URL content)

On creation of JPPFClassLocader the JPPFNode knows what unique hashCodes (ClassLoaderURLs) are need to download -> downloads URLs content from client

JPPFClassLocader extends URLClassLoader that has protected method addURL(URL url) but  JPPFClassLocader uses only internal cache for class and resource search.

I have made simple JPPFTaskDownloader(final File... files) that downloads files to JPPFNode. It took only ~25 seconds to download several megabytes on slow WiFi, not 2 minutes.

public class JPPFTaskDownloader {
    private final List<File> source = new ArrayList<File>();

  public JPPFTaskDownloader(final Collection<File> files) {
      source.addAll(files);
}

    public void run() {
        System.out.println("Task init");
        long totalDur = System.nanoTime();
        try {
            ClientDataProvider dataProvider = (ClientDataProvider) getDataProvider();

            ClassLoader classLoader = getClass().getClassLoader();
            if(classLoader instanceof AbstractJPPFClassLoader && !source.isEmpty()) {
                JPPFClassLoader jppfClassLoader = (JPPFClassLoader) classLoader;
                for (File file : source) {
                    long dur = System.nanoTime();
                    byte[] data = safeComputeValue(dataProvider, file.getAbsolutePath(), new DownloadFile(file));

                    File out = File.createTempFile("jppf-", "-download");

                    FileOutputStream os = null;
                    try {
                        os = new FileOutputStream(out);
                        os.write(data);
                    } finally {
                        if(os != null) os.close();
                    }
                    dur = System.nanoTime() - dur;
                    System.out.printf("Adding file: %s - source: %s - size: %d, dur: %f%n", out.getName(), file.getName(), data.length, dur / 1000000.0);
                    file.deleteOnExit();
                    jppfClassLoader.addURL(file.toURI().toURL());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            setException(e);
        } catch (Throwable t) {
            t.printStackTrace();
            setException(new JPPFException(t));
        }  finally {
            totalDur = System.nanoTime() - totalDur;
            System.out.println("FINSIHED in: " + (totalDur / 1000000.0));
        }
    }

    public static class DownloadFile implements JPPFCallable<byte[]> {
        private static final long serialVersionUID = 8363386268214414851L;

        private final File file;

        public DownloadFile(final File file) {
            this.file = file;
        }

        @Override
        public byte[] call() throws Exception {
            System.out.printf("Downloading: %s%n", file.getAbsolutePath());
            FileInputStream is = null;
            byte[] result;
            try {
                is = new FileInputStream(file);
                result = new byte[(int) file.length()];
                readFully(is, result);
            } finally {
                if(is != null) is.close();
            }
            return result;
        }

        protected static void readFully(final FileInputStream in, final byte b[]) throws IOException {
            int n = 0;
            while (n < b.length) {
                int count = in.read(b, n, b.length - n);
                if (count < 0) throw new EOFException();
                n += count;
            }
        }
    }

    public static <V> V safeComputeValue(final ClientDataProvider dataProvider, final Object key, final JPPFCallable<V> callable) {
        if (key == null) return null;
        Object result = dataProvider.computeValue(key, callable);
        if (result instanceof Throwable) {
//                System.out.println("Result: " + result);
            ((Throwable) result).printStackTrace();
        }
        return (V) result;
    }
}


SHA-256
                MessageDigest digest = MessageDigest.getInstance("SHA-256");
                digest.reset();
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ...
                bos.write(<data>)
               ...
                bos.close();
                byte[] hashCode = digest.digest(bos.toByteArray());

Cached file

File file = File.createTemporaryFile("jppf-", "-" + toHex(hashCode))...
file.deleteOnExit();
...

« Last Edit: June 12, 2011, 01:29:48 PM by jandam »
Logged

lolo

  • Administrator
  • JPPF Council Member
  • *****
  • Posts: 1436
    • JPPF Web site
Re: RFE: Extends JPPFClassLoader for downloading whole JARs
« Reply #1 on: June 14, 2011, 09:18:33 AM »

Martin,

Thank you for this. I am exploring another solution that may be simpler and doesn't require any modification of the JPPF code. I will get back to you very shortly on this.

-Laurent
Logged

lolo

  • Administrator
  • JPPF Council Member
  • *****
  • Posts: 1436
    • JPPF Web site
Re: RFE: Extends JPPFClassLoader for downloading whole JARs
« Reply #2 on: June 20, 2011, 08:40:06 AM »

Hi Martin,

After some more investigation, I found out that there is a problem with the class loader implementation of findClass(). The problem is that it doesn't call super.findClass(), so adding a jar file via URLClassLoader.addURL() has no effect. I registered a bug for this: 3321904 - AbstractJPPFClassLoader is not calling super.findClass()

So what I propose as a solution:

1. Fix this bug  :)

2. Add the capability for the class loader to lookup resources on the file system of the server or client - this will allow you to effectively download jar files even if they are not in the class path. See feature request 3322847 - Enable classloader to lookup resources in file system. Note that this feature will also introduce a new method that will allow you to download multiple files at once.

3. Override URLClassLoader.addURL() (in AbstractJPPFClassLoader) and make it public so it is easily available from the tasks or extensions. See 3322850 - Make AbstractJPPFClassLoader.addURL() public

4. We will release a technical update for JPPF, v2.5.1 that will include these features, and all bug fixes included included in the current patches for 2.5, plus a few minor features as well. The plan is to make the release early next week.

How does that sound?

Thanks,
-Laurent
Logged

jandam

  • JPPF Master
  • ***
  • Posts: 38
Re: RFE: Extends JPPFClassLoader for downloading whole JARs
« Reply #3 on: June 20, 2011, 04:14:00 PM »

It sounds good. I already take a look at your changes in trunk. And your fixes will allow me to provide my own persistent 'ResourceCache'.

I suppose that there will be at least 1 driver running on server (with local node enabled). And other desktop computers. They will act as Nodes (windows service) and Clients. These desktops are switched off every day (need for persistent ResourceCache)

  Thank you very much
      Martin
Logged
Pages: [1]   Go Up
 
Support This Project Powered by SMF 2.0 RC5 | SMF © 2006–2011, Simple Machines LLC Powered by Parallel Matters Get JPPF at SourceForge.net. Fast, secure and Free Open Source software downloads