0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.jca;
0031:
0032: import com.caucho.config.ConfigException;
0033: import com.caucho.config.types.Period;
0034: import com.caucho.lifecycle.Lifecycle;
0035: import com.caucho.management.server.AbstractManagedObject;
0036: import com.caucho.management.server.ConnectionPoolMXBean;
0037: import com.caucho.sql.ManagedConnectionImpl;
0038: import com.caucho.util.Alarm;
0039: import com.caucho.util.AlarmListener;
0040: import com.caucho.util.L10N;
0041: import com.caucho.util.FifoSet;
0042: import com.caucho.util.WeakAlarm;
0043:
0044: import javax.resource.NotSupportedException;
0045: import javax.resource.ResourceException;
0046: import javax.resource.spi.ConnectionManager;
0047: import javax.resource.spi.ConnectionRequestInfo;
0048: import javax.resource.spi.ManagedConnection;
0049: import javax.resource.spi.ManagedConnectionFactory;
0050: import javax.resource.spi.ValidatingManagedConnectionFactory;
0051: import javax.security.auth.Subject;
0052: import javax.transaction.xa.XAResource;
0053: import javax.transaction.xa.Xid;
0054: import java.util.ArrayList;
0055: import java.util.Set;
0056: import java.util.Date;
0057: import java.util.logging.Level;
0058: import java.util.logging.Logger;
0059:
0060: /**
0061: * Implementation of the connection manager.
0062: */
0063: public class ConnectionPool extends AbstractManagedObject implements
0064: ConnectionManager, AlarmListener, ConnectionPoolMXBean {
0065: private static final L10N L = new L10N(ConnectionPool.class);
0066: private static final Logger log = Logger
0067: .getLogger(ConnectionPool.class.getName());
0068:
0069: private static int _idGen;
0070:
0071: private String _name;
0072:
0073: private UserTransactionProxy _tm;
0074:
0075: // the maximum number of connections
0076: private int _maxConnections = 128;
0077:
0078: // the maximum number of overflow connections
0079: private int _maxOverflowConnections = 0;
0080:
0081: // the maximum number of connections being created
0082: private int _maxCreateConnections = 5;
0083:
0084: // max idle size
0085: private int _maxIdleCount = 1024;
0086:
0087: // time before an idle connection is closed (30s default)
0088: private long _maxIdleTime = 30000L;
0089:
0090: // time before an active connection is closed (6h default)
0091: private long _maxActiveTime = 6L * 3600L * 1000L;
0092:
0093: // time a connection is allowed to be used (24h default)
0094: private long _maxPoolTime = 24L * 3600L * 1000L;
0095:
0096: // the time to wait for a connection (10m)
0097: private long _connectionWaitTime = 600 * 1000L;
0098:
0099: // the time to wait for a connection
0100: private long _connectionWaitCount = _connectionWaitTime / 1000L;
0101:
0102: // True if the connector supports local transactions.
0103: private boolean _enableLocalTransaction = true;
0104:
0105: // True if the connector supports XA transactions.
0106: private boolean _enableXA = true;
0107:
0108: // True if the local transaction optimization is allowed.
0109: private boolean _isLocalTransactionOptimization = true;
0110:
0111: // server/3087
0112: private boolean _isShareable = true;
0113:
0114: // If true, the save a stack trace when the collection is allocated
0115: private boolean _saveAllocationStackTrace = false;
0116:
0117: // If true, close dangling connections
0118: private boolean _isCloseDanglingConnections = true;
0119:
0120: private final ArrayList<PoolItem> _pool = new ArrayList<PoolItem>();
0121:
0122: private IdlePoolSet _idlePool;
0123:
0124: // temporary connection list for the alarm callback
0125: private final ArrayList<PoolItem> _alarmConnections = new ArrayList<PoolItem>();
0126:
0127: private Alarm _alarm;
0128:
0129: // time of the last validation check
0130: private long _lastValidCheckTime;
0131: // time the idle set was last empty
0132: private long _lastIdlePoolEmptyTime;
0133:
0134: private int _idCount;
0135:
0136: private int _createCount;
0137:
0138: //
0139: // statistics
0140: //
0141:
0142: private long _connectionCountTotal;
0143: private long _connectionCreateCountTotal;
0144: private long _connectionFailCountTotal;
0145: private long _lastFailTime;
0146:
0147: private final Lifecycle _lifecycle = new Lifecycle();
0148:
0149: ConnectionPool() {
0150: }
0151:
0152: /**
0153: * Sets the connection pool name.
0154: */
0155: public void setName(String name) {
0156: _name = name;
0157: }
0158:
0159: /**
0160: * Gets the connection pool name.
0161: */
0162: public String getName() {
0163: return _name;
0164: }
0165:
0166: /**
0167: * Sets the transaction manager.
0168: */
0169: public void setTransactionManager(UserTransactionProxy tm) {
0170: _tm = tm;
0171: }
0172:
0173: /**
0174: * Returns the transaction manager.
0175: */
0176: public UserTransactionProxy getTransactionManager() {
0177: return _tm;
0178: }
0179:
0180: /**
0181: * Returns true if shared connections are allowed.
0182: */
0183: public boolean isShareable() {
0184: return _isShareable;
0185: }
0186:
0187: /**
0188: * Returns true if shared connections are allowed.
0189: */
0190: public void setShareable(boolean isShareable) {
0191: _isShareable = isShareable;
0192: }
0193:
0194: /**
0195: * Returns true if the local transaction optimization is enabled
0196: */
0197: public boolean isLocalTransactionOptimization() {
0198: return _isLocalTransactionOptimization;
0199: }
0200:
0201: /**
0202: * Returns true if the local transaction optimization is enabled
0203: */
0204: public void setLocalTransactionOptimization(boolean enable) {
0205: _isLocalTransactionOptimization = enable;
0206: }
0207:
0208: /**
0209: * Returns true if the local transaction optimization is enabled
0210: */
0211: public boolean allowLocalTransactionOptimization() {
0212: return _isLocalTransactionOptimization && _isShareable;
0213: }
0214:
0215: /**
0216: * Returns true if a stack trace should be shared on allocation
0217: */
0218: public boolean getSaveAllocationStackTrace() {
0219: return _saveAllocationStackTrace;
0220: }
0221:
0222: /**
0223: * Returns true if a stack trace should be shared on allocation
0224: */
0225: public void setSaveAllocationStackTrace(boolean save) {
0226: _saveAllocationStackTrace = save;
0227: }
0228:
0229: /**
0230: * Returns true if dangling connections should be closed
0231: */
0232: public boolean isCloseDanglingConnections() {
0233: return _isCloseDanglingConnections;
0234: }
0235:
0236: /**
0237: * True if dangling connections should be closed.
0238: */
0239: public void setCloseDanglingConnections(boolean isClose) {
0240: _isCloseDanglingConnections = isClose;
0241: }
0242:
0243: /**
0244: * Set true for local transaction support.
0245: */
0246: public void setLocalTransaction(boolean localTransaction) {
0247: _enableLocalTransaction = localTransaction;
0248: }
0249:
0250: /**
0251: * Set true for local transaction support.
0252: */
0253: public boolean isLocalTransaction() {
0254: return _enableLocalTransaction;
0255: }
0256:
0257: /**
0258: * Set true for XA transaction support.
0259: */
0260: public void setXATransaction(boolean enable) {
0261: _enableXA = enable;
0262: }
0263:
0264: /**
0265: * Set true for XA transaction support.
0266: */
0267: public boolean isXATransaction() {
0268: return _enableXA;
0269: }
0270:
0271: /**
0272: * Returns the max idle time.
0273: */
0274: public long getMaxIdleTime() {
0275: if (Long.MAX_VALUE / 2 <= _maxIdleTime)
0276: return -1;
0277: else
0278: return _maxIdleTime;
0279: }
0280:
0281: /**
0282: * Sets the max idle time.
0283: */
0284: public void setMaxIdleTime(long maxIdleTime) {
0285: if (maxIdleTime < 0)
0286: _maxIdleTime = Long.MAX_VALUE / 2;
0287: else
0288: _maxIdleTime = maxIdleTime;
0289: }
0290:
0291: /**
0292: * Returns the max idle count.
0293: */
0294: public int getMaxIdleCount() {
0295: return _maxIdleCount;
0296: }
0297:
0298: /**
0299: * Sets the max idle count.
0300: */
0301: public void setMaxIdleCount(int maxIdleCount) {
0302: if (maxIdleCount < 0)
0303: _maxIdleCount = 0;
0304: else
0305: _maxIdleCount = maxIdleCount;
0306: }
0307:
0308: /**
0309: * Returns the max active time.
0310: */
0311: public long getMaxActiveTime() {
0312: if (Long.MAX_VALUE / 2 <= _maxActiveTime)
0313: return -1;
0314: else
0315: return _maxActiveTime;
0316: }
0317:
0318: /**
0319: * Sets the max active time.
0320: */
0321: public void setMaxActiveTime(long maxActiveTime) {
0322: if (maxActiveTime < 0)
0323: _maxActiveTime = Long.MAX_VALUE / 2;
0324: else
0325: _maxActiveTime = maxActiveTime;
0326: }
0327:
0328: /**
0329: * Returns the max pool time.
0330: */
0331: public long getMaxPoolTime() {
0332: if (Long.MAX_VALUE / 2 <= _maxPoolTime)
0333: return -1;
0334: else
0335: return _maxPoolTime;
0336: }
0337:
0338: /**
0339: * Sets the max pool time.
0340: */
0341: public void setMaxPoolTime(long maxPoolTime) {
0342: if (maxPoolTime < 0)
0343: _maxPoolTime = Long.MAX_VALUE / 2;
0344: else
0345: _maxPoolTime = maxPoolTime;
0346: }
0347:
0348: /**
0349: * Sets the max number of connections
0350: */
0351: public void setMaxConnections(int maxConnections)
0352: throws ConfigException {
0353: if (maxConnections == 0)
0354: throw new ConfigException(L
0355: .l("max-connections '0' must be at least 1."));
0356:
0357: _maxConnections = maxConnections;
0358:
0359: if (maxConnections < 0)
0360: _maxConnections = Integer.MAX_VALUE / 2;
0361: }
0362:
0363: /**
0364: * Gets the maximum number of connections
0365: */
0366: public int getMaxConnections() {
0367: if (_maxConnections < Integer.MAX_VALUE / 2)
0368: return _maxConnections;
0369: else
0370: return -1;
0371: }
0372:
0373: /**
0374: * Sets the time to wait for connections
0375: */
0376: public void setConnectionWaitTime(Period waitTime) {
0377: _connectionWaitTime = waitTime.getPeriod();
0378:
0379: if (_connectionWaitTime < 0)
0380: _connectionWaitTime = Long.MAX_VALUE / 2;
0381:
0382: _connectionWaitCount = _connectionWaitTime / 1000;
0383: }
0384:
0385: /**
0386: * Sets the time to wait for connections
0387: */
0388: public long getConnectionWaitTime() {
0389: if (_connectionWaitTime < Long.MAX_VALUE / 2)
0390: return _connectionWaitTime;
0391: else
0392: return -1;
0393: }
0394:
0395: /**
0396: * Sets the max number of overflow connections
0397: */
0398: public void setMaxOverflowConnections(int maxOverflowConnections) {
0399: _maxOverflowConnections = maxOverflowConnections;
0400: }
0401:
0402: /**
0403: * Gets the max number of overflow connections
0404: */
0405: public int getMaxOverflowConnections() {
0406: return _maxOverflowConnections;
0407: }
0408:
0409: /**
0410: * Sets the max number of connections simultaneously creating
0411: */
0412: public void setMaxCreateConnections(int maxConnections)
0413: throws ConfigException {
0414: if (maxConnections == 0)
0415: throw new ConfigException(
0416: L
0417: .l("max-create-connections '0' must be at least 1."));
0418:
0419: _maxCreateConnections = maxConnections;
0420:
0421: if (maxConnections < 0)
0422: _maxCreateConnections = Integer.MAX_VALUE / 2;
0423:
0424: }
0425:
0426: /**
0427: * Gets the maximum number of connections simultaneously creating
0428: */
0429: public int getMaxCreateConnections() {
0430: if (_maxCreateConnections < Integer.MAX_VALUE / 2)
0431: return _maxCreateConnections;
0432: else
0433: return -1;
0434: }
0435:
0436: /**
0437: * Initialize the connection manager.
0438: */
0439: public Object init(ManagedConnectionFactory mcf)
0440: throws ConfigException, ResourceException {
0441: if (!_lifecycle.toInit())
0442: return null;
0443:
0444: if (_name == null)
0445: _name = "connection-pool-" + _idGen++;
0446:
0447: if (_tm == null)
0448: throw new ConfigException(
0449: L
0450: .l("the connection manager needs a transaction manager."));
0451:
0452: _idlePool = new IdlePoolSet(_maxIdleCount);
0453:
0454: registerSelf();
0455:
0456: _alarm = new WeakAlarm(this );
0457:
0458: if (!(mcf instanceof ValidatingManagedConnectionFactory)) {
0459: // never check
0460: _lastValidCheckTime = Long.MAX_VALUE / 2;
0461: }
0462:
0463: // recover any resources on startup
0464: if (_enableXA) {
0465: Subject subject = null;
0466: ManagedConnection mConn = mcf.createManagedConnection(
0467: subject, null);
0468:
0469: try {
0470: XAResource xa = mConn.getXAResource();
0471:
0472: _tm.recover(xa);
0473: } catch (NotSupportedException e) {
0474: _enableXA = false;
0475: log.finer(e.toString());
0476: } catch (Throwable e) {
0477: log.log(Level.FINER, e.toString(), e);
0478: } finally {
0479: mConn.destroy();
0480: }
0481: }
0482:
0483: return mcf.createConnectionFactory(this );
0484: }
0485:
0486: /**
0487: * start the connection manager.
0488: */
0489: public void start() {
0490: if (!_lifecycle.toActive())
0491: return;
0492:
0493: if (0 < _maxIdleTime && _maxIdleTime < 1000)
0494: _alarm.queue(1000);
0495: else if (1000 < _maxIdleTime && _maxIdleTime < 60000)
0496: _alarm.queue(_maxIdleTime);
0497: else
0498: _alarm.queue(60000);
0499: }
0500:
0501: /**
0502: * Generates a connection id.
0503: */
0504: String generateId() {
0505: return String.valueOf(_idCount++);
0506: }
0507:
0508: /**
0509: * Allocates the connection.
0510: *
0511: * @return connection handle for EIS specific connection.
0512: */
0513: public Object allocateConnection(ManagedConnectionFactory mcf,
0514: ConnectionRequestInfo info) throws ResourceException {
0515: Subject subject = null;
0516:
0517: Object conn = allocate(mcf, subject, info);
0518:
0519: synchronized (this ) {
0520: _connectionCountTotal++;
0521: }
0522:
0523: return conn;
0524: }
0525:
0526: /**
0527: * Adds a connection to the idle pool.
0528: */
0529: void toIdle(PoolItem item) {
0530: if (_pool.size() <= _maxConnections
0531: && !item.isConnectionError()) {
0532: ManagedConnection mConn = item.getManagedConnection();
0533: if (mConn != null) {
0534: try {
0535: mConn.cleanup();
0536:
0537: ManagedConnection oldIdleConn = null;
0538:
0539: synchronized (_idlePool) {
0540: long now = Alarm.getCurrentTime();
0541:
0542: if (_idlePool.size() == 0)
0543: _lastIdlePoolEmptyTime = now;
0544:
0545: if (now - _lastIdlePoolEmptyTime < _maxIdleTime
0546: && _idlePool.add(mConn)) {
0547: return;
0548: } else {
0549: _lastIdlePoolEmptyTime = now;
0550: }
0551: }
0552: } catch (Throwable e) {
0553: log.log(Level.FINE, e.toString(), e);
0554: } finally {
0555: synchronized (_pool) {
0556: _pool.notify();
0557: }
0558: }
0559: }
0560: }
0561:
0562: toDead(item);
0563: }
0564:
0565: /**
0566: * Returns the delegated pool item.
0567: */
0568: public PoolItem getDelegatePoolItem(Xid xid) {
0569: ArrayList<PoolItem> pool = _pool;
0570:
0571: synchronized (pool) {
0572: int size = pool.size();
0573: for (int i = 0; i < size; i++) {
0574: PoolItem item = pool.get(i);
0575:
0576: if (xid.equals(item.getXid()))
0577: return item;
0578: }
0579: }
0580:
0581: return null;
0582: }
0583:
0584: //
0585: // statistics
0586: //
0587:
0588: /**
0589: * Returns the total connections.
0590: */
0591: public int getConnectionCount() {
0592: return _pool.size();
0593: }
0594:
0595: /**
0596: * Returns the idle connections.
0597: */
0598: public int getConnectionIdleCount() {
0599: return _idlePool.size();
0600: }
0601:
0602: /**
0603: * Returns the active connections.
0604: */
0605: public int getConnectionActiveCount() {
0606: return _pool.size() - _idlePool.size();
0607: }
0608:
0609: /**
0610: * Returns the total connections.
0611: */
0612: public long getConnectionCountTotal() {
0613: return _connectionCountTotal;
0614: }
0615:
0616: /**
0617: * Returns the total connections.
0618: */
0619: public long getConnectionCreateCountTotal() {
0620: return _connectionCreateCountTotal;
0621: }
0622:
0623: /**
0624: * Returns the total failed connections.
0625: */
0626: public long getConnectionFailCountTotal() {
0627: return _connectionFailCountTotal;
0628: }
0629:
0630: /**
0631: * Returns the last fail time
0632: */
0633: public Date getLastFailTime() {
0634: return new Date(_lastFailTime);
0635: }
0636:
0637: /**
0638: * Clears the idle connections in the pool.
0639: */
0640: public void clear() {
0641: ArrayList<PoolItem> pool = _pool;
0642:
0643: if (pool == null)
0644: return;
0645:
0646: ArrayList<PoolItem> clearItems = new ArrayList<PoolItem>();
0647:
0648: synchronized (_idlePool) {
0649: _idlePool.clear();
0650: }
0651:
0652: synchronized (pool) {
0653: clearItems.addAll(pool);
0654:
0655: pool.clear();
0656: }
0657:
0658: for (int i = 0; i < clearItems.size(); i++) {
0659: PoolItem poolItem = clearItems.get(i);
0660:
0661: try {
0662: poolItem.destroy();
0663: } catch (Throwable e) {
0664: log.log(Level.WARNING, e.toString(), e);
0665: }
0666: }
0667: }
0668:
0669: /**
0670: * Returns the transaction.
0671: */
0672: UserTransactionImpl getTransaction() {
0673: return _tm.getUserTransaction();
0674: }
0675:
0676: /**
0677: * Allocates a connection.
0678: */
0679: private Object allocate(ManagedConnectionFactory mcf,
0680: Subject subject, ConnectionRequestInfo info)
0681: throws ResourceException {
0682: UserPoolItem userPoolItem = null;
0683:
0684: try {
0685: UserTransactionImpl transaction = _tm.getUserTransaction();
0686:
0687: if (transaction == null)
0688: return allocatePool(mcf, subject, info, null)
0689: .allocateUserConnection();
0690:
0691: userPoolItem = transaction.allocate(mcf, subject, info);
0692:
0693: if (userPoolItem == null)
0694: userPoolItem = allocatePool(mcf, subject, info, null);
0695:
0696: return userPoolItem.allocateUserConnection();
0697: } catch (RuntimeException e) {
0698: if (userPoolItem != null)
0699: userPoolItem.close();
0700:
0701: throw e;
0702: } catch (ResourceException e) {
0703: if (userPoolItem != null)
0704: userPoolItem.close();
0705:
0706: throw e;
0707: } catch (Throwable e) {
0708: if (userPoolItem != null)
0709: userPoolItem.close();
0710:
0711: throw new ResourceException(e);
0712: }
0713: }
0714:
0715: /**
0716: * Allocates a connection.
0717: */
0718: UserPoolItem allocatePool(ManagedConnectionFactory mcf,
0719: Subject subject, ConnectionRequestInfo info,
0720: UserPoolItem oldUserItem) throws ResourceException {
0721: long timeoutCount = _connectionWaitCount;
0722:
0723: while (_lifecycle.isActive()) {
0724: UserPoolItem userPoolItem = allocateIdle(mcf, subject,
0725: info, oldUserItem);
0726:
0727: if (userPoolItem != null)
0728: return userPoolItem;
0729:
0730: userPoolItem = create(mcf, subject, info, false,
0731: oldUserItem);
0732:
0733: if (userPoolItem != null)
0734: return userPoolItem;
0735:
0736: if (timeoutCount-- < 0)
0737: break;
0738: }
0739:
0740: if (!_lifecycle.isActive())
0741: throw new IllegalStateException(L
0742: .l("connection pool closed"));
0743:
0744: UserPoolItem userPoolItem = create(mcf, subject, info, true,
0745: oldUserItem);
0746:
0747: if (userPoolItem == null)
0748: throw new NullPointerException(
0749: L
0750: .l("ConnectionPool create should not return a null PoolItem for overflow connections."));
0751:
0752: return userPoolItem;
0753: }
0754:
0755: /**
0756: * Allocates a connection from the idle pool.
0757: */
0758: private UserPoolItem allocateIdle(ManagedConnectionFactory mcf,
0759: Subject subject, ConnectionRequestInfo info,
0760: UserPoolItem oldUserItem) throws ResourceException {
0761: while (_lifecycle.isActive()) {
0762: ManagedConnection mConn;
0763:
0764: long now = Alarm.getCurrentTime();
0765:
0766: if (_lastValidCheckTime + 1000L < now) {
0767: _lastValidCheckTime = now;
0768:
0769: if (mcf instanceof ValidatingManagedConnectionFactory) {
0770: ValidatingManagedConnectionFactory vmcf;
0771: vmcf = (ValidatingManagedConnectionFactory) mcf;
0772:
0773: validate(vmcf);
0774: }
0775: }
0776:
0777: // asks the Driver's ManagedConnectionFactory to match an
0778: // idle connection
0779: synchronized (_idlePool) {
0780: mConn = mcf.matchManagedConnections(_idlePool, subject,
0781: info);
0782:
0783: // If there are no more idle connections, return null
0784: if (mConn == null)
0785: return null;
0786:
0787: _idlePool.remove(mConn);
0788: }
0789:
0790: PoolItem poolItem = null;
0791:
0792: synchronized (_pool) {
0793: for (int i = _pool.size() - 1; i >= 0; i--) {
0794: poolItem = _pool.get(i);
0795:
0796: if (poolItem.getManagedConnection() == mConn)
0797: break;
0798: }
0799: }
0800:
0801: if (poolItem == null)
0802: throw new IllegalStateException(L.l(
0803: "No matching PoolItem found for {0}", mConn));
0804:
0805: UserPoolItem userPoolItem = null;
0806:
0807: // Ensure the connection is still valid
0808: userPoolItem = poolItem
0809: .toActive(subject, info, oldUserItem);
0810: if (userPoolItem != null)
0811: return userPoolItem;
0812:
0813: toDead(poolItem);
0814: }
0815:
0816: return null;
0817: }
0818:
0819: /**
0820: * Validates the pool.
0821: */
0822: private void validate(ValidatingManagedConnectionFactory mcf) {
0823: Set invalid = null;
0824: /*
0825: synchronized (_idlePool) {
0826: } */
0827: }
0828:
0829: /**
0830: * Creates a new connection.
0831: */
0832: private UserPoolItem create(ManagedConnectionFactory mcf,
0833: Subject subject, ConnectionRequestInfo info,
0834: boolean isOverflow, UserPoolItem oldUserItem)
0835: throws ResourceException {
0836: synchronized (_pool) {
0837: int size = _pool.size();
0838:
0839: if (isOverflow
0840: && _maxConnections + _maxOverflowConnections <= _createCount
0841: + size) {
0842: throw new ResourceException(
0843: L
0844: .l("Connection pool is full. Can't allocate connection."));
0845: }
0846: // if the pool is full, don't create, and wait
0847: else if (!isOverflow
0848: && (_maxConnections <= _createCount + size || _maxCreateConnections <= _createCount)) {
0849: try {
0850: _pool.wait(1000);
0851: } catch (Exception e) {
0852: log.log(Level.FINE, e.toString(), e);
0853: }
0854:
0855: return null;
0856: }
0857:
0858: _createCount++;
0859: }
0860:
0861: PoolItem poolItem = null;
0862: try {
0863: ManagedConnection mConn = mcf.createManagedConnection(
0864: subject, info);
0865:
0866: if (mConn == null)
0867: throw new ResourceException(
0868: L
0869: .l(
0870: "'{0}' did not return a connection from createManagedConnection",
0871: mcf));
0872:
0873: poolItem = new PoolItem(this , mcf, mConn);
0874:
0875: UserPoolItem userPoolItem;
0876:
0877: // Ensure the connection is still valid
0878: userPoolItem = poolItem
0879: .toActive(subject, info, oldUserItem);
0880: if (userPoolItem != null) {
0881: synchronized (this ) {
0882: _connectionCreateCountTotal++;
0883: }
0884:
0885: return userPoolItem;
0886: }
0887:
0888: throw new IllegalStateException(L.l(
0889: "Connection '{0}' was not valid on creation",
0890: poolItem));
0891: } catch (RuntimeException e) {
0892: synchronized (this ) {
0893: _connectionFailCountTotal++;
0894: _lastFailTime = Alarm.getCurrentTime();
0895: }
0896:
0897: throw e;
0898: } catch (ResourceException e) {
0899: synchronized (this ) {
0900: _connectionFailCountTotal++;
0901: _lastFailTime = Alarm.getCurrentTime();
0902: }
0903:
0904: throw e;
0905: } finally {
0906: synchronized (_pool) {
0907: _createCount--;
0908:
0909: if (poolItem != null)
0910: _pool.add(poolItem);
0911:
0912: _pool.notify();
0913: }
0914: }
0915: }
0916:
0917: /**
0918: * Alarm listener.
0919: */
0920: public void handleAlarm(Alarm alarm) {
0921: if (!_lifecycle.isActive())
0922: return;
0923:
0924: try {
0925: long now = Alarm.getCurrentTime();
0926:
0927: _alarmConnections.clear();
0928:
0929: synchronized (_pool) {
0930: _alarmConnections.addAll(_pool);
0931: }
0932:
0933: for (int i = _alarmConnections.size() - 1; i >= 0; i--) {
0934: PoolItem item = _alarmConnections.get(i);
0935:
0936: if (!item.isValid())
0937: toDead(item);
0938: }
0939:
0940: _alarmConnections.clear();
0941: } finally {
0942: if (!_lifecycle.isActive()) {
0943: } else if (0 < _maxIdleTime && _maxIdleTime < 1000)
0944: _alarm.queue(1000);
0945: else if (1000 < _maxIdleTime && _maxIdleTime < 60000)
0946: _alarm.queue(_maxIdleTime);
0947: else
0948: _alarm.queue(60000);
0949: }
0950: }
0951:
0952: /**
0953: * Removes a connection
0954: */
0955: void toDead(PoolItem item) {
0956: synchronized (_idlePool) {
0957: _idlePool.remove(item.getManagedConnection());
0958: }
0959:
0960: synchronized (_pool) {
0961: _pool.remove(item);
0962: _pool.notify();
0963: }
0964:
0965: try {
0966: item.destroy();
0967: } catch (Throwable e) {
0968: log.log(Level.WARNING, e.toString(), e);
0969: }
0970: }
0971:
0972: /*
0973: * Removes a connection from the pool.
0974: */
0975: public void markForPoolRemoval(ManagedConnectionImpl mConn) {
0976: for (PoolItem poolItem : _pool) {
0977: if (poolItem.getManagedConnection() == mConn) {
0978: poolItem.setConnectionError();
0979: break;
0980: }
0981: }
0982: }
0983:
0984: /**
0985: * Stops the manager.
0986: */
0987: public void stop() {
0988: if (!_lifecycle.toStop())
0989: return;
0990:
0991: if (_alarm != null)
0992: _alarm.dequeue();
0993: }
0994:
0995: /**
0996: * Destroys the manager.
0997: */
0998: public void destroy() {
0999: stop();
1000:
1001: if (!_lifecycle.toDestroy())
1002: return;
1003:
1004: ArrayList<PoolItem> pool = _pool;
1005:
1006: synchronized (pool) {
1007: for (int i = 0; i < pool.size(); i++) {
1008: PoolItem poolItem = pool.get(i);
1009:
1010: try {
1011: poolItem.destroy();
1012: } catch (Throwable e) {
1013: log.log(Level.WARNING, e.toString(), e);
1014: }
1015: }
1016:
1017: pool.clear();
1018: _idlePool.clear();
1019: }
1020: }
1021:
1022: public String toString() {
1023: return "ConnectionPool[" + getName() + "]";
1024: }
1025: }
|