asmuts      02/01/14 22:48:21

  Added:       src/java/org/apache/stratum/jcs/utils/reuse
                        HashMapPoolManager.java HashtablePoolManager.java
                        ICleanForPool.java IJglQueue.java
                        IKnowCreateTime.java IThreadPoolRunnable.java
                        ITomcatQueue.java IZombie.java JglQueue.java
                        ObjectPreserver.java ReadWriteLock.java
                        ReadWriteLockManager.java RwLockGC.java
                        RwLockHolder.java ThreadPoolManager.java
                        TomcatJglQueue.java TomcatQueue.java
  Log:
  pooling . . . .
  
  Revision  Changes    Path
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/HashMapPoolManager.java
  
  Index: HashMapPoolManager.java
  ===================================================================
  package org.apache.stratum.jcs.utils.reuse;
  
  import java.util.*;
  
  import org.apache.stratum.jcs.utils.log.*;
  
  /**
    * Very simple utility class to be sued by proxy servlets that pass values by means
    * of Hastables.  Not a singleton manager and not set up to decrement.
    * Only get's us about a 15% boost for this line.
    */
  public class HashMapPoolManager {
  
    Logger log;
  
    HashMap[] pool;
    boolean[] inUse;
  
  
    ///////////////////////////////////////////////////////
    public static void main( String args[] ) {
      HashMapPoolManager hpm = new HashMapPoolManager( 200 );
  
      int num = 1000000;
  
      long start = System.currentTimeMillis();
      for ( int i = 0; i < num; i++ ) {
        HashMap ht = new HashMap();
      }
      long end = System.currentTimeMillis();
      System.out.println( "New HashMap creation took " + String.valueOf( end - start ) 
+ " millis." );
  
      start = System.currentTimeMillis();
      for ( int i = 0; i < num; i++ ) {
        HashMap ht = hpm.getHashMap();
        //ht.put( "tre", "ret" );
        hpm.returnHashMap( ht );
      }
      end = System.currentTimeMillis();
      System.out.println( "Pooled get and return of Hashtable took " + String.valueOf( 
end - start ) + " millis." );
  
    }
  
  
  
    ////////////////////////////////////////////////////////////
    public HashMapPoolManager(int initialPoolSize) {
  
      log = LoggerManager.getLogger( this );
  
      log.info( "initialPoolSize = " + initialPoolSize );
  
      pool = new HashMap[initialPoolSize];
      inUse = new boolean[initialPoolSize];
      for (int i = pool.length-1; i>=0; i--) {
        pool[i] = new HashMap();
        inUse[i] = false;
      }
    }
  
    ////////////////////////////////////////////////////////////
    public synchronized HashMap getHashMap() {
      for (int i = inUse.length-1; i >= 0; i--)
        if (!inUse[i]) {
          inUse[i] = true;
          return pool[i];
        }
  
      //If we got here, then all the HashMaps are in use. We will increase the number 
in our
      //pool by 10.
      boolean[] old_inUse = inUse;
      inUse = new boolean[old_inUse.length+10];
      System.arraycopy(old_inUse, 0, inUse, 0, old_inUse.length);
  
      HashMap[] old_pool = pool;
      pool = new HashMap[old_pool.length+10];
      System.arraycopy(old_pool, 0, pool, 0, old_pool.length);
  
      for (int i = old_pool.length; i < pool.length; i++) {
        pool[i] = new HashMap();
        inUse[i] = false;
      }
      inUse[pool.length-1] = true;
      return pool[pool.length-1];
    }
  
    ////////////////////////////////////////////////////////////
    public synchronized void returnHashMap(HashMap v) {
      for (int i = inUse.length-1; i >= 0; i--) {
        if (pool[i] == v) {
          inUse[i] = false;
          v.clear();
          return;
        }
      }
      log.warn( "Hashtable was not obtained from the pool: " + v );
    }
  
  } // end class
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/HashtablePoolManager.java
  
  Index: HashtablePoolManager.java
  ===================================================================
  package org.apache.stratum.jcs.utils.reuse;
  
  import java.util.*;
  
  import org.apache.stratum.jcs.utils.log.*;
  
  /**
    * Very simple utility class to be sued by proxy servlets that pass values by means
    * of Hastables.  Not a singleton manager and not set up to decrement.
    * Only get's us about a 15% boost for this line.
    */
  public class HashtablePoolManager {
  
    Logger log;
  
    Hashtable[] pool;
    boolean[] inUse;
  
  
    ///////////////////////////////////////////////////////
    public static void main( String args[] ) {
      HashtablePoolManager hpm = new HashtablePoolManager( 200 );
  
      int num = 1000000;
  
      long start = System.currentTimeMillis();
      for ( int i = 0; i < num; i++ ) {
        Hashtable ht = new Hashtable();
        //ht.put( "tre", "ret" );
      }
      long end = System.currentTimeMillis();
      System.out.println( "New Hashtable creation took " + String.valueOf( end - start 
) + " millis." );
  
      start = System.currentTimeMillis();
      for ( int i = 0; i < num; i++ ) {
        Hashtable ht = hpm.getHashtable();
        //ht.put( "tre", "ret" );
        hpm.returnHashtable( ht );
      }
      end = System.currentTimeMillis();
      System.out.println( "Pooled get and return of Hashtable took " + String.valueOf( 
end - start ) + " millis." );
  
    }
  
  
  
    ////////////////////////////////////////////////////////////
    public HashtablePoolManager(int initialPoolSize) {
  
      LoggerManager lm = LoggerManager.getInstance();
      log = lm.getLogger( this );
  
      log.info( "initialPoolSize = " + initialPoolSize );
  
      pool = new Hashtable[initialPoolSize];
      inUse = new boolean[initialPoolSize];
      for (int i = pool.length-1; i>=0; i--) {
        pool[i] = new Hashtable();
        inUse[i] = false;
      }
    }
  
    ////////////////////////////////////////////////////////////
    public synchronized Hashtable getHashtable() {
      for (int i = inUse.length-1; i >= 0; i--)
        if (!inUse[i]) {
          inUse[i] = true;
          return pool[i];
        }
  
      //If we got here, then all the Hashtable are in use. We will increase the number 
in our
      //pool by 10.
      boolean[] old_inUse = inUse;
      inUse = new boolean[old_inUse.length+10];
      System.arraycopy(old_inUse, 0, inUse, 0, old_inUse.length);
  
      Hashtable[] old_pool = pool;
      pool = new Hashtable[old_pool.length+10];
      System.arraycopy(old_pool, 0, pool, 0, old_pool.length);
  
      for (int i = old_pool.length; i < pool.length; i++) {
        pool[i] = new Hashtable();
        inUse[i] = false;
      }
      inUse[pool.length-1] = true;
      return pool[pool.length-1];
    }
  
    ////////////////////////////////////////////////////////////
    public synchronized void returnHashtable(Hashtable v) {
      for (int i = inUse.length-1; i >= 0; i--) {
        if (pool[i] == v) {
          inUse[i] = false;
          v.clear();
          return;
        }
      }
      log.warn( "Hashtable was not obtained from the pool: " + v );
    }
  
  } // end class
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/ICleanForPool.java
  
  Index: ICleanForPool.java
  ===================================================================
  /*
   * put your module comment here
   * formatted with JxBeauty (c) [EMAIL PROTECTED]
   */
  
  
  package  org.apache.stratum.jcs.utils.reuse;
  
  import  java.io.*;
  import  java.util.*;
  
  
  ////////////////////////////////////
  public interface ICleanForPool {
  
    /**
     *  Resets default values for reinsertion into a pool.
     */
    public void clean ();
  }               // end interface
  
  
  
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/IJglQueue.java
  
  Index: IJglQueue.java
  ===================================================================
  
  package org.apache.stratum.jcs.utils.reuse;
  
  import java.util.*;
  /** Used to define the interface of a queue from the jgl library. */
  public interface IJglQueue {
    /**
     * Remove all of my objects.
     */
    public void clear();
    /**
     * Return true if I contain no objects.
     */
    public boolean isEmpty();
    /**
     * Return the number of objects that I contain.
     */
    public int size();
    /**
     * Return the maximum number of objects that I can contain.
     */
    public int maxSize();
    /**
     * Return the object at my front.
     * @exception com.objectspace.jgl.InvalidOperationException If the Queue is empty.
     */
    public Object front();
    /**
     * Return the object at my back.
     * @exception com.objectspace.jgl.InvalidOperationException If the Queue is empty.
     */
    public Object back();
    /**
     * Add an object to my back.
     * @param object The object to add.
     */
    public Object add (Object object);
    /**
     * Add an object to my back.
     */
    public void push (Object object);
    /**
     * Remove an object from my front and return it.
     * @exception com.objectspace.jgl.InvalidOperationException If the Queue is empty.
     */
    public Object pop();
    /**
     * Return an Enumeration of my components.
     */
    public Enumeration elements();
  }
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/IKnowCreateTime.java
  
  Index: IKnowCreateTime.java
  ===================================================================
  /*
   * put your module comment here
   * formatted with JxBeauty (c) [EMAIL PROTECTED]
   */
  
  
  package  org.apache.stratum.jcs.utils.reuse;
  
  
  public interface IKnowCreateTime {
  
    public long getCreateTime ();
  }
  
  
  
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/IThreadPoolRunnable.java
  
  Index: IThreadPoolRunnable.java
  ===================================================================
  
  package org.apache.stratum.jcs.utils.reuse;
  
  import org.apache.tomcat.util.*;
  
  /** 
   * Implemented if you want to run a piece of code inside a thread pool.
   */
  public interface IThreadPoolRunnable extends ThreadPoolRunnable {
      // Super-interface methods duplicated here for easy reference.
      /** 
       * Called when this object is first loaded in the thread pool.
       * Important: all workers in a pool must be of the same type,
       * otherwise the mechanism becomes more complex.
       */
      // public Object[] getInitData();
      /** 
       * This method will be executed in one of the pool's threads. The
       * thread will be returned to the pool.
       */
      // public void runIt(Object thData[]);
  }
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/ITomcatQueue.java
  
  Index: ITomcatQueue.java
  ===================================================================
  
  package org.apache.stratum.jcs.utils.reuse;
  /** Used to define the interface of a queue from Jakarta Tomcat library. */
  public interface ITomcatQueue {
    /**
     * Put the object into the queue.
     *
     * @param   object          the object to be appended to the
     *                          queue.
     */
    public void put(Object object);
    /**
     * Pull the first object out of the queue. Wait if the queue is
     * empty.
     */
    public Object pull();
    /**
     * Get the first object out of the queue. Return null if the queue
     * is empty.
     */
    public Object get();
    /**
     * Peek to see if something is available.
     */
    public Object peek();
    /**
     * Is the queue empty?
     */
    public boolean isEmpty();
    /**
     * How many elements are there in this queue?
     */
    public int size();
  }
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/IZombie.java
  
  Index: IZombie.java
  ===================================================================
  package org.apache.stratum.jcs.utils.reuse;
  
  /** Interface to mark an object as zombie for error recovery purposes. */
  public interface IZombie {
  }
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/JglQueue.java
  
  Index: JglQueue.java
  ===================================================================
  package org.apache.stratum.jcs.utils.reuse;
  
  import com.objectspace.jgl.*;
  
  public class JglQueue extends Queue implements IJglQueue {
  }
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/ObjectPreserver.java
  
  Index: ObjectPreserver.java
  ===================================================================
  package org.apache.stratum.jcs.utils.reuse;
  
  import java.util.*;
  
  /**
   * This class can help ensure that an object is never garbage
   * collected.
   */
  public class ObjectPreserver implements Runnable {
  
      // This keeps this class and everything it references from being
      // garbage collected
      private static ObjectPreserver lifeLine = new ObjectPreserver();
  
      // Since this class won't be garbage collected, neither will this
      // HashSet or the object that it references.
      private static HashSet protectedSet = new HashSet();
  
      /**
       * Constructor.
       */
      private ObjectPreserver() {
          new Thread(this).start();
      } // constructor()
  
      public void run() {
        while (true) {
          try {
            synchronized(this) {
              wait();
            }
          } catch (InterruptedException e) {
          }
        }
      }
  
      /**
       * Garbage collection of objects passed to this method will be
       * prevented until they are passed to the unpreserveObject method.
       */
      public static void preserveObject(Object o) {
          protectedSet.add(o);
      } // preserveObject()
  
      /**
       * Objects passed to this method lose the protection that the
       * preserveObject method gave them from garbage collection.
       */
      public static void unpreserveObject(Object o) {
          protectedSet.remove(o);
      } // unpreserveObject(Object)
  } // class ObjectPreserver
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/ReadWriteLock.java
  
  Index: ReadWriteLock.java
  ===================================================================
  
  package  org.apache.stratum.jcs.utils.reuse;
  
  import  java.util.*;
  
  
  /**
   * This class coordinates concurrent calls to an object's get and set methods so 
that calls to the
   * object set methods do not interfere with each other or with calls to the object's 
get methods.
   *<br><br>
   * Only a single instance of this class should be created per specific resource
   * that requires Read/Write lock protection.
   * <br><br>
   * The invariant required by this class is that the method <code>done</code> must be 
called,
   * and only be called, after a previous call to either the method
   * <code>readLock</code> or <code>writeLock</code>.
   */
  class ReadWriteLock {
    //////////////// debug MUST BE SET TO false in production! ///////////////////
    private boolean debug = false; //true;
  
    /** Number of threads waiting to read. */
    private int waitingForReadLock = 0;
  
    /** Number of threads reading. */
    private int outstandingReadLocks = 0;
  
    /** The thread that has the write lock or null. */
    private Thread writeLockedThread;
  
    /** The number of (nested) write locks that have been requested from 
writeLockedThread. */
    private int outstandingWriteLocks = 0;
  
    /**
     * Threads waiting to get a write lock are tracked in this ArrayList
     * to ensure that write locks are issued in the same order they are
     * requested.
     */
    private ArrayList waitingForWriteLock = new ArrayList();
  
    /** Default constructor. */
    ReadWriteLock () {
    }
  
    /**
     * Issue a read lock if there is no outstanding write lock or
     * threads waiting to get a write lock.
     * Caller of this method must be careful to avoid synchronizing the calling code 
so as to avoid deadlock.
     */
    synchronized void readLock () throws InterruptedException {
      waitingForReadLock++;
      while (writeLockedThread != null) {
        p("readLock wait");
        wait();
        p("wake up from readLock wait");
      }
      if (debug)
        p("readLock acquired");
      waitingForReadLock--;
      outstandingReadLocks++;
    }
  
    /**
     * Issue a write lock if there are no outstanding read or write locks.
     * Caller of this method must be careful to avoid synchronizing the calling code 
so as to avoid deadlock.
     */
    void writeLock () throws InterruptedException {
      Thread thisThread = Thread.currentThread();
      synchronized (this) {
        if (writeLockedThread == null && outstandingReadLocks == 0) {
          writeLockedThread = Thread.currentThread();
          outstandingWriteLocks++;
          if (debug)
            p("writeLock acquired without waiting");
          return;
        }
        if (writeLockedThread == thisThread)      // nested write locks from the same 
thread.
          outstandingWriteLocks++;
        waitingForWriteLock.add(thisThread);
      }
      synchronized (thisThread) {
        while (thisThread != writeLockedThread) {
          p("writeLock wait");
          // set this so if there is an error the app will not completely die!
          thisThread.wait(2000);
          p("wake up from writeLock wait");
        }
        if (debug)
          p("writeLock acquired");
      }
      synchronized (this) {
        int i = waitingForWriteLock.indexOf(thisThread);
        waitingForWriteLock.remove(i);
      }
    }
  
    /**
     * Threads call this method to relinquish a lock that they
     * previously got from this object.
     * @throws IllegalStateException if called when there are no
     *            outstanding locks or there is a write lock issued to a
     *            different thread.
     */
    synchronized void done () {
      if (outstandingReadLocks > 0) {
        outstandingReadLocks--;
        if (outstandingReadLocks == 0 && waitingForWriteLock.size() > 0) {
          writeLockedThread = (Thread)waitingForWriteLock.get(0);
          if (debug)
            p("readLock released and before notifying a write lock waiting thread "
                + writeLockedThread);
          synchronized (writeLockedThread) {
            writeLockedThread.notifyAll();
          }
          if (debug)
            p("readLock released and after  notifying a write lock waiting thread "
                + writeLockedThread);
        }
        else if (debug)
          p("readLock released without fuss");
        return;
      }
      if (Thread.currentThread() == writeLockedThread) {
        outstandingWriteLocks--;
        if (outstandingWriteLocks > 0) {
          p("writeLock released for a nested writeLock request.");
          return;
        }
        if (outstandingReadLocks == 0 && waitingForWriteLock.size() > 0) {
          writeLockedThread = (Thread)waitingForWriteLock.get(0);
          if (debug)
            p("writeLock released and before notifying a write lock waiting thread "
                + writeLockedThread);
          synchronized (writeLockedThread) {
            writeLockedThread.notifyAll();
          }
          if (debug)
            p("writeLock released and after notifying a write lock waiting thread "
                + writeLockedThread);
        }
        else {
          writeLockedThread = null;
          if (waitingForReadLock > 0) {
            if (debug)
              p("writeLock released and notify all read lock waiting threads.");
            notifyAll();
          }
          else if (debug)
            p("writeLock released without fuss.");
        }
        return;
      }
      //////////////// debug MUST BE SET TO false in production! ///////////////////
      if (debug) {
        try {
          System.in.read();
        } catch (java.io.IOException ignore) {}
      }
      throw  new IllegalStateException("Thread does not have lock");
    }
  
    private void p (String s) {
      if (debug)
        System.out.println("ReadWriteLock: " + Thread.currentThread() + ">>" +
            s);
    }
  }
  
  
  
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/ReadWriteLockManager.java
  
  Index: ReadWriteLockManager.java
  ===================================================================
  
  package  org.apache.stratum.jcs.utils.reuse;
  
  import  java.util.*;
  
  
  /** The Generic ReadWriteLock Manager for various resources. */
  public abstract class ReadWriteLockManager {
  
    public static final boolean debug = false;
  
    /** Used to asynchronously remove unused RwLockHolder objects managed ty this 
manager. */
    private static RwLockGC gc;
  
    /** Class name for debugging purposes. */
    private String clsname;
  
    /** Places a read lock on the specified resource. */
    final public void readLock (String id) throws InterruptedException {
      lock(id, false);
    }
  
    /** Places a write lock on the specified resource. */
    final public void writeLock (String id) throws InterruptedException {
      lock(id, true);
    }
  
    /** Release the read/write lock previously placed on the specified resource. */
    final public void done (String id) {
      Hashtable ht = getLocks();
      RwLockHolder holder = (RwLockHolder)ht.get(id);
  
      if (holder == null) {
  
        p("Method done of " + getClass().getName() + " invoked without an outstanding 
lock; id=" + id);
        //System.exit(1);
  
        throw  new IllegalStateException("Method done of " + getClass().getName()
            + " invoked without an outstanding lock; id=" + id);
      }
      holder.rwlock.done();
      if ( debug ) {
        p("lock done for id = " + id );
      }
      // Somehow if we don't synchronize while changing the count,
      // the count went down below zero!
      // Theoretically this should never happen, as a "done" is always preceeded
      // by either a read or write lock issued from the very same thread.
      // So for the moment, let's blame the JVM and make it work via synchronization,
      // until futher investigation.
      int lcount; // used to minimize the time spent in the synchronized block.
      synchronized(ht) {
        lcount = --holder.lcount;
      }
      if (lcount > 0) {
        return;
      }
  
      //  p("-- holder.lcount=" + holder.lcount);
      if (lcount == 0) {
        holder.lastInactiveTime = System.currentTimeMillis();
        //p("notify: Gargage available");
        gc.notifyGarbage();
        return;
      }
      // lcount is negative! should never get here.
        /*
        p("holder.lcount went down below zero (" + holder.lcount + ") for id=" + id);
        System.exit(1);
        */
      throw  new IllegalStateException("holder.lcount went down below zero ("
          + holder.lcount + ") for id=" + id);
    }
  
  
    /** Places either a read or write lock on the specified resource. */
    private void lock (String id, boolean isWrite) throws InterruptedException {
      if ( debug ) {
         p("about to get lock, isWrite=" + isWrite + " for id = " + id);
      }
      RwLockHolder holder;
      Hashtable ht = getLocks();
      if (gc == null) {
        synchronized (this) {
          if (gc == null) {
            gc = new RwLockGC(ht);
            gc.setDaemon(true);
            gc.start();
          }
        }
      }
      synchronized(ht) {
        holder = (RwLockHolder)ht.get(id);
        if (holder != null) {
          // Lock already exists.  So just use it.
          holder.lcount++;
          if ( debug ) {
            p("++ holder.lcount=" + holder.lcount + ", isWrite=" + isWrite + " for id 
= " + id);
          }
        }
      }
      if (holder == null) {
        // Lock does not exist.  So create a new one.
        RwLockHolder newHolder = new RwLockHolder(new ReadWriteLock());
        if ( debug ) {
          p("holder is null, isWrite=" + isWrite);
        }
        synchronized(ht) {
          holder = (RwLockHolder)ht.put(id, newHolder);
          if (holder != null) {
            // Oops, the lock is already created by someone else concurrently.
            // So we increment, put it back and discard the new lock we just created.
            // We use this strategy to minimize the time spent in the synchronized 
block.
            holder.lcount++;
            ht.put(id, holder);
          }
        }
        if (holder == null) {
          // no concurrency issue -- the new lock is now used.
          holder = newHolder;
        }
        if (debug) {
          p((isWrite ? "Write" : "Read") + " lock created for " + id);
        }
      }
      // Be careful not to put the following code into a synchronized block.
      // Otherwise, deadlock can easily happen as the writeLock() and readLock() may 
result
      // in the ReadWriteLock object being waited!
      if (isWrite) {
        holder.rwlock.writeLock();
      } else {
        holder.rwlock.readLock();
      }
      return;
    }
  
    /** Returns the lock table of all the resources managed by the subclass. */
    abstract protected Hashtable getLocks ();
  
    /** Subclass must always override this constructor to create and preserve a 
singleton instance of the subclass. */
    protected ReadWriteLockManager () {
      clsname = getClass().getName();
      clsname = clsname.substring(clsname.lastIndexOf('.') + 1);
    }
  
    private void p (String s) {
      //    System.err.println(clsname + "#" + Thread.currentThread() + ">>" + s);
      System.err.println(">> " + s);
    }
  }
  
  
  
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/RwLockGC.java
  
  Index: RwLockGC.java
  ===================================================================
  
  package  org.apache.stratum.jcs.utils.reuse;
  
  import  org.apache.stratum.jcs.utils.log.*;
  import  java.util.*;
  
  
  /**
   * Used to enhance performance by delaying the removal of unreferenced RwLockHolder 
objects
   * managed by the ReadWriteLockManager.
   */
  public class RwLockGC extends Thread {
    private final Hashtable ht;
    private static final long IDLE_PERIOD = 60*1000;    // 60 seconds.
    private Logger log = LoggerManager.getInstance().getLogger(this);
    private boolean clean = true;
  
    RwLockGC (Hashtable ht) {
      this.ht = ht;
    }
  
    /**
     * Notifies the garbage collection that there is garbage available,
     * and kicks off the garbage collection process.
     */
    void notifyGarbage () {
      dirty();
      synchronized (this) {
        notify();
      }
    }
    // Run forever.
    // Minimize the use of any synchronization in the process of garbage collection
    // for performance reason.
    public void run () {
      do {
        if (clean) {
          synchronized (this) {
            if (clean) {
  //p("RwLockGC entering into a wait state");
              // Garbage driven mode.
              try {
                wait();           // wake up only if there is garbage.
              } catch (InterruptedException ignore) {}
            }
          }
        }
        // Time driven mode: sleep between each round of garbage collection.
        try {
  //p("RwLockGC sleeping for " + IDLE_PERIOD);
          Thread.currentThread().sleep(IDLE_PERIOD);
        } catch (InterruptedException ex) {
        // ignore;
        }
        // The "clean" flag must be false here.
        // Simply presume we can collect all the garbage until proven otherwise.
        synchronized (this) {
          clean = true;
        }
        long now = System.currentTimeMillis();
        // Take a snapshot of the hashtable.
        Map.Entry[] entries = (Map.Entry[])ht.entrySet().toArray(new Map.Entry[0]);
  //p("RwLockHolder garbage collecting...");
        for (int i = 0; i < entries.length; i++) {
          RwLockHolder holder = (RwLockHolder)entries[i].getValue();
          if (holder.removable(now)) {
            Object key = entries[i].getKey();
            synchronized (ht) {
              holder = (RwLockHolder)ht.get(key);
              // holder cannot possibly be null as this should be the only thread 
removing them.
              if (holder.removable(now)) {
                ht.remove(key);
  /*
  p("removing key=" + key + ", now=" + now + ", holder.lastInactiveTime="
  + holder.lastInactiveTime);
  */
              }
            }
          }
        } // end for loop.
      } while (true);
    }
  
    /** Sets the "clean" flag to false in a critial section. */
    private void dirty () {
      if (clean) {
        synchronized (this) {
          clean = false;
        }
      }
    }
  
    private void p (String s) {
      System.out.println("RwLockGC:" + s);
    }
  }
  
  
  
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/RwLockHolder.java
  
  Index: RwLockHolder.java
  ===================================================================
  
  package  org.apache.stratum.jcs.utils.reuse;
  
  
  /**
   * Used to keep track of the total number of outstanding locks placed
   * but not yet released for a given resource.
   */
  class RwLockHolder {
    private static final long UNUSED_TIME = 10*1000;              // 10 seconds.
  
    /** Read/Write lock for a specific resource. */
    final ReadWriteLock rwlock;
  
    /** Number of locks that have been placed on the rwlock and not yet released. */
    int lcount = 1;
  
    /** Last timestamp when the lcount was zero. */
    long lastInactiveTime = -1;
  
    /** Constructs with a Read/Write lock for a specific resource. */
    RwLockHolder (ReadWriteLock rwlock) {
      this.rwlock = rwlock;
    }
    /**
     * Returns true iff this object satisfies the condition of removing RwLockHolder
     *  from the managing ReadWriteLockManager.
     */
    boolean removable (long now) {
      return  lcount == 0 && lastInactiveTime > 0 && now - lastInactiveTime > 
UNUSED_TIME;
    }
  }
  
  
  
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/ThreadPoolManager.java
  
  Index: ThreadPoolManager.java
  ===================================================================
  
  package org.apache.stratum.jcs.utils.reuse;
  
  import java.util.*;
  import org.apache.tomcat.util.*;
  /** Provides a singleton thread pool. */
  public class ThreadPoolManager {
    /** The singleton thread pool manager. */
    private static final ThreadPoolManager singleton = new ThreadPoolManager();
  
    /** The thread pool. */
    private ThreadPool pool = new ThreadPool();
    /** True iff the thread pool has been started. */
    private boolean started;
    /** Can only be constructed by this class. */
    private ThreadPoolManager() {}
    /**
     * Sets the max number of threads that you can open in the pool.
     * Will only be effective if called before the getInstance method is invoked for 
the first time.
     */
    public static void setMaxThreads(int maxThreads) {
      singleton.pool.setMaxThreads(maxThreads);
    }
    /**
     * Sets the min number of idle threads that you can leave in the pool.
     * Will only be effective if called before the getInstance method is invoked for 
the first time.
     */
    public static void setMinSpareThreads(int minSpareThreads) {
      singleton.pool.setMinSpareThreads(minSpareThreads);
    }
    /**
     * Sets the max number of idle threads that you can leave in the pool.
     * Will only be effective if called before the getInstance method is invoked for 
the first time.
     */
    public static void setMaxSpareThreads(int maxSpareThreads) {
      singleton.pool.setMaxSpareThreads(maxSpareThreads);
    }
    /**
     * Gets the max number of threads that you can open in the pool.
     * Will only be accurate if called after the getInstance method is invoked for the 
first time.
     */
    public static int getMaxThreads() {
      return singleton.pool.getMaxThreads();
    }
    /**
     * Gets the min number of idle threads that you can leave in the pool.
     * Will only be accurate if called after the getInstance method is invoked for the 
first time.
     */
    public static int getMinSpareThreads() {
      return singleton.pool.getMinSpareThreads();
    }
    /**
     * Gets the max number of idle threads that you can leave in the pool.
     * Will only be accurate if called after the getInstance method is invoked for the 
first time.
     */
    public static int getMaxSpareThreads() {
      return singleton.pool.getMaxSpareThreads();
    }
    /**
     * Returns the singleton thread pool manager, which can be used to execute a
     * given IThreadPoolRunnable on a thread in the pool.
     * Configuration of the thread pool must be made prior to invoking this method.
     */
    public static ThreadPoolManager getInstance() {
      if (!singleton.started) {
        synchronized(singleton) {
          if (!singleton.started) {
            singleton.pool.start();
            singleton.started = true;
          }
        }
      }
      return singleton;
    }
    /**
     * Shuts down the thread pool and re-initializes it to the default.
     */
    public static void reset() {
      synchronized(singleton) {
        if (singleton.started) {
          singleton.started = false;
          singleton.pool.shutdown();
        }
        singleton.pool = new ThreadPool();
      }
      return;
    }
    /**
     * Executes a given IThreadPoolRunnable on a thread in the pool, block if needed.
     */
    public void runIt(IThreadPoolRunnable r) {
      pool.runIt(r);
    }
  }
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/TomcatJglQueue.java
  
  Index: TomcatJglQueue.java
  ===================================================================
  
  package org.apache.stratum.jcs.utils.reuse;
  
  /**
   * A simple FIFO queue class which causes the calling thread to wait
   * if the queue is empty and notifies threads that are waiting when it
   * is not empty.  Implemented using JGL for better performance.
   */
  public class TomcatJglQueue implements ITomcatQueue {
    private IJglQueue q = new JglQueue();
    /**
     * Put the object into the queue.
     *
     * @param   object          the object to be appended to the
     *                          queue.
     */
    public void put(Object object) {
      synchronized(q) {
        q.push(object);
        q.notify();
      }
    }
  
    /**
     * Pull the first object out of the queue. Wait if the queue is
     * empty.
     */
    public Object pull() {
      synchronized(q) {
        while (q.isEmpty()) {
          try {
            q.wait();
          } catch(InterruptedException ex) {}
        }
        return  q.pop();
      }
    }
  
    /**
     * Get the first object out of the queue. Return null if the queue
     * is empty.
     */
    public Object get() {
      synchronized(q) {
        return q.isEmpty() ? null : q.pop();
      }
    }
  
    /**
     * Peek to see if something is available.
     */
    public Object peek() {
      synchronized(q) {
        return q.isEmpty() ? null : q.front();
      }
    }
  
    /**
     * Is the queue empty?
     */
    public boolean isEmpty() {
      return  q.isEmpty();
    }
  
    /**
     * How many elements are there in this queue?
     */
    public int size() {
      return  q.size();
    }
  }
  
  
  
  1.1                  
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/utils/reuse/TomcatQueue.java
  
  Index: TomcatQueue.java
  ===================================================================
  package org.apache.stratum.jcs.utils.reuse;
  
  import org.apache.tomcat.util.*;
  
  /**
   * A simple FIFO queue class which causes the calling thread to wait
   * if the queue is empty and notifies threads that are waiting when it
   * is not empty.  Implemented using the Tomcat Queue.
   */
  public class TomcatQueue extends Queue implements ITomcatQueue {
  }
  
  
  

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

Reply via email to