HArrayPool.java

00001 
00031 package org.objectweb.jonas.resource.pool.lib;
00032 
00033 import java.util.HashSet;
00034 import java.util.Hashtable;
00035 import java.util.LinkedList;
00036 import java.util.Iterator;
00037 import java.util.Vector;
00038 
00039 import javax.resource.spi.ManagedConnection;
00040 
00041 import org.objectweb.jonas.resource.pool.api.Pool;
00042 import org.objectweb.jonas.resource.pool.api.PoolItemStats;
00043 import org.objectweb.jonas.resource.pool.api.PoolMatchFactory;
00044 import org.objectweb.util.monolog.api.BasicLevel;
00045 import org.objectweb.util.monolog.api.Logger;
00046 
00055 public class HArrayPool implements Pool {
00056 
00060     private Logger logger = null;
00061 
00065     private long timeout = 0;
00069     private PoolMatchFactory matchFactory = null;
00073     private HashSet freeList = null;
00077     private LinkedList linkList = null;
00081     private HashSet activeList = null;
00085     private Hashtable infoList = null;
00086 
00090     private static final int NO_LIMIT = -1;
00091 
00095     private static final long ONE_DAY = 1440L * 60L * 1000L;
00096 
00101     private static final int MAX_REMOVE_FREELIST = 10;
00102 
00106     private int busyMin = 0;
00107 
00111     private int busyMax = 0;
00112 
00116     private int initSize = -1;
00117 
00121     private long maxAge = 0;
00122 
00126     private long maxOpentime = 0;
00127 
00131     private int maxSize = -1;
00132 
00136     private int maxWaiters = 1000;
00137 
00141     private long maxWaitTimeout = 10000;
00142 
00146     private int minSize = 0;
00147 
00151     private HArrayPoolMonitor poolMonitor = null;
00152 
00156     private int samplingPeriod = 60; // defaultSamplingPeriod;
00157 
00161     private int waiterCount = 0;
00162 
00166     private long waitingTime = 0;
00167 
00168 
00173     public HArrayPool(Logger logger) {
00174         this.logger = logger;
00175         freeList = new HashSet();
00176         linkList = new LinkedList();
00177         activeList = new HashSet();
00178         infoList = new Hashtable();
00179     }
00180 
00181     // ----------------------------------------------------------------
00182     // Config properties (Getters & Setters)
00183     // ----------------------------------------------------------------
00184 
00188     public int getCurrentBusy() {
00189         return activeList.size();
00190     }
00191 
00195     public int getCurrentOpened() {
00196         return getSize();
00197     }
00198 
00202     public int getInitSize() {
00203         return initSize;
00204     }
00205 
00209     public synchronized void setInitSize(int initsize) throws Exception {
00210         if (matchFactory == null) {
00211             throw new Exception("The matchFactory is mandatory!");
00212         }
00213         if (initSize < 0 && initsize >= 0) {
00214             initSize = initsize;
00215             setInitSize();
00216         }
00217     }
00218 
00223     private void setInitSize() throws Exception {
00224         int initsize;
00225 
00226         if (initSize <= 0) {
00227             return;
00228         }
00229 
00230         if (maxSize < 0) {
00231             initsize = initSize;
00232         } else {
00233             initsize = initSize < maxSize ? initSize : maxSize;
00234         }
00235         initsize = initsize < minSize ? 0 : initsize - minSize;
00236 
00237         ManagedConnection res;
00238         for (int i = 0; i < initsize; i++) {
00239             res = createResource(null);
00240             freeList.add(res);
00241             linkList.addLast(res);
00242             infoList.put(res, new PoolItemStats());
00243         }
00244     }
00245 
00249     public long getMaxAge() {
00250         return maxAge;
00251     }
00252 
00256     public void setMaxAge(long maxAge) {
00257         this.maxAge = maxAge;
00258         if (maxOpentime == 0) {
00259             maxOpentime = maxAge;
00260         }
00261     }
00262 
00266     public long getMaxOpentime() {
00267         return maxOpentime;
00268     }
00269 
00273     public void setMaxOpentime(long mx) {
00274         maxOpentime = mx;
00275     }
00276 
00280     public int getMaxSize() {
00281         return maxSize;
00282     }
00283 
00287     public synchronized void setMaxSize(int maxsize) throws Exception {
00288         if (matchFactory == null) {
00289             throw new Exception("The matchFactory mandatory!!");
00290         }
00291         if (maxsize < minSize || maxsize == maxSize) {
00292             return;
00293         }
00294 
00295         // Determine if we need to adjust the pool
00296         if (maxsize < 0) {
00297             if (currentWaiters > 0) {
00298                 notify();
00299             }
00300             maxSize = maxsize;
00301         } else {
00302             if (currentWaiters > 0 && maxSize < maxsize) {
00303                 notify();
00304             }
00305             maxSize = maxsize;
00306             adjust();
00307         }
00308     }
00309 
00313     public int getMaxWaiters() {
00314         return maxWaiters;
00315     }
00316 
00320     public void setMaxWaiters(int nb) {
00321         maxWaiters = nb;
00322     }
00323 
00327     public int getMaxWaitTime() {
00328         return (int) (maxWaitTimeout / 1000L);
00329     }
00330 
00334     public void setMaxWaitTime(int sec) {
00335         maxWaitTimeout = sec * 1000L;
00336     }
00337 
00341     public int getMinSize() {
00342         return minSize;
00343     }
00344 
00348     public synchronized void setMinSize(int minsize) throws Exception {
00349         if (matchFactory == null) {
00350             throw new Exception("A matchFactory is mandatory!");
00351         }
00352         if ((minsize < 0) || (minsize > maxSize) || (minsize == minSize)) {
00353             return;
00354         }
00355         if (minsize < minSize) {
00356             minSize = minsize;
00357             return;
00358         }
00359         minSize = minsize;
00360         adjust();
00361     }
00362 
00366     public int getSamplingPeriod() {
00367         return samplingPeriod;
00368     }
00369 
00373     public void setSamplingPeriod(int sec) {
00374         if (sec > 0) {
00375             samplingPeriod = sec;
00376             poolMonitor.setSamplingPeriod(sec);
00377         }
00378     }
00379 
00384     public int getSize() {
00385         return (activeList.size() + freeList.size());
00386     }
00387 
00391     public long getTimeout() {
00392         return timeout;
00393     }
00394 
00398     public synchronized void setTimeout(long crto) {
00399     }
00400 
00401 
00402     // ----------------------------------------------------------------
00403     // Monitoring Attributes
00404     // Each attribute should have a get accessor.
00405     // ----------------------------------------------------------------
00406 
00410     private int busyMaxRecent = 0;
00411 
00415     public int getBusyMaxRecent() {
00416         return busyMaxRecent;
00417     }
00418 
00422     private int busyMinRecent = 0;
00423 
00427     public int getBusyMinRecent() {
00428         return busyMinRecent;
00429     }
00430 
00434     private int currentWaiters = 0;
00435 
00439     public int getCurrentWaiters() {
00440         return currentWaiters;
00441     }
00442 
00446     private int openedCount = 0;
00447 
00451     public int getOpenedCount() {
00452         return openedCount;
00453     }
00454 
00458     private int connectionFailures = 0;
00459 
00463     public int getConnectionFailures() {
00464         return connectionFailures;
00465     }
00466 
00472     private int connectionLeaks = 0;
00473 
00477     public int getConnectionLeaks() {
00478         return connectionLeaks;
00479     }
00480 
00484     private int servedOpen = 0;
00485 
00489     public int getServedOpen() {
00490         return servedOpen;
00491     }
00492 
00496     private int rejectedFull = 0;
00497 
00501     public int getRejectedFull() {
00502         return rejectedFull;
00503     }
00504 
00508     private int rejectedTimeout = 0;
00509 
00513     public int getRejectedTimeout() {
00514         return rejectedTimeout;
00515     }
00516 
00520     private int rejectedOther = 0;
00521 
00525     public int getRejectedOther() {
00526         return rejectedOther;
00527     }
00528 
00532     public int getRejectedOpen() {
00533         return rejectedFull + rejectedTimeout + rejectedOther;
00534     }
00535 
00539     private int waitersHigh = 0;
00540 
00544     public int getWaitersHigh() {
00545         return waitersHigh;
00546     }
00547 
00551     private int waitersHighRecent = 0;
00552 
00556     public int getWaitersHighRecent() {
00557         return waitersHighRecent;
00558     }
00559 
00563     private int totalWaiterCount = 0;
00564 
00568     public int getWaiterCount() {
00569         return totalWaiterCount;
00570     }
00571 
00575     private long totalWaitingTime = 0;
00576 
00580     public long getWaitingTime() {
00581         return totalWaitingTime;
00582     }
00583 
00587     private long waitingHigh = 0;
00588 
00592     public long getWaitingHigh() {
00593         return waitingHigh;
00594     }
00595 
00599     private long waitingHighRecent = 0;
00600 
00604     public long getWaitingHighRecent() {
00605         return waitingHighRecent;
00606     }
00607 
00608     // IMPLEMENTATION OF METHODS FROM THE Pool INTERFACE
00609 
00613     public synchronized Object getResource(Object hints)
00614         throws Exception {
00615 
00616         if (matchFactory == null) {
00617             throw new Exception("The matchFactory mandatory!!");
00618         }
00619         ManagedConnection res = null;
00620         long timetowait = maxWaitTimeout;
00621         long starttime = 0;
00622         while (res == null) {
00623             if (!freeList.isEmpty()) {
00624                 try {
00625                     logger.log(BasicLevel.DEBUG, "Free entries available");
00626                     res = (ManagedConnection) matchFactory.matchResource(freeList, hints);
00627                     if (res != null) {
00628                         freeList.remove(res);
00629                         linkList.remove(res);
00630                         activeList.add(res);
00631                     }
00632                 } catch (Exception ex) {
00633                     logger.log(BasicLevel.DEBUG, "Error from matchResource" + ex);
00634                 }
00635             }
00636             if (res == null) {
00637                 int curSize = activeList.size() + freeList.size();
00638                 if (maxSize < 0 || curSize < maxSize) {
00639                     res = createResource(hints);
00640                     activeList.add(res);
00641                 } else if (freeList.size() > 0) {
00642                     res = (ManagedConnection) linkList.getFirst();
00643                     matchFactory.releaseResource(res);
00644                     res.destroy();
00645                     freeList.remove(res);
00646                     linkList.remove(res);
00647                     infoList.remove(res);
00648                     // Create a new one and return it
00649                     res = createResource(hints);
00650                     activeList.add(res);
00651                 } else {
00652                     boolean stoplooping = true;
00653                     // Determine if waiting is an option
00654                     if (timetowait > 0) {
00655                         if (currentWaiters < maxWaiters) {
00656                             currentWaiters++;
00657                             // Store the maximum concurrent waiters
00658                             if (waiterCount < currentWaiters) {
00659                                 waiterCount = currentWaiters;
00660                             }
00661                             if (starttime == 0) {
00662                                 starttime = System.currentTimeMillis();
00663                                 logger.log(BasicLevel.DEBUG, "Wait for a free Connection");
00664                             }
00665                             try {
00666                                 wait(timetowait);
00667                             } catch (InterruptedException ign) {
00668                                 logger.log(BasicLevel.WARN, "Interrupted");
00669                             } finally {
00670                                 currentWaiters--;
00671                             }
00672                             long stoptime = System.currentTimeMillis();
00673                             long stillwaited = stoptime - starttime;
00674                             timetowait = maxWaitTimeout - stillwaited;
00675                             stoplooping = (timetowait <= 0);
00676                             if (stoplooping) {
00677                                 // We have been woken up by the timeout.
00678                                 totalWaiterCount++;
00679                                 totalWaitingTime += stillwaited;
00680                                 if (waitingTime < stillwaited) {
00681                                     waitingTime = stillwaited;
00682                                 }
00683                             } else {
00684                                 if (!freeList.isEmpty()) {
00685                                     // We have been notified by a connection release.
00686                                     logger.log(BasicLevel.DEBUG, "Notified after " + stillwaited);
00687                                     totalWaiterCount++;
00688                                     totalWaitingTime += stillwaited;
00689                                     if (waitingTime < stillwaited) {
00690                                         waitingTime = stillwaited;
00691                                     }
00692                                 }
00693                                 continue;
00694                             }
00695                         }
00696                     }
00697                     if (stoplooping && freeList.isEmpty()) {
00698                         if (starttime > 0) {
00699                             rejectedTimeout++;
00700                             logger.log(BasicLevel.WARN, "Cannot create a Connection - timeout");
00701                         } else {
00702                             rejectedFull++;
00703                             logger.log(BasicLevel.WARN, "Cannot create a Connection");
00704                         }
00705                         throw new Exception("No more connections");
00706                     }
00707                 }
00708             }
00709         }
00710         infoList.put(res, new PoolItemStats());
00711 
00712         printLists();
00713         setItemStats(res);
00714         recomputeBusy();
00715         return res;
00716     }
00717 
00724     private ManagedConnection createResource(Object hints) throws Exception {
00725         ManagedConnection res = null;
00726         try {
00727             res = (ManagedConnection) matchFactory.createResource(hints);
00728             if (res == null) {
00729                 Exception exc = new Exception("A null ManagedConnection was returned.");
00730                 throw exc;
00731             }
00732             openedCount++;
00733         } catch (Exception ex) {
00734             connectionFailures++;
00735             rejectedOther++;
00736             logger.log(BasicLevel.DEBUG, "Cannot create new Connection: " + ex);
00737             throw ex;
00738         }
00739         logger.log(BasicLevel.DEBUG, "Created Resource: " + res);
00740         return res;
00741     }
00742 
00746     public synchronized void releaseResource(Object resource, boolean destroy, boolean adjustment)
00747         throws Exception {
00748 
00749         ManagedConnection res = (ManagedConnection) resource;
00750         if (matchFactory == null) {
00751             throw new Exception("The matchFactory mandatory!!");
00752         }
00753         if (activeList == null) {
00754             throw new Exception("No active resources to releases!!");
00755         }
00756         if (!activeList.contains(res)) {
00757             //Temp fix making the assumption that the item is already released
00758             return;
00759             //throw new Exception("Attempt to release inactive resource(" + res + ")");
00760         }
00761         activeList.remove(res);
00762         if (!destroy) {
00763             freeList.add(res);
00764             linkList.addLast(res);
00765             PoolItemStats pis = (PoolItemStats) infoList.get(res);
00766             if (pis != null) {
00767                 pis.setTotalConnectionTime(System.currentTimeMillis() - pis.getStartTime());
00768             }
00769         } else {
00770             infoList.remove(res);
00771             res.destroy();
00772         }
00773         // Notify 1 thread waiting for a Connection.
00774         if (currentWaiters > 0) {
00775             notify();
00776         }
00777         if (adjustment) {
00778             adjust();
00779         }
00780     }
00781 
00785     public PoolMatchFactory getMatchFactory() {
00786         return matchFactory;
00787     }
00788 
00792     public synchronized void setMatchFactory(PoolMatchFactory pmf) {
00793         matchFactory = pmf;
00794     }
00795 
00799     public void startMonitor() {
00800         poolMonitor = new HArrayPoolMonitor(this);
00801         poolMonitor.start();
00802     }
00803 
00807     public void validateMCs() throws Exception {
00808         matchFactory.validateResource(freeList);
00809     }
00810 
00816     public synchronized void adjust() throws Exception {
00817         // Remove max aged elements in freelist
00818         // - Not more than MAX_REMOVE_FREELIST
00819         // - Don't reduce pool size less than minSize
00820         //logger.log(BasicLevel.DEBUG, "");
00821         int count = activeList.size() - minSize;
00822         long curTime = System.currentTimeMillis();
00823         if (count > 0) {
00824             if (count > MAX_REMOVE_FREELIST) {
00825                 count = MAX_REMOVE_FREELIST;
00826             }
00827             Vector rList = new Vector();
00828             Iterator it = null;
00829             for (it = freeList.iterator(); it.hasNext();) {
00830                 ManagedConnection res = (ManagedConnection) it.next();
00831                 PoolItemStats pis = (PoolItemStats) infoList.get(res);
00832                 if (maxOpentime > 0 && pis != null && pis.getMaxOpenTimeout() > 0
00833                         && curTime > pis.getMaxOpenTimeout()) {
00834                     rList.add(res);
00835                 }
00836             }
00837             // Bug: 300351 Use the list built above to remove the MCs
00838             it = rList.iterator();
00839             while (it.hasNext()) {
00840                 ManagedConnection res = (ManagedConnection) it.next();
00841                 try {
00842                     matchFactory.releaseResource(res);
00843                 } catch (Exception ex) {
00844                     ex.printStackTrace();
00845                 }
00846                 freeList.remove(res);
00847                 try {
00848                     res.destroy();
00849                 } catch (Exception ex) {
00850                     ex.printStackTrace();
00851                 }
00852                 linkList.remove(res);
00853             }
00854         }
00855 
00856         // Close (physically) connections lost (opened for too long time)
00857         curTime = System.currentTimeMillis();
00858         Vector aList = new Vector();
00859         Iterator it = null;
00860         for (it = activeList.iterator(); it.hasNext();) {
00861             ManagedConnection res = (ManagedConnection) it.next();
00862             PoolItemStats pis = (PoolItemStats) infoList.get(res);
00863             if (maxOpentime > 0 && pis != null && pis.getMaxOpenTimeout() > 0
00864                     && curTime > pis.getMaxOpenTimeout()) {
00865                 aList.add(res);
00866             }
00867         }
00868         it = aList.iterator();
00869         while (it.hasNext()) {
00870             ManagedConnection item = (ManagedConnection) it.next();
00871             logger.log(BasicLevel.WARN, "close a timed out active connection");
00872             logger.log(BasicLevel.WARN, "MC = " + item);
00873             releaseResource(item, true, false);
00874             connectionLeaks++;
00875         }
00876 
00877 
00878         int curSize = activeList.size() + freeList.size();
00879         if (maxSize > 0 && maxSize < curSize) {
00880             // Removes as many free entries as possible
00881             int nbRemove = curSize - maxSize;
00882             if (freeList != null) {
00883                 while (!freeList.isEmpty() && nbRemove > 0) {
00884                     ManagedConnection res = (ManagedConnection) linkList.getFirst();
00885                     matchFactory.releaseResource(res);
00886                     res.destroy();
00887                     freeList.remove(res);
00888                     linkList.remove(res);
00889                     infoList.remove(res);
00890                     nbRemove--;
00891                     curSize--;
00892                 }
00893             }
00894         }
00895 
00896         // Recreate more Connections while minSize is not reached
00897         ManagedConnection res;
00898         while (minSize > curSize) {
00899             res = createResource(null);
00900             freeList.add(res);
00901             linkList.addLast(res);
00902             infoList.put(res, new PoolItemStats());
00903             curSize++;
00904         }
00905 
00906         recomputeBusy();
00907     }
00908 
00912     public void recomputeBusy() {
00913         int busy = getCurrentBusy();
00914         if (busyMax < busy) {
00915             busyMax = busy;
00916         }
00917         if (busyMin > busy) {
00918             busyMin = busy;
00919         }
00920     }
00921 
00925     public void sampling() throws Exception {
00926         //matchFactory.sampling();
00927         waitingHighRecent = waitingTime;
00928         if (waitingHigh < waitingTime) {
00929             waitingHigh = waitingTime;
00930         }
00931         waitingTime = 0;
00932 
00933         waitersHighRecent = waiterCount;
00934         if (waitersHigh < waiterCount) {
00935             waitersHigh = waiterCount;
00936         }
00937         waiterCount = 0;
00938 
00939         busyMaxRecent = busyMax;
00940         busyMax = getCurrentBusy();
00941         busyMinRecent = busyMin;
00942         busyMin = getCurrentBusy();
00943     }
00944 
00949     private void setItemStats(Object res) {
00950         PoolItemStats pis = (PoolItemStats) infoList.get(res);
00951         if (pis != null) {
00952             pis.incrementUses();
00953             long sTime = System.currentTimeMillis();
00954             pis.setStartTime(sTime);
00955             if (maxAge > 0 && pis.getMaxAgeTimeout() == 0) {
00956                 pis.setMaxAgeTimeout(sTime + maxAge);
00957             }
00958             if (maxOpentime > 0) {
00959                 pis.setMaxOpenTimeout(sTime + maxOpentime);
00960             }
00961         }
00962         servedOpen++;
00963     }
00964 
00969     void printLists() {
00970         int count = 0;
00971         if (logger.isLoggable(BasicLevel.DEBUG)) {
00972             logger.log(BasicLevel.DEBUG, "minSize=" + minSize + ", maxSize=" + maxSize
00973                                          + ",  freeSize=" + freeList.size());
00974             logger.log(BasicLevel.DEBUG, "activeList:");
00975             if (activeList == null) {
00976                 logger.log(BasicLevel.DEBUG, " null");
00977             } else {
00978                 Iterator it = activeList.iterator();
00979                 while (it.hasNext() && ++count < 40) {
00980                     logger.log(BasicLevel.DEBUG, " " + (ManagedConnection) it.next());
00981                 }
00982             }
00983             logger.log(BasicLevel.DEBUG, "freeList:");
00984             if (freeList == null) {
00985                 logger.log(BasicLevel.DEBUG, " null");
00986             } else {
00987                 count = 0;
00988                 Iterator it = freeList.iterator();
00989                 while (it.hasNext() && ++count < 40) {
00990                     logger.log(BasicLevel.DEBUG, " " + (ManagedConnection) it.next());
00991                 }
00992             }
00993         }
00994     }
00995 
00996 }

Generated on Tue Feb 15 15:05:19 2005 for JOnAS by  doxygen 1.3.9.1