asmuts      02/01/30 21:10:52

  Added:       src/java/org/apache/stratum/jcs/engine/memory/mru
                        MRUMemoryCache.java
  Log:
  A MRUCache suinga  technique presented on
  http://developer.java.sun.com/developer/onlineTraining/Programming/JDCBook/perf4.html
  
  It is terrible.  The LinkedList remove method is horribly inefficient.
  
  This should not be used.  It is for example purposes and comparison.
  
  Revision  Changes    Path
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/engine/memory/mru/MRUMemoryCache.java
  
  Index: MRUMemoryCache.java
  ===================================================================
  package org.apache.stratum.jcs.engine.memory.mru;
  
  import java.io.IOException;
  import java.io.Serializable;
  
  import java.util.HashMap;
  import java.util.Hashtable;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.ListIterator;
  import java.util.Map;
  import java.util.Set;
  
  import java.util.Map.Entry;
  
  import org.apache.stratum.jcs.engine.Attributes;
  import org.apache.stratum.jcs.engine.CacheElement;
  
  import org.apache.stratum.jcs.engine.behavior.ICache;
  import org.apache.stratum.jcs.engine.behavior.ICacheElement;
  import org.apache.stratum.jcs.engine.behavior.ICacheHub;
  import org.apache.stratum.jcs.engine.behavior.ICacheType;
  import org.apache.stratum.jcs.engine.behavior.ICompositeCacheAttributes;
  
  import org.apache.stratum.jcs.engine.memory.MemoryElementDescriptor;
  import org.apache.stratum.jcs.engine.memory.behavior.IMemoryCache;
  
  import org.apache.stratum.jcs.utils.log.Logger;
  import org.apache.stratum.jcs.utils.log.LoggerManager;
  
  /////////////////////////////////////////////////////
  /**
   *  A SLOW AS HELL reference management system. The most recently used items move to 
the
   *  front of the list and get spooled to disk if the cache hub is configured to
   *  use a disk cache.
   *
   *@author     asmuts
   *@created    January 15, 2002
   */
  public class MRUMemoryCache implements IMemoryCache, ICache, Serializable
  {
  
      private final static boolean debugcmd = false;
      // removal
      private final static boolean debugR = false;
      //true;
  
      // MOVE TO MEMORYMANAGER
      String cacheName;
  
      /**
       *  Storage of cache items.
       */
      protected HashMap map = new HashMap();
  
      protected int[] lockMe = new int[0];
  
      /**
       *  MRU list.
       */
      protected LinkedList mrulist = new LinkedList();
  
      // Region Elemental Attributes
      /**
       *  Description of the Field
       */
      public Attributes attr;
  
      // Cache Attributes
      /**
       *  Description of the Field
       */
      public ICompositeCacheAttributes cattr;
  
      private String source_id = 
"org.apache.stratum.jcs.engine.memory.mru.MRUMemoryCache";
  
      // need to convert to log4j
      /**
       *  Description of the Field
       */
      protected final static Logger log = LoggerManager.getLogger( 
MRUMemoryCache.class );
  
      // The HUB
      ICacheHub hub;
  
      // status
      private int status = this.STATUS_ERROR;
  
      // make configurable
      private int chunkSize = 5;
  
  
      ////////////////////////////////////////////////////////////////////
      // for reflection
      /**
       *  Constructor for the LRUMemoryCache object
       */
      public MRUMemoryCache()
      {
          // might want to consider this an error state
          status = this.STATUS_ERROR;
      }
  
  
      /**
       *  Constructor for the LRUMemoryCache object
       *
       *@param  cacheName  Description of the Parameter
       *@param  cattr      Description of the Parameter
       *@param  hub        Description of the Parameter
       */
      public MRUMemoryCache( String cacheName, ICompositeCacheAttributes cattr, 
ICacheHub hub )
      {
          initialize( cacheName, cattr, hub );
      }
  
  
      // for post reflection creation initialization
      /**
       *  Description of the Method
       *
       *@param  cacheName  Description of the Parameter
       *@param  cattr      Description of the Parameter
       *@param  hub        Description of the Parameter
       */
      public void initialize( String cacheName, ICompositeCacheAttributes cattr, 
ICacheHub hub )
      {
          this.cacheName = cacheName;
          this.cattr = cattr;
          this.hub = hub;
          status = this.STATUS_ALIVE;
      }
  
  
      ///////////////////////////////////////////////////
      /**
       *  Gets the sourceId attribute of the LRUMemoryCache object
       *
       *@return    The sourceId value
       */
      public Serializable getSourceId()
      {
          return this.source_id;
      }
  
  
      /**
       *  Gets the cacheType attribute of the LRUMemoryCache object
       *
       *@return    The cacheType value
       */
      public int getCacheType()
      {
          return ICacheType.MEMORY_CACHE;
      }
  
  
      /**
       *  Puts an item to the cache.
       *
       *@param  ce               Description of the Parameter
       *@exception  IOException  Description of the Exception
       */
      public void update( ICacheElement ce )
          throws IOException
      {
  
          Serializable key = ce.getKey();
  
          // need a more fine grained locking here
          boolean replace = false;
          if(map.containsKey(key)) {
              replace = true;
          }
          synchronized ( lockMe )
          {
              map.put( key, ce );
              if ( replace ) {
                // the slowest method I've ever seen
                mrulist.remove( (String)key );
              }
              mrulist.addFirst( (String)key );
          }
  
          // save a microsecond on the second call.
          int size = map.size();
          // need to spool at a certain percentage synchronously
          if ( size < this.cattr.getMaxObjects() )
          {
              return;
          }
          else
          {
  
              // SPOOL LAST -- need to make this a grouping in a queue
              if ( debugcmd )
              {
                  p( "IN RAM overflow" );
              }
  
              // write the last item to disk.
              try
              {
  
                  // PUSH 5 TO DISK TO MINIMIZE THE TYPICAL
                  int chunkSizeCorrected = Math.min( size, chunkSize );
  
                  if ( debugcmd )
                  {
                      p( "update: About to spool to disk cache, map.size() = " + size 
+ ", this.cattr.getMaxObjects() = " + this.cattr.getMaxObjects() + ", 
chunkSizeCorrected = " + chunkSizeCorrected );
                  }
  
                  // The spool will put them in a disk event queue, so there is no
                  // need to pre-queue the queuing.  This would be a bit wasteful
                  // and wouldn't save much time in this synchronous call.
                  for ( int i = 0; i < chunkSizeCorrected; i++ )
                  {
                      // Might want to rename this "overflow" incase the hub
                      // wants to do something else.
                      Serializable last = (Serializable)mrulist.getLast();
                      ICacheElement ceL = (ICacheElement)map.get(last);
                      hub.spoolToDisk( ceL );
  
                      // need a more fine grained locking here
                      synchronized ( map )
                      {
                          map.remove( last );
                          mrulist.remove( last );
                      }
                  }
  
                  if ( debugcmd )
                  {
                      p( "update: After spool, map.size() = " + size + ", 
this.cattr.getMaxObjects() = " + this.cattr.getMaxObjects() + ", chunkSizeCorrected = 
" + chunkSizeCorrected );
                  }
                  if ( log.logLevel >= log.DEBUG )
                  {
                      log.debug( "update: After spool,  map.size() = " + size + ", 
this.cattr.getMaxObjects() = " + this.cattr.getMaxObjects() + ", chunkSizeCorrected = 
" + chunkSizeCorrected );
                  }
  
              }
              catch ( Exception ex )
              {
                  // impossible case.
                  ex.printStackTrace();
                  throw new IllegalStateException( ex.getMessage() );
              }
  
          }
  
      }
      // end update
  
      // TODO: Implement or modify interface, just implement
      // may need insert if we want to distinguish b/wn put and replace
      /**
       *  Description of the Method
       *
       *@param  key              Description of the Parameter
       *@param  val              Description of the Parameter
       *@exception  IOException  Description of the Exception
       */
      public void put( Serializable key, Serializable val )
          throws IOException
      {
          // not used
      }
  
  
      /**
       *  Description of the Method
       *
       *@param  key              Description of the Parameter
       *@param  val              Description of the Parameter
       *@param  attr             Description of the Parameter
       *@exception  IOException  Description of the Exception
       */
      public void put( Serializable key, Serializable val, Attributes attr )
          throws IOException
      {
          // not used
      }
  
  
      /**
       *  Gets an item from the cache.
       *
       *@param  key              Description of the Parameter
       *@return                  Description of the Return Value
       *@exception  IOException  Description of the Exception
       */
      public Serializable get( Serializable key )
          throws IOException
      {
          return get( key, true );
      }
  
  
      /**
       *  Description of the Method
       *
       *@param  key              Description of the Parameter
       *@param  container        Description of the Parameter
       *@return                  Description of the Return Value
       *@exception  IOException  Description of the Exception
       */
      public Serializable get( Serializable key, boolean container )
          throws IOException
      {
  
          ICacheElement ce = null;
          boolean found = false;
  
          try
          {
  
              if ( log.logLevel >= log.DEBUG )
              {
                  log.debug( "get> key=" + key );
                  log.debug( "get> key=" + key.toString() );
              }
  
              ce = ( ICacheElement ) map.get( key );
              if ( log.logLevel >= log.DEBUG )
              {
                  log.debug( "ce =" + ce );
              }
  
              if ( ce == null )
              {
  
              }
              else
              {
                  found = true;
  
                  //ramHit++;
                  if ( log.logLevel >= log.DEBUG )
                  {
                      log.debug( cacheName + " -- RAM-HIT for " + key );
                  }
              }
  
          }
          catch ( Exception e )
          {
              log.error( e );
          }
  
          try
          {
  
              if ( !found )
              {
                  // Item not found in all caches.
                  //miss++;
                  if ( log.logLevel >= log.DEBUG )
                  {
                      log.debug( cacheName + " -- MISS for " + key );
                  }
                  return null;
                  //throw new ObjectNotFoundException( key + " not found in cache" );
              }
          }
          catch ( Exception e )
          {
              log.error( e, "Error handling miss" );
              return null;
          }
  
          try
          {
              synchronized( lockMe )
              {
                     mrulist.remove(ce.getKey());
                 mrulist.addFirst(ce.getKey());
              }
          }
          catch ( Exception e )
          {
              log.error( e, "Error making first" );
              return null;
          }
  
          if ( container )
          {
              return ce;
          }
          else
          {
              return ce.getVal();
          }
  
      }
      // end get
  
      /**
       *  Removes an item from the cache.
       *
       *@param  key              Description of the Parameter
       *@return                  Description of the Return Value
       *@exception  IOException  Description of the Exception
       */
      public boolean remove( Serializable key )
          throws IOException
      {
  
          if ( log.logLevel >= log.DEBUG )
          {
              log.debug( "remove> key=" + key );
              //+, nonLocal="+nonLocal);
          }
  
          //p("remove> key="+key+", nonLocal="+nonLocal);
          boolean removed = false;
  
          // handle partial removal
          if ( key instanceof String && key.toString().endsWith( 
NAME_COMPONENT_DELIMITER ) )
          {
              // remove all keys of the same name hierarchy.
              synchronized ( map )
              {
                  for ( Iterator itr = map.entrySet().iterator(); itr.hasNext();  )
                  {
                      Map.Entry entry = ( Map.Entry ) itr.next();
                      Object k = entry.getKey();
                      if ( k instanceof String && k.toString().startsWith( 
key.toString() ) )
                      {
                          itr.remove();
                          Serializable keyR = (ICacheElement)entry.getKey();
                          map.remove( keyR );
                          mrulist.remove( keyR );
                          removed = true;
                      }
                  }
              }
          }
          else
          {
              // remove single item.
              if ( map.containsKey(key) )
              {
              synchronized ( lockMe )
              {
  
                          map.remove( key );
                          mrulist.remove( key );
              }
                  removed = true;
              }
          }
          // end else not hierarchical removal
          return removed;
      }
  
  
      /**
       *  Removes all cached items from the cache.
       *
       *@exception  IOException  Description of the Exception
       */
      public void removeAll()
          throws IOException
      {
          map = new HashMap();
      }
  
  
      /**
       *  Prepares for shutdown.
       *
       *@exception  IOException  Description of the Exception
       */
      public void dispose()
          throws IOException
      {
      }
  
  
      /**
       *  Returns the cache statistics.
       *
       *@return    The stats value
       */
      public String getStats()
      {
          return "";
      }
  
  
      /**
       *  Returns the current cache size.
       *
       *@return    The size value
       */
      public int getSize()
      {
          return this.map.size();
      }
  
  
      /**
       *  Returns the cache status.
       *
       *@return    The status value
       */
      public int getStatus()
      {
          return this.status;
          //return this.STATUS_ALIVE;
      }
  
  
      /**
       *  Returns the cache name.
       *
       *@return    The cacheName value
       */
      public String getCacheName()
      {
          return this.cattr.getCacheName();
      }
  
  
      ///////////////////////////////////////////////
      /**
       *  Gets the iterator attribute of the LRUMemoryCache object
       *
       *@return    The iterator value
       */
      public Iterator getIterator()
      {
          //return Collections.enumeration(map.entrySet());
          return map.entrySet().iterator();
      }
  
  
      /**
       *  Dump the cache map for debugging.
       */
      public void dumpMap()
      {
          log.debug( "dumpingMap" );
          for ( Iterator itr = map.entrySet().iterator(); itr.hasNext();  )
          {
              //for ( Iterator itr = memCache.getIterator(); itr.hasNext();) {
              Map.Entry e = ( Map.Entry ) itr.next();
              MemoryElementDescriptor me = ( MemoryElementDescriptor ) e.getValue();
              log.debug( "dumpMap> key=" + e.getKey() + ", val=" + me.ce.getVal() );
          }
      }
  
  
      /**
       *  Dump the cache entries from first to list for debugging.
       */
      public void dumpCacheEntries()
      {
          log.debug( "dumpingCacheEntries" );
          ListIterator li = mrulist.listIterator();
          while( li.hasNext() )
          {
              Serializable key = (Serializable)li.next();
              log.debug( "dumpCacheEntries> key=" + key + ", val=" + 
((ICacheElement)map.get(key)).getVal() );
          }
      }
  
  
      ///////////////////////////////////////////////////
      /**
       *  Description of the Method
       *
       *@param  s  Description of the Parameter
       */
      public static void p( String s )
      {
          System.out.println( "MRUMemoryCache: " + s );
      }
  
  }
  // end LRUMemoryCache
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to