[jboss-cvs] JBossAS SVN: r73688 - projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Mon May 26 13:33:40 EDT 2008


Author: mstruk
Date: 2008-05-26 13:33:40 -0400 (Mon, 26 May 2008)
New Revision: 73688

Added:
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileLockReaper.java
Modified:
   projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileWrapper.java
Log:
Async archive file release optimization - 5 seconds inactivity period triggers release

Added: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileLockReaper.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileLockReaper.java	                        (rev 0)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileLockReaper.java	2008-05-26 17:33:40 UTC (rev 73688)
@@ -0,0 +1,149 @@
+package org.jboss.virtual.plugins.context.zip;
+
+import org.jboss.logging.Logger;
+
+import java.util.Iterator;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * Monitoring object that closes ZipFiles when they haven't been used for a while
+ *
+ * @author <a href="strukelj at parsek.net">Marko Strukelj</a>
+ * @version $Revision: 1.0 $
+ */
+
+public class ZipFileLockReaper
+{
+   /** Logger */
+   private static final Logger log = Logger.getLogger(ZipFileLockReaper.class);
+
+   /**
+    * Time after which unused ZipFiles can be closed. This shouldn't be a large number
+    * to ensure smooth releasing of file locks
+    */
+   private static final int PERIOD = 5000;
+
+   /** Timer thread period */
+   private static final int TIMER_PERIOD = 1000;
+
+   /** If timer finds out there are no open ZipFiles for a while it shuts down until some are (re)opened */
+   private static final int TIMER_UNUSED_PERIOD = 30000;
+
+   /** There is only one instance that serves all ZipFileWrappers */
+   private static ZipFileLockReaper singleton;
+
+   /** A list of monitored ZipFileWrappers */
+   private ConcurrentLinkedQueue monitored = new ConcurrentLinkedQueue();
+
+   /** The number of monitored ZipFileWrappers */
+   private int monitoredCount = 0;
+
+   /** Timer used for actual reaping - async closure of ZipFiles */
+   private Timer timer;
+
+   /** Timestamp of last unregister() call */
+   private long lastUsed;
+
+
+   /**
+    * Private constructor - to force retrieval through {@link #getInstance()}
+    */
+   private ZipFileLockReaper()
+   {
+
+   }
+
+   /** Factory method to be used to retrieve reference to ZipFileLockReaper */
+   public synchronized static ZipFileLockReaper getInstance()
+   {
+      if (singleton == null)
+         singleton = new ZipFileLockReaper();
+
+      return singleton;
+   }
+
+
+   /** Register a ZipFileWrapper instance with this reaper */
+   public synchronized void register(ZipFileWrapper w)
+   {
+      monitored.add(w);
+      monitoredCount++;
+      if (timer == null)
+      {
+         timer = new Timer("ZipFile Lock Reaper", true);
+         timer.schedule(new ReaperTimerTask(), TIMER_PERIOD, TIMER_PERIOD);
+      }
+      log.debug("Registered: " + w);
+   }
+
+   /** Unregister a ZipFileWrapper instance from this reaper */
+   public synchronized void unregister(ZipFileWrapper w)
+   {
+      monitored.remove(w);
+      monitoredCount--;
+      lastUsed = System.currentTimeMillis();
+      log.debug("Unregistered: " + w);
+   }
+
+
+
+   /** Timer task that does the actual reaping */
+   class ReaperTimerTask extends TimerTask
+   {
+      public void run()
+      {
+         log.debug("Timer called");
+
+         long now = System.currentTimeMillis();
+         synchronized (ZipFileLockReaper.this)
+         {
+            if (monitoredCount == 0)
+            {
+               if (now - lastUsed > TIMER_UNUSED_PERIOD)
+               {
+                  timer.cancel();
+                  timer = null;
+                  log.debug("Cancelled the timer");
+               }
+               return;
+            }
+         }
+
+         Iterator it = monitored.iterator();
+         while (it.hasNext())
+         {
+            ZipFileWrapper w = (ZipFileWrapper) it.next();
+
+            // stream leak debug
+            /*
+            Iterator<ZipEntryInputStream> sit = w.streams.iterator();
+            while (sit.hasNext())
+            {
+               ZipEntryInputStream eis = sit.next();
+               if (!eis.isClosed())
+               {
+                  System.out.println("Stream not closed: " + eis.debugCount + " - " + eis);
+               }
+            }
+            */
+
+            if (w.getReferenceCount() <= 0 && now - w.getLastUsed() > PERIOD)
+            {
+               try
+               {
+                  w.closeZipFile();
+                  log.debug("Asynchronously closed an unused ZipFile: " + w);
+               }
+               catch(Exception ex)
+               {
+                  // ignore the exception
+                  log.debug("Failed to close ZipFile: ", ex);
+               }
+            }
+         }
+      }
+   }
+
+}

Modified: projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileWrapper.java
===================================================================
--- projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileWrapper.java	2008-05-26 17:17:42 UTC (rev 73687)
+++ projects/vfs/branches/jar-alter-work/src/main/java/org/jboss/virtual/plugins/context/zip/ZipFileWrapper.java	2008-05-26 17:33:40 UTC (rev 73688)
@@ -30,6 +30,10 @@
 
    private int refCount = 0;
 
+   // used for debugging stream leaks
+   //ConcurrentLinkedQueue<ZipEntryInputStream> streams = new ConcurrentLinkedQueue<ZipEntryInputStream>();
+
+
    public ZipFileWrapper(File archive)
    {
       file = archive;
@@ -58,21 +62,35 @@
       return file.isFile();
    }
 
+   long getLastUsed()
+   {
+      return lastUsed;
+   }
+
+   int getReferenceCount()
+   {
+      return refCount;
+   }
+
    private ZipFile ensureZipFile() throws IOException
    {
       if (zipFile == null)
+      {
          zipFile = new ZipFile(file);
+         ZipFileLockReaper.getInstance().register(this);
+      }
 
       return zipFile;
    }
 
-   private void closeZipFile() throws IOException
+   synchronized void closeZipFile() throws IOException
    {
-      if (zipFile != null)
+      if (zipFile != null && refCount <= 0)
       {
          ZipFile zf = zipFile;
          zipFile = null;
          zf.close();
+         ZipFileLockReaper.getInstance().unregister(this);
       }
    }
 
@@ -81,6 +99,10 @@
       ensureZipFile();
       InputStream is = zipFile.getInputStream(ent);
       ZipEntryInputStream zis = new ZipEntryInputStream(this, is);
+
+      // debugging code
+      //streams.add(zis);
+
       refCount++;
       lastUsed = System.currentTimeMillis();
       return zis;
@@ -95,7 +117,8 @@
          try
          {
             lastUsed = System.currentTimeMillis();
-            closeZipFile();
+            // let the reaper do its job
+            //closeZipFile();
          }
          catch(Exception ex)
          {
@@ -122,4 +145,9 @@
          log.warn("Failed to release file: " + file);
       }
    }
+
+   public String toString()
+   {
+      return super.toString() + " - " + file.getAbsolutePath();
+   }
 }




More information about the jboss-cvs-commits mailing list