Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / jigsaw / src / org / w3c / www / protocol / http / cache / CacheGeneration.java
diff --git a/JMCR-Stable/real-world application/jigsaw/src/org/w3c/www/protocol/http/cache/CacheGeneration.java b/JMCR-Stable/real-world application/jigsaw/src/org/w3c/www/protocol/http/cache/CacheGeneration.java
new file mode 100644 (file)
index 0000000..cb078db
--- /dev/null
@@ -0,0 +1,663 @@
+// CacheGeneration.java\r
+// $Id: CacheGeneration.java,v 1.1 2010/06/15 12:25:09 smhuang Exp $\r
+// (c) COPYRIGHT MIT, INRIA and Keio, 1999.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.www.protocol.http.cache;\r
+\r
+import java.util.Enumeration;\r
+import java.util.Hashtable;\r
+import java.util.Vector;\r
+\r
+import java.io.File;\r
+import java.io.PrintStream;\r
+\r
+import org.w3c.util.LRUAble;\r
+import org.w3c.util.LRUList;\r
+import org.w3c.util.LookupTable;\r
+import org.w3c.util.SyncLRUList;\r
+\r
+public class CacheGeneration implements LRUAble {\r
+    // the usual debug flag\r
+    private static final boolean debug = true;\r
+\r
+    // hashtable of resources\r
+    private Hashtable lookupTable = null;\r
+    // the LRUList of resources\r
+    private SyncLRUList lruList = null;\r
+    // the occupation of this generation\r
+    private long bytecount = 0;\r
+    // the capacity of this generation\r
+    private long bytelimit = 0;\r
+    // stored size\r
+    private long bytestored = 0;\r
+    // serialization flag\r
+    private boolean saved = false;\r
+    // serialization flag\r
+    private boolean loaded = false;\r
+    // resource count\r
+    private int cr_count = 0;\r
+    // the ID of this generation\r
+    private int id = 0;\r
+\r
+    // a Vector or resource to be removed\r
+    private Vector toDel = null;\r
+\r
+    // our father\r
+    private CacheStore store = null;\r
+\r
+    protected File generationFile = null;\r
+\r
+    /**\r
+     * set the file where the generation is stored\r
+     * @param generationFile the file\r
+     */\r
+    public void setGenerationFile(File generationFile) {\r
+       this.generationFile = generationFile;\r
+    }\r
+\r
+    /**\r
+     * get the generation file\r
+     * @return a File\r
+     */\r
+    public File getGenerationFile() {\r
+       return generationFile;\r
+    }\r
+\r
+    /**\r
+     * Is the generation loaded?\r
+     * @return a boolean\r
+     */\r
+    public boolean isLoaded() {\r
+       return loaded;\r
+    }\r
+\r
+    /**\r
+     * Set the generation as loaded or unloaded\r
+     * @param loaded the new loaded flag\r
+     */\r
+    protected void setLoaded(boolean loaded) {\r
+       this.loaded = loaded;\r
+    }\r
+\r
+    /**\r
+     * Is the generation saved?\r
+     * @return a boolean\r
+     */\r
+    public boolean isSaved() {\r
+       return saved;\r
+    }\r
+\r
+    /**\r
+     * Set the generation as saved or not.\r
+     * @param saved a boolean\r
+     */\r
+    protected void setSaved(boolean saved) {\r
+       this.saved = saved;\r
+    }\r
+\r
+    /**\r
+     * LRU management - previous entry.\r
+     */\r
+    protected LRUAble prev = null;\r
+    /**\r
+     * LRU management - next entry.\r
+     */\r
+    protected LRUAble next = null;\r
+\r
+    /**\r
+     * LRU management - Get next node.\r
+     * @return A CacheGeneration instance.\r
+     */\r
+    public LRUAble getNext() {\r
+       return next;\r
+    }\r
+\r
+    /**\r
+     * LRU management - Get previous node.\r
+     * @return A CacheGeneration instance.\r
+     */\r
+    public LRUAble getPrev() {\r
+       return prev;\r
+    }\r
+\r
+    /**\r
+     * LRU management - Set next node.\r
+     */\r
+    public synchronized void setNext(LRUAble next) {\r
+       this.next = next;\r
+    }\r
+\r
+    /**\r
+     * LRU management - Set previous node.\r
+     */\r
+    public synchronized void setPrev(LRUAble prev) {\r
+       this.prev = prev;\r
+    }\r
+\r
+    /**\r
+     * Get the ID of this generation\r
+     * @return an int, the generation number\r
+     */\r
+    public int getId() {\r
+       return id;\r
+    }\r
+\r
+    /**\r
+     * Set the ID of this generation\r
+     * Useful to reuse generation\r
+     * @param an integer, the new generation number\r
+     */\r
+    public synchronized void setId(int id) {\r
+       this.id = id;\r
+    }\r
+\r
+    /**\r
+     * Give the acual occupation level of this generation\r
+     * @return a long, the number of bytes of this generation\r
+     */\r
+    public long getCachedByteCount() {\r
+       return bytecount;\r
+    }\r
+\r
+    /**\r
+     * Give the fill ratio for the cached resources\r
+     * @return a float between 0 and 1\r
+     */\r
+    public float getFillRatio() {\r
+       return ((float) bytecount / (float) bytelimit);\r
+    }\r
+\r
+    /**\r
+     * Give the acual storeage occupation level of this generation\r
+     * @return a long, the number of bytes of this generation\r
+     */\r
+    public long getStoredByteCount() {\r
+       return bytestored;\r
+    }\r
+\r
+    /**\r
+     * Get the bytecount limit for this generation\r
+     * @return a long, the maximum number of bytes\r
+     */\r
+    public long getByteLimit() {\r
+       return bytelimit;\r
+    }\r
+\r
+    /**\r
+     * Set the new bytecount limit, not that it may perform a cleanup\r
+     * if necessary.\r
+     * @param long, the new maximum number of bytes\r
+     */\r
+    public synchronized void setByteLimit(long newlimit) {\r
+       bytelimit = newlimit;\r
+       if (newlimit >= bytecount) {\r
+           return;\r
+       }\r
+       // try to get some space \r
+       long to_save = newlimit - bytecount;\r
+       // be nice\r
+       to_save -= collectSpace(newlimit - bytecount, true);\r
+       // then get the space we want ;)\r
+       to_save -= collectSpace(to_save, false);\r
+    }\r
+\r
+    /**\r
+     * Deletes a resource from the "to be deleted" vector\r
+     * it updates also the number of bye stored in this generation\r
+     * @return the number of bytes saved.\r
+     */\r
+    public long deleteStored(CachedResource cr) {\r
+       if (! loaded)\r
+           throw new UnloadedGenerationException("generation "+id);\r
+       if (debug) {\r
+           System.out.println("Deleting "+cr.getIdentifier()+\r
+                              "from generation: "+id);\r
+       }\r
+       toDel.removeElement(cr);\r
+       long saved = cr.delete();\r
+       synchronized(this) {\r
+           bytestored -= saved;\r
+       }\r
+       store.getState().notifyResourceDeleted(cr);\r
+       return saved;\r
+    }\r
+\r
+    /**\r
+     * Check if a resource has been cached in this generation\r
+     * @param url the resource url\r
+     * @return a boolean\r
+     */\r
+    public synchronized boolean containsResource(String url) {\r
+       return (lookupTable.get(url) != null);\r
+    }\r
+\r
+    /**\r
+     * Get all the files handled by this generation\r
+     * @return an enumeration of File\r
+     */\r
+    public synchronized Enumeration getFiles() {\r
+       Vector files = new Vector();\r
+       if (loaded) {\r
+           Enumeration fenum = lookupTable.elements();\r
+           while (fenum.hasMoreElements()) {\r
+               CachedResource cr = (CachedResource) fenum.nextElement();\r
+               File file = cr.getFile();\r
+               if (file != null) {\r
+                   files.addElement(file);\r
+               }\r
+           }\r
+       } else {\r
+           Enumeration fenum = lookupTable.elements();\r
+           while (fenum.hasMoreElements()) {\r
+               String file = (String) fenum.nextElement();\r
+               if (! file.equals("")) {\r
+                   files.addElement(new File(file));\r
+               }\r
+           }\r
+       }\r
+       return files.elements();\r
+    }\r
+\r
+    /**\r
+     * Get the CachedResource relative to the given URL.\r
+     * @param url the URL of the CachedResource to find\r
+     * @return a CachedResource or null.\r
+     */\r
+    public synchronized CachedResource lookupResource(String url) {\r
+       if (! loaded)\r
+           throw new UnloadedGenerationException("generation "+id);\r
+       return (CachedResource)lookupTable.get(url);\r
+    }\r
+\r
+    /**\r
+     * can this resource be stored?\r
+     * If the resource is in the generation, only the delta will be taken\r
+     * into account\r
+     * @param CachedResource cr, the candidate.\r
+     * @param long size, the size of the candidate.\r
+     * @return a boolean, if this generation can cache it or not\r
+     */\r
+    private boolean canStore(CachedResource cr, long size) {\r
+       if (! loaded)\r
+           throw new UnloadedGenerationException("generation "+id);\r
+       CachedResource old_cr = null;\r
+       old_cr = (CachedResource) lookupTable.get(cr.getIdentifier());\r
+       if (old_cr != null) {\r
+           long delta = size - old_cr.getCurrentLength();\r
+           if ( (bytecount + delta) > bytelimit) {\r
+               return false;\r
+           }\r
+       }\r
+       if ((size + bytecount) > bytelimit) {\r
+           return false;\r
+       }\r
+       return true;\r
+    }\r
+\r
+    /**\r
+     * Adds this resource, if possible\r
+     * @param cr, the candidate.\r
+     * @param size, the size of the candidate.\r
+     * @return a boolean, true if this resource has been cached\r
+     */\r
+    public synchronized boolean addResource(CachedResource cr, \r
+                                           long size,\r
+                                           long oldsize)\r
+    {\r
+       if (! loaded)\r
+           throw new UnloadedGenerationException("generation "+id);\r
+       if (canStore(cr, size)) {\r
+           CachedResource old_cr = null;\r
+           old_cr = (CachedResource) lookupTable.get(cr.getIdentifier());\r
+           // do we already have this resource?\r
+           if (old_cr != null) {\r
+               // this is the real oldsize\r
+               oldsize = old_cr.getCurrentLength();\r
+               long delta   = size - oldsize;\r
+               if  ((bytecount + delta) > bytelimit) {\r
+                   return false;\r
+               } \r
+               lookupTable.remove(cr.getIdentifier());\r
+               lruList.remove(cr);\r
+               bytecount -= oldsize;\r
+               toDel.addElement(old_cr);\r
+               store.getState().notifyResourceReplaced(cr, oldsize);\r
+           } else {\r
+               store.getState().notifyResourceAdded(cr, oldsize);\r
+           }\r
+           lookupTable.put(cr.getIdentifier(), cr);\r
+           cr.generation = this;\r
+           lruList.toHead(cr);\r
+           bytestored += size;\r
+           bytecount  += size;\r
+           saved       = false;\r
+           cr_count++;\r
+           return true;\r
+       }\r
+       return false;\r
+    }\r
+\r
+    /**\r
+     * Load a CachedResource in this generation. (to be used only at\r
+     * generation loading). This method load only valid cachedresource.\r
+     * Check if the associated file exists and has the right size.\r
+     * @param CachedResource the CachedResource to load.\r
+     */\r
+    protected void loadCachedResource(CachedResource cr) {\r
+       File file = cr.getFile();\r
+       if ((file != null) && \r
+           ((! file.exists()) || (file.length() != cr.getCurrentLength()))) {\r
+           //don't load invalid cachedresource\r
+           return;\r
+       }\r
+       lookupTable.put(cr.getIdentifier(), cr);\r
+       cr.generation = this;\r
+       lruList.toHead(cr);\r
+       long size   = cr.getCurrentLength();\r
+       bytestored += size;\r
+       bytecount  += size;\r
+       cr_count++;\r
+    }\r
+\r
+    /**\r
+     * Remove the resource from the generation (but don't delete it).\r
+     * @param cr the CachedResource to remove.\r
+     * @return the number of byte saved\r
+     * @exception NoSuchResourceException if this resource was not in this \r
+     * generation     \r
+     */\r
+    public synchronized long removeResource(CachedResource cr) \r
+       throws NoSuchResourceException\r
+    {\r
+       if (! loaded)\r
+           throw new UnloadedGenerationException("generation "+id);\r
+       return removeResource(cr.getIdentifier());\r
+    }\r
+\r
+    /**\r
+     * Remove the resource from the generation (but don't delete it).\r
+     * @param cr the CachedResource to remove.\r
+     * @return the number of byte saved\r
+     * @exception NoSuchResourceException if this resource was not in this \r
+     * generation     \r
+     */\r
+    public synchronized long removeResource(String url) \r
+       throws NoSuchResourceException\r
+    {\r
+       if (! loaded)\r
+           throw new UnloadedGenerationException("generation "+id);\r
+       CachedResource old_cr = _removeResource(url);\r
+       return old_cr.getCurrentLength();\r
+    }\r
+\r
+    /**\r
+     * Remove the resource from the generation and update the bytecount \r
+     * variable.\r
+     * @param url the CachedResource URL\r
+     * @return the CachedResource removed.\r
+     * @exception NoSuchResourceException if this resource was not in this \r
+     * generation\r
+     */\r
+    private CachedResource _removeResource(String url) \r
+       throws NoSuchResourceException\r
+    {\r
+       if (debug) {\r
+           System.err.println("*** removing from generation "+id+": " + url);\r
+       }\r
+       CachedResource old_cr = (CachedResource) lookupTable.get(url);\r
+       if (old_cr == null) {\r
+           String msg = url + " not found in generation " + id;\r
+           throw new NoSuchResourceException(msg);\r
+       }\r
+       lookupTable.remove(url);\r
+       lruList.remove(old_cr);\r
+       long b_saved = old_cr.getCurrentLength();\r
+       if (debug) {\r
+           System.err.println("*** removed... saved " + b_saved + " bytes");\r
+       }\r
+       bytecount  -= b_saved;\r
+       bytestored -= b_saved;\r
+       saved = false;\r
+       cr_count--;\r
+       return old_cr;\r
+    }\r
+\r
+    /**\r
+     * will garbage collect up to "size" bytes in this generation.\r
+     * WARNING: this is not synchronized, use with caution!\r
+     * @param long the number of bytes to be collected\r
+     * @param check, a boolean, used to validate or not the resource before\r
+     * deleting them (ie: delete only invalid resources)\r
+     * @return a long, the number of bytes saved\r
+     * from disk afterward using delete.\r
+     */\r
+\r
+    public long collectSpace(long size, boolean check) {\r
+       if (! loaded) {\r
+           // load me, and unload another generation is necessary.\r
+           try {\r
+               store.loadGeneration(this);\r
+           } catch (InvalidCacheException ex) {\r
+               // oups! cache corrupted?\r
+               if (debug) {\r
+                   System.err.println("*** Collecting "+\r
+                                      "Unable to load generation ["+\r
+                                      getId()+"]");\r
+                   System.err.println(ex.getMessage());\r
+               }\r
+               return 0;\r
+           }\r
+       }\r
+       Vector res_vect = new Vector();\r
+       long collected = 0;\r
+       CachedResource cr, ncr;\r
+       CacheValidator validator;\r
+       \r
+       if (debug) {\r
+           System.err.println("*** Collecting " + size + " bytes " + \r
+                              ((check) ? "with" : "without") + " checking");\r
+       }\r
+       // dumb check\r
+       if (size <= 0)\r
+           return 0;\r
+       if ((size > bytecount) && !check) {\r
+           return emptyGeneration();\r
+       }\r
+       validator = store.getValidator();\r
+       // start with the oldest ones\r
+       cr = (CachedResource) lruList.getTail();\r
+       while (cr != null) {\r
+           // check if we can delete the resource or not\r
+           if (check) {\r
+               if (validator.checkStaleness(cr)) {\r
+                   cr = (CachedResource) lruList.getPrev(cr);\r
+                   continue;\r
+               }\r
+           }\r
+           ncr = (CachedResource) lruList.getPrev(cr);\r
+           synchronized(this) {\r
+               lookupTable.remove(cr.getIdentifier());\r
+               lruList.remove(cr);\r
+               saved = false;\r
+               cr_count--;\r
+               store.getState().notifyResourceToBeDeleted(cr);\r
+           }\r
+           collected += cr.getCurrentLength();\r
+           toDel.addElement(cr);\r
+           if (collected >= size) {\r
+               break;\r
+           }\r
+           cr = ncr;\r
+       }\r
+       synchronized (this) {\r
+           bytecount -= collected;\r
+       }\r
+       if (debug) {\r
+           System.err.println("*** Collected " + collected + \r
+                              " bytes from generation "+id);\r
+       }\r
+       return collected;\r
+    }\r
+\r
+    /**\r
+     * empty this generation\r
+     * @return a long, the number of bytes saved\r
+     */\r
+    protected long emptyGeneration() {\r
+       if (! loaded)\r
+           throw new UnloadedGenerationException("generation "+id);\r
+       Hashtable saved_table;\r
+       long collected;\r
+       if (debug) {\r
+           System.err.println("*** Deleting Generation " + id + " ("\r
+                              + bytecount + ")");\r
+       }\r
+       synchronized (this) {\r
+           collected = bytecount;\r
+           saved_table = lookupTable;\r
+           lookupTable = new Hashtable();\r
+           lruList = new SyncLRUList();\r
+           bytecount = 0;\r
+           cr_count = 0;\r
+       }\r
+       Enumeration e = saved_table.elements();\r
+       while (e.hasMoreElements()) {\r
+           CachedResource cr = (CachedResource) e.nextElement();\r
+           toDel.addElement(cr);\r
+           store.getState().notifyResourceToBeDeleted(cr);\r
+       }\r
+       generationFile.delete();\r
+       saved = false;\r
+       return collected;\r
+    }\r
+\r
+    /**\r
+     * Get the CachedResource of this generation (except the "to be\r
+     * deleted" resources)\r
+     * @return an Enumeration of CachedResource\r
+     */\r
+    public Enumeration getCachedResources() {\r
+       if (! loaded)\r
+           throw new UnloadedGenerationException("generation "+id);\r
+       return lookupTable.elements();\r
+    }\r
+\r
+    /**\r
+     * get the deleted but still stored resource\r
+     * @returns an enumeration of CachedResources\r
+     */\r
+    public Enumeration getDeletedResources() {\r
+       return toDel.elements();\r
+    }\r
+\r
+    /**\r
+     * Set this Generation as a description (update the saved and loaded \r
+     * status)\r
+     * @param tables the LookupTables containing attribute descriptions\r
+     */\r
+    protected void setDescription(LookupTable tables[]) {\r
+       clean();\r
+       saved      = true;\r
+       bytestored = 0;\r
+       bytecount  = 0;\r
+       cr_count   = 0;\r
+       for (int i = 0 ; i < tables.length ; i++) {\r
+           LookupTable table = tables[i];\r
+           try {\r
+               String stored = \r
+                   (String)table.get(CachedResource.NAME_CURRENT_LENGTH);\r
+               String id = \r
+                   (String)table.get(CachedResource.NAME_IDENTIFIER);\r
+               String file =\r
+                   (String)table.get(CachedResource.NAME_FILE);\r
+               file = (file == null) ? "" : file;\r
+               bytestored += Integer.parseInt(stored);\r
+               lookupTable.put(id, file);\r
+           } catch (Exception ex) {\r
+               if (debug) {\r
+                   System.err.println("Unable to load description in ["+\r
+                                      getId()+"] "+ex.getMessage());\r
+               }\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Unload the generation, transform CachedResources to descriptions.\r
+     */\r
+    public void unload() {\r
+       // bytestored unchanged\r
+       clean();\r
+       saved             = true;\r
+       bytecount         = 0;\r
+       cr_count          = 0;\r
+       Enumeration kenum = lookupTable.keys();\r
+       while(kenum.hasMoreElements()) {\r
+           lookupTable.put(kenum.nextElement(), Boolean.TRUE);\r
+       }\r
+    }\r
+\r
+    /**\r
+     * delete the serialized resource file from the disk\r
+     */\r
+    protected void deleteGenerationFile() {\r
+       generationFile.delete();\r
+    }\r
+\r
+    /**\r
+     * Get the current number of resource loaded.\r
+     * @return an long\r
+     */\r
+    public int getCRCount() {\r
+       return cr_count;\r
+    }\r
+\r
+    /**\r
+     * Clean this generation.\r
+     */\r
+    public void clean() {\r
+       this.lookupTable = new Hashtable();\r
+       this.lruList     = new SyncLRUList();\r
+       this.loaded      = false;\r
+    }\r
+\r
+    /**\r
+     * copy the content of the generation here\r
+     * @parameter a CacheGeneration, the one we want to dump here\r
+     */\r
+    protected synchronized void copyInto(CacheGeneration gen) {\r
+       // add everything at the "right" place\r
+       LRUList ngenLruList = gen.lruList;\r
+       CachedResource cr = (CachedResource) ngenLruList.getHead();\r
+       while (cr != null) {\r
+           CachedResource next_cr = (CachedResource) ngenLruList.getNext(cr);\r
+           cr.generation = this;\r
+           lruList.toTail(cr);\r
+           lookupTable.put(cr.getIdentifier(), cr);\r
+           cr = next_cr;\r
+       }\r
+       gen.setSaved(false);\r
+       // now dump the toDel vector\r
+       Enumeration e = gen.toDel.elements();\r
+       while (e.hasMoreElements()) {\r
+           toDel.add(e.nextElement());\r
+       }\r
+       // update the values\r
+       cr_count += gen.cr_count;\r
+       bytecount += gen.bytecount;\r
+       bytestored += gen.bytestored;\r
+       // finally state that we have been modified\r
+       saved = false;\r
+    }\r
+\r
+    public CacheGeneration(CacheStore store, long maxsize) {\r
+       this.store       = store;\r
+       this.toDel       = new Vector();\r
+       this.lookupTable = new Hashtable();\r
+       this.bytelimit   = maxsize;\r
+       this.lruList     = new SyncLRUList();\r
+    }\r
+}\r
+\r
+\r