src/share/classes/com/sun/jndi/ldap/pool/Pool.java

Print this page




  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.ldap.pool;
  27 
  28 import java.util.Map;
  29 import java.util.WeakHashMap;
  30 import java.util.Collection;
  31 import java.util.Collections;
  32 import java.util.Iterator;
  33 import java.util.Set;
  34 import java.util.LinkedList;
  35 
  36 import java.io.PrintStream;
  37 import java.lang.ref.Reference;
  38 import java.lang.ref.ReferenceQueue;
  39 import javax.naming.NamingException;
  40 
  41 /**
  42  * A map of pool ids to Connections.
  43  * Key is an object that uniquely identifies a PooledConnection request
  44  * (typically information needed to create the connection).
  45  * The definitions of the key's equals() and hashCode() methods are
  46  * vital to its unique identification in a Pool.
  47  *
  48  * Value is a ConnectionsRef, which is a reference to Connections,
  49  * a list of equivalent connections.
  50  *
  51  * Supports methods that
  52  * - retrieves (or creates as necessary) a connection from the pool
  53  * - removes expired connections from the pool


  66  * clearing the weak references is made by the GC it puts the corresponding
  67  * ConnectionsWeakRef object into the reference queue.
  68  * The reference queue is monitored lazily for reclaimable Connections
  69  * whenever a pooled connection is requested or a call to remove the expired
  70  * connections is made. The monitoring is done regularly when idle connection
  71  * timeout is set as the PoolCleaner removes expired connections periodically.
  72  * As determined by the experiements, cleanup of resources using the
  73  * ReferenceQueue mechanism is reliable and has immidiate effect than the
  74  * finalizer approach.
  75  *
  76  * @author Rosanna Lee
  77  */
  78 
  79 final public class Pool {
  80 
  81     static final boolean debug = com.sun.jndi.ldap.LdapPoolManager.debug;
  82 
  83     /*
  84      * Used for connections cleanup
  85      */
  86     private static final ReferenceQueue queue = new ReferenceQueue();
  87     private static final Collection weakRefs =
  88                 Collections.synchronizedList(new LinkedList());

  89 
  90     final private int maxSize;    // max num of identical conn per pool
  91     final private int prefSize;   // preferred num of identical conn per pool
  92     final private int initSize;   // initial number of identical conn to create
  93     final private Map map;
  94 
  95     public Pool(int initSize, int prefSize, int maxSize) {
  96         map = new WeakHashMap();
  97         this.prefSize = prefSize;
  98         this.maxSize = maxSize;
  99         this.initSize = initSize;
 100     }
 101 
 102     /**
 103      * Gets a pooled connection for id. The pooled connection might be
 104      * newly created, as governed by the maxSize and prefSize settings.
 105      * If a pooled connection is unavailable and cannot be created due
 106      * to the maxSize constraint, this call blocks until the constraint
 107      * is removed or until 'timeout' ms has elapsed.
 108      *
 109      * @param id identity of the connection to get
 110      * @param timeout the number of milliseconds to wait before giving up
 111      * @param factory the factory to use for creating the connection if
 112      *          creation is necessary
 113      * @return a pooled connection
 114      * @throws NamingException the connection could not be created due to
 115      *                          an error.
 116      */


 118         PooledConnectionFactory factory) throws NamingException {
 119 
 120         d("get(): ", id);
 121         d("size: ", map.size());
 122 
 123         expungeStaleConnections();
 124 
 125         Connections conns;
 126         synchronized (map) {
 127             conns = getConnections(id);
 128             if (conns == null) {
 129                 d("get(): creating new connections list for ", id);
 130 
 131                 // No connections for this id so create a new list
 132                 conns = new Connections(id, initSize, prefSize, maxSize,
 133                     factory);
 134                 ConnectionsRef connsRef = new ConnectionsRef(conns);
 135                 map.put(id, connsRef);
 136 
 137                 // Create a weak reference to ConnectionsRef
 138                 Reference weakRef = new ConnectionsWeakRef(connsRef, queue);

 139 
 140                 // Keep the weak reference through the element of a linked list
 141                 weakRefs.add(weakRef);
 142             }
 143         }
 144 
 145         d("get(): size after: ", map.size());
 146 
 147         return conns.get(timeout, factory); // get one connection from list
 148     }
 149 
 150     private Connections getConnections(Object id) {
 151         ConnectionsRef ref = (ConnectionsRef) map.get(id);
 152         return (ref != null) ? ref.getConnections() : null;
 153     }
 154 
 155     /**
 156      * Goes through the connections in this Pool and expires ones that
 157      * have been idle before 'threshold'. An expired connection is closed
 158      * and then removed from the pool (removePooledConnection() will eventually
 159      * be called, and the list of pools itself removed if it becomes empty).
 160      *
 161      * @param threshold connections idle before 'threshold' should be closed
 162      *          and removed.
 163      */
 164     public void expire(long threshold) {
 165         synchronized (map) {
 166             Collection coll = map.values();
 167             Iterator iter = coll.iterator();
 168             Connections conns;
 169             while (iter.hasNext()) {
 170                 conns = ((ConnectionsRef) (iter.next())).getConnections();
 171                 if (conns.expire(threshold)) {
 172                     d("expire(): removing ", conns);
 173                     iter.remove();
 174                 }
 175             }
 176         }
 177         expungeStaleConnections();
 178     }
 179 
 180     /*
 181      * Closes the connections contained in the ConnectionsRef object that
 182      * is going to be reclaimed by the GC. Called by getPooledConnection()
 183      * and expire() methods of this class.
 184      */
 185     private static void expungeStaleConnections() {
 186         ConnectionsWeakRef releaseRef = null;
 187         while ((releaseRef = (ConnectionsWeakRef) queue.poll())
 188                                         != null) {
 189             Connections conns = releaseRef.getConnections();
 190 
 191             if (debug) {
 192                 System.err.println(
 193                         "weak reference cleanup: Closing Connections:" + conns);
 194             }
 195 
 196             // cleanup
 197             conns.close();
 198             weakRefs.remove(releaseRef);
 199             releaseRef.clear();
 200          }
 201     }
 202 
 203 
 204     public void showStats(PrintStream out) {
 205         Map.Entry entry;
 206         Object id;
 207         Connections conns;
 208 
 209         out.println("===== Pool start ======================");
 210         out.println("maximum pool size: " + maxSize);
 211         out.println("preferred pool size: " + prefSize);
 212         out.println("initial pool size: " + initSize);
 213         out.println("current pool size: " + map.size());
 214 
 215         Set entries = map.entrySet();
 216         Iterator iter = entries.iterator();
 217 
 218         while (iter.hasNext()) {
 219             entry = (Map.Entry) iter.next();
 220             id = entry.getKey();
 221             conns = ((ConnectionsRef) entry.getValue()).getConnections();
 222             out.println("   " + id + ":" + conns.getStats());
 223         }
 224 
 225         out.println("====== Pool end =====================");
 226     }
 227 
 228     public String toString() {
 229         return super.toString() + " " + map.toString();
 230     }
 231 
 232     private void d(String msg, int i) {
 233         if (debug) {
 234             System.err.println(this + "." + msg + i);
 235         }
 236     }
 237 
 238     private void d(String msg, Object obj) {
 239         if (debug) {
 240             System.err.println(this + "." + msg + obj);
 241         }


  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.ldap.pool;
  27 
  28 import java.util.Map;
  29 import java.util.WeakHashMap;
  30 import java.util.Collection;
  31 import java.util.Collections;
  32 import java.util.Iterator;

  33 import java.util.LinkedList;
  34 
  35 import java.io.PrintStream;
  36 import java.lang.ref.Reference;
  37 import java.lang.ref.ReferenceQueue;
  38 import javax.naming.NamingException;
  39 
  40 /**
  41  * A map of pool ids to Connections.
  42  * Key is an object that uniquely identifies a PooledConnection request
  43  * (typically information needed to create the connection).
  44  * The definitions of the key's equals() and hashCode() methods are
  45  * vital to its unique identification in a Pool.
  46  *
  47  * Value is a ConnectionsRef, which is a reference to Connections,
  48  * a list of equivalent connections.
  49  *
  50  * Supports methods that
  51  * - retrieves (or creates as necessary) a connection from the pool
  52  * - removes expired connections from the pool


  65  * clearing the weak references is made by the GC it puts the corresponding
  66  * ConnectionsWeakRef object into the reference queue.
  67  * The reference queue is monitored lazily for reclaimable Connections
  68  * whenever a pooled connection is requested or a call to remove the expired
  69  * connections is made. The monitoring is done regularly when idle connection
  70  * timeout is set as the PoolCleaner removes expired connections periodically.
  71  * As determined by the experiements, cleanup of resources using the
  72  * ReferenceQueue mechanism is reliable and has immidiate effect than the
  73  * finalizer approach.
  74  *
  75  * @author Rosanna Lee
  76  */
  77 
  78 final public class Pool {
  79 
  80     static final boolean debug = com.sun.jndi.ldap.LdapPoolManager.debug;
  81 
  82     /*
  83      * Used for connections cleanup
  84      */
  85     private static final ReferenceQueue<ConnectionsRef> queue =
  86         new ReferenceQueue<>();
  87     private static final Collection<Reference<ConnectionsRef>> weakRefs =
  88         Collections.synchronizedList(new LinkedList<Reference<ConnectionsRef>>());
  89 
  90     final private int maxSize;    // max num of identical conn per pool
  91     final private int prefSize;   // preferred num of identical conn per pool
  92     final private int initSize;   // initial number of identical conn to create
  93     final private Map<Object, ConnectionsRef> map;
  94 
  95     public Pool(int initSize, int prefSize, int maxSize) {
  96         map = new WeakHashMap<>();
  97         this.prefSize = prefSize;
  98         this.maxSize = maxSize;
  99         this.initSize = initSize;
 100     }
 101 
 102     /**
 103      * Gets a pooled connection for id. The pooled connection might be
 104      * newly created, as governed by the maxSize and prefSize settings.
 105      * If a pooled connection is unavailable and cannot be created due
 106      * to the maxSize constraint, this call blocks until the constraint
 107      * is removed or until 'timeout' ms has elapsed.
 108      *
 109      * @param id identity of the connection to get
 110      * @param timeout the number of milliseconds to wait before giving up
 111      * @param factory the factory to use for creating the connection if
 112      *          creation is necessary
 113      * @return a pooled connection
 114      * @throws NamingException the connection could not be created due to
 115      *                          an error.
 116      */


 118         PooledConnectionFactory factory) throws NamingException {
 119 
 120         d("get(): ", id);
 121         d("size: ", map.size());
 122 
 123         expungeStaleConnections();
 124 
 125         Connections conns;
 126         synchronized (map) {
 127             conns = getConnections(id);
 128             if (conns == null) {
 129                 d("get(): creating new connections list for ", id);
 130 
 131                 // No connections for this id so create a new list
 132                 conns = new Connections(id, initSize, prefSize, maxSize,
 133                     factory);
 134                 ConnectionsRef connsRef = new ConnectionsRef(conns);
 135                 map.put(id, connsRef);
 136 
 137                 // Create a weak reference to ConnectionsRef
 138                 Reference<ConnectionsRef> weakRef =
 139                         new ConnectionsWeakRef(connsRef, queue);
 140 
 141                 // Keep the weak reference through the element of a linked list
 142                 weakRefs.add(weakRef);
 143             }
 144         }
 145 
 146         d("get(): size after: ", map.size());
 147 
 148         return conns.get(timeout, factory); // get one connection from list
 149     }
 150 
 151     private Connections getConnections(Object id) {
 152         ConnectionsRef ref = map.get(id);
 153         return (ref != null) ? ref.getConnections() : null;
 154     }
 155 
 156     /**
 157      * Goes through the connections in this Pool and expires ones that
 158      * have been idle before 'threshold'. An expired connection is closed
 159      * and then removed from the pool (removePooledConnection() will eventually
 160      * be called, and the list of pools itself removed if it becomes empty).
 161      *
 162      * @param threshold connections idle before 'threshold' should be closed
 163      *          and removed.
 164      */
 165     public void expire(long threshold) {
 166         synchronized (map) {
 167             Iterator<ConnectionsRef> iter = map.values().iterator();

 168             Connections conns;
 169             while (iter.hasNext()) {
 170                 conns = iter.next().getConnections();
 171                 if (conns.expire(threshold)) {
 172                     d("expire(): removing ", conns);
 173                     iter.remove();
 174                 }
 175             }
 176         }
 177         expungeStaleConnections();
 178     }
 179 
 180     /*
 181      * Closes the connections contained in the ConnectionsRef object that
 182      * is going to be reclaimed by the GC. Called by getPooledConnection()
 183      * and expire() methods of this class.
 184      */
 185     private static void expungeStaleConnections() {
 186         ConnectionsWeakRef releaseRef = null;
 187         while ((releaseRef = (ConnectionsWeakRef) queue.poll())
 188                                         != null) {
 189             Connections conns = releaseRef.getConnections();
 190 
 191             if (debug) {
 192                 System.err.println(
 193                         "weak reference cleanup: Closing Connections:" + conns);
 194             }
 195 
 196             // cleanup
 197             conns.close();
 198             weakRefs.remove(releaseRef);
 199             releaseRef.clear();
 200          }
 201     }
 202 
 203 
 204     public void showStats(PrintStream out) {

 205         Object id;
 206         Connections conns;
 207 
 208         out.println("===== Pool start ======================");
 209         out.println("maximum pool size: " + maxSize);
 210         out.println("preferred pool size: " + prefSize);
 211         out.println("initial pool size: " + initSize);
 212         out.println("current pool size: " + map.size());
 213 
 214         for (Map.Entry<Object, ConnectionsRef> entry : map.entrySet()) {




 215             id = entry.getKey();
 216             conns = entry.getValue().getConnections();
 217             out.println("   " + id + ":" + conns.getStats());
 218         }
 219 
 220         out.println("====== Pool end =====================");
 221     }
 222 
 223     public String toString() {
 224         return super.toString() + " " + map.toString();
 225     }
 226 
 227     private void d(String msg, int i) {
 228         if (debug) {
 229             System.err.println(this + "." + msg + i);
 230         }
 231     }
 232 
 233     private void d(String msg, Object obj) {
 234         if (debug) {
 235             System.err.println(this + "." + msg + obj);
 236         }