KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jonas > dbm > Pool


1 /**
2  * JOnAS: Java(TM) Open Application Server
3  * Copyright (C) 1999 Bull S.A.
4  * Contact: jonas-team@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: Pool.java,v 1.63 2005/06/30 14:50:07 durieuxp Exp $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.jonas.dbm;
27
28 import java.sql.SQLException JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.LinkedList JavaDoc;
32 import java.util.Map JavaDoc;
33
34 import javax.sql.XAConnection JavaDoc;
35 import javax.transaction.SystemException JavaDoc;
36 import javax.transaction.Transaction JavaDoc;
37
38 import org.objectweb.jonas.common.Log;
39 import org.objectweb.jonas.jdbc_xa.ConnectionImpl;
40 import org.objectweb.jonas.jdbc_xa.XADataSourceImpl;
41 import org.objectweb.jonas.jtm.TransactionService;
42 import org.objectweb.jonas.service.ServiceException;
43 import org.objectweb.jonas.service.ServiceManager;
44 import org.objectweb.transaction.jta.TransactionManager;
45 import org.objectweb.util.monolog.api.BasicLevel;
46 import org.objectweb.util.monolog.api.Logger;
47
48 /**
49  * Connection Pool
50  * @author Philippe Durieux
51  * Contributor(s):
52  * 00/01/08 Markus Fritz
53  * make connection pooling thread safe (with same tx)
54  * introduce MaxAge for connections
55  * optimize pooling
56  * add some 'paranoia code': test conns before returning them from the pool.
57  * 00/18/04 Jun Inamori (j-office@osa.att.ne.jp)
58  * For closing correctly all connections at server shutdown.
59  * 01/11/06 Christophe Ney cney@batisseurs.com for Lutris Technologies
60  * Added ResourceManagerListener mechanism.
61  * 02/01/15 Dean Jennings - Map instead of Hashtable for lists
62  * 03/05/15 Adriana Danes - Introduce pool size configuration
63  */

64 public class Pool {
65
66     // ----------------------------------------------------------------
67
// Private data
68
// ----------------------------------------------------------------
69

70     /**
71      * Logger used for traces
72      */

73     private Logger logger = null;
74
75     /**
76      * Keep a ref on the Transaction Manager.
77      */

78     private TransactionManager tm = null;
79
80     /**
81      * My PoolKeeper : This thread periodically adjust pooling
82      * and compute statistics.
83      */

84     private PoolKeeper poolKeeper;
85
86     /**
87      * This HashMap gives the pool item by its XAConnection.
88      * The size of this table gives the current number of opened connection
89      */

90     private Map JavaDoc xac2item = new HashMap JavaDoc();
91
92     /**
93      * List of free available items
94      * This avoids closing and reopening physical connections.
95      * We try to keep a minimum of minConPool elements here.
96      */

97     private LinkedList JavaDoc freeList = new LinkedList JavaDoc();
98
99     /**
100      * This HashMap gives the pool item by its transaction
101      * Requests with same tx get always the same conn
102      */

103     private Map JavaDoc tx2item = new HashMap JavaDoc();
104
105     /**
106      * the pool's connection manager
107      */

108     private ConnectionManager cmgr;
109
110     /**
111      * the XA datasource managed by the connection manager
112      */

113     private XADataSourceImpl xads;
114
115     /**
116      * count max waiters during current period.
117      */

118     private int waiterCount = 0;
119
120     /**
121      * count max waiting time during current period.
122      */

123     private long waitingTime = 0;
124
125     /**
126      * count max busy connection during current period.
127      */

128     private int busyMax = 0;
129
130     /**
131      * count min busy connection during current period.
132      */

133     private int busyMin = 0;
134
135     // ----------------------------------------------------------------
136
// Configuration
137
// Each attibute have setter and getter, plus a default value.
138
// ----------------------------------------------------------------
139

140     /**
141      * High Value for no limit for the connection pool
142      */

143     private static final int NO_LIMIT = 99999;
144
145     /**
146      * Nb of milliseconds in a day
147      */

148     private static final long ONE_DAY = 1440L * 60L * 1000L;
149
150     /**
151      * max number of remove at once in the freelist
152      * We avoid removing too much items at once for perf reasons.
153      */

154     private static final int MAX_REMOVE_FREELIST = 10;
155
156     /**
157      * minimum size of the connection pool
158      */

159     private int poolMin = 0;
160
161     /**
162      * @return min pool size
163      */

164     public int getPoolMin() {
165         return poolMin;
166     }
167
168     /**
169      * @param min minimum connection pool size to be set.
170      */

171     public synchronized void setPoolMin(int min) {
172         if (poolMin != min) {
173             poolMin = min;
174             adjust();
175         }
176     }
177
178     /**
179      * maximum size of the connection pool.
180      * default value is "NO LIMIT".
181      */

182     private int poolMax = NO_LIMIT;
183
184     /**
185      * @return actual max pool size
186      */

187     public int getPoolMax() {
188         return poolMax;
189     }
190
191     /**
192      * @param max max pool size. -1 means "no limit".
193      */

194     public synchronized void setPoolMax(int max) {
195         if (poolMax != max) {
196             if (max < 0 || max > NO_LIMIT) {
197                 if (currentWaiters > 0) {
198                     notify();
199                 }
200                 poolMax = NO_LIMIT;
201             } else {
202                 if (currentWaiters > 0 && poolMax < max) {
203                     notify();
204                 }
205                 poolMax = max;
206                 adjust();
207             }
208         }
209     }
210
211     /**
212      * Max age of a Connection in milliseconds.
213      * When the time is elapsed, the connection will be closed.
214      * This avoids keeping connections open too long for nothing.
215      */

216     private long maxAge = ONE_DAY;
217
218     /**
219      * Same value in mns
220      */

221     private int maxAgeMn;
222
223     /**
224      * @return max age for connections (in mm)
225      */

226     public int getMaxAge() {
227         return maxAgeMn;
228     }
229
230     /**
231      * @return max age for connections (in millisec)
232      */

233     public long getMaxAgeMilli() {
234         return maxAge;
235     }
236
237     /**
238      * @param mn max age of connection in minutes
239      */

240     public void setMaxAge(int mn) {
241         maxAgeMn = mn;
242         // set times in milliseconds
243
maxAge = mn * 60L * 1000L;
244     }
245
246     /**
247      * max open time for a connection, in millisec
248      */

249     private long maxOpenTime = ONE_DAY;
250
251     /**
252      * Same value in mn
253      */

254     private int maxOpenTimeMn;
255
256     /**
257      * @return max age for connections (in mns)
258      */

259     public int getMaxOpenTime() {
260         return maxOpenTimeMn;
261     }
262
263     /**
264      * @return max age for connections (in millisecs)
265      */

266     public long getMaxOpenTimeMilli() {
267         return maxOpenTime;
268     }
269
270     /**
271      * @param mn max time of open connection in minutes
272      */

273     public void setMaxOpenTime(int mn) {
274         maxOpenTimeMn = mn;
275         // set times in milliseconds
276
maxOpenTime = mn * 60L * 1000L;
277     }
278
279     /**
280      * max nb of milliseconds to wait for a connection when pool is full
281      */

282     private long waiterTimeout = 10000;
283
284     /**
285      * @return waiter timeout in seconds
286      */

287     public int getMaxWaitTime() {
288         return (int) (waiterTimeout / 1000L);
289     }
290
291     /**
292      * @param sec max time to wait for a connection, in seconds
293      */

294     public void setMaxWaitTime(int sec) {
295         waiterTimeout = sec * 1000L;
296     }
297
298     /**
299      * max nb of waiters allowed to wait for a Connection
300      */

301     private int maxWaiters = 1000;
302
303     /**
304      * @return max nb of waiters
305      */

306     public int getMaxWaiters() {
307         return maxWaiters;
308     }
309
310     /**
311      * @param nb max nb of waiters
312      */

313     public void setMaxWaiters(int nb) {
314         maxWaiters = nb;
315     }
316
317     /**
318      * sampling period in sec.
319      */

320     private int samplingPeriod = 60; //default sampling period
321

322     /**
323      * @return sampling period in sec.
324      */

325     public int getSamplingPeriod() {
326         return samplingPeriod;
327     }
328
329     /**
330      * @param sec sampling period in sec.
331      */

332     public void setSamplingPeriod(int sec) {
333         if (sec > 0) {
334             samplingPeriod = sec;
335             poolKeeper.setSamplingPeriod(sec);
336         }
337     }
338
339     /**
340      * Level of checking on connections when got from the pool.
341      * this avoids reusing bad connections because too old, for example
342      * when database was restarted...
343      * 0 = no checking
344      * 1 = check that still physically opened.
345      * 2 = try a null statement.
346      */

347     private int checkLevel = 1; // default = 1
348

349     /**
350      * @return connection checking level
351      */

352     public int getCheckLevel() {
353         return checkLevel;
354     }
355
356     /**
357      * @param level jdbc connection checking level (0, 1, or 2)
358      */

359     public void setCheckLevel(int level) {
360         checkLevel = level;
361     }
362
363     /**
364      * test statement used when checkLevel = 2.
365      */

366     private String JavaDoc testStatement;
367
368     /**
369      * @return test statement used when checkLevel = 2.
370      */

371     public String JavaDoc getTestStatement() {
372         return testStatement;
373     }
374
375     /**
376      * @param s test statement
377      */

378     public void setTestStatement(String JavaDoc s) {
379         testStatement = s;
380     }
381
382     // ----------------------------------------------------------------
383
// Monitoring Attributes
384
// Each attribute should have a get accessor.
385
// ----------------------------------------------------------------
386

387     /**
388      * maximum nb of busy connections in last sampling period
389      */

390     private int busyMaxRecent = 0;
391
392     /**
393      * @return maximum nb of busy connections in last sampling period
394      */

395     public int getBusyMaxRecent() {
396         return busyMaxRecent;
397     }
398
399     /**
400      * minimum nb of busy connections in last sampling period
401      */

402     private int busyMinRecent = 0;
403
404     /**
405      * @return minimum nb of busy connections in last sampling period
406      */

407     public int getBusyMinRecent() {
408         return busyMinRecent;
409     }
410
411     /**
412      * nb of threads waiting for a Connection
413      */

414     private int currentWaiters = 0;
415
416     /**
417      * @return current number of connection waiters
418      */

419     public int getCurrentWaiters() {
420         return currentWaiters;
421     }
422
423     /**
424      * total number of opened physical connections since the datasource creation.
425      */

426     private int openedCount = 0;
427
428     /**
429      * @return int number of physical jdbc connection opened
430      */

431     public int getOpenedCount() {
432         return openedCount;
433     }
434
435     /**
436      * total nb of physical connection failures
437      */

438     private int connectionFailures = 0;
439
440     /**
441      * @return int number of xa connection failures on open
442      */

443     public int getConnectionFailures() {
444         return connectionFailures;
445     }
446
447     /**
448      * total nb of connection leaks.
449      * A connection leak occurs when the caller never issues a close method
450      * on the connection.
451      */

452     private int connectionLeaks = 0;
453
454     /**
455      * @return int number of connection leaks
456      */

457     public int getConnectionLeaks() {
458         return connectionLeaks;
459     }
460
461     /**
462      * total number of opened connections since the datasource creation.
463      */

464     private int servedOpen = 0;
465
466     /**
467      * @return int number of xa connection served
468      */

469     public int getServedOpen() {
470         return servedOpen;
471     }
472
473     /**
474      * total nb of open connection failures because waiter overflow
475      */

476     private int rejectedFull = 0;
477
478     /**
479      * @return int number of open calls that were rejected due to waiter overflow
480      */

481     public int getRejectedFull() {
482         return rejectedFull;
483     }
484
485     /**
486      * total nb of open connection failures because timeout
487      */

488     private int rejectedTimeout = 0;
489
490     /**
491      * @return int number of open calls that were rejected by timeout
492      */

493     public int getRejectedTimeout() {
494         return rejectedTimeout;
495     }
496
497     /**
498      * total nb of open connection failures for any other reason.
499      */

500     private int rejectedOther = 0;
501
502     /**
503      * @return int number of open calls that were rejected
504      */

505     public int getRejectedOther() {
506         return rejectedOther;
507     }
508
509     /**
510      * @return int number of open calls that were rejected
511      */

512     public int getRejectedOpen() {
513         return rejectedFull + rejectedTimeout + rejectedOther;
514     }
515
516     /**
517      * maximum nb of waiters since datasource creation
518      */

519     private int waitersHigh = 0;
520
521     /**
522      * @return maximum nb of waiters since the datasource creation
523      */

524     public int getWaitersHigh() {
525         return waitersHigh;
526     }
527
528     /**
529      * maximum nb of waiters in last sampling period
530      */

531     private int waitersHighRecent = 0;
532
533     /**
534      * @return maximum nb of waiters in last sampling period
535      */

536     public int getWaitersHighRecent() {
537         return waitersHighRecent;
538     }
539
540     /**
541      * total nb of waiters since datasource creation
542      */

543     private int totalWaiterCount = 0;
544
545     /**
546      * @return total nb of waiters since the datasource creation
547      */

548     public int getWaiterCount() {
549         return totalWaiterCount;
550     }
551
552     /**
553      * total waiting time in milliseconds
554      */

555     private long totalWaitingTime = 0;
556
557     /**
558      * @return total waiting time since the datasource creation
559      */

560     public long getWaitingTime() {
561         return totalWaitingTime;
562     }
563
564     /**
565      * max waiting time in milliseconds
566      */

567     private long waitingHigh = 0;
568
569     /**
570      * @return max waiting time since the datasource creation
571      */

572     public long getWaitingHigh() {
573         return waitingHigh;
574     }
575
576     /**
577      * max waiting time in milliseconds in last sampling period
578      */

579     private long waitingHighRecent = 0;
580
581     /**
582      * @return max waiting time in last sampling period
583      */

584     public long getWaitingHighRecent() {
585         return waitingHighRecent;
586     }
587
588     // ----------------------------------------------------------------
589
// Constructors
590
// ----------------------------------------------------------------
591

592     /**
593      * Pool constructor
594      * @param xads XA DataSource implementation created by this pool's Connection manager. Allows
595      * for getting XA Connections.
596      * @param cmgr the pool's Connection manager has to be registered as ConnectionEventListener of the XA connections
597      * created at the pool creation
598      * @throws Exception The pool could not be initialized
599      */

600     public Pool(ConnectionManager cmgr, XADataSourceImpl xads, Logger log) throws Exception JavaDoc {
601         this.cmgr = cmgr;
602         this.xads = xads;
603         this.logger = log;
604         ServiceManager sm = ServiceManager.getInstance();
605         TransactionService ts = (TransactionService) sm.getTransactionService();
606         tm = ts.getTransactionManager();
607         poolKeeper = new PoolKeeper(this, logger);
608         poolKeeper.start();
609     }
610
611     // ----------------------------------------------------------------
612
// Public Methods
613
// ----------------------------------------------------------------
614

615     
616     /**
617      * @return int number of xa connection
618      */

619     public int getCurrentOpened() {
620         return xac2item.size();
621     }
622
623     /**
624      * @return int number of busy xa connection
625      */

626     public int getCurrentBusy() {
627         return xac2item.size() - freeList.size();
628     }
629
630     /**
631      * compute current min/max busyConnections
632      */

633     public void recomputeBusy() {
634         int busy = getCurrentBusy();
635         if (logger.isLoggable(BasicLevel.DEBUG)) {
636             logger.log(BasicLevel.DEBUG, "Busy Connections = " + busy);
637         }
638         if (busyMax < busy) {
639             busyMax = busy;
640         }
641         if (busyMin > busy) {
642             busyMin = busy;
643         }
644     }
645
646     /**
647      * @return int number of xa connection reserved for tx
648      */

649     public int getCurrentInTx() {
650         return tx2item.size();
651     }
652
653     /**
654      * lookup connection in the pool for this user/tx
655      * @param user user name
656      * @param tx Transaction the connection is involved
657      * @return the free PoolItem (never null)
658      * @throws SQLException Cannot open a connection because the pool's max size is reached
659      */

660     public synchronized PoolItem openConnection(String JavaDoc user, Transaction JavaDoc tx) throws SQLException JavaDoc {
661         PoolItem item = null;
662
663         // If a Connection exists already for this tx, just return it.
664
// If no transaction, never reuse a connection already used.
665
if (tx != null) {
666             item = (PoolItem) tx2item.get(tx);
667             if (item != null) {
668                 if (logger.isLoggable(BasicLevel.DEBUG)) {
669                     logger.log(BasicLevel.DEBUG, "Reuse a Connection for same tx");
670                 }
671                 item.open();
672                 servedOpen++;
673                 return item;
674             }
675         }
676
677         // Loop until a valid item is found
678
long timetowait = waiterTimeout;
679         long starttime = 0;
680         while (item == null) {
681             // try to find an item in the free list
682
if (freeList.isEmpty()) {
683                 // In case we have reached the maximum limit of the pool,
684
// we must wait until a connection is released.
685
if (xac2item.size() >= poolMax) {
686                     boolean stoplooping = true;
687                     // If a timeout has been specified, wait, unless maxWaiters is reached.
688
if (timetowait > 0) {
689                         if (currentWaiters < maxWaiters) {
690                             currentWaiters++;
691                             // Store the maximum concurrent waiters
692
if (waiterCount < currentWaiters) {
693                                 waiterCount = currentWaiters;
694                             }
695                             if (starttime == 0) {
696                                 starttime = System.currentTimeMillis();
697                                 if (logger.isLoggable(BasicLevel.DEBUG)) {
698                                     logger.log(BasicLevel.DEBUG, "Wait for a free Connection" + xac2item.size());
699                                 }
700                             }
701                             try {
702                                 wait(timetowait);
703                             } catch (InterruptedException JavaDoc ign) {
704                                 logger.log(BasicLevel.WARN, "Interrupted");
705                             } finally {
706                                 currentWaiters--;
707                             }
708                             long stoptime = System.currentTimeMillis();
709                             long stillwaited = stoptime - starttime;
710                             timetowait = waiterTimeout - stillwaited;
711                             stoplooping = (timetowait <= 0);
712                             if (stoplooping) {
713                                 // We have been waked up by the timeout.
714
totalWaiterCount++;
715                                 totalWaitingTime += stillwaited;
716                                 if (waitingTime < stillwaited) {
717                                     waitingTime = stillwaited;
718                                 }
719                             } else {
720                                 if (!freeList.isEmpty() || xac2item.size() < poolMax) {
721                                     // We have been notified by a connection released.
722
if (logger.isLoggable(BasicLevel.DEBUG)) {
723                                         logger.log(BasicLevel.DEBUG, "Notified after " + stillwaited);
724                                     }
725                                     totalWaiterCount++;
726                                     totalWaitingTime += stillwaited;
727                                     if (waitingTime < stillwaited) {
728                                         waitingTime = stillwaited;
729                                     }
730                                 }
731                                 continue;
732                             }
733                         }
734                     }
735                     if (stoplooping && freeList.isEmpty() && xac2item.size() >= poolMax) {
736                         if (starttime > 0) {
737                             rejectedTimeout++;
738                             logger.log(BasicLevel.WARN, "Cannot create a Connection - timeout");
739                         } else {
740                             rejectedFull++;
741                             logger.log(BasicLevel.WARN, "Cannot create a Connection");
742                         }
743                         throw new SQLException JavaDoc("No more connections in " + cmgr.getDatasourceName());
744                     }
745                     continue;
746                 }
747                 if (logger.isLoggable(BasicLevel.DEBUG)) {
748                     logger.log(BasicLevel.DEBUG, "empty free list: Create a new Connection");
749                 }
750                 XAConnection JavaDoc xac = null;
751                 try {
752                     // create a new XA Connection
753
xac = xads.getXAConnection();
754                     openedCount++;
755                 } catch (SQLException JavaDoc e) {
756                     connectionFailures++;
757                     rejectedOther++;
758                     logger.log(BasicLevel.WARN, "Cannot create new Connection for tx");
759                     throw e;
760                 }
761                 item = new PoolItem(this, xac, user, logger);
762                 // Register the connection manager as a ConnectionEventListener
763
xac.addConnectionEventListener(cmgr);
764                 xac2item.put(xac, item);
765             } else {
766                 item = (PoolItem) freeList.removeFirst();
767
768                 // Check the connection before reusing it
769
if (checkLevel > 0) {
770                     try {
771                         ConnectionImpl conn = (ConnectionImpl) item.getXACon().getConnection();
772                         if (conn.isPhysicallyClosed()) {
773                             logger.log(BasicLevel.WARN, "The JDBC connection has been closed!");
774                             destroyItem(item);
775                             starttime = 0;
776                             item = null;
777                             continue;
778                         }
779                         if (checkLevel > 1) {
780                             java.sql.Statement JavaDoc stmt = conn.createStatement();
781                             stmt.execute(testStatement);
782                             stmt.close();
783                         }
784                     } catch (Exception JavaDoc e) {
785                         logger.log(BasicLevel.ERROR, "DataSource " + cmgr.getDatasourceName()
786                                    + " error: removing invalid item", e);
787                         destroyItem(item);
788                         starttime = 0;
789                         item = null;
790                         continue;
791                     }
792                 }
793             }
794         }
795         recomputeBusy();
796         item.setTx(tx);
797         if (tx == null) {
798             if (logger.isLoggable(BasicLevel.DEBUG)) {
799                 logger.log(BasicLevel.DEBUG, "Got a Connection - no TX: ");
800             }
801         } else {
802             if (logger.isLoggable(BasicLevel.DEBUG)) {
803                 logger.log(BasicLevel.DEBUG, "Got a Connection for TX: ");
804             }
805             // register synchronization
806
try {
807                 tx.registerSynchronization(item);
808                 tx2item.put(tx, item); // only if registerSynchronization was OK.
809
} catch (javax.transaction.RollbackException JavaDoc e) {
810                 /// optimization is probably possible at this point
811
if (logger.isLoggable(BasicLevel.WARN)) {
812                     logger.log(BasicLevel.WARN, "DataSource " + cmgr.getDatasourceName()
813                             + " error: Pool item registered, but tx is rollback only", e);
814                 }
815             } catch (javax.transaction.SystemException JavaDoc e) {
816                 if (logger.isLoggable(BasicLevel.ERROR)) {
817                     logger.log(BasicLevel.ERROR, "DataSource " + cmgr.getDatasourceName()
818                             + " error in pool: system exception from transaction manager ", e);
819                 }
820             } catch (IllegalStateException JavaDoc e) {
821                 // In case transaction has already committed, do as if no tx.
822
if (logger.isLoggable(BasicLevel.WARN)) {
823                     logger.log(BasicLevel.WARN, "Got a Connection - committed TX: ", e);
824                 }
825                 item.setTx(null);
826             }
827         }
828         item.open();
829         servedOpen++;
830         return item;
831     }
832
833     /**
834      * The transaction has committed (or rolled back). We can return its
835      * connections to the pool of available connections.
836      * @param tx the non null transaction
837      */

838     public synchronized void freeConnections(Transaction JavaDoc tx) {
839         if (logger.isLoggable(BasicLevel.DEBUG)) {
840             logger.log(BasicLevel.DEBUG, "free connection for Tx = " + tx);
841         }
842         PoolItem item = (PoolItem) tx2item.remove(tx);
843         if (item == null) {
844             logger.log(BasicLevel.ERROR, "pool: no connection found to free for Tx = " + tx);
845             return;
846         }
847         item.setTx(null);
848         if (item.isOpen()) {
849             // Connection may be not closed in case of stateful session bean that
850
// keeps connection to be reused in another method of the bean.
851
logger.log(BasicLevel.WARN, "WARNING: Connection not closed by caller");
852             return;
853         }
854         freeItem(item);
855     }
856
857     /**
858      * Mark a specific Connection in the pool as closed.
859      * If it is no longer associated to a Tx, we can free it.
860      * @param xac XAConnection being closed
861      * @param flag TMSUCCESS (normal close) or TMFAIL (error)
862      * @return the PoolItem the connection is in (=> tx)
863      * or null if error.
864      */

865     public synchronized PoolItem closeConnection(XAConnection JavaDoc xac, int flag) {
866         PoolItem item = (PoolItem) xac2item.get(xac);
867         if (item == null) {
868             logger.log(BasicLevel.ERROR, "Pool: no item for this xac!");
869             return null;
870         }
871         // The connection will be available only if not associated
872
// to a transaction. Else, it will be reusable only for the
873
// same transaction.
874
if (!item.close()) {
875             return null;
876         }
877         if (item.getTx() != null) {
878             if (logger.isLoggable(BasicLevel.DEBUG)) {
879                 logger.log(BasicLevel.DEBUG, "keep the Connection for this tx");
880             }
881         } else {
882             freeItem(item);
883         }
884
885         // delist Resource if in transaction
886
Transaction JavaDoc tx = null;
887         try {
888             tx = tm.getTransaction();
889         } catch (NullPointerException JavaDoc n) {
890             // current is null: we are not in JOnAS Server.
891
logger.log(BasicLevel.ERROR, "Pool: should not be used outside a JOnAS Server", n);
892         } catch (SystemException JavaDoc e) {
893             logger.log(BasicLevel.ERROR, "Pool: getTransaction failed:", e);
894         }
895         if (tx != null && item.isClosed()) {
896             try {
897                 tx.delistResource(xac.getXAResource(), flag);
898             } catch (Exception JavaDoc e) {
899                 logger.log(BasicLevel.ERROR, "Pool: Exception while delisting resource:", e);
900             }
901         }
902
903         return item;
904     }
905
906     /**
907      * make samples with some monitoring values
908      */

909     public synchronized void sampling() {
910         waitingHighRecent = waitingTime;
911         if (waitingHigh < waitingTime) {
912             waitingHigh = waitingTime;
913         }
914         waitingTime = 0;
915
916         waitersHighRecent = waiterCount;
917         if (waitersHigh < waiterCount) {
918             waitersHigh = waiterCount;
919         }
920         waiterCount = 0;
921
922         busyMaxRecent = busyMax;
923         busyMax = getCurrentBusy();
924         busyMinRecent = busyMin;
925         busyMin = getCurrentBusy();
926     }
927
928     /**
929      * Adjust the pool size, according to poolMax and poolMin values.
930      * Also remove old connections in the freeList.
931      */

932     public synchronized void adjust() {
933         if (logger.isLoggable(BasicLevel.DEBUG)) {
934             logger.log(BasicLevel.DEBUG, "");
935         }
936
937         // Remove max aged elements in freelist
938
// - Not more than MAX_REMOVE_FREELIST
939
// - Don't reduce pool size less than poolMin
940
int count = xac2item.size() - poolMin;
941         // In case count is null, a new connection will be
942
// recreated just after
943
if (count >= 0) {
944             if (count > MAX_REMOVE_FREELIST) {
945                 count = MAX_REMOVE_FREELIST;
946             }
947             for (Iterator JavaDoc i = freeList.iterator(); i.hasNext();) {
948                 PoolItem item = (PoolItem) i.next();
949                 if (item.isAged()) {
950                     if (logger.isLoggable(BasicLevel.DEBUG)) {
951                         logger.log(BasicLevel.DEBUG, "remove a timed out connection");
952                     }
953                     i.remove();
954                     destroyItem(item);
955                     count--;
956                     if (count <= 0) {
957                         break;
958                     }
959                 }
960             }
961         }
962         recomputeBusy();
963
964         // Close (physically) connections lost (opened for too long time)
965
for (Iterator JavaDoc i = xac2item.values().iterator(); i.hasNext();) {
966             PoolItem item = (PoolItem) i.next();
967             if (item.inactive()) {
968                 logger.log(BasicLevel.WARN, "close a timed out open connection");
969                 i.remove();
970                 // destroy item
971
item.remove();
972                 connectionLeaks++;
973                 // Notify 1 thread waiting for a Connection.
974
if (currentWaiters > 0) {
975                     notify();
976                 }
977             }
978         }
979
980         // Shrink the pool in case of max pool size
981
// This occurs when max pool size has been reduced by jonas admin.
982
if (poolMax != NO_LIMIT) {
983             while (freeList.size() > poolMin && xac2item.size() > poolMax) {
984                 PoolItem item = (PoolItem) freeList.removeFirst();
985                 destroyItem(item);
986             }
987         }
988         recomputeBusy();
989
990         // Recreate more Connections while poolMin is not reached
991
while (xac2item.size() < poolMin) {
992             XAConnection JavaDoc xac = null;
993             try {
994                 xac = xads.getXAConnection();
995                 openedCount++;
996             } catch (SQLException JavaDoc e) {
997                 throw new ServiceException("Could not create " + poolMin + " items in the pool : ", e);
998             }
999             // tx = null. Assumes maxage already configured.
1000
if (logger.isLoggable(BasicLevel.DEBUG)) {
1001                logger.log(BasicLevel.DEBUG, "Create a new available Connection");
1002            }
1003            PoolItem item = new PoolItem(this, xac, null, logger);
1004            freeList.addLast(item);
1005            xac2item.put(xac, item);
1006            xac.addConnectionEventListener(cmgr);
1007        }
1008    }
1009
1010    /**
1011     * Close all connections in the pool, when server is shut down.
1012     */

1013    public synchronized void closeAllConnections() {
1014        if (logger.isLoggable(BasicLevel.DEBUG)) {
1015            logger.log(BasicLevel.DEBUG, "");
1016        }
1017
1018        // Stop the pool keeper, since all connections will be closed.
1019
poolKeeper.stop();
1020
1021        // Close physically all connections
1022
Iterator JavaDoc it = xac2item.keySet().iterator();
1023        try {
1024            while (it.hasNext()) {
1025                XAConnection JavaDoc xac = (XAConnection JavaDoc) it.next();
1026                xac.close();
1027            }
1028        } catch (java.sql.SQLException JavaDoc e) {
1029            logger.log(BasicLevel.ERROR, "Error while closing a Connection:", e);
1030        }
1031    }
1032
1033    // ----------------------------------------------------------------
1034
// Private Methods
1035
// ----------------------------------------------------------------
1036

1037    /**
1038     * Free item and return it in the free list.
1039     * @param item The item to be freed
1040     */

1041    private void freeItem(PoolItem item) {
1042        // Add it to the free list
1043
// Even if maxage is reached, because we avoids going under min pool size.
1044
// PoolKeeper will manage aged connections.
1045
freeList.addLast(item);
1046        if (logger.isLoggable(BasicLevel.DEBUG)) {
1047            logger.log(BasicLevel.DEBUG, "item added to freeList: " + freeList.size());
1048        }
1049        // Notify 1 thread waiting for a Connection.
1050
if (currentWaiters > 0) {
1051            notify();
1052        }
1053        recomputeBusy();
1054    }
1055
1056    /**
1057     * Destroy an item because connection closed or error occured
1058     * @param item The item to be destroyed
1059     */

1060    private void destroyItem(PoolItem item) {
1061        if (logger.isLoggable(BasicLevel.DEBUG)) {
1062            logger.log(BasicLevel.DEBUG, "remove an item in xac2item");
1063        }
1064        xac2item.remove(item.getXACon());
1065        item.remove();
1066        // Notify 1 thread waiting for a Connection.
1067
if (currentWaiters > 0) {
1068            notify();
1069        }
1070        recomputeBusy();
1071    }
1072
1073}
1074
Popular Tags