[armedbear-cvs] r12451 - trunk/abcl/src/org/armedbear/lisp
Mark Evenson
mevenson at common-lisp.net
Fri Feb 12 11:08:21 UTC 2010
Author: mevenson
Date: Fri Feb 12 06:08:20 2010
New Revision: 12451
Log:
Fix for ZipException under interpreted ANSI tests.
Check that the cache entries still accesses an open ZipFile when it is
handed out.
Use SYS:DISABLE-ZIP-CACHE to disable the ZipCache entirely.
Implemented some notion of thread synchronization, although we cannot
guard against the case where two or more references to a ZipFile
exist, and one thread closes the ZipFile.
Modified:
trunk/abcl/src/org/armedbear/lisp/Autoload.java
trunk/abcl/src/org/armedbear/lisp/ZipCache.java
Modified: trunk/abcl/src/org/armedbear/lisp/Autoload.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/Autoload.java (original)
+++ trunk/abcl/src/org/armedbear/lisp/Autoload.java Fri Feb 12 06:08:20 2010
@@ -606,6 +606,7 @@
autoload(PACKAGE_SYS, "create-new-file", "create_new_file");
autoload(PACKAGE_SYS, "default-time-zone", "Time");
autoload(PACKAGE_SYS, "disassemble-class-bytes", "disassemble_class_bytes", true);
+ autoload(PACKAGE_SYS, "disable-zip-cache", "ZipCache", true);
autoload(PACKAGE_SYS, "double-float-high-bits", "FloatFunctions", true);
autoload(PACKAGE_SYS, "double-float-low-bits", "FloatFunctions", true);
autoload(PACKAGE_SYS, "float-infinity-p", "FloatFunctions", true);
Modified: trunk/abcl/src/org/armedbear/lisp/ZipCache.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/ZipCache.java (original)
+++ trunk/abcl/src/org/armedbear/lisp/ZipCache.java Fri Feb 12 06:08:20 2010
@@ -36,71 +36,140 @@
import static org.armedbear.lisp.Lisp.*;
import java.io.File;
+import java.io.InputStream;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
/**
* A cache for all zip/jar file accesses by URL that uses the last
* modified time of the cached resource.
+ *
+ * This implementation is NOT thread safe, although usage without
+ * multiple threads recompiling code that is then re-loaded should be
+ * fine.
+ *
+ * If you run into problems with caching, use
+ * (SYS::DISABLE-ZIP-CACHE). Once disabled, the caching cannot be
+ * re-enabled.
+ *
*/
public class ZipCache {
- static class Entry {
- long lastModified;
- ZipFile file;
- }
-
- static HashMap<URL, Entry> zipCache = new HashMap<URL, Entry>();
-
- public static ZipFile get(LispObject arg) {
- return get(Pathname.makeURL(arg));
- }
-
- public static ZipFile get(URL url) {
- Entry entry = zipCache.get(url);
- if (entry != null) {
- if (url.getProtocol().equals("file")) {
- File f = new File(url.getPath());
+
+ // To make this thread safe, we should return a proxy for ZipFile
+ // that keeps track of the number of outstanding references handed
+ // out, not allowing ZipFile.close() to succeed until that count
+ // has been reduced to 1 or the finalizer is executing.
+ // Unfortunately the relatively simple strategy of extended
+ // ZipFile via a CachedZipFile does not work because there is not
+ // a null arg constructor for ZipFile.
+ static class Entry {
+ long lastModified;
+ ZipFile file;
+ }
+
+ static boolean cacheEnabled = true;
+
+ private final static Primitive DISABLE_ZIP_CACHE = new disable_zip_cache();
+ final static class disable_zip_cache extends Primitive {
+ disable_zip_cache() {
+ super("disable-zip-cache", PACKAGE_SYS, true, "",
+ "Disable all caching of ABCL FASLs and ZIPs.");
+ }
+ @Override
+ public LispObject execute() {
+ ZipCache.disable();
+ return T;
+ }
+ }
+
+ static public synchronized void disable() {
+ cacheEnabled = false;
+ zipCache.clear();
+ }
+
+ static HashMap<URL, Entry> zipCache = new HashMap<URL, Entry>();
+
+ synchronized public static ZipFile get(LispObject arg) {
+ return get(Pathname.makeURL(arg));
+ }
+
+ synchronized public static ZipFile get(final URL url) {
+ if (!cacheEnabled) {
+ if (url.getProtocol().equals("file")) {
+ File f = new File(url.getPath());
+ try {
+ return new ZipFile(f);
+ } catch (ZipException e) {
+ Debug.trace(e); // XXX
+ return null;
+ } catch (IOException e) {
+ Debug.trace(e); // XXX
+ return null;
+ }
+ } else {
+ Entry e = fetchURL(url, false);
+ return e.file;
+ }
+ }
+
+ Entry entry = zipCache.get(url);
+
+ // Check that the cache entry still accesses a valid ZipFile
+ if (entry != null) {
+ // Simplest way to call private ZipFile.ensureOpen()
+ try {
+ int size = entry.file.size();
+ } catch (IllegalStateException e) {
+ zipCache.remove(url);
+ entry = null;
+ }
+ }
+
+ if (entry != null) {
+ if (url.getProtocol().equals("file")) {
+ File f = new File(url.getPath());
long current = f.lastModified();
if (current > entry.lastModified) {
try {
- entry.file.close();
- entry.file = new ZipFile(f);
- entry.lastModified = current;
+ entry.file = new ZipFile(f);
+ entry.lastModified = current;
} catch (IOException e) {
Debug.trace(e.toString()); // XXX
}
}
} else {
- // Unfortunately, the Apple JDK under OS X doesn't do
- // HTTP HEAD requests, instead refetching the entire
- // resource, so the following code is a waste. I assume
- // this is the case in all Sun-dervied JVMs. We'll have
- // to implement a custom HTTP lastModified checker.
-
- // URLConnection connection;
- // try {
- // connection = url.openConnection();
- // } catch (IOException ex) {
- // Debug.trace("Failed to open "
- // + "'" + url + "'");
- // return null;
- // }
- // long current = connection.getLastModified();
- // if (current > entry.lastModified) {
- // try {
- // entry.file.close();
- // } catch (IOException ex) {}
- // entry = fetchURL(url, false);
- // }
+ // Unfortunately, the Apple JDK under OS X doesn't do
+ // HTTP HEAD requests, instead refetching the entire
+ // resource, so the following code is a waste. I assume
+ // this is the case in all Sun-dervied JVMs. We'll have
+ // to implement a custom HTTP lastModified checker.
+
+ // URLConnection connection;
+ // try {
+ // connection = url.openConnection();
+ // } catch (IOException ex) {
+ // Debug.trace("Failed to open "
+ // + "'" + url + "'");
+ // return null;
+ // }
+ // long current = connection.getLastModified();
+ // if (current > entry.lastModified) {
+ // try {
+ // entry.file.close();
+ // } catch (IOException ex) {}
+ // entry = fetchURL(url, false);
+ // }
}
} else {
- if (url.getProtocol().equals("file")) {
+ if (url.getProtocol().equals("file")) {
entry = new Entry();
File f = new File(url.getPath());
entry.lastModified = f.lastModified();
@@ -119,81 +188,78 @@
zipCache.put(url, entry);
}
return entry.file;
- }
+ }
- static private Entry fetchURL(URL url, boolean cached) {
- Entry result = new Entry();
- URL jarURL = null;
- try {
- jarURL = new URL("jar:" + url + "!/");
- } catch (MalformedURLException e) {
- Debug.trace(e);
- Debug.assertTrue(false); // XXX
- }
- URLConnection connection;
- try {
- connection = jarURL.openConnection();
- } catch (IOException ex) {
- Debug.trace("Failed to open "
- + "'" + jarURL + "'");
- return null;
- }
- if (!(connection instanceof JarURLConnection)) {
- // XXX
- Debug.trace("Could not get a URLConnection from " + jarURL);
- return null;
- }
- JarURLConnection jarURLConnection = (JarURLConnection) connection;
- jarURLConnection.setUseCaches(cached);
- try {
- result.file = jarURLConnection.getJarFile();
- } catch (IOException e) {
- Debug.trace(e);
- Debug.assertTrue(false); // XXX
- }
- result.lastModified = jarURLConnection.getLastModified();
- return result;
- }
+ static private Entry fetchURL(URL url, boolean cached) {
+ Entry result = new Entry();
+ URL jarURL = null;
+ try {
+ jarURL = new URL("jar:" + url + "!/");
+ } catch (MalformedURLException e) {
+ Debug.trace(e);
+ Debug.assertTrue(false); // XXX
+ }
+ URLConnection connection;
+ try {
+ connection = jarURL.openConnection();
+ } catch (IOException ex) {
+ Debug.trace("Failed to open "
+ + "'" + jarURL + "'");
+ return null;
+ }
+ if (!(connection instanceof JarURLConnection)) {
+ // XXX
+ Debug.trace("Could not get a URLConnection from " + jarURL);
+ return null;
+ }
+ JarURLConnection jarURLConnection = (JarURLConnection) connection;
+ jarURLConnection.setUseCaches(cached);
+ try {
+ result.file = jarURLConnection.getJarFile();
+ } catch (IOException e) {
+ Debug.trace(e);
+ Debug.assertTrue(false); // XXX
+ }
+ result.lastModified = jarURLConnection.getLastModified();
+ return result;
+ }
+ // ## remove-zip-cache-entry pathname => boolean
+ private static final Primitive REMOVE_ZIP_CACHE_ENTRY = new remove_zip_cache_entry();
+ private static class remove_zip_cache_entry extends Primitive {
+ remove_zip_cache_entry() {
+ super("remove-zip-cache-entry", PACKAGE_SYS, true, "pathname");
+ }
+ @Override
+ public LispObject execute(LispObject arg) {
+ Pathname p = coerceToPathname(arg);
+ boolean result = ZipCache.remove(p);
+ return result ? T : NIL;
+ }
+ }
+
+ synchronized public static boolean remove(URL url) {
+ Entry entry = zipCache.get(url);
+ if (entry != null) {
+ try {
+ entry.file.close();
+ } catch (IOException e) {}
+ zipCache.remove(entry);
+ return true;
+ }
+ return false;
+ }
+ synchronized public static boolean remove(Pathname p) {
+ URL url = Pathname.makeURL(p);
+ if (url == null) {
+ return false;
+ }
+ return ZipCache.remove(url);
+ }
- // ## remove-zip-cache-entry pathname => boolean
- private static final Primitive REMOVE_ZIP_CACHE_ENTRY = new remove_zip_cache_entry();
- private static class remove_zip_cache_entry extends Primitive {
- remove_zip_cache_entry() {
- super("remove-zip-cache-entry", PACKAGE_SYS, true, "pathname");
- }
- @Override
- public LispObject execute(LispObject arg) {
- Pathname p = coerceToPathname(arg);
- boolean result = ZipCache.remove(p);
- return result ? T : NIL;
+ synchronized public static boolean remove(File f) {
+ Pathname p = Pathname.makePathname(f);
+ return ZipCache.remove(p);
}
- }
-
- public static boolean remove(URL url) {
- Entry entry = zipCache.get(url);
- if (entry != null) {
- try {
- entry.file.close();
- } catch (IOException e) {}
- zipCache.remove(entry);
- return true;
- }
- return false;
- }
-
- public static boolean remove(Pathname p) {
- URL url = Pathname.makeURL(p);
- if (url == null) {
- return false;
- }
- return ZipCache.remove(url);
- }
-
- public static boolean remove(File f) {
- Pathname p = Pathname.makePathname(f);
- return ZipCache.remove(p);
- }
-
}
\ No newline at end of file
More information about the armedbear-cvs
mailing list