src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeStore.java

Print this page

        

*** 32,116 **** import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Map; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.runtime.logging.DebugLogger; import jdk.nashorn.internal.runtime.logging.Loggable; import jdk.nashorn.internal.runtime.logging.Logger; /** * A code cache for persistent caching of compiled scripts. */ @Logger(name="codestore") ! final class CodeStore implements Loggable { ! ! private final File dir; ! private final int minSize; ! private final DebugLogger log; ! ! // Default minimum size for storing a compiled script class ! private final static int DEFAULT_MIN_SIZE = 1000; /** ! * Constructor ! * @throws IOException */ ! public CodeStore(final Context context, final String path) throws IOException { ! this(context, path, DEFAULT_MIN_SIZE); ! } /** * Constructor - * @param path directory to store code in - * @param minSize minimum file size for caching scripts - * @throws IOException */ ! public CodeStore(final Context context, final String path, final int minSize) throws IOException { ! this.dir = checkDirectory(path); ! this.minSize = minSize; ! this.log = initLogger(context); } @Override public DebugLogger initLogger(final Context context) { ! return context.getLogger(getClass()); } @Override public DebugLogger getLogger() { return log; } ! private static File checkDirectory(final String path) throws IOException { try { ! return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() { ! @Override ! public File run() throws IOException { ! final File dir = new File(path).getAbsoluteFile(); ! if (!dir.exists() && !dir.mkdirs()) { ! throw new IOException("Could not create directory: " + dir.getPath()); ! } else if (!dir.isDirectory()) { ! throw new IOException("Not a directory: " + dir.getPath()); ! } else if (!dir.canRead() || !dir.canWrite()) { ! throw new IOException("Directory not readable or writable: " + dir.getPath()); } ! return dir; } ! }); ! } catch (final PrivilegedActionException e) { ! throw (IOException) e.getException(); } } ! ! private File getCacheFile(final Source source, final String functionKey) { ! return new File(dir, source.getDigest() + '-' + functionKey); } /** * Generate a string representing the function with {@code functionId} and {@code paramTypes}. * @param functionId function id --- 32,179 ---- import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; + import java.security.AccessControlException; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; + import java.util.Iterator; import java.util.Map; + import java.util.ServiceLoader; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.runtime.logging.DebugLogger; import jdk.nashorn.internal.runtime.logging.Loggable; import jdk.nashorn.internal.runtime.logging.Logger; + import jdk.nashorn.internal.runtime.options.Options; /** * A code cache for persistent caching of compiled scripts. */ @Logger(name="codestore") ! public abstract class CodeStore implements Loggable { /** ! * Permission needed to provide a CodeStore instance via ServiceLoader. */ ! public final static String NASHORN_PROVIDE_CODE_STORE = "nashorn.provideCodeStore"; ! ! private DebugLogger log; /** * Constructor */ ! protected CodeStore() { } @Override public DebugLogger initLogger(final Context context) { ! log = context.getLogger(getClass()); ! return log; } @Override public DebugLogger getLogger() { return log; } ! /** ! * Returns a new code store instance. ! * ! * @param context the current context ! * @return The instance ! * @throws IOException If an error occurs ! */ ! public static CodeStore newCodeStore(final Context context) throws IOException { ! final Class<CodeStore> baseClass = CodeStore.class; try { ! // security check first ! final SecurityManager sm = System.getSecurityManager(); ! if (sm != null) { ! sm.checkPermission(new RuntimePermission(NASHORN_PROVIDE_CODE_STORE)); ! } ! final ServiceLoader<CodeStore> services = ServiceLoader.load(baseClass); ! final Iterator<CodeStore> iterator = services.iterator(); ! if (iterator.hasNext()) { ! final CodeStore store = iterator.next(); ! store.initLogger(context).info("using code store provider ", store.getClass().getCanonicalName()); ! return store; ! } ! } catch (final AccessControlException e) { ! context.getLogger(CodeStore.class).warning("failed to load code store provider ", e); ! } ! final CodeStore store = new DirectoryCodeStore(); ! store.initLogger(context); ! return store; } ! ! ! /** ! * Store a compiled script in the cache. ! * ! * @param functionKey the function key ! * @param source the source ! * @param mainClassName the main class name ! * @param classBytes a map of class bytes ! * @param initializers the function initializers ! * @param constants the constants array ! * @param compilationId the compilation id ! */ ! public StoredScript store(final String functionKey, ! final Source source, ! final String mainClassName, ! final Map<String, byte[]> classBytes, ! final Map<Integer, FunctionInitializer> initializers, ! final Object[] constants, ! final int compilationId) { ! return store(functionKey, source, storedScriptFor(source, mainClassName, classBytes, initializers, constants, compilationId)); } ! ! /** ! * Stores a compiled script. ! * ! * @param functionKey the function key ! * @param source the source ! * @param script The compiled script ! * @return The compiled script or {@code null} if not stored ! */ ! public abstract StoredScript store(final String functionKey, ! final Source source, ! final StoredScript script); ! ! /** ! * Return a compiled script from the cache, or null if it isn't found. ! * ! * @param source the source ! * @param functionKey the function key ! * @return the stored script or null ! */ ! public abstract StoredScript load(final Source source, final String functionKey); ! ! /** ! * Returns a new StoredScript instance. ! * ! * @param mainClassName the main class name ! * @param classBytes a map of class bytes ! * @param initializers function initializers ! * @param constants the constants array ! * @param compilationId the compilation id ! * @return The compiled script ! */ ! public StoredScript storedScriptFor(final Source source, final String mainClassName, ! final Map<String, byte[]> classBytes, ! final Map<Integer, FunctionInitializer> initializers, ! final Object[] constants, final int compilationId) { ! for (final Object constant : constants) { ! // Make sure all constant data is serializable ! if (!(constant instanceof Serializable)) { ! getLogger().warning("cannot store ", source, " non serializable constant ", constant); ! return null; } } ! return new StoredScript(compilationId, mainClassName, classBytes, initializers, constants); } /** * Generate a string representing the function with {@code functionId} and {@code paramTypes}. * @param functionId function id
*** 127,143 **** } return b.toString(); } /** ! * Return a compiled script from the cache, or null if it isn't found. * ! * @param source the source ! * @param functionKey the function key ! * @return the stored script or null */ ! public StoredScript loadScript(final Source source, final String functionKey) { if (source.getLength() < minSize) { return null; } final File file = getCacheFile(source, functionKey); --- 190,261 ---- } return b.toString(); } /** ! * A store using a file system directory. ! */ ! public static class DirectoryCodeStore extends CodeStore { ! ! // Default minimum size for storing a compiled script class ! private final static int DEFAULT_MIN_SIZE = 1000; ! ! private final File dir; ! private final boolean readOnly; ! private final int minSize; ! ! /** ! * Constructor * ! * @throws IOException ! */ ! public DirectoryCodeStore() throws IOException { ! this(Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"), false, DEFAULT_MIN_SIZE); ! } ! ! /** ! * Constructor ! * ! * @param path directory to store code in ! * @param minSize minimum file size for caching scripts ! * @throws IOException */ ! public DirectoryCodeStore(final String path, final boolean readOnly, final int minSize) throws IOException { ! this.dir = checkDirectory(path, readOnly); ! this.readOnly = readOnly; ! this.minSize = minSize; ! } ! ! private static File checkDirectory(final String path, final boolean readOnly) throws IOException { ! try { ! return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() { ! @Override ! public File run() throws IOException { ! final File dir = new File(path).getAbsoluteFile(); ! if (readOnly) { ! if (!dir.exists() || !dir.isDirectory()) { ! throw new IOException("Not a directory: " + dir.getPath()); ! } else if (!dir.canRead()) { ! throw new IOException("Directory not readable: " + dir.getPath()); ! } ! } else if (!dir.exists() && !dir.mkdirs()) { ! throw new IOException("Could not create directory: " + dir.getPath()); ! } else if (!dir.isDirectory()) { ! throw new IOException("Not a directory: " + dir.getPath()); ! } else if (!dir.canRead() || !dir.canWrite()) { ! throw new IOException("Directory not readable or writable: " + dir.getPath()); ! } ! return dir; ! } ! }); ! } catch (final PrivilegedActionException e) { ! throw (IOException) e.getException(); ! } ! } ! ! @Override ! public StoredScript load(final Source source, final String functionKey) { if (source.getLength() < minSize) { return null; } final File file = getCacheFile(source, functionKey);
*** 160,206 **** getLogger().warning("failed to load ", source, "-", functionKey, ": ", e.getException()); return null; } } ! /** ! * Store a compiled script in the cache. ! * ! * @param functionKey the function key ! * @param source the source ! * @param mainClassName the main class name ! * @param classBytes a map of class bytes ! * @param constants the constants array ! */ ! public void storeScript(final String functionKey, final Source source, final String mainClassName, final Map<String, byte[]> classBytes, ! final Map<Integer, FunctionInitializer> initializers, final Object[] constants, final int compilationId) { ! if (source.getLength() < minSize) { ! return; ! } ! for (final Object constant : constants) { ! // Make sure all constant data is serializable ! if (! (constant instanceof Serializable)) { ! getLogger().warning("cannot store ", source, " non serializable constant ", constant); ! return; ! } } final File file = getCacheFile(source, functionKey); - final StoredScript script = new StoredScript(compilationId, mainClassName, classBytes, initializers, constants); try { ! AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { @Override ! public Void run() throws IOException { try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { out.writeObject(script); } getLogger().info("stored ", source, "-", functionKey); ! return null; } }); } catch (final PrivilegedActionException e) { getLogger().warning("failed to store ", script, "-", functionKey, ": ", e.getException()); } } } --- 278,322 ---- getLogger().warning("failed to load ", source, "-", functionKey, ": ", e.getException()); return null; } } ! @Override ! public StoredScript store(final String functionKey, final Source source, final StoredScript script) { ! if (readOnly || script == null || belowThreshold(source)) { ! return null; } final File file = getCacheFile(source, functionKey); try { ! return AccessController.doPrivileged(new PrivilegedExceptionAction<StoredScript>() { @Override ! public StoredScript run() throws IOException { try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { out.writeObject(script); } getLogger().info("stored ", source, "-", functionKey); ! return script; } }); } catch (final PrivilegedActionException e) { getLogger().warning("failed to store ", script, "-", functionKey, ": ", e.getException()); + return null; + } + } + + + private File getCacheFile(final Source source, final String functionKey) { + return new File(dir, source.getDigest() + '-' + functionKey); + } + + private boolean belowThreshold(final Source source) { + if (source.getLength() < minSize) { + getLogger().info("below size threshold ", source); + return true; + } + return false; } } }