0001: /**
0002: * JOnAS: Java(TM) Open Application Server
0003: * Copyright (C) 1999 Bull S.A.
0004: * Contact: jonas-team@objectweb.org
0005: *
0006: * ObjectWeb Connector: an implementation of JCA Sun specification along
0007: * with some extensions of this specification.
0008: * Copyright (C) 2001-2002 France Telecom R&D - INRIA
0009: *
0010: * This library is free software; you can redistribute it and/or
0011: * modify it under the terms of the GNU Lesser General Public
0012: * License as published by the Free Software Foundation; either
0013: * version 2 of the License, or (at your option) any later version.
0014: *
0015: * This library is distributed in the hope that it will be useful,
0016: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0017: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0018: * Lesser General Public License for more details.
0019: *
0020: * You should have received a copy of the GNU Lesser General Public
0021: * License along with this library; if not, write to the Free Software
0022: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0023: *
0024: * Based on LArrayPool in ObjectWeb common
0025: *
0026: * --------------------------------------------------------------------------
0027: * $Id: HArrayPool.java 9932 2007-01-18 00:03:16Z ehardesty $
0028: * --------------------------------------------------------------------------
0029: */package org.objectweb.jonas.resource.pool.lib;
0030:
0031: import java.sql.Connection;
0032: import java.sql.SQLException;
0033: import java.util.LinkedHashSet;
0034: import java.util.HashSet;
0035: import java.util.Hashtable;
0036: import java.util.Iterator;
0037: import java.util.Vector;
0038:
0039: import javax.resource.spi.ManagedConnection;
0040:
0041: import org.objectweb.jonas.common.Log;
0042: import org.objectweb.jonas.resource.ConnectionManagerImpl;
0043: import org.objectweb.jonas.resource.pool.api.Pool;
0044: import org.objectweb.jonas.resource.pool.api.PoolItemStats;
0045: import org.objectweb.jonas.resource.pool.api.PoolMatchFactory;
0046: import org.objectweb.util.monolog.api.BasicLevel;
0047: import org.objectweb.util.monolog.api.Logger;
0048:
0049: /**
0050: * The class <b>HArrayPool</b> implements a Pool as a HashSet of ManagedConnections,
0051: * managing free/active resources.
0052: *
0053: * Updated to use an LRU list of free resources
0054: *
0055: * Author: Eric HARDESTY
0056: */
0057: public class HArrayPool implements Pool {
0058:
0059: /**
0060: * The Logger instance where messages are written.
0061: */
0062: private Logger logger = null;
0063: private Logger conLogger = null;
0064:
0065: /**
0066: * timeout value
0067: */
0068: private long timeout = 0;
0069: /**
0070: * Pool match factory for this pool
0071: */
0072: private PoolMatchFactory matchFactory = null;
0073: /**
0074: * Free list of ManagedConnections
0075: */
0076: private LinkedHashSet freeList = null;
0077: /**
0078: * Active list of ManagedConnections
0079: */
0080: private HashSet activeList = null;
0081: /**
0082: * PoolItem information list
0083: */
0084: private Hashtable infoList = null;
0085:
0086: /**
0087: * No Pooling is desired. Objects are just wrappers until any
0088: * transactional states have been updated as needed
0089: */
0090: private static final int NO_POOLING = -2;
0091:
0092: /**
0093: * High Value for no limit for the connection pool
0094: */
0095: private static final int NO_LIMIT = -1;
0096:
0097: /**
0098: * Nb of milliseconds in a day
0099: */
0100: private static final long ONE_DAY = 1440L * 60L * 1000L;
0101:
0102: /**
0103: * max number of remove at once in the freelist
0104: * We avoid removing too many items at once for perf reasons.
0105: */
0106: private static final int MAX_REMOVE_FREELIST = 10;
0107:
0108: /**
0109: * count min busy connection during current period.
0110: */
0111: private int busyMin = 0;
0112:
0113: /**
0114: * count max busy connection during current period.
0115: */
0116: private int busyMax = 0;
0117:
0118: /**
0119: * initial size of the pool
0120: */
0121: private int initSize = -1;
0122:
0123: /**
0124: * jdbcConnLevel of the pool
0125: */
0126: private int jdbcConnLevel = 0;
0127:
0128: /**
0129: * initial jdbcTestStatement
0130: */
0131: private String jdbcTestStatement = "";
0132:
0133: /**
0134: * max age a connection will be available for use
0135: */
0136: private int maxAge = 0;
0137:
0138: /**
0139: * max open time for a connection, in minutes
0140: */
0141: private int maxOpentime = 0;
0142:
0143: /**
0144: * max size of the pool
0145: */
0146: private int maxSize = -1;
0147:
0148: /**
0149: * max nb of waiters allowed to wait for a Connection
0150: */
0151: private int maxWaiters = 1000;
0152:
0153: /**
0154: * max nb of milliseconds to wait for a connection when pool is full
0155: */
0156: private long maxWaitTimeout = 10000;
0157:
0158: /**
0159: * minimum size of the pool
0160: */
0161: private int minSize = 0;
0162:
0163: /**
0164: * min limit has been reached
0165: */
0166: private boolean minLimit = false;
0167:
0168: /**
0169: * pool monitor
0170: */
0171: private HArrayPoolMonitor poolMonitor = null;
0172:
0173: /**
0174: * sampling period in sec.
0175: */
0176: private int samplingPeriod = 60; // defaultSamplingPeriod;
0177:
0178: /**
0179: * count max waiters during current period.
0180: */
0181: private int waiterCount = 0;
0182:
0183: /**
0184: * count max waiting time during current period.
0185: */
0186: private long waitingTime = 0;
0187:
0188: /**
0189: * The jndiname
0190: */
0191: private String jndiName = null;
0192:
0193: /**
0194: * Pool closed indicator
0195: */
0196: private boolean poolClosed = false;
0197:
0198: /**
0199: * HArrayPool constructor
0200: * @param logger Logger for the pool to use
0201: */
0202: public HArrayPool(Logger logger, String jndiname) {
0203: this .logger = logger;
0204: if (conLogger == null) {
0205: conLogger = Log.getLogger(Log.JONAS_JCA_PREFIX
0206: + ".connection");
0207: }
0208: freeList = new LinkedHashSet();
0209: activeList = new HashSet();
0210: infoList = new Hashtable();
0211: jndiName = jndiname;
0212: }
0213:
0214: // ----------------------------------------------------------------
0215: // Config properties (Getters & Setters)
0216: // ----------------------------------------------------------------
0217:
0218: /**
0219: * @return int number of busy connections
0220: */
0221: public int getCurrentBusy() {
0222: return activeList.size();
0223: }
0224:
0225: /**
0226: * @return int number of opened connections
0227: */
0228: public int getCurrentOpened() {
0229: return getSize();
0230: }
0231:
0232: /**
0233: * @see org.objectweb.jonas.resource.pool.api.Pool#getInitSize
0234: */
0235: public int getInitSize() {
0236: return initSize;
0237: }
0238:
0239: /**
0240: * @see org.objectweb.jonas.resource.pool.api.Pool#setInitSize
0241: */
0242: public synchronized void setInitSize(int initsize) throws Exception {
0243: if (matchFactory == null) {
0244: throw new Exception("The matchFactory is mandatory!");
0245: }
0246: if (initSize < 0 && initsize >= 0) {
0247: initSize = initsize;
0248: setInitSize();
0249: }
0250: }
0251:
0252: /**
0253: * Internal setInitSize
0254: * @throws Exception if an error is encountered
0255: */
0256: private void setInitSize() throws Exception {
0257: int initsize;
0258:
0259: if (initSize <= 0 || maxSize == NO_POOLING) {
0260: return;
0261: }
0262:
0263: if (maxSize < 0) {
0264: initsize = initSize;
0265: } else {
0266: initsize = initSize < maxSize ? initSize : maxSize;
0267: }
0268: if (initsize >= minSize) {
0269: minLimit = true;
0270: }
0271:
0272: ManagedConnection res;
0273: synchronized (this ) {
0274: for (int i = 0; i < initsize; i++) {
0275: res = createResource(null);
0276: freeList.add(res);
0277: infoList.put(res, new PoolItemStats());
0278: setItemStats(res);
0279: }
0280: }
0281: }
0282:
0283: /**
0284: * @see org.objectweb.jonas.resource.pool.api.Pool#getJdbcConnLevel
0285: */
0286: public int getJdbcConnLevel() {
0287: return jdbcConnLevel;
0288: }
0289:
0290: /**
0291: * @see org.objectweb.jonas.resource.pool.api.Pool#setJdbcConnLevel
0292: */
0293: public void setJdbcConnLevel(int jdbcConnLevel) {
0294: this .jdbcConnLevel = jdbcConnLevel;
0295: }
0296:
0297: /**
0298: * @see org.objectweb.jonas.resource.pool.api.Pool#getJdbcTestStatement
0299: */
0300: public String getJdbcTestStatement() {
0301: return jdbcTestStatement;
0302: }
0303:
0304: /**
0305: * @see org.objectweb.jonas.resource.pool.api.Pool#setJdbcTestStatement
0306: */
0307: public void setJdbcTestStatement(String jdbcTestStatement) {
0308: this .jdbcTestStatement = jdbcTestStatement;
0309: }
0310:
0311: /**
0312: * @see org.objectweb.jonas.resource.pool.api.Pool#getMaxAge
0313: */
0314: public int getMaxAge() {
0315: return maxAge;
0316: }
0317:
0318: /**
0319: * @see org.objectweb.jonas.resource.pool.api.Pool#setMaxAge
0320: */
0321: public void setMaxAge(int maxAge) {
0322: this .maxAge = maxAge;
0323: }
0324:
0325: /**
0326: * @return max age for connections (in mns)
0327: */
0328: public int getMaxOpentime() {
0329: return maxOpentime;
0330: }
0331:
0332: /**
0333: * @param mx max time of open connection in minutes
0334: */
0335: public void setMaxOpentime(int mx) {
0336: maxOpentime = mx;
0337: }
0338:
0339: /**
0340: * @see org.objectweb.jonas.resource.pool.api.Pool#getMaxSize
0341: */
0342: public int getMaxSize() {
0343: return maxSize;
0344: }
0345:
0346: /**
0347: * @see org.objectweb.jonas.resource.pool.api.Pool#setMaxSize
0348: */
0349: public synchronized void setMaxSize(int maxsize) throws Exception {
0350: if (matchFactory == null) {
0351: throw new Exception("The matchFactory mandatory!!");
0352: }
0353: if ((maxsize < minSize && maxsize > 0) || maxsize == maxSize) {
0354: return;
0355: }
0356:
0357: // Determine if we need to adjust the pool
0358: if (maxsize < 0) {
0359: if (currentWaiters > 0) {
0360: notify();
0361: }
0362: maxSize = maxsize;
0363: } else {
0364: if (currentWaiters > 0 && maxSize < maxsize) {
0365: notify();
0366: }
0367: maxSize = maxsize;
0368: adjust();
0369: }
0370: }
0371:
0372: /**
0373: * @return max nb of waiters
0374: */
0375: public int getMaxWaiters() {
0376: return maxWaiters;
0377: }
0378:
0379: /**
0380: * @param nb max nb of waiters
0381: */
0382: public void setMaxWaiters(int nb) {
0383: maxWaiters = nb;
0384: }
0385:
0386: /**
0387: * @return waiter timeout in seconds
0388: */
0389: public int getMaxWaitTime() {
0390: return (int) (maxWaitTimeout / 1000L);
0391: }
0392:
0393: /**
0394: * @param sec max time to wait for a connection, in seconds
0395: */
0396: public void setMaxWaitTime(int sec) {
0397: maxWaitTimeout = sec * 1000L;
0398: }
0399:
0400: /**
0401: * @see org.objectweb.jonas.resource.pool.api.Pool#getMinSize
0402: */
0403: public int getMinSize() {
0404: return minSize;
0405: }
0406:
0407: /**
0408: * @see org.objectweb.jonas.resource.pool.api.Pool#setMinSize
0409: */
0410: public synchronized void setMinSize(int minsize) throws Exception {
0411: if (matchFactory == null) {
0412: throw new Exception("A matchFactory is mandatory!");
0413: }
0414: if ((minsize < 0) || (minsize > maxSize)
0415: || (minsize == minSize)) {
0416: return;
0417: }
0418: if (minsize < minSize) {
0419: minSize = minsize;
0420: return;
0421: }
0422: minSize = minsize;
0423: adjust();
0424: }
0425:
0426: /**
0427: * @return sampling period in sec.
0428: */
0429: public int getSamplingPeriod() {
0430: return samplingPeriod;
0431: }
0432:
0433: /**
0434: * @param sec sampling period in sec.
0435: */
0436: public void setSamplingPeriod(int sec) {
0437: if (sec > 0) {
0438: samplingPeriod = sec;
0439: poolMonitor.setSamplingPeriod(sec);
0440: }
0441: }
0442:
0443: /**
0444: * Get the size of the pool
0445: * @return int size of the pool
0446: */
0447: public synchronized int getSize() {
0448: return (activeList.size() + freeList.size());
0449: }
0450:
0451: /**
0452: * @see org.objectweb.jonas.resource.pool.api.Pool#getTimeout
0453: */
0454: public long getTimeout() {
0455: return timeout;
0456: }
0457:
0458: /**
0459: * @see org.objectweb.jonas.resource.pool.api.Pool#setTimeout
0460: */
0461: public synchronized void setTimeout(long crto) {
0462: }
0463:
0464: // ----------------------------------------------------------------
0465: // Monitoring Attributes
0466: // Each attribute should have a get accessor.
0467: // ----------------------------------------------------------------
0468:
0469: /**
0470: * maximum nb of busy connections in last sampling period
0471: */
0472: private int busyMaxRecent = 0;
0473:
0474: /**
0475: * @return maximum nb of busy connections in last sampling period
0476: */
0477: public int getBusyMaxRecent() {
0478: return busyMaxRecent;
0479: }
0480:
0481: /**
0482: * minimum nb of busy connections in last sampling period
0483: */
0484: private int busyMinRecent = 0;
0485:
0486: /**
0487: * @return minimum nb of busy connections in last sampling period
0488: */
0489: public int getBusyMinRecent() {
0490: return busyMinRecent;
0491: }
0492:
0493: /**
0494: * nb of threads waiting for a Connection
0495: */
0496: private int currentWaiters = 0;
0497:
0498: /**
0499: * @return current number of connection waiters
0500: */
0501: public int getCurrentWaiters() {
0502: return currentWaiters;
0503: }
0504:
0505: /**
0506: * total number of opened physical connections since the datasource creation.
0507: */
0508: private int openedCount = 0;
0509:
0510: /**
0511: * @return int number of physical jdbc connection opened
0512: */
0513: public int getOpenedCount() {
0514: return openedCount;
0515: }
0516:
0517: /**
0518: * total nb of physical connection failures
0519: */
0520: private int connectionFailures = 0;
0521:
0522: /**
0523: * @return int number of connection failures on open
0524: */
0525: public int getConnectionFailures() {
0526: return connectionFailures;
0527: }
0528:
0529: /**
0530: * total nb of connection leaks.
0531: * A connection leak occurs when the caller never issues a close method
0532: * on the connection.
0533: */
0534: private int connectionLeaks = 0;
0535:
0536: /**
0537: * @return int number of connection leaks
0538: */
0539: public int getConnectionLeaks() {
0540: return connectionLeaks;
0541: }
0542:
0543: /**
0544: * total number of opened connections since the datasource creation.
0545: */
0546: private int servedOpen = 0;
0547:
0548: /**
0549: * @return int number of connection served
0550: */
0551: public int getServedOpen() {
0552: return servedOpen;
0553: }
0554:
0555: /**
0556: * total nb of open connection failures because waiter overflow
0557: */
0558: private int rejectedFull = 0;
0559:
0560: /**
0561: * @return int number of open calls that were rejected due to waiter overflow
0562: */
0563: public int getRejectedFull() {
0564: return rejectedFull;
0565: }
0566:
0567: /**
0568: * total nb of open connection failures because timeout
0569: */
0570: private int rejectedTimeout = 0;
0571:
0572: /**
0573: * @return int number of open calls that were rejected by timeout
0574: */
0575: public int getRejectedTimeout() {
0576: return rejectedTimeout;
0577: }
0578:
0579: /**
0580: * total nb of open connection failures for any other reason.
0581: */
0582: private int rejectedOther = 0;
0583:
0584: /**
0585: * @return int number of open calls that were rejected
0586: */
0587: public int getRejectedOther() {
0588: return rejectedOther;
0589: }
0590:
0591: /**
0592: * @return int number of open calls that were rejected
0593: */
0594: public int getRejectedOpen() {
0595: return rejectedFull + rejectedTimeout + rejectedOther;
0596: }
0597:
0598: /**
0599: * maximum nb of waiters since datasource creation
0600: */
0601: private int waitersHigh = 0;
0602:
0603: /**
0604: * @return maximum nb of waiters since the datasource creation
0605: */
0606: public int getWaitersHigh() {
0607: return waitersHigh;
0608: }
0609:
0610: /**
0611: * maximum nb of waiters in last sampling period
0612: */
0613: private int waitersHighRecent = 0;
0614:
0615: /**
0616: * @return maximum nb of waiters in last sampling period
0617: */
0618: public int getWaitersHighRecent() {
0619: return waitersHighRecent;
0620: }
0621:
0622: /**
0623: * total nb of waiters since datasource creation
0624: */
0625: private int totalWaiterCount = 0;
0626:
0627: /**
0628: * @return total nb of waiters since the datasource creation
0629: */
0630: public int getWaiterCount() {
0631: return totalWaiterCount;
0632: }
0633:
0634: /**
0635: * total waiting time in milliseconds
0636: */
0637: private long totalWaitingTime = 0;
0638:
0639: /**
0640: * @return total waiting time since the datasource creation
0641: */
0642: public long getWaitingTime() {
0643: return totalWaitingTime;
0644: }
0645:
0646: /**
0647: * max waiting time in milliseconds
0648: */
0649: private long waitingHigh = 0;
0650:
0651: /**
0652: * @return max waiting time since the datasource creation
0653: */
0654: public long getWaitingHigh() {
0655: return waitingHigh;
0656: }
0657:
0658: /**
0659: * max waiting time in milliseconds in last sampling period
0660: */
0661: private long waitingHighRecent = 0;
0662:
0663: /**
0664: * @return max waiting time in last sampling period
0665: */
0666: public long getWaitingHighRecent() {
0667: return waitingHighRecent;
0668: }
0669:
0670: // IMPLEMENTATION OF METHODS FROM THE Pool INTERFACE
0671:
0672: /**
0673: * @see org.objectweb.jonas.resource.pool.api.Pool#getResource
0674: */
0675: public Object getResource(Object hints) throws Exception {
0676: return getResource(hints, false);
0677: }
0678:
0679: public synchronized Object getResource(Object hints,
0680: boolean freeListOnly) throws Exception {
0681: if (matchFactory == null) {
0682: throw new Exception("The matchFactory mandatory!!");
0683: }
0684: ManagedConnection res = null;
0685: long timetowait = maxWaitTimeout;
0686: long starttime = 0;
0687: while (res == null) {
0688: if (!freeList.isEmpty()) {
0689: try {
0690: if (logger.isLoggable(BasicLevel.DEBUG)) {
0691: logger.log(BasicLevel.DEBUG,
0692: "Free entries available");
0693: }
0694: res = (ManagedConnection) matchFactory
0695: .matchResource(freeList, hints);
0696: if (res != null) {
0697: freeList.remove(res);
0698: activeList.add(res);
0699: if (conLogger.isLoggable(BasicLevel.DEBUG)) {
0700: conLogger.log(BasicLevel.DEBUG,
0701: "Returned Resource: " + res);
0702: }
0703: }
0704: } catch (Exception ex) {
0705: if (logger.isLoggable(BasicLevel.DEBUG)) {
0706: logger.log(BasicLevel.DEBUG,
0707: "Error from matchResource", ex);
0708: }
0709: }
0710: }
0711: if (res == null && freeListOnly) {
0712: throw new Exception("No Free entry");
0713: }
0714:
0715: if (res == null) {
0716: int curSize = activeList.size() + freeList.size();
0717: if (maxSize < 0 || curSize < maxSize) {
0718: res = createResource(hints);
0719: activeList.add(res);
0720: } else if (freeList.size() > 0) {
0721: res = (ManagedConnection) freeList.iterator()
0722: .next();
0723: matchFactory.releaseResource(res);
0724: res.destroy();
0725: freeList.remove(res);
0726: infoList.remove(res);
0727: // Create a new one and return it
0728: res = createResource(hints);
0729: activeList.add(res);
0730: } else {
0731: boolean stoplooping = true;
0732: // Determine if waiting is an option
0733: if (timetowait > 0) {
0734: if (currentWaiters < maxWaiters) {
0735: currentWaiters++;
0736: // Store the maximum concurrent waiters
0737: if (waiterCount < currentWaiters) {
0738: waiterCount = currentWaiters;
0739: }
0740: if (starttime == 0) {
0741: starttime = System.currentTimeMillis();
0742: if (logger.isLoggable(BasicLevel.DEBUG)) {
0743: logger
0744: .log(BasicLevel.DEBUG,
0745: "Wait for a free Connection");
0746: }
0747: }
0748: try {
0749: wait(timetowait);
0750: } catch (InterruptedException ign) {
0751: logger.log(BasicLevel.WARN,
0752: "Interrupted");
0753: } finally {
0754: currentWaiters--;
0755: }
0756: long stoptime = System.currentTimeMillis();
0757: long stillwaited = stoptime - starttime;
0758: timetowait = maxWaitTimeout - stillwaited;
0759: stoplooping = (timetowait <= 0);
0760: if (stoplooping) {
0761: // We have been woken up by the timeout.
0762: totalWaiterCount++;
0763: totalWaitingTime += stillwaited;
0764: if (waitingTime < stillwaited) {
0765: waitingTime = stillwaited;
0766: }
0767: } else {
0768: if (!freeList.isEmpty()) {
0769: // We have been notified by a connection release.
0770: if (logger
0771: .isLoggable(BasicLevel.DEBUG)) {
0772: logger.log(BasicLevel.DEBUG,
0773: "Notified after "
0774: + stillwaited);
0775: }
0776: totalWaiterCount++;
0777: totalWaitingTime += stillwaited;
0778: if (waitingTime < stillwaited) {
0779: waitingTime = stillwaited;
0780: }
0781: }
0782: continue;
0783: }
0784: }
0785: }
0786: if (stoplooping && freeList.isEmpty()) {
0787: if (starttime > 0) {
0788: rejectedTimeout++;
0789: logger
0790: .log(BasicLevel.WARN,
0791: "Cannot create a Connection - timeout");
0792: } else {
0793: rejectedFull++;
0794: logger.log(BasicLevel.WARN,
0795: "Cannot create a Connection");
0796: }
0797: throw new Exception("No more connections");
0798: }
0799: }
0800: }
0801: }
0802: if (infoList.get(res) == null) {
0803: infoList.put(res, new PoolItemStats());
0804: }
0805:
0806: printLists();
0807: setItemStats(res);
0808: recomputeBusy();
0809: return res;
0810: }
0811:
0812: /**
0813: * Create a resource
0814: * @param hints Object to pass to the matchFactory
0815: * @return ManagedConnection object returned from the matchFactory
0816: * @throws Exception if an exception occured
0817: */
0818: private ManagedConnection createResource(Object hints)
0819: throws Exception {
0820: ManagedConnection res = null;
0821: try {
0822: res = (ManagedConnection) matchFactory
0823: .createResource(hints);
0824: if (res == null) {
0825: Exception exc = new Exception(
0826: "A null ManagedConnection was returned.");
0827: throw exc;
0828: }
0829: openedCount++;
0830: } catch (Exception ex) {
0831: connectionFailures++;
0832: rejectedOther++;
0833: if (logger.isLoggable(BasicLevel.DEBUG)) {
0834: logger.log(BasicLevel.DEBUG,
0835: "Cannot create new Connection", ex);
0836: }
0837: throw ex;
0838: }
0839: if (conLogger.isLoggable(BasicLevel.DEBUG)) {
0840: conLogger.log(BasicLevel.DEBUG, "Created Resource: " + res);
0841: }
0842: if (!minLimit && getSize() >= minSize) {
0843: minLimit = true;
0844: }
0845: return res;
0846: }
0847:
0848: /**
0849: * @see org.objectweb.jonas.resource.pool.api.Pool#releaseResource
0850: */
0851: public synchronized void releaseResource(Object resource,
0852: boolean destroy, boolean adjustment) throws Exception {
0853:
0854: ManagedConnection res = (ManagedConnection) resource;
0855: if (matchFactory == null) {
0856: throw new Exception("The matchFactory mandatory!!");
0857: }
0858: if (activeList == null) {
0859: throw new Exception("No active resources to releases!!");
0860: }
0861: if (!activeList.contains(res)) {
0862: //Temp fix making the assumption that the item is already released
0863: return;
0864: //throw new Exception("Attempt to release inactive resource(" + res + ")");
0865: }
0866: activeList.remove(res);
0867: if (conLogger.isLoggable(BasicLevel.DEBUG)) {
0868: conLogger.log(BasicLevel.DEBUG, "Removed Resource: " + res);
0869: }
0870: if (maxSize == NO_POOLING || destroy) {
0871: infoList.remove(res);
0872: res.destroy();
0873: if (conLogger.isLoggable(BasicLevel.DEBUG)) {
0874: conLogger.log(BasicLevel.DEBUG, "Destroyed Resource: "
0875: + res);
0876: }
0877: } else {
0878: freeList.add(res);
0879: PoolItemStats pis = (PoolItemStats) infoList.get(res);
0880: if (pis != null) {
0881: pis.setTotalConnectionTime(System.currentTimeMillis()
0882: - pis.getStartTime());
0883: }
0884: }
0885: // Notify 1 thread waiting for a Connection.
0886: if (currentWaiters > 0) {
0887: notify();
0888: }
0889: if (adjustment) {
0890: adjust();
0891: }
0892: }
0893:
0894: /**
0895: * Close all connections in the pool when server is shutting down.
0896: */
0897: public synchronized void closeAllConnections() {
0898: logger.log(BasicLevel.DEBUG, "");
0899:
0900: // Stop the pool keeper, since all connections will be closed.
0901: poolMonitor.stopit();
0902:
0903: // Close physically all connections
0904: Iterator it = freeList.iterator();
0905: while (it.hasNext()) {
0906: ManagedConnection res = (ManagedConnection) it.next();
0907: try {
0908: res.destroy();
0909: } catch (Exception e) {
0910: logger.log(BasicLevel.ERROR,
0911: "Error while closing a Connection:", e);
0912: }
0913: }
0914: freeList.clear();
0915:
0916: it = activeList.iterator();
0917: while (it.hasNext()) {
0918: ManagedConnection res = (ManagedConnection) it.next();
0919: try {
0920: res.destroy();
0921: } catch (Exception e) {
0922: logger.log(BasicLevel.ERROR,
0923: "Error while closing a Connection:", e);
0924: }
0925: }
0926: activeList.clear();
0927:
0928: poolClosed = true;
0929: }
0930:
0931: /**
0932: * @see org.objectweb.jonas.resource.pool.api.Pool#getMatchFactory
0933: */
0934: public PoolMatchFactory getMatchFactory() {
0935: return matchFactory;
0936: }
0937:
0938: /**
0939: * @see org.objectweb.jonas.resource.pool.api.Pool#setMatchFactory
0940: */
0941: public synchronized void setMatchFactory(PoolMatchFactory pmf) {
0942: matchFactory = pmf;
0943: }
0944:
0945: /**
0946: * @see org.objectweb.jonas.resource.pool.api.Pool#startMonitor
0947: */
0948: public void startMonitor() {
0949: logger.log(BasicLevel.DEBUG, "");
0950: poolMonitor = new HArrayPoolMonitor(this , jndiName);
0951: poolMonitor.start();
0952: }
0953:
0954: /**
0955: * @see org.objectweb.jonas.resource.pool.api.Pool#validateMCs
0956: */
0957: public synchronized void validateMCs() throws Exception {
0958: if (poolClosed) {
0959: return;
0960: }
0961: matchFactory.validateResource(freeList);
0962: }
0963:
0964: /**
0965: * Adjust the pool size, according to poolMax and minSize values.
0966: * Also remove old connections in the freeList.
0967: * @throws Exception if an exception occurs
0968: */
0969: public synchronized void adjust() throws Exception {
0970: // Remove max aged elements in freelist
0971: // - Not more than MAX_REMOVE_FREELIST
0972: // - Don't reduce pool size less than minSize
0973:
0974: if (poolClosed) {
0975: return;
0976: }
0977: long curTime = System.currentTimeMillis();
0978: if (conLogger.isLoggable(BasicLevel.DEBUG)) {
0979: conLogger.log(BasicLevel.DEBUG, " activeList.size() = "
0980: + activeList.size() + " minSize= " + minSize);
0981: }
0982: this .printLists();
0983: // count is used to remove not more than MAX_REMOVE_FREELIST
0984: int count = 0;
0985: Vector rList = new Vector();
0986: Iterator it = freeList.iterator();
0987:
0988: while (it.hasNext()) {
0989: ManagedConnection res = (ManagedConnection) it.next();
0990: PoolItemStats pis = (PoolItemStats) infoList.get(res);
0991: if (maxAge > 0 && pis != null && pis.getMaxAgeTimeout() > 0
0992: && curTime > pis.getMaxAgeTimeout()) {
0993: if (conLogger.isLoggable(BasicLevel.DEBUG)) {
0994: conLogger.log(BasicLevel.DEBUG,
0995: "remove a timed out connection " + res);
0996: }
0997: rList.add(res);
0998: count++;
0999:
1000: if (count >= MAX_REMOVE_FREELIST) {
1001: break;
1002: }
1003: }
1004: }
1005: // Bug: 300351 Use the list built above to remove the MCs
1006: it = rList.iterator();
1007: while (it.hasNext()) {
1008: ManagedConnection res = (ManagedConnection) it.next();
1009: try {
1010: matchFactory.releaseResource(res);
1011: } catch (Exception ex) {
1012: ex.printStackTrace();
1013: }
1014: freeList.remove(res);
1015: infoList.remove(res);
1016: try {
1017: res.destroy();
1018: } catch (Exception ex) {
1019: ex.printStackTrace();
1020: }
1021: }
1022:
1023: // Close (physically) connections lost (opened for too long time)
1024: curTime = System.currentTimeMillis();
1025: Vector aList = new Vector();
1026: for (it = activeList.iterator(); it.hasNext();) {
1027: ManagedConnection res = (ManagedConnection) it.next();
1028: PoolItemStats pis = (PoolItemStats) infoList.get(res);
1029: if (maxOpentime > 0 && pis != null
1030: && pis.getMaxOpenTimeout() > 0
1031: && curTime > pis.getMaxOpenTimeout()) {
1032: aList.add(res);
1033: }
1034: }
1035: it = aList.iterator();
1036: while (it.hasNext()) {
1037: ManagedConnection item = (ManagedConnection) it.next();
1038: logger.log(BasicLevel.WARN,
1039: "close a timed out active connection");
1040: logger.log(BasicLevel.WARN, "MC = " + item);
1041: releaseResource(item, true, false);
1042: connectionLeaks++;
1043: }
1044:
1045: int curSize = this .getSize();
1046: if ((maxSize > 0 && maxSize < curSize)
1047: || (maxSize == NO_POOLING)) {
1048: // Removes as many free entries as possible
1049: int nbRemove = curSize;
1050: if (maxSize > 0) {
1051: nbRemove -= maxSize;
1052: }
1053: if (freeList != null) {
1054: while (!freeList.isEmpty() && nbRemove > 0) {
1055: ManagedConnection res = (ManagedConnection) freeList
1056: .iterator().next();
1057: matchFactory.releaseResource(res);
1058: res.destroy();
1059: freeList.remove(res);
1060: infoList.remove(res);
1061: nbRemove--;
1062: curSize--;
1063: }
1064: }
1065: }
1066:
1067: // Recreate more Connections while minSize is not reached
1068: ManagedConnection res;
1069: if (maxSize != NO_POOLING) {
1070: while (minSize > curSize) {
1071: res = createResource(null);
1072: if (logger.isLoggable(BasicLevel.DEBUG)) {
1073: logger.log(BasicLevel.DEBUG, "recreate connection "
1074: + res);
1075: }
1076: freeList.add(res);
1077: infoList.put(res, new PoolItemStats());
1078: setItemStats(res);
1079: curSize++;
1080: }
1081: }
1082:
1083: recomputeBusy();
1084: }
1085:
1086: /**
1087: * compute current min/max busyConnections
1088: */
1089: public void recomputeBusy() {
1090: int busy = getCurrentBusy();
1091: if (busyMax < busy) {
1092: busyMax = busy;
1093: }
1094: if (busyMin > busy) {
1095: busyMin = busy;
1096: }
1097: }
1098:
1099: /**
1100: * @see org.objectweb.jonas.resource.pool.api.Pool#sampling
1101: */
1102: public void sampling() throws Exception {
1103:
1104: if (poolClosed) {
1105: return;
1106: }
1107: //matchFactory.sampling();
1108: waitingHighRecent = waitingTime;
1109: if (waitingHigh < waitingTime) {
1110: waitingHigh = waitingTime;
1111: }
1112: waitingTime = 0;
1113:
1114: waitersHighRecent = waiterCount;
1115: if (waitersHigh < waiterCount) {
1116: waitersHigh = waiterCount;
1117: }
1118: waiterCount = 0;
1119:
1120: busyMaxRecent = busyMax;
1121: busyMax = getCurrentBusy();
1122: busyMinRecent = busyMin;
1123: busyMin = getCurrentBusy();
1124:
1125: //Check JDBC Keep Alive state
1126: if (jdbcConnLevel == ConnectionManagerImpl.JDBC_KEEP_ALIVE
1127: && jdbcTestStatement != null
1128: && jdbcTestStatement.length() > 0) {
1129:
1130: Vector mcs = new Vector();
1131: Connection connection = null;
1132: int fSize = freeList.size();
1133: boolean releaseRes = false;
1134: for (int i = 0; i < fSize; i++) {
1135: ManagedConnection mc = null;
1136: try {
1137: mc = (ManagedConnection) getResource(null, true);
1138: } catch (Exception e) {
1139: return;
1140: }
1141: connection = (Connection) mc.getConnection(null, null);
1142: java.sql.Statement stmt = null;
1143: if (conLogger.isLoggable(BasicLevel.DEBUG)) {
1144: conLogger.log(BasicLevel.DEBUG, "Sending "
1145: + jdbcTestStatement + " on MC " + mc);
1146: }
1147: try {
1148: stmt = connection.createStatement();
1149: stmt.execute(jdbcTestStatement);
1150: stmt.close();
1151: connection.close();
1152: } catch (SQLException se) {
1153: // An error will cause us to remove this connection
1154: try {
1155: releaseRes = true;
1156: if (stmt != null) {
1157: stmt.close();
1158: }
1159: } catch (Exception e) {
1160: }
1161: try {
1162: connection.close();
1163: } catch (Exception e) {
1164: }
1165: }
1166: releaseResource(mc, releaseRes, false);
1167: }
1168: }
1169: }
1170:
1171: /**
1172: * Set the item statistics
1173: * @param res Object of the resource
1174: */
1175: private void setItemStats(Object res) {
1176: PoolItemStats pis = (PoolItemStats) infoList.get(res);
1177: if (pis != null) {
1178: pis.incrementUses();
1179: long sTime = System.currentTimeMillis();
1180: pis.setStartTime(sTime);
1181: if (maxAge > 0 && pis.getMaxAgeTimeout() == 0) {
1182: pis.setMaxAgeTimeout(sTime + (maxAge * 60L * 1000));
1183: }
1184: if (maxOpentime > 0) {
1185: pis.setMaxOpenTimeout(sTime
1186: + (maxOpentime * 60L * 1000));
1187: }
1188: }
1189: servedOpen++;
1190: }
1191:
1192: /**
1193: * Print information about the pool
1194: *
1195: */
1196: void printLists() {
1197: int count = 0;
1198: if (logger.isLoggable(BasicLevel.DEBUG)) {
1199: logger.log(BasicLevel.DEBUG, "minSize=" + minSize
1200: + ", maxSize=" + maxSize + ", freeSize="
1201: + freeList.size());
1202: logger.log(BasicLevel.DEBUG, "activeList:");
1203: if (activeList == null) {
1204: logger.log(BasicLevel.DEBUG, " null");
1205: } else {
1206: Iterator it = activeList.iterator();
1207: while (it.hasNext() && ++count < 40) {
1208: ManagedConnection mc = (ManagedConnection) it
1209: .next();
1210: PoolItemStats pis = (PoolItemStats) infoList
1211: .get(mc);
1212: logger.log(BasicLevel.DEBUG, " " + mc);
1213: logger.log(BasicLevel.DEBUG, " " + pis.toString());
1214: }
1215: }
1216: logger.log(BasicLevel.DEBUG, "freeList:");
1217: if (freeList == null) {
1218: logger.log(BasicLevel.DEBUG, " null");
1219: } else {
1220: count = 0;
1221: Iterator it = freeList.iterator();
1222: while (it.hasNext() && ++count < 40) {
1223: ManagedConnection mc = (ManagedConnection) it
1224: .next();
1225: PoolItemStats pis = (PoolItemStats) infoList
1226: .get(mc);
1227: logger.log(BasicLevel.DEBUG, " " + mc);
1228: logger.log(BasicLevel.DEBUG, " " + pis.toString());
1229: }
1230: }
1231: }
1232: }
1233:
1234: }
|