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;
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
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
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
00404
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
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
00649 res = createResource(hints);
00650 activeList.add(res);
00651 } else {
00652 boolean stoplooping = true;
00653
00654 if (timetowait > 0) {
00655 if (currentWaiters < maxWaiters) {
00656 currentWaiters++;
00657
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
00678 totalWaiterCount++;
00679 totalWaitingTime += stillwaited;
00680 if (waitingTime < stillwaited) {
00681 waitingTime = stillwaited;
00682 }
00683 } else {
00684 if (!freeList.isEmpty()) {
00685
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
00758 return;
00759
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
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
00818
00819
00820
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
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
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
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
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
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 }