[jboss-cvs] JBossAS SVN: r74575 - in projects/vfs/trunk/src/main/java/org/jboss/virtual: plugins/context/zip and 1 other directory.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Sun Jun 15 10:50:45 EDT 2008
Author: mstruk
Date: 2008-06-15 10:50:44 -0400 (Sun, 15 Jun 2008)
New Revision: 74575
Modified:
projects/vfs/trunk/src/main/java/org/jboss/virtual/VFSUtils.java
projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java
projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipStreamWrapper.java
Log:
Implemented performance optimized in-memory nested archives, added jboss.vfs.optimizeForMemory system property for situations where lesser memory consumption wins over degraded performance
Modified: projects/vfs/trunk/src/main/java/org/jboss/virtual/VFSUtils.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/virtual/VFSUtils.java 2008-06-15 14:28:27 UTC (rev 74574)
+++ projects/vfs/trunk/src/main/java/org/jboss/virtual/VFSUtils.java 2008-06-15 14:50:44 UTC (rev 74575)
@@ -90,6 +90,11 @@
public static final String CASE_SENSITIVE_QUERY = "caseSensitive";
/**
+ * Key used to turn on memory optimizations - less cache use at the expense of performance
+ */
+ public static final String OPTIMIZE_FOR_MEMORY_KEY = "jboss.vfs.optimizeForMemory";
+
+ /**
* Get the paths string for a collection of virtual files
*
* @param paths the paths
Modified: projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java 2008-06-15 14:28:27 UTC (rev 74574)
+++ projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipEntryContext.java 2008-06-15 14:50:44 UTC (rev 74575)
@@ -66,12 +66,16 @@
*
* Nested archives are processed through this same class.
* By default nested archives are cached in memory and mounted as new
- * instances of <tt>ZipEntryContext</tt> with <tt>ZipStremWrapper</tt> as a source.
+ * instances of <tt>ZipEntryContext</tt> with <tt>ZipStreamWrapper</tt> as a source.
* If system property <em>jboss.vfs.forceCopy=true</em> is specified,
* or URL query parameter <em>forceCopy=true</em> is present,
* nested archives are extracted into a temp directory before being
* mounted as new instances of <tt>ZipEntryContext</tt>.
*
+ * In-memory nested archives may consume a lot of memory. To reduce memory footprint
+ * at the expense of performance, system property <em>jboss.vfs.optimizeForMemory=true<em>
+ * can be set.
+ *
* This context implementation has two modes of releasing file locks.
* <em>Asynchronous</em> mode is the default one since it is better performant.
* To switch this to <em>synchronous</em> mode a system property
Modified: projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipStreamWrapper.java
===================================================================
--- projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipStreamWrapper.java 2008-06-15 14:28:27 UTC (rev 74574)
+++ projects/vfs/trunk/src/main/java/org/jboss/virtual/plugins/context/zip/ZipStreamWrapper.java 2008-06-15 14:50:44 UTC (rev 74575)
@@ -21,10 +21,19 @@
*/
package org.jboss.virtual.plugins.context.zip;
+import org.jboss.virtual.VFSUtils;
+import org.jboss.logging.Logger;
+
import java.io.*;
import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
/**
* ZipStreamWrapper - for abstracted access to in-memory zip file
@@ -34,6 +43,26 @@
*/
class ZipStreamWrapper extends ZipBytesWrapper
{
+ /** Logger */
+ private static final Logger log = Logger.getLogger(ZipStreamWrapper.class);
+
+ /** Is optimizeForMemory turned on */
+ private static boolean optimizeForMemory;
+
+ static
+ {
+ optimizeForMemory = AccessController.doPrivileged(new CheckOptimizeForMemory());
+
+ if (optimizeForMemory)
+ log.info("VFS optimizeForMemory is enabled.");
+ }
+
+ /** zip archive - as individual inflated in-memory files */
+ private Map<String, InMemoryFile> inMemoryFiles = new LinkedHashMap<String, InMemoryFile>();
+
+ /** size of the zip file composed back from inMemoryFiles */
+ private int size;
+
/**
* ZipStreamWrapper is not aware of actual zip source so it can not detect
* if it's been modified, like ZipFileWrapper does.
@@ -46,65 +75,157 @@
ZipStreamWrapper(InputStream zipStream, String name, long lastModified) throws IOException
{
super(zipStream, name, lastModified);
+
+ ZipInputStream zis = new ZipInputStream(super.getRootAsStream());
+ ZipEntry ent = zis.getNextEntry();
+ while (ent != null)
+ {
+ byte [] fileBytes;
+ if (ent.isDirectory() == false)
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ copyStream(zis, baos);
+ fileBytes = baos.toByteArray();
+ ent.setSize(fileBytes.length);
+ }
+ else
+ {
+ fileBytes = new byte[0];
+ }
+
+ inMemoryFiles.put(ent.getName(), new InMemoryFile(ent, fileBytes));
+ ent = zis.getNextEntry();
+ }
+
+ if (optimizeForMemory) {
+ initZipSize();
+
+ // we don't need memory buffer any more
+ super.close();
+ }
}
InputStream openStream(ZipEntry ent) throws IOException
{
- ZipInputStream zis = new ZipInputStream(getRootAsStream());
+ InMemoryFile memFile = inMemoryFiles.get(ent.getName());
- // first find the entry
- ZipEntry entry = zis.getNextEntry();
- while(entry != null)
+ if (memFile == null)
+ throw new FileNotFoundException("Failed to find nested jar entry: " + ent.getName() + " in zip stream: " + toString());
+
+ return new ByteArrayInputStream(memFile.fileBytes);
+ }
+
+ Enumeration<? extends ZipEntry> entries() throws IOException
+ {
+ return new ZipStreamEnumeration();
+ }
+
+ InputStream getRootAsStream() throws FileNotFoundException
+ {
+ if (optimizeForMemory)
{
- if(entry.getName().equals(ent.getName()))
- break;
- entry = zis.getNextEntry();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try
+ {
+ recomposeZip(baos);
+ return new ByteArrayInputStream(baos.toByteArray());
+ }
+ catch (IOException ex)
+ {
+ FileNotFoundException e = new FileNotFoundException("Failed to recompose inflated nested archive " + getName());
+ e.initCause(ex);
+ throw e;
+ }
}
- if(entry == null)
- throw new IOException("Failed to find nested jar entry: " + ent.getName() + " in zip stream: " + toString());
+ else
+ {
+ return super.getRootAsStream();
+ }
+ }
- // then read it
- return new SizeLimitedInputStream(zis, ent.getSize());
+ long getSize()
+ {
+ if (optimizeForMemory)
+ return size;
+ else
+ return super.getSize();
}
- Enumeration<? extends ZipEntry> entries() throws IOException
+ void close() {
+ inMemoryFiles = null;
+ super.close();
+ }
+
+ private void initZipSize() throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ recomposeZip(baos);
+ this.size = baos.size();
+ }
+
+ private void recomposeZip(ByteArrayOutputStream baos) throws IOException
{
- return new ZipStreamEnumeration(new ZipInputStream(getRootAsStream()));
+ ZipOutputStream zout = new ZipOutputStream(baos);
+ zout.setMethod(ZipOutputStream.STORED);
+
+ Iterator<InMemoryFile> it = inMemoryFiles.values().iterator();
+ while(it.hasNext())
+ {
+ InMemoryFile memFile = it.next();
+ zout.putNextEntry(memFile.entry);
+ zout.write(memFile.fileBytes);
+ }
+ zout.close();
}
- /**
- * Zip stream enumeration.
- */
- class ZipStreamEnumeration implements Enumeration<ZipEntry>
+ private static void copyStream(InputStream is, OutputStream os) throws IOException
{
- private ZipInputStream zis;
+ byte [] buff = new byte[4096];
+ int rc = is.read(buff);
+ while (rc != -1)
+ {
+ os.write(buff, 0, rc);
+ rc = is.read(buff);
+ }
+ }
- private ZipEntry entry;
+ static class InMemoryFile
+ {
+ ZipEntry entry;
+ byte [] fileBytes;
- ZipStreamEnumeration(ZipInputStream zis) throws IOException
+ public InMemoryFile(ZipEntry entry, byte[] fileBytes)
{
- this.zis = zis;
- entry = zis.getNextEntry();
+ this.entry = entry;
+ this.fileBytes = fileBytes;
}
+ }
+ class ZipStreamEnumeration implements Enumeration<ZipEntry>
+ {
+ private Iterator<InMemoryFile> it;
+
+ ZipStreamEnumeration()
+ {
+ it = inMemoryFiles.values().iterator();
+ }
+
public boolean hasMoreElements()
{
- return entry != null;
+ return it.hasNext();
}
public ZipEntry nextElement()
{
- ZipEntry ret = entry;
- try
- {
- entry = zis.getNextEntry();
- }
- catch (IOException ex)
- {
- throw new RuntimeException("Failed to retrieve next entry from zip stream", ex);
- }
+ return it.next().entry;
+ }
+ }
- return ret;
+ private static class CheckOptimizeForMemory implements PrivilegedAction<Boolean>
+ {
+ public Boolean run()
+ {
+ String forceString = System.getProperty(VFSUtils.OPTIMIZE_FOR_MEMORY_KEY, "false");
+ return Boolean.valueOf(forceString);
}
}
}
More information about the jboss-cvs-commits
mailing list