Package erjang

Source Code of erjang.ErjangCodeCache$PersistRequest

/** -*- tab-width: 4 -*-
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2011 by Trifork
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

package erjang;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.jar.JarOutputStream;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;

import erjang.beam.BeamLoader;
import erjang.beam.Compiler;
import erjang.beam.RamClassRepo;

public class ErjangCodeCache {
  static final Logger log = Logger.getLogger("erjang.beam.cache");
    // Config:
    static final String ERJ_CACHE_DIR;
    static final boolean useAsyncPersisting;
    static final boolean useSyncPersisting;
    static final Persister persister;
    static {
  String cacheDir = System.getenv("ERJ_CACHE_DIR");
  if (cacheDir == null) cacheDir = System.getProperty("user.home");
  ERJ_CACHE_DIR = cacheDir;

  String mode = System.getProperty("erjang.codecache.mode");
  if ("async".equals(mode)) {
      useAsyncPersisting = true;
      useSyncPersisting = false;
  } else if ("sync".equals(mode)) {
      useAsyncPersisting = false;
      useSyncPersisting = true;
  } else if ("off".equals(mode)) {
      useAsyncPersisting = false;
      useSyncPersisting = false;
  } else {
      // TODO: Warn?
      // Default to 'async':
      useAsyncPersisting = true;
      useSyncPersisting = false;
  } // Other values which might make sense: 'read-only', 'existing-only'

  if (useAsyncPersisting) {
      persister = new Persister();
      Thread t = new Thread(persister, "Erjang Code Cache Persister");
      t.setDaemon(true);
      t.setPriority(Thread.MIN_PRIORITY);
      t.start();
  } else persister = null;
    }


    private static Map<String, RamClassRepo> cache = Collections.synchronizedMap(new HashMap<String, RamClassRepo>());


    public static EModuleClassLoader getModuleClassLoader(String moduleName, EBinary beam_data, BeamLoader beam_parser) throws IOException {
  long crc = beam_data.crc();
//  crc ^= BIFUtil.all_bif_hash();

  File jarFile = new File(erjdir(), moduleJarFileName(moduleName, crc));

  if (jarFile.exists()) {
      return new EModuleClassLoader(jarFile.toURI().toURL());
  }
  RamClassRepo repo = new RamClassRepo();

  try {
      Compiler.compile(beam_parser.load(beam_data.getByteArray()), repo);

      repo.close();
      cache.put(moduleName, repo);
      if (useAsyncPersisting) persister.enqueue(jarFile, repo);
      else if (useSyncPersisting) persister.persist(jarFile, repo);
  } finally {
      try {repo.close();
    // jarFile.delete();
      } catch (Exception e) {}
  }

  return new EModuleClassLoader(jarFile.toURI().toURL(), repo);
    }

    static File erjdir() throws IOException {
  File home = ERT.newFile(ERJ_CACHE_DIR);

  File dir = new File(home, ".erjang");
  if (!dir.exists()) {
      if (!dir.mkdirs())
    throw new IOException("cannot create " + dir);

  } else if (!dir.canWrite()) {
      throw new IOException("cannot write to " + dir);
  }

  return dir;
    }

    public static String moduleJarFileName(String moduleName, long crc) {
  return moduleFileName(moduleName, crc, "jar");
    }
    /*
    static String moduleJarBackupFileName(String moduleName, long crc) {
  return moduleFileName(moduleName, crc, "ja#");
    }
    */

    static String moduleFileName(String moduleName, long crc, String extension) {
  return mangle(moduleName)
      + "-" + Long.toHexString(crc)
      + "." + extension;
    }

    /** Mangle string so that the result contains only [a-z0-9_$]. */
    static String mangle(String s) {
  // TODO: Faster handling of the normal case.
  StringBuffer sb = new StringBuffer();
  for (int i=0; i<s.length(); i++) {
      char c = s.charAt(i);
      if (('a' <= c && c <= 'z') ||
          ('A' <= c && c <= 'Z') ||
          ('0' <= c && c <= '9') ||
          c == '-' ||
            c == '.' ||
          c == '_')
    sb.append(c);
      else
    sb.append('$').append(Integer.toHexString(c)).append('$');
  }
  return sb.toString();
    }

    static class PersistRequest { // Just a Pair<File,RamClassRepo>, really.
  final File file;
  final RamClassRepo repo;
  public PersistRequest(File file, RamClassRepo repo) {
      this.file = file;
      this.repo = repo;
  }
    }

    static class Persister implements Runnable {
  final Queue<PersistRequest> queue = new LinkedList<PersistRequest>();

  public void run() {
      while (true) {
    PersistRequest request;
    synchronized (queue) {
        while ((request = queue.poll()) == null) {
      try { queue.wait(); }
      catch (InterruptedException ie) {}
        }
    }

    persist(request.file, request.repo);
      }
  }

  void enqueue(File file, RamClassRepo repo) {
      synchronized (queue) {
    queue.add(new PersistRequest(file, repo));
    queue.notify();
      }
  }

  static void persist(File file, RamClassRepo repo) {
      try {
    File tmpFile = File.createTempFile(file.getName(), "tmp",
               file.getParentFile());
    JarOutputStream jo = new JarOutputStream(new FileOutputStream(tmpFile));
    jo.setLevel(0);
    for (Map.Entry<String,byte[]> e : repo.entrySet()) {
        String classFilename = e.getKey() + ".class";
        byte[] classContents = e.getValue();
        jo.putNextEntry(new ZipEntry(classFilename));
        jo.write(classContents);
        jo.closeEntry();
    }
    jo.close();
    tmpFile.renameTo(file);
      } catch (IOException ioe) {
        log.warning("Warning: Failed to store cached module in "+file);
      }
  }
    }
}
TOP

Related Classes of erjang.ErjangCodeCache$PersistRequest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.