Source Code Cross Referenced for BasicResourcePool.java in  » Database-JDBC-Connection-Pool » c3p0 » com » mchange » v2 » resourcepool » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database JDBC Connection Pool » c3p0 » com.mchange.v2.resourcepool 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Distributed as part of c3p0 v.0.9.1.2
0003:         *
0004:         * Copyright (C) 2005 Machinery For Change, Inc.
0005:         *
0006:         * Author: Steve Waldman <swaldman@mchange.com>
0007:         *
0008:         * This library is free software; you can redistribute it and/or modify
0009:         * it under the terms of the GNU Lesser General Public License version 2.1, as 
0010:         * published by the Free Software Foundation.
0011:         *
0012:         * This software is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015:         * GNU Lesser General Public License for more details.
0016:         *
0017:         * You should have received a copy of the GNU Lesser General Public License
0018:         * along with this software; see the file LICENSE.  If not, write to the
0019:         * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
0020:         * Boston, MA 02111-1307, USA.
0021:         */
0022:
0023:        package com.mchange.v2.resourcepool;
0024:
0025:        import java.util.*;
0026:        import com.mchange.v2.async.*;
0027:        import com.mchange.v2.log.*;
0028:        import com.mchange.v2.lang.ThreadUtils;
0029:        import com.mchange.v2.util.ResourceClosedException;
0030:
0031:        class BasicResourcePool implements  ResourcePool {
0032:            private final static MLogger logger = MLog
0033:                    .getLogger(BasicResourcePool.class);
0034:
0035:            final static int AUTO_CULL_FREQUENCY_DIVISOR = 4;
0036:            final static int AUTO_MAX_CULL_FREQUENCY = (15 * 60 * 1000); //15 mins
0037:            final static int AUTO_MIN_CULL_FREQUENCY = (1 * 1000); //15 mins
0038:
0039:            //XXX: temporary -- for selecting between AcquireTask types
0040:            //     remove soon, and use only ScatteredAcquireTask,
0041:            //     presuming no problems appear
0042:            final static String USE_SCATTERED_ACQUIRE_TASK_KEY = "com.mchange.v2.resourcepool.experimental.useScatteredAcquireTask";
0043:            final static boolean USE_SCATTERED_ACQUIRE_TASK;
0044:            static {
0045:                String checkScattered = com.mchange.v2.cfg.MultiPropertiesConfig
0046:                        .readVmConfig().getProperty(
0047:                                USE_SCATTERED_ACQUIRE_TASK_KEY);
0048:                if (checkScattered != null
0049:                        && checkScattered.trim().toLowerCase().equals("true")) {
0050:                    USE_SCATTERED_ACQUIRE_TASK = true;
0051:                    if (logger.isLoggable(MLevel.INFO))
0052:                        logger.info(BasicResourcePool.class.getName()
0053:                                + " using experimental ScatteredAcquireTask.");
0054:                } else
0055:                    USE_SCATTERED_ACQUIRE_TASK = false;
0056:            }
0057:            // end temporary switch between acquire task types
0058:
0059:            //MT: unchanged post c'tor
0060:            final Manager mgr;
0061:
0062:            final int start;
0063:            final int min;
0064:            final int max;
0065:            final int inc;
0066:
0067:            final int num_acq_attempts;
0068:            final int acq_attempt_delay;
0069:
0070:            final long check_idle_resources_delay; //milliseconds
0071:            final long max_resource_age; //milliseconds
0072:            final long max_idle_time; //milliseconds
0073:            final long excess_max_idle_time; //milliseconds
0074:            final long destroy_unreturned_resc_time; //milliseconds
0075:            final long expiration_enforcement_delay; //milliseconds
0076:
0077:            final boolean break_on_acquisition_failure;
0078:            final boolean debug_store_checkout_exceptions;
0079:
0080:            final long pool_start_time = System.currentTimeMillis();
0081:
0082:            //MT: not-reassigned, thread-safe, and independent
0083:            final BasicResourcePoolFactory factory;
0084:            final AsynchronousRunner taskRunner;
0085:            final RunnableQueue asyncEventQueue;
0086:            final ResourcePoolEventSupport rpes;
0087:
0088:            //MT: protected by this' lock
0089:            Timer cullAndIdleRefurbishTimer;
0090:            TimerTask cullTask;
0091:            TimerTask idleRefurbishTask;
0092:            HashSet acquireWaiters = new HashSet();
0093:            HashSet otherWaiters = new HashSet();
0094:
0095:            int pending_acquires;
0096:            int pending_removes;
0097:
0098:            int target_pool_size;
0099:
0100:            /*  keys are all valid, managed resources, value is a PunchCard */
0101:            HashMap managed = new HashMap();
0102:
0103:            /* all valid, managed resources currently available for checkout */
0104:            LinkedList unused = new LinkedList();
0105:
0106:            /* resources which have been invalidated somehow, but which are */
0107:            /* still checked out and in use.                                */
0108:            HashSet excluded = new HashSet();
0109:
0110:            Map formerResources = new WeakHashMap();
0111:
0112:            Set idleCheckResources = new HashSet();
0113:
0114:            boolean force_kill_acquires = false;
0115:
0116:            boolean broken = false;
0117:
0118:            //  long total_acquired = 0;
0119:
0120:            long failed_checkins = 0;
0121:            long failed_checkouts = 0;
0122:            long failed_idle_tests = 0;
0123:
0124:            Throwable lastCheckinFailure = null;
0125:            Throwable lastCheckoutFailure = null;
0126:            Throwable lastIdleTestFailure = null;
0127:            Throwable lastResourceTestFailure = null;
0128:
0129:            Throwable lastAcquisitionFailiure = null;
0130:
0131:            //DEBUG only!
0132:            Object exampleResource;
0133:
0134:            public long getStartTime() {
0135:                return pool_start_time;
0136:            }
0137:
0138:            public long getUpTime() {
0139:                return System.currentTimeMillis() - pool_start_time;
0140:            }
0141:
0142:            public synchronized long getNumFailedCheckins() {
0143:                return failed_checkins;
0144:            }
0145:
0146:            public synchronized long getNumFailedCheckouts() {
0147:                return failed_checkouts;
0148:            }
0149:
0150:            public synchronized long getNumFailedIdleTests() {
0151:                return failed_idle_tests;
0152:            }
0153:
0154:            public synchronized Throwable getLastCheckinFailure() {
0155:                return lastCheckinFailure;
0156:            }
0157:
0158:            //must be called from a pre-existing sync'ed block
0159:            private void setLastCheckinFailure(Throwable t) {
0160:                assert (Thread.holdsLock(this ));
0161:
0162:                this .lastCheckinFailure = t;
0163:                this .lastResourceTestFailure = t;
0164:            }
0165:
0166:            public synchronized Throwable getLastCheckoutFailure() {
0167:                return lastCheckoutFailure;
0168:            }
0169:
0170:            //must be called from a pre-existing sync'ed block
0171:            private void setLastCheckoutFailure(Throwable t) {
0172:                assert (Thread.holdsLock(this ));
0173:
0174:                this .lastCheckoutFailure = t;
0175:                this .lastResourceTestFailure = t;
0176:            }
0177:
0178:            public synchronized Throwable getLastIdleCheckFailure() {
0179:                return lastIdleTestFailure;
0180:            }
0181:
0182:            //must be called from a pre-existing sync'ed block
0183:            private void setLastIdleCheckFailure(Throwable t) {
0184:                assert (Thread.holdsLock(this ));
0185:
0186:                this .lastIdleTestFailure = t;
0187:                this .lastResourceTestFailure = t;
0188:            }
0189:
0190:            public synchronized Throwable getLastResourceTestFailure() {
0191:                return lastResourceTestFailure;
0192:            }
0193:
0194:            public synchronized Throwable getLastAcquisitionFailure() {
0195:                return lastAcquisitionFailiure;
0196:            }
0197:
0198:            // ought not be called while holding this' lock
0199:            private synchronized void setLastAcquisitionFailure(Throwable t) {
0200:                this .lastAcquisitionFailiure = t;
0201:            }
0202:
0203:            public synchronized int getNumCheckoutWaiters() {
0204:                return acquireWaiters.size();
0205:            }
0206:
0207:            private void addToFormerResources(Object resc) {
0208:                formerResources.put(resc, null);
0209:            }
0210:
0211:            private boolean isFormerResource(Object resc) {
0212:                return formerResources.keySet().contains(resc);
0213:            }
0214:
0215:            /**
0216:             * @param factory may be null
0217:             */
0218:            public BasicResourcePool(Manager mgr, int start, int min, int max,
0219:                    int inc, int num_acq_attempts, int acq_attempt_delay,
0220:                    long check_idle_resources_delay, long max_resource_age,
0221:                    long max_idle_time, long excess_max_idle_time,
0222:                    long destroy_unreturned_resc_time,
0223:                    long expiration_enforcement_delay,
0224:                    boolean break_on_acquisition_failure,
0225:                    boolean debug_store_checkout_exceptions,
0226:                    AsynchronousRunner taskRunner,
0227:                    RunnableQueue asyncEventQueue,
0228:                    Timer cullAndIdleRefurbishTimer,
0229:                    BasicResourcePoolFactory factory)
0230:                    throws ResourcePoolException {
0231:                try {
0232:                    this .mgr = mgr;
0233:                    this .start = start;
0234:                    this .min = min;
0235:                    this .max = max;
0236:                    this .inc = inc;
0237:                    this .num_acq_attempts = num_acq_attempts;
0238:                    this .acq_attempt_delay = acq_attempt_delay;
0239:                    this .check_idle_resources_delay = check_idle_resources_delay;
0240:                    this .max_resource_age = max_resource_age;
0241:                    this .max_idle_time = max_idle_time;
0242:                    this .excess_max_idle_time = excess_max_idle_time;
0243:                    this .destroy_unreturned_resc_time = destroy_unreturned_resc_time;
0244:                    //this.expiration_enforcement_delay     = expiration_enforcement_delay; -- set up below
0245:                    this .break_on_acquisition_failure = break_on_acquisition_failure;
0246:                    this .debug_store_checkout_exceptions = (debug_store_checkout_exceptions && destroy_unreturned_resc_time > 0);
0247:                    this .taskRunner = taskRunner;
0248:                    this .asyncEventQueue = asyncEventQueue;
0249:                    this .cullAndIdleRefurbishTimer = cullAndIdleRefurbishTimer;
0250:                    this .factory = factory;
0251:
0252:                    this .pending_acquires = 0;
0253:                    this .pending_removes = 0;
0254:
0255:                    this .target_pool_size = Math.max(start, min);
0256:
0257:                    if (asyncEventQueue != null)
0258:                        this .rpes = new ResourcePoolEventSupport(this );
0259:                    else
0260:                        this .rpes = null;
0261:
0262:                    //start acquiring our initial resources
0263:                    ensureStartResources();
0264:
0265:                    if (mustEnforceExpiration()) {
0266:                        if (expiration_enforcement_delay <= 0)
0267:                            this .expiration_enforcement_delay = automaticExpirationEnforcementDelay();
0268:                        else
0269:                            this .expiration_enforcement_delay = expiration_enforcement_delay;
0270:
0271:                        this .cullTask = new CullTask();
0272:                        //System.err.println("minExpirationTime(): " + minExpirationTime());
0273:                        //System.err.println("this.expiration_enforcement_delay: " + this.expiration_enforcement_delay);
0274:                        cullAndIdleRefurbishTimer.schedule(cullTask,
0275:                                minExpirationTime(),
0276:                                this .expiration_enforcement_delay);
0277:                    } else
0278:                        this .expiration_enforcement_delay = expiration_enforcement_delay;
0279:
0280:                    //System.err.println("this.check_idle_resources_delay: " + this.check_idle_resources_delay);
0281:                    if (check_idle_resources_delay > 0) {
0282:                        this .idleRefurbishTask = new CheckIdleResourcesTask();
0283:                        cullAndIdleRefurbishTimer.schedule(idleRefurbishTask,
0284:                                check_idle_resources_delay,
0285:                                check_idle_resources_delay);
0286:                    }
0287:
0288:                    if (logger.isLoggable(MLevel.FINER))
0289:                        logger.finer(this  + " config: [start -> " + this .start
0290:                                + "; min -> " + this .min + "; max -> "
0291:                                + this .max + "; inc -> " + this .inc
0292:                                + "; num_acq_attempts -> "
0293:                                + this .num_acq_attempts
0294:                                + "; acq_attempt_delay -> "
0295:                                + this .acq_attempt_delay
0296:                                + "; check_idle_resources_delay -> "
0297:                                + this .check_idle_resources_delay
0298:                                + "; mox_resource_age -> "
0299:                                + this .max_resource_age + "; max_idle_time -> "
0300:                                + this .max_idle_time
0301:                                + "; excess_max_idle_time -> "
0302:                                + this .excess_max_idle_time
0303:                                + "; destroy_unreturned_resc_time -> "
0304:                                + this .destroy_unreturned_resc_time
0305:                                + "; expiration_enforcement_delay -> "
0306:                                + this .expiration_enforcement_delay
0307:                                + "; break_on_acquisition_failure -> "
0308:                                + this .break_on_acquisition_failure
0309:                                + "; debug_store_checkout_exceptions -> "
0310:                                + this .debug_store_checkout_exceptions + "]");
0311:
0312:                } catch (Exception e) {
0313:                    //          if ( logger.isLoggable( MLevel.WARNING) )
0314:                    //          logger.log( MLevel.WARNING, "Could not create resource pool due to Exception!", e );
0315:
0316:                    throw ResourcePoolUtils.convertThrowable(e);
0317:                }
0318:            }
0319:
0320:            //  private boolean timerRequired()
0321:            //  { return mustEnforceExpiration() || mustTestIdleResources(); }
0322:
0323:            // no need to sync
0324:            private boolean mustTestIdleResources() {
0325:                return check_idle_resources_delay > 0;
0326:            }
0327:
0328:            // no need to sync
0329:            private boolean mustEnforceExpiration() {
0330:                return max_resource_age > 0 || max_idle_time > 0
0331:                        || excess_max_idle_time > 0
0332:                        || destroy_unreturned_resc_time > 0;
0333:            }
0334:
0335:            // no need to sync
0336:            private long minExpirationTime() {
0337:                long out = Long.MAX_VALUE;
0338:                if (max_resource_age > 0)
0339:                    out = Math.min(out, max_resource_age);
0340:                if (max_idle_time > 0)
0341:                    out = Math.min(out, max_idle_time);
0342:                if (excess_max_idle_time > 0)
0343:                    out = Math.min(out, excess_max_idle_time);
0344:                if (destroy_unreturned_resc_time > 0)
0345:                    out = Math.min(out, destroy_unreturned_resc_time);
0346:                return out;
0347:            }
0348:
0349:            private long automaticExpirationEnforcementDelay() {
0350:                long out = minExpirationTime();
0351:                out /= AUTO_CULL_FREQUENCY_DIVISOR;
0352:                out = Math.min(out, AUTO_MAX_CULL_FREQUENCY);
0353:                out = Math.max(out, AUTO_MIN_CULL_FREQUENCY);
0354:                return out;
0355:            }
0356:
0357:            public long getEffectiveExpirationEnforcementDelay() {
0358:                return expiration_enforcement_delay;
0359:            }
0360:
0361:            private synchronized boolean isBroken() {
0362:                return broken;
0363:            }
0364:
0365:            // no need to sync
0366:            private boolean supportsEvents() {
0367:                return asyncEventQueue != null;
0368:            }
0369:
0370:            public Object checkoutResource() throws ResourcePoolException,
0371:                    InterruptedException {
0372:                try {
0373:                    return checkoutResource(0);
0374:                } catch (TimeoutException e) {
0375:                    //this should never happen
0376:                    //e.printStackTrace();
0377:                    if (logger.isLoggable(MLevel.WARNING))
0378:                        logger
0379:                                .log(
0380:                                        MLevel.WARNING,
0381:                                        "Huh??? TimeoutException with no timeout set!!!",
0382:                                        e);
0383:
0384:                    throw new ResourcePoolException(
0385:                            "Huh??? TimeoutException with no timeout set!!!", e);
0386:                }
0387:            }
0388:
0389:            // must be called from synchronized method, idempotent
0390:            private void _recheckResizePool() {
0391:                assert Thread.holdsLock(this );
0392:
0393:                if (!broken) {
0394:                    int msz = managed.size();
0395:                    //int expected_size = msz + pending_acquires - pending_removes;
0396:
0397:                    //          System.err.print("target: " + target_pool_size);
0398:                    //          System.err.println(" (msz: " + msz + "; pending_acquires: " + pending_acquires + "; pending_removes: " + pending_removes + ')');
0399:                    //new Exception( "_recheckResizePool() STACK TRACE" ).printStackTrace();
0400:
0401:                    int shrink_count;
0402:                    int expand_count;
0403:
0404:                    if ((shrink_count = msz - pending_removes
0405:                            - target_pool_size) > 0)
0406:                        shrinkPool(shrink_count);
0407:                    else if ((expand_count = target_pool_size
0408:                            - (msz + pending_acquires)) > 0)
0409:                        expandPool(expand_count);
0410:                }
0411:            }
0412:
0413:            private synchronized void incrementPendingAcquires() {
0414:                ++pending_acquires;
0415:
0416:                if (logger.isLoggable(MLevel.FINEST))
0417:                    logger.finest("incremented pending_acquires: "
0418:                            + pending_acquires);
0419:                //new Exception("ACQUIRE SOURCE STACK TRACE").printStackTrace();
0420:            }
0421:
0422:            private synchronized void incrementPendingRemoves() {
0423:                ++pending_removes;
0424:
0425:                if (logger.isLoggable(MLevel.FINEST))
0426:                    logger.finest("incremented pending_removes: "
0427:                            + pending_removes);
0428:                //new Exception("REMOVE SOURCE STACK TRACE").printStackTrace();
0429:            }
0430:
0431:            private synchronized void decrementPendingAcquires() {
0432:                --pending_acquires;
0433:
0434:                if (logger.isLoggable(MLevel.FINEST))
0435:                    logger.finest("decremented pending_acquires: "
0436:                            + pending_acquires);
0437:                //new Exception("ACQUIRE SOURCE STACK TRACE").printStackTrace();
0438:            }
0439:
0440:            private synchronized void decrementPendingRemoves() {
0441:                --pending_removes;
0442:
0443:                if (logger.isLoggable(MLevel.FINEST))
0444:                    logger.finest("decremented pending_removes: "
0445:                            + pending_removes);
0446:                //new Exception("ACQUIRE SOURCE STACK TRACE").printStackTrace();
0447:            }
0448:
0449:            // idempotent
0450:            private synchronized void recheckResizePool() {
0451:                _recheckResizePool();
0452:            }
0453:
0454:            // must be called from synchronized method
0455:            private void expandPool(int count) {
0456:                assert Thread.holdsLock(this );
0457:
0458:                // XXX: temporary switch -- assuming no problems appear, we'll get rid of AcquireTask
0459:                //      in favor of ScatteredAcquireTask
0460:                if (USE_SCATTERED_ACQUIRE_TASK) {
0461:                    for (int i = 0; i < count; ++i)
0462:                        taskRunner.postRunnable(new ScatteredAcquireTask());
0463:                } else {
0464:                    for (int i = 0; i < count; ++i)
0465:                        taskRunner.postRunnable(new AcquireTask());
0466:                }
0467:            }
0468:
0469:            // must be called from synchronized method
0470:            private void shrinkPool(int count) {
0471:                assert Thread.holdsLock(this );
0472:
0473:                for (int i = 0; i < count; ++i)
0474:                    taskRunner.postRunnable(new RemoveTask());
0475:            }
0476:
0477:            /*
0478:             * This function recursively calls itself... under nonpathological
0479:             * situations, it shouldn't be a problem, but if resources can never
0480:             * successfully check out for some reason, we might blow the stack...
0481:             *
0482:             * by the semantics of wait(), a timeout of zero means forever.
0483:             */
0484:            public Object checkoutResource(long timeout)
0485:                    throws TimeoutException, ResourcePoolException,
0486:                    InterruptedException {
0487:                Object resc = prelimCheckoutResource(timeout);
0488:
0489:                boolean refurb = attemptRefurbishResourceOnCheckout(resc);
0490:
0491:                synchronized (this ) {
0492:                    if (!refurb) {
0493:                        removeResource(resc);
0494:                        ensureMinResources();
0495:                        resc = null;
0496:                    } else {
0497:                        asyncFireResourceCheckedOut(resc, managed.size(),
0498:                                unused.size(), excluded.size());
0499:                        if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
0500:                            trace();
0501:
0502:                        PunchCard card = (PunchCard) managed.get(resc);
0503:                        if (card == null) //the resource has been removed!
0504:                        {
0505:                            if (logger.isLoggable(MLevel.FINE))
0506:                                logger
0507:                                        .fine("Resource "
0508:                                                + resc
0509:                                                + " was removed from the pool while it was being checked out "
0510:                                                + " or refurbished for checkout.");
0511:                            resc = null;
0512:                        } else {
0513:                            card.checkout_time = System.currentTimeMillis();
0514:                            if (debug_store_checkout_exceptions)
0515:                                card.checkoutStackTraceException = new Exception(
0516:                                        "DEBUG ONLY: Overdue resource check-out stack trace.");
0517:                        }
0518:                    }
0519:                }
0520:
0521:                // best to do the recheckout while we don't hold this'
0522:                // lock, so we don't refurbish-on-checkout while holding.
0523:                if (resc == null)
0524:                    return checkoutResource(timeout);
0525:                else
0526:                    return resc;
0527:            }
0528:
0529:            private synchronized Object prelimCheckoutResource(long timeout)
0530:                    throws TimeoutException, ResourcePoolException,
0531:                    InterruptedException {
0532:                try {
0533:                    ensureNotBroken();
0534:
0535:                    int available = unused.size();
0536:                    if (available == 0) {
0537:                        int msz = managed.size();
0538:
0539:                        if (msz < max) {
0540:                            // to cover all the load, we need the current size, plus those waiting already for acquisition, 
0541:                            // plus the current client 
0542:                            int desired_target = msz + acquireWaiters.size()
0543:                                    + 1;
0544:
0545:                            if (logger.isLoggable(MLevel.FINER))
0546:                                logger.log(MLevel.FINER,
0547:                                        "acquire test -- pool size: " + msz
0548:                                                + "; target_pool_size: "
0549:                                                + target_pool_size
0550:                                                + "; desired target? "
0551:                                                + desired_target);
0552:
0553:                            if (desired_target >= target_pool_size) {
0554:                                //make sure we don't grab less than inc Connections at a time, if we can help it.
0555:                                desired_target = Math.max(desired_target,
0556:                                        target_pool_size + inc);
0557:
0558:                                //make sure our target is within its bounds
0559:                                target_pool_size = Math.max(Math.min(max,
0560:                                        desired_target), min);
0561:
0562:                                _recheckResizePool();
0563:                            }
0564:                        } else {
0565:                            if (logger.isLoggable(MLevel.FINER))
0566:                                logger.log(MLevel.FINER,
0567:                                        "acquire test -- pool is already maxed out. [managed: "
0568:                                                + msz + "; max: " + max + "]");
0569:                        }
0570:
0571:                        awaitAvailable(timeout); //throws timeout exception
0572:                    }
0573:
0574:                    Object resc = unused.get(0);
0575:
0576:                    // this is a hack -- but "doing it right" adds a lot of complexity, and collisions between
0577:                    // an idle check and a checkout should be relatively rare. anyway, it should work just fine.
0578:                    if (idleCheckResources.contains(resc)) {
0579:                        if (Debug.DEBUG && logger.isLoggable(MLevel.FINER))
0580:                            logger
0581:                                    .log(
0582:                                            MLevel.FINER,
0583:                                            "Resource we want to check out is in idleCheck! (waiting until idle-check completes.) ["
0584:                                                    + this  + "]");
0585:
0586:                        // we'll move remove() to after the if, so we don't have to add back
0587:                        // unused.add(0, resc );
0588:
0589:                        // we'll wait for "something to happen" -- probably an idle check to
0590:                        // complete -- then we'll try again and hope for the best.
0591:                        Thread t = Thread.currentThread();
0592:                        try {
0593:                            otherWaiters.add(t);
0594:                            this .wait(timeout);
0595:                            ensureNotBroken();
0596:                        } finally {
0597:                            otherWaiters.remove(t);
0598:                        }
0599:                        return prelimCheckoutResource(timeout);
0600:                    } else if (shouldExpire(resc)) {
0601:                        removeResource(resc);
0602:                        ensureMinResources();
0603:                        return prelimCheckoutResource(timeout);
0604:                    } else {
0605:                        unused.remove(0);
0606:                        return resc;
0607:                    }
0608:                } catch (ResourceClosedException e) // one of our async threads died
0609:                {
0610:                    //System.err.println(this + " -- the pool was found to be closed or broken during an attempt to check out a resource.");
0611:                    //e.printStackTrace();
0612:                    if (logger.isLoggable(MLevel.SEVERE))
0613:                        logger
0614:                                .log(
0615:                                        MLevel.SEVERE,
0616:                                        this 
0617:                                                + " -- the pool was found to be closed or broken during an attempt to check out a resource.",
0618:                                        e);
0619:
0620:                    this .unexpectedBreak();
0621:                    throw e;
0622:                } catch (InterruptedException e) {
0623:                    // 		System.err.println(this + " -- an attempt to checkout a resource was interrupted: some other thread " +
0624:                    // 				   "must have either interrupted the Thread attempting checkout, or close() was called on the pool.");
0625:                    // 		e.printStackTrace();
0626:                    if (broken) {
0627:                        if (logger.isLoggable(MLevel.FINER))
0628:                            logger
0629:                                    .log(
0630:                                            MLevel.FINER,
0631:                                            this 
0632:                                                    + " -- an attempt to checkout a resource was interrupted, because the pool is now closed. "
0633:                                                    + "[Thread: "
0634:                                                    + Thread.currentThread()
0635:                                                            .getName() + ']', e);
0636:                        else if (logger.isLoggable(MLevel.INFO))
0637:                            logger
0638:                                    .log(
0639:                                            MLevel.INFO,
0640:                                            this 
0641:                                                    + " -- an attempt to checkout a resource was interrupted, because the pool is now closed. "
0642:                                                    + "[Thread: "
0643:                                                    + Thread.currentThread()
0644:                                                            .getName() + ']');
0645:                    } else {
0646:                        if (logger.isLoggable(MLevel.WARNING)) {
0647:                            logger
0648:                                    .log(
0649:                                            MLevel.WARNING,
0650:                                            this 
0651:                                                    + " -- an attempt to checkout a resource was interrupted, and the pool is still live: some other thread "
0652:                                                    + "must have either interrupted the Thread attempting checkout!",
0653:                                            e);
0654:                        }
0655:                    }
0656:                    throw e;
0657:                }
0658:            }
0659:
0660:            public synchronized void checkinResource(Object resc)
0661:                    throws ResourcePoolException {
0662:                try {
0663:                    //we permit straggling resources to be checked in 
0664:                    //without exception even if we are broken
0665:                    if (managed.keySet().contains(resc))
0666:                        doCheckinManaged(resc);
0667:                    else if (excluded.contains(resc))
0668:                        doCheckinExcluded(resc);
0669:                    else if (isFormerResource(resc)) {
0670:                        if (logger.isLoggable(MLevel.FINER))
0671:                            logger
0672:                                    .finer("Resource "
0673:                                            + resc
0674:                                            + " checked-in after having been checked-in already, or checked-in after "
0675:                                            + " having being destroyed for being checked-out too long.");
0676:                    } else
0677:                        throw new ResourcePoolException("ResourcePool"
0678:                                + (broken ? " [BROKEN!]" : "")
0679:                                + ": Tried to check-in a foreign resource!");
0680:                    if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
0681:                        trace();
0682:                } catch (ResourceClosedException e) // one of our async threads died
0683:                {
0684:                    //          System.err.println(this + 
0685:                    //          " - checkinResource( ... ) -- even broken pools should allow checkins without exception. probable resource pool bug.");
0686:                    //          e.printStackTrace();
0687:
0688:                    if (logger.isLoggable(MLevel.SEVERE))
0689:                        logger
0690:                                .log(
0691:                                        MLevel.SEVERE,
0692:                                        this 
0693:                                                + " - checkinResource( ... ) -- even broken pools should allow checkins without exception. probable resource pool bug.",
0694:                                        e);
0695:
0696:                    this .unexpectedBreak();
0697:                    throw e;
0698:                }
0699:            }
0700:
0701:            public synchronized void checkinAll() throws ResourcePoolException {
0702:                try {
0703:                    Set checkedOutNotExcluded = new HashSet(managed.keySet());
0704:                    checkedOutNotExcluded.removeAll(unused);
0705:                    for (Iterator ii = checkedOutNotExcluded.iterator(); ii
0706:                            .hasNext();)
0707:                        doCheckinManaged(ii.next());
0708:                    for (Iterator ii = excluded.iterator(); ii.hasNext();)
0709:                        doCheckinExcluded(ii.next());
0710:                } catch (ResourceClosedException e) // one of our async threads died
0711:                {
0712:                    //          System.err.println(this + 
0713:                    //          " - checkinAll() -- even broken pools should allow checkins without exception. probable resource pool bug.");
0714:                    //          e.printStackTrace();
0715:
0716:                    if (logger.isLoggable(MLevel.SEVERE))
0717:                        logger
0718:                                .log(
0719:                                        MLevel.SEVERE,
0720:                                        this 
0721:                                                + " - checkinAll() -- even broken pools should allow checkins without exception. probable resource pool bug.",
0722:                                        e);
0723:
0724:                    this .unexpectedBreak();
0725:                    throw e;
0726:                }
0727:            }
0728:
0729:            public synchronized int statusInPool(Object resc)
0730:                    throws ResourcePoolException {
0731:                try {
0732:                    if (unused.contains(resc))
0733:                        return KNOWN_AND_AVAILABLE;
0734:                    else if (managed.keySet().contains(resc)
0735:                            || excluded.contains(resc))
0736:                        return KNOWN_AND_CHECKED_OUT;
0737:                    else
0738:                        return UNKNOWN_OR_PURGED;
0739:                } catch (ResourceClosedException e) // one of our async threads died
0740:                {
0741:                    //          e.printStackTrace();
0742:                    if (logger.isLoggable(MLevel.SEVERE))
0743:                        logger.log(MLevel.SEVERE, "Apparent pool break.", e);
0744:                    this .unexpectedBreak();
0745:                    throw e;
0746:                }
0747:            }
0748:
0749:            public synchronized void markBroken(Object resc) {
0750:                try {
0751:                    if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX
0752:                            && logger.isLoggable(MLevel.FINER))
0753:                        logger.log(MLevel.FINER, "Resource " + resc
0754:                                + " marked broken by pool (" + this  + ").");
0755:
0756:                    _markBroken(resc);
0757:                    ensureMinResources();
0758:                } catch (ResourceClosedException e) // one of our async threads died
0759:                {
0760:                    //e.printStackTrace();
0761:                    if (logger.isLoggable(MLevel.SEVERE))
0762:                        logger.log(MLevel.SEVERE, "Apparent pool break.", e);
0763:                    this .unexpectedBreak();
0764:                }
0765:            }
0766:
0767:            //min is immutable, no need to synchronize
0768:            public int getMinPoolSize() {
0769:                return min;
0770:            }
0771:
0772:            //max is immutable, no need to synchronize
0773:            public int getMaxPoolSize() {
0774:                return max;
0775:            }
0776:
0777:            public synchronized int getPoolSize() throws ResourcePoolException {
0778:                return managed.size();
0779:            }
0780:
0781:            //  //i don't think i like the async, no-guarantees approach
0782:            //  public synchronized void requestResize( int req_sz )
0783:            //  {
0784:            //  if (req_sz > max)
0785:            //  req_sz = max;
0786:            //  else if (req_sz < min)
0787:            //  req_sz = min;
0788:            //  int sz = managed.size();
0789:            //  if (req_sz > sz)
0790:            //  postAcquireUntil( req_sz );
0791:            //  else if (req_sz < sz)
0792:            //  postRemoveTowards( req_sz );
0793:            //  }
0794:
0795:            public synchronized int getAvailableCount() {
0796:                return unused.size();
0797:            }
0798:
0799:            public synchronized int getExcludedCount() {
0800:                return excluded.size();
0801:            }
0802:
0803:            public synchronized int getAwaitingCheckinCount() {
0804:                return managed.size() - unused.size() + excluded.size();
0805:            }
0806:
0807:            public synchronized void resetPool() {
0808:                try {
0809:                    for (Iterator ii = cloneOfManaged().keySet().iterator(); ii
0810:                            .hasNext();)
0811:                        markBrokenNoEnsureMinResources(ii.next());
0812:                    ensureMinResources();
0813:                } catch (ResourceClosedException e) // one of our async threads died
0814:                {
0815:                    //e.printStackTrace();
0816:                    if (logger.isLoggable(MLevel.SEVERE))
0817:                        logger.log(MLevel.SEVERE, "Apparent pool break.", e);
0818:                    this .unexpectedBreak();
0819:                }
0820:            }
0821:
0822:            public synchronized void close() throws ResourcePoolException {
0823:                //we permit closes when we are already broken, so
0824:                //that resources that were checked out when the break
0825:                //occured can still be cleaned up
0826:                close(true);
0827:            }
0828:
0829:            public void finalize() throws Throwable {
0830:                //obviously, clients mustn't rely on finalize,
0831:                //but must close pools ASAP after use.
0832:                //System.err.println("finalizing..." + this);
0833:
0834:                if (!broken)
0835:                    this .close();
0836:            }
0837:
0838:            //no need to sync
0839:            public void addResourcePoolListener(ResourcePoolListener rpl) {
0840:                if (!supportsEvents())
0841:                    throw new RuntimeException(
0842:                            this 
0843:                                    + " does not support ResourcePoolEvents. "
0844:                                    + "Probably it was constructed by a BasicResourceFactory configured not to support such events.");
0845:                else
0846:                    rpes.addResourcePoolListener(rpl);
0847:            }
0848:
0849:            //no need to sync
0850:            public void removeResourcePoolListener(ResourcePoolListener rpl) {
0851:                if (!supportsEvents())
0852:                    throw new RuntimeException(
0853:                            this 
0854:                                    + " does not support ResourcePoolEvents. "
0855:                                    + "Probably it was constructed by a BasicResourceFactory configured not to support such events.");
0856:                else
0857:                    rpes.removeResourcePoolListener(rpl);
0858:            }
0859:
0860:            private synchronized boolean isForceKillAcquiresPending() {
0861:                return force_kill_acquires;
0862:            }
0863:
0864:            // this is designed as a response to a determination that our resource source is down.
0865:            // rather than declaring ourselves broken in this case (as we did previously), we
0866:            // kill all pending acquisition attempts, but retry on new acqusition requests.
0867:            private synchronized void forceKillAcquires()
0868:                    throws InterruptedException {
0869:                Thread t = Thread.currentThread();
0870:
0871:                try {
0872:                    force_kill_acquires = true;
0873:                    this .notifyAll(); //wake up any threads waiting on an acquire, and force them all to die.
0874:                    while (acquireWaiters.size() > 0) //we want to let all the waiting acquires die before we unset force_kill_acquires
0875:                    {
0876:                        otherWaiters.add(t);
0877:                        this .wait();
0878:                    }
0879:                    force_kill_acquires = false;
0880:                } finally {
0881:                    otherWaiters.remove(t);
0882:                }
0883:            }
0884:
0885:            //same as close(), but we do not destroy checked out
0886:            //resources
0887:            private synchronized void unexpectedBreak() {
0888:                if (logger.isLoggable(MLevel.SEVERE))
0889:                    logger.log(MLevel.SEVERE, this 
0890:                            + " -- Unexpectedly broken!!!",
0891:                            new ResourcePoolException(
0892:                                    "Unexpected Break Stack Trace!"));
0893:                close(false);
0894:            }
0895:
0896:            // no need to sync
0897:            private boolean canFireEvents() {
0898:                return (asyncEventQueue != null && !isBroken());
0899:            }
0900:
0901:            // no need to sync
0902:            private void asyncFireResourceAcquired(final Object resc,
0903:                    final int pool_size, final int available_size,
0904:                    final int removed_but_unreturned_size) {
0905:                if (canFireEvents()) {
0906:                    Runnable r = new Runnable() {
0907:                        public void run() {
0908:                            rpes
0909:                                    .fireResourceAcquired(resc, pool_size,
0910:                                            available_size,
0911:                                            removed_but_unreturned_size);
0912:                        }
0913:                    };
0914:                    asyncEventQueue.postRunnable(r);
0915:                }
0916:            }
0917:
0918:            // no need to sync
0919:            private void asyncFireResourceCheckedIn(final Object resc,
0920:                    final int pool_size, final int available_size,
0921:                    final int removed_but_unreturned_size) {
0922:                if (canFireEvents()) {
0923:                    Runnable r = new Runnable() {
0924:                        public void run() {
0925:                            rpes
0926:                                    .fireResourceCheckedIn(resc, pool_size,
0927:                                            available_size,
0928:                                            removed_but_unreturned_size);
0929:                        }
0930:                    };
0931:                    asyncEventQueue.postRunnable(r);
0932:                }
0933:            }
0934:
0935:            // no need to sync
0936:            private void asyncFireResourceCheckedOut(final Object resc,
0937:                    final int pool_size, final int available_size,
0938:                    final int removed_but_unreturned_size) {
0939:                if (canFireEvents()) {
0940:                    Runnable r = new Runnable() {
0941:                        public void run() {
0942:                            rpes
0943:                                    .fireResourceCheckedOut(resc, pool_size,
0944:                                            available_size,
0945:                                            removed_but_unreturned_size);
0946:                        }
0947:                    };
0948:                    asyncEventQueue.postRunnable(r);
0949:                }
0950:            }
0951:
0952:            // no need to sync
0953:            private void asyncFireResourceRemoved(final Object resc,
0954:                    final boolean checked_out_resource, final int pool_size,
0955:                    final int available_size,
0956:                    final int removed_but_unreturned_size) {
0957:                if (canFireEvents()) {
0958:                    //System.err.println("ASYNC RSRC REMOVED");
0959:                    //new Exception().printStackTrace();
0960:                    Runnable r = new Runnable() {
0961:                        public void run() {
0962:                            rpes
0963:                                    .fireResourceRemoved(resc,
0964:                                            checked_out_resource, pool_size,
0965:                                            available_size,
0966:                                            removed_but_unreturned_size);
0967:                        }
0968:                    };
0969:                    asyncEventQueue.postRunnable(r);
0970:                }
0971:            }
0972:
0973:            // needn't be called from a sync'ed method
0974:            private void destroyResource(final Object resc) {
0975:                destroyResource(resc, false);
0976:            }
0977:
0978:            // needn't be called from a sync'ed method
0979:            private void destroyResource(final Object resc, boolean synchronous) {
0980:                class DestroyResourceTask implements  Runnable {
0981:                    public void run() {
0982:                        try {
0983:                            if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX
0984:                                    && logger.isLoggable(MLevel.FINER))
0985:                                logger.log(MLevel.FINER,
0986:                                        "Preparing to destroy resource: "
0987:                                                + resc);
0988:
0989:                            mgr.destroyResource(resc);
0990:
0991:                            if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX
0992:                                    && logger.isLoggable(MLevel.FINER))
0993:                                logger.log(MLevel.FINER,
0994:                                        "Successfully destroyed resource: "
0995:                                                + resc);
0996:                        } catch (Exception e) {
0997:                            if (logger.isLoggable(MLevel.WARNING))
0998:                                logger.log(MLevel.WARNING,
0999:                                        "Failed to destroy resource: " + resc,
1000:                                        e);
1001:
1002:                            // System.err.println("Failed to destroy resource: " + resc);
1003:                            // e.printStackTrace();
1004:                        }
1005:                    }
1006:                }
1007:
1008:                Runnable r = new DestroyResourceTask();
1009:                if (synchronous || broken) //if we're broken, our taskRunner may be dead, so we destroy synchronously
1010:                {
1011:                    if (logger.isLoggable(MLevel.FINEST)
1012:                            && !broken
1013:                            && Boolean.TRUE.equals(ThreadUtils
1014:                                    .reflectiveHoldsLock(this )))
1015:                        logger
1016:                                .log(
1017:                                        MLevel.FINEST,
1018:                                        this 
1019:                                                + ": Destroyiong a resource on an active pool, synchronousy while holding pool's lock! "
1020:                                                + "(not a bug, but a potential bottleneck... is there a good reason for this?)",
1021:                                        new Exception("DEBUG STACK TRACE"));
1022:
1023:                    r.run();
1024:                } else {
1025:                    try {
1026:                        taskRunner.postRunnable(r);
1027:                    } catch (Exception e) {
1028:                        if (logger.isLoggable(MLevel.FINER))
1029:                            logger
1030:                                    .log(
1031:                                            MLevel.FINER,
1032:                                            "AsynchronousRunner refused to accept task to destroy resource. "
1033:                                                    + "It is probably shared, and has probably been closed underneath us. "
1034:                                                    + "Reverting to synchronous destruction. This is not usually a problem.",
1035:                                            e);
1036:                        destroyResource(resc, true);
1037:                    }
1038:                }
1039:            }
1040:
1041:            //this method SHOULD NOT be invoked from a synchronized
1042:            //block!!!!
1043:            private void doAcquire() throws Exception {
1044:                assert !Thread.holdsLock(this );
1045:
1046:                Object resc = mgr.acquireResource(); //note we acquire the resource while we DO NOT hold the pool's lock!
1047:
1048:                boolean destroy = false;
1049:                int msz;
1050:
1051:                synchronized (this ) //assimilate resc if we do need it
1052:                {
1053:                    //          ++total_acquired;
1054:
1055:                    //          if (logger.isLoggable( MLevel.FINER))
1056:                    //          logger.log(MLevel.FINER, "acquired new resource, total_acquired: " + total_acquired);
1057:
1058:                    msz = managed.size();
1059:                    if (msz < target_pool_size)
1060:                        assimilateResource(resc);
1061:                    else
1062:                        destroy = true;
1063:                }
1064:
1065:                if (destroy) {
1066:                    mgr.destroyResource(resc); //destroy resc if superfluous, without holding the pool's lock
1067:                    if (logger.isLoggable(MLevel.FINER))
1068:                        logger.log(MLevel.FINER,
1069:                                "destroying overacquired resource: " + resc);
1070:                }
1071:
1072:            }
1073:
1074:            public synchronized void setPoolSize(int sz)
1075:                    throws ResourcePoolException {
1076:                try {
1077:                    setTargetPoolSize(sz);
1078:                    while (managed.size() != sz)
1079:                        this .wait();
1080:                } catch (Exception e) {
1081:                    String msg = "An exception occurred while trying to set the pool size!";
1082:                    if (logger.isLoggable(MLevel.FINER))
1083:                        logger.log(MLevel.FINER, msg, e);
1084:                    throw ResourcePoolUtils.convertThrowable(msg, e);
1085:                }
1086:            }
1087:
1088:            public synchronized void setTargetPoolSize(int sz) {
1089:                if (sz > max) {
1090:                    throw new IllegalArgumentException("Requested size [" + sz
1091:                            + "] is greater than max [" + max + "].");
1092:                } else if (sz < min) {
1093:                    throw new IllegalArgumentException("Requested size [" + sz
1094:                            + "] is less than min [" + min + "].");
1095:                }
1096:
1097:                this .target_pool_size = sz;
1098:
1099:                _recheckResizePool();
1100:            }
1101:
1102:            //  private void acquireUntil(int num) throws Exception
1103:            //  {
1104:            //  int msz = managed.size();
1105:            //  for (int i = msz; i < num; ++i)
1106:            //  assimilateResource();
1107:            //  }
1108:
1109:            //the following methods should only be invoked from 
1110:            //sync'ed methods / blocks...
1111:
1112:            //  private Object useUnusedButNotInIdleCheck()
1113:            //  {
1114:            //  for (Iterator ii = unused.iterator(); ii.hasNext(); )
1115:            //  {
1116:            //  Object maybeOut = ii.next();
1117:            //  if (! idleCheckResources.contains( maybeOut ))
1118:            //  {
1119:            //  ii.remove();
1120:            //  return maybeOut;
1121:            //  }
1122:            //  }
1123:            //  throw new RuntimeException("Internal Error -- the pool determined that it did have a resource available for checkout, but was unable to find one.");
1124:            //  }
1125:
1126:            //  private int actuallyAvailable()
1127:            //  { return unused.size() - idleCheckResources.size(); }
1128:
1129:            // must own this' lock
1130:            private void markBrokenNoEnsureMinResources(Object resc) {
1131:                assert Thread.holdsLock(this );
1132:
1133:                try {
1134:                    _markBroken(resc);
1135:                } catch (ResourceClosedException e) // one of our async threads died
1136:                {
1137:                    //e.printStackTrace();
1138:                    if (logger.isLoggable(MLevel.SEVERE))
1139:                        logger.log(MLevel.SEVERE, "Apparent pool break.", e);
1140:                    this .unexpectedBreak();
1141:                }
1142:            }
1143:
1144:            // must own this' lock
1145:            private void _markBroken(Object resc) {
1146:                assert Thread.holdsLock(this );
1147:
1148:                if (unused.contains(resc))
1149:                    removeResource(resc);
1150:                else
1151:                    excludeResource(resc);
1152:            }
1153:
1154:            //DEBUG
1155:            //Exception firstClose = null;
1156:
1157:            public synchronized void close(boolean close_checked_out_resources) {
1158:                if (!broken) //ignore repeated calls to close
1159:                {
1160:                    //DEBUG
1161:                    //firstClose = new Exception("First close() -- debug stack trace [CRAIG]");
1162:                    //firstClose.printStackTrace();
1163:
1164:                    this .broken = true;
1165:                    final Collection cleanupResources = (close_checked_out_resources ? (Collection) cloneOfManaged()
1166:                            .keySet()
1167:                            : (Collection) cloneOfUnused());
1168:                    if (cullTask != null)
1169:                        cullTask.cancel();
1170:                    if (idleRefurbishTask != null)
1171:                        idleRefurbishTask.cancel();
1172:
1173:                    // we destroy resources asynchronously, but with a dedicated one-off Thread, rather than
1174:                    // our asynchronous runner, because our asynchrous runner may be shutting down. The
1175:                    // destruction is asynchrounous because destroying a resource might require the resource's
1176:                    // lock, and we already have the pool's lock. But client threads may well have the resource's
1177:                    // lock while they try to check-in to the pool. The async destruction of resources avoids
1178:                    // the possibility of deadlock.
1179:
1180:                    managed.keySet().removeAll(cleanupResources);
1181:                    unused.removeAll(cleanupResources);
1182:                    Thread resourceDestroyer = new Thread(
1183:                            "Resource Destroyer in BasicResourcePool.close()") {
1184:                        public void run() {
1185:                            for (Iterator ii = cleanupResources.iterator(); ii
1186:                                    .hasNext();) {
1187:                                try {
1188:                                    Object resc = ii.next();
1189:                                    //System.err.println("Destroying resource... " + resc);
1190:
1191:                                    destroyResource(resc, true);
1192:                                } catch (Exception e) {
1193:                                    if (Debug.DEBUG) {
1194:                                        //e.printStackTrace();
1195:                                        if (logger.isLoggable(MLevel.FINE))
1196:                                            logger
1197:                                                    .log(
1198:                                                            MLevel.FINE,
1199:                                                            "BasicResourcePool -- A resource couldn't be cleaned up on close()",
1200:                                                            e);
1201:                                    }
1202:                                }
1203:                            }
1204:                        }
1205:                    };
1206:                    resourceDestroyer.start();
1207:
1208:                    for (Iterator ii = acquireWaiters.iterator(); ii.hasNext();)
1209:                        ((Thread) ii.next()).interrupt();
1210:                    for (Iterator ii = otherWaiters.iterator(); ii.hasNext();)
1211:                        ((Thread) ii.next()).interrupt();
1212:                    if (factory != null)
1213:                        factory.markBroken(this );
1214:
1215:                    // System.err.println(this + " closed.");
1216:                } else {
1217:                    if (logger.isLoggable(MLevel.WARNING))
1218:                        logger.warning(this 
1219:                                + " -- close() called multiple times.");
1220:                    //System.err.println(this + " -- close() called multiple times.");
1221:
1222:                    //DEBUG
1223:                    //firstClose.printStackTrace();
1224:                    //new Exception("Repeat close() [CRAIG]").printStackTrace();
1225:                }
1226:            }
1227:
1228:            private void doCheckinManaged(final Object resc)
1229:                    throws ResourcePoolException {
1230:                assert Thread.holdsLock(this );
1231:
1232:                if (unused.contains(resc)) {
1233:                    if (Debug.DEBUG)
1234:                        throw new ResourcePoolException(
1235:                                "Tried to check-in an already checked-in resource: "
1236:                                        + resc);
1237:                } else if (broken)
1238:                    removeResource(resc, true); //synchronous... if we're broken, async tasks might not work
1239:                else {
1240:                    class RefurbishCheckinResourceTask implements  Runnable {
1241:                        public void run() {
1242:                            boolean resc_okay = attemptRefurbishResourceOnCheckin(resc);
1243:                            synchronized (BasicResourcePool.this ) {
1244:                                PunchCard card = (PunchCard) managed.get(resc);
1245:
1246:                                if (resc_okay && card != null) //we have to check that the resource is still in the pool
1247:                                {
1248:                                    unused.add(0, resc);
1249:
1250:                                    card.last_checkin_time = System
1251:                                            .currentTimeMillis();
1252:                                    card.checkout_time = -1;
1253:                                } else {
1254:                                    if (card != null)
1255:                                        card.checkout_time = -1; //so we don't see this as still checked out and log an overdue cxn in removeResource()
1256:
1257:                                    removeResource(resc);
1258:                                    ensureMinResources();
1259:
1260:                                    if (card == null
1261:                                            && logger.isLoggable(MLevel.FINE))
1262:                                        logger
1263:                                                .fine("Resource "
1264:                                                        + resc
1265:                                                        + " was removed from the pool during its refurbishment for checkin.");
1266:                                }
1267:
1268:                                asyncFireResourceCheckedIn(resc,
1269:                                        managed.size(), unused.size(), excluded
1270:                                                .size());
1271:                                BasicResourcePool.this .notifyAll();
1272:                            }
1273:                        }
1274:                    }
1275:
1276:                    Runnable doMe = new RefurbishCheckinResourceTask();
1277:                    taskRunner.postRunnable(doMe);
1278:                }
1279:            }
1280:
1281:            private void doCheckinExcluded(Object resc) {
1282:                assert Thread.holdsLock(this );
1283:
1284:                excluded.remove(resc);
1285:                destroyResource(resc);
1286:            }
1287:
1288:            /*
1289:             * by the semantics of wait(), a timeout of zero means forever.
1290:             */
1291:            private void awaitAvailable(long timeout)
1292:                    throws InterruptedException, TimeoutException,
1293:                    ResourcePoolException {
1294:                assert Thread.holdsLock(this );
1295:
1296:                if (force_kill_acquires)
1297:                    throw new ResourcePoolException(
1298:                            "A ResourcePool cannot acquire a new resource -- the factory or source appears to be down.");
1299:
1300:                Thread t = Thread.currentThread();
1301:                try {
1302:                    acquireWaiters.add(t);
1303:
1304:                    int avail;
1305:                    long start = (timeout > 0 ? System.currentTimeMillis() : -1);
1306:                    if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) {
1307:                        if (logger.isLoggable(MLevel.FINE))
1308:                            logger
1309:                                    .fine("awaitAvailable(): "
1310:                                            + (exampleResource != null ? exampleResource
1311:                                                    : "[unknown]"));
1312:                        trace();
1313:                    }
1314:                    while ((avail = unused.size()) == 0) {
1315:                        // the if case below can only occur when 1) a user attempts a
1316:                        // checkout which would provoke an acquire; 2) this
1317:                        // increments the pending acquires, so we go to the
1318:                        // wait below without provoking postAcquireMore(); 3)
1319:                        // the resources are acquired; 4) external management
1320:                        // of the pool (via for instance unpoolResource() 
1321:                        // depletes the newly acquired resources before we
1322:                        // regain this' monitor; 5) we fall into wait() with
1323:                        // no acquires being scheduled, and perhaps a managed.size()
1324:                        // of zero, leading to deadlock. This could only occur in
1325:                        // fairly pathological situations where the pool is being
1326:                        // externally forced to a very low (even zero) size, but 
1327:                        // since I've seen it, I've fixed it.
1328:                        if (pending_acquires == 0 && managed.size() < max)
1329:                            _recheckResizePool();
1330:
1331:                        this .wait(timeout);
1332:                        if (timeout > 0
1333:                                && System.currentTimeMillis() - start > timeout)
1334:                            throw new TimeoutException(
1335:                                    "A client timed out while waiting to acquire a resource from "
1336:                                            + this 
1337:                                            + " -- timeout at awaitAvailable()");
1338:                        if (force_kill_acquires)
1339:                            throw new CannotAcquireResourceException(
1340:                                    "A ResourcePool could not acquire a resource from its primary factory or source.");
1341:                        ensureNotBroken();
1342:                    }
1343:                } finally {
1344:                    acquireWaiters.remove(t);
1345:                    if (acquireWaiters.size() == 0)
1346:                        this .notifyAll();
1347:                }
1348:            }
1349:
1350:            private void assimilateResource(Object resc) throws Exception {
1351:                assert Thread.holdsLock(this );
1352:
1353:                managed.put(resc, new PunchCard());
1354:                unused.add(0, resc);
1355:                //System.err.println("assimilate resource... unused: " + unused.size());
1356:                asyncFireResourceAcquired(resc, managed.size(), unused.size(),
1357:                        excluded.size());
1358:                this .notifyAll();
1359:                if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
1360:                    trace();
1361:                if (Debug.DEBUG && exampleResource == null)
1362:                    exampleResource = resc;
1363:            }
1364:
1365:            // should NOT be called from synchronized method
1366:            private void synchronousRemoveArbitraryResource() {
1367:                assert !Thread.holdsLock(this );
1368:
1369:                Object removeMe = null;
1370:
1371:                synchronized (this ) {
1372:                    if (unused.size() > 0) {
1373:                        removeMe = unused.get(0);
1374:                        managed.remove(removeMe);
1375:                        unused.remove(removeMe);
1376:                    } else {
1377:                        Set checkedOut = cloneOfManaged().keySet();
1378:                        if (checkedOut.isEmpty()) {
1379:                            unexpectedBreak();
1380:                            logger
1381:                                    .severe("A pool from which a resource is requested to be removed appears to have no managed resources?!");
1382:                        } else
1383:                            excludeResource(checkedOut.iterator().next());
1384:                    }
1385:                }
1386:
1387:                if (removeMe != null)
1388:                    destroyResource(removeMe, true);
1389:            }
1390:
1391:            private void removeResource(Object resc) {
1392:                removeResource(resc, false);
1393:            }
1394:
1395:            private void removeResource(Object resc, boolean synchronous) {
1396:                assert Thread.holdsLock(this );
1397:
1398:                PunchCard pc = (PunchCard) managed.remove(resc);
1399:
1400:                if (pc != null) {
1401:                    if (pc.checkout_time > 0 && !broken) //this is a checked-out resource in an active pool, must be overdue if we are removing it
1402:                    {
1403:                        if (logger.isLoggable(MLevel.INFO)) {
1404:                            logger
1405:                                    .info("A checked-out resource is overdue, and will be destroyed: "
1406:                                            + resc);
1407:                            if (pc.checkoutStackTraceException != null) {
1408:                                logger
1409:                                        .log(
1410:                                                MLevel.INFO,
1411:                                                "Logging the stack trace by which the overdue resource was checked-out.",
1412:                                                pc.checkoutStackTraceException);
1413:                            }
1414:                        }
1415:                    }
1416:                } else if (logger.isLoggable(MLevel.FINE))
1417:                    logger
1418:                            .fine("Resource "
1419:                                    + resc
1420:                                    + " was removed twice. (Lotsa reasons a resource can be removed, sometimes simultaneously. It's okay)");
1421:
1422:                unused.remove(resc);
1423:                destroyResource(resc, synchronous);
1424:                addToFormerResources(resc);
1425:                asyncFireResourceRemoved(resc, false, managed.size(), unused
1426:                        .size(), excluded.size());
1427:
1428:                if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
1429:                    trace();
1430:                //System.err.println("RESOURCE REMOVED!");
1431:            }
1432:
1433:            //when we want to conceptually remove a checked
1434:            //out resource from the pool
1435:            private void excludeResource(Object resc) {
1436:                assert Thread.holdsLock(this );
1437:
1438:                managed.remove(resc);
1439:                excluded.add(resc);
1440:                if (Debug.DEBUG && unused.contains(resc))
1441:                    throw new InternalError(
1442:                            "We should only \"exclude\" checked-out resources!");
1443:                asyncFireResourceRemoved(resc, true, managed.size(), unused
1444:                        .size(), excluded.size());
1445:            }
1446:
1447:            private void removeTowards(int new_sz) {
1448:                assert Thread.holdsLock(this );
1449:
1450:                int num_to_remove = managed.size() - new_sz;
1451:                int count = 0;
1452:                for (Iterator ii = cloneOfUnused().iterator(); ii.hasNext()
1453:                        && count < num_to_remove; ++count) {
1454:                    Object resc = ii.next();
1455:                    removeResource(resc);
1456:                }
1457:            }
1458:
1459:            private void cullExpired() {
1460:                assert Thread.holdsLock(this );
1461:
1462:                if (logger.isLoggable(MLevel.FINER))
1463:                    logger.log(MLevel.FINER,
1464:                            "BEGIN check for expired resources.  [" + this 
1465:                                    + "]");
1466:
1467:                // if we do not time-out checkedout resources, we only need to test unused resources
1468:                Collection checkMe = (destroy_unreturned_resc_time > 0 ? (Collection) cloneOfManaged()
1469:                        .keySet()
1470:                        : cloneOfUnused());
1471:
1472:                for (Iterator ii = checkMe.iterator(); ii.hasNext();) {
1473:                    Object resc = ii.next();
1474:                    if (shouldExpire(resc)) {
1475:                        if (logger.isLoggable(MLevel.FINER))
1476:                            logger.log(MLevel.FINER,
1477:                                    "Removing expired resource: " + resc + " ["
1478:                                            + this  + "]");
1479:
1480:                        target_pool_size = Math.max(min, target_pool_size - 1); //expiring a resource resources the target size to match
1481:
1482:                        removeResource(resc);
1483:
1484:                        if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
1485:                            trace();
1486:                    }
1487:                }
1488:                if (logger.isLoggable(MLevel.FINER))
1489:                    logger.log(MLevel.FINER,
1490:                            "FINISHED check for expired resources.  [" + this 
1491:                                    + "]");
1492:                ensureMinResources();
1493:            }
1494:
1495:            private void checkIdleResources() {
1496:                assert Thread.holdsLock(this );
1497:
1498:                List u = cloneOfUnused();
1499:                for (Iterator ii = u.iterator(); ii.hasNext();) {
1500:                    Object resc = ii.next();
1501:                    if (idleCheckResources.add(resc))
1502:                        taskRunner.postRunnable(new AsyncTestIdleResourceTask(
1503:                                resc));
1504:                }
1505:
1506:                if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
1507:                    trace();
1508:            }
1509:
1510:            private boolean shouldExpire(Object resc) {
1511:                assert Thread.holdsLock(this );
1512:
1513:                boolean expired = false;
1514:
1515:                PunchCard pc = (PunchCard) managed.get(resc);
1516:
1517:                // the resource has already been removed
1518:                // we return true, because removing twice does no harm
1519:                // (false should work as well, but true seems safer.
1520:                //  we certainly don't want to do anything else with
1521:                //  this resource.)
1522:                if (pc == null) {
1523:                    if (logger.isLoggable(MLevel.FINE))
1524:                        logger
1525:                                .fine("Resource "
1526:                                        + resc
1527:                                        + " was being tested for expiration, but has already been removed from the pool.");
1528:                    return true;
1529:                }
1530:
1531:                long now = System.currentTimeMillis();
1532:
1533:                if (pc.checkout_time < 0) //resource is not checked out
1534:                {
1535:                    long idle_age = now - pc.last_checkin_time;
1536:                    if (excess_max_idle_time > 0) {
1537:                        int msz = managed.size();
1538:                        expired = (msz > min && idle_age > excess_max_idle_time);
1539:                        if (expired && logger.isLoggable(MLevel.FINER))
1540:                            logger.log(MLevel.FINER,
1541:                                    "EXPIRED excess idle resource: " + resc
1542:                                            + " ---> idle_time: " + idle_age
1543:                                            + "; excess_max_idle_time: "
1544:                                            + excess_max_idle_time
1545:                                            + "; pool_size: " + msz
1546:                                            + "; min_pool_size: " + min + " ["
1547:                                            + this  + "]");
1548:                    }
1549:                    if (!expired && max_idle_time > 0) {
1550:                        expired = idle_age > max_idle_time;
1551:                        if (expired && logger.isLoggable(MLevel.FINER))
1552:                            logger.log(MLevel.FINER, "EXPIRED idle resource: "
1553:                                    + resc + " ---> idle_time: " + idle_age
1554:                                    + "; max_idle_time: " + max_idle_time
1555:                                    + " [" + this  + "]");
1556:                    }
1557:                    if (!expired && max_resource_age > 0) {
1558:                        long abs_age = now - pc.acquisition_time;
1559:                        expired = (abs_age > max_resource_age);
1560:
1561:                        if (expired && logger.isLoggable(MLevel.FINER))
1562:                            logger.log(MLevel.FINER, "EXPIRED old resource: "
1563:                                    + resc + " ---> absolute_age: " + abs_age
1564:                                    + "; max_absolute_age: " + max_resource_age
1565:                                    + " [" + this  + "]");
1566:                    }
1567:                } else //resource is checked out
1568:                {
1569:                    long checkout_age = now - pc.checkout_time;
1570:                    expired = checkout_age > destroy_unreturned_resc_time;
1571:                }
1572:
1573:                return expired;
1574:            }
1575:
1576:            //  private boolean resourcesInIdleCheck()
1577:            //  { return idleCheckresources.size() > 0; }
1578:
1579:            //  private int countAvailable()
1580:            //  { return unused.size() - idleCheckResources.size(); }
1581:
1582:            // we needn't hold this' lock
1583:            private void ensureStartResources() {
1584:                recheckResizePool();
1585:            }
1586:
1587:            // we needn't hold this' lock
1588:            private void ensureMinResources() {
1589:                recheckResizePool();
1590:            }
1591:
1592:            private boolean attemptRefurbishResourceOnCheckout(Object resc) {
1593:                assert !Thread.holdsLock(this );
1594:
1595:                try {
1596:                    mgr.refurbishResourceOnCheckout(resc);
1597:                    return true;
1598:                } catch (Exception e) {
1599:                    //uh oh... bad resource...
1600:                    if (Debug.DEBUG) {
1601:                        //e.printStackTrace();
1602:                        if (logger.isLoggable(MLevel.FINE))
1603:                            logger.log(MLevel.FINE,
1604:                                    "A resource could not be refurbished for checkout. ["
1605:                                            + resc + ']', e);
1606:                    }
1607:                    synchronized (this ) {
1608:                        ++failed_checkouts;
1609:                        setLastCheckoutFailure(e);
1610:                    }
1611:                    return false;
1612:                }
1613:            }
1614:
1615:            private boolean attemptRefurbishResourceOnCheckin(Object resc) {
1616:                assert !Thread.holdsLock(this );
1617:
1618:                try {
1619:                    mgr.refurbishResourceOnCheckin(resc);
1620:                    return true;
1621:                } catch (Exception e) {
1622:                    //uh oh... bad resource...
1623:                    if (Debug.DEBUG) {
1624:                        //e.printStackTrace();
1625:                        if (logger.isLoggable(MLevel.FINE))
1626:                            logger.log(MLevel.FINE,
1627:                                    "A resource could not be refurbished on checkin. ["
1628:                                            + resc + ']', e);
1629:                    }
1630:                    synchronized (this ) {
1631:                        ++failed_checkins;
1632:                        setLastCheckinFailure(e);
1633:                    }
1634:                    return false;
1635:                }
1636:            }
1637:
1638:            private void ensureNotBroken() throws ResourcePoolException {
1639:                assert Thread.holdsLock(this );
1640:
1641:                if (broken)
1642:                    throw new ResourcePoolException(
1643:                            "Attempted to use a closed or broken resource pool");
1644:            }
1645:
1646:            private void trace() {
1647:                assert Thread.holdsLock(this );
1648:
1649:                if (logger.isLoggable(MLevel.FINEST)) {
1650:                    String exampleResStr = (exampleResource == null ? ""
1651:                            : " (e.g. " + exampleResource + ")");
1652:                    logger.finest("trace " + this  + " [managed: "
1653:                            + managed.size() + ", " + "unused: "
1654:                            + unused.size() + ", excluded: " + excluded.size()
1655:                            + ']' + exampleResStr);
1656:                }
1657:            }
1658:
1659:            private final HashMap cloneOfManaged() {
1660:                assert Thread.holdsLock(this );
1661:
1662:                return (HashMap) managed.clone();
1663:            }
1664:
1665:            private final LinkedList cloneOfUnused() {
1666:                assert Thread.holdsLock(this );
1667:
1668:                return (LinkedList) unused.clone();
1669:            }
1670:
1671:            private final HashSet cloneOfExcluded() {
1672:                assert Thread.holdsLock(this );
1673:
1674:                return (HashSet) excluded.clone();
1675:            }
1676:
1677:            class ScatteredAcquireTask implements  Runnable {
1678:                int attempts_remaining;
1679:
1680:                ScatteredAcquireTask() {
1681:                    this ((num_acq_attempts >= 0 ? num_acq_attempts : -1), true);
1682:                }
1683:
1684:                private ScatteredAcquireTask(int attempts_remaining,
1685:                        boolean first_attempt) {
1686:                    this .attempts_remaining = attempts_remaining;
1687:                    if (first_attempt) {
1688:                        incrementPendingAcquires();
1689:                        if (logger.isLoggable(MLevel.FINEST))
1690:                            logger
1691:                                    .finest("Starting acquisition series. Incremented pending_acquires ["
1692:                                            + pending_acquires
1693:                                            + "], "
1694:                                            + " attempts_remaining: "
1695:                                            + attempts_remaining);
1696:                    } else {
1697:                        if (logger.isLoggable(MLevel.FINEST))
1698:                            logger
1699:                                    .finest("Continuing acquisition series. pending_acquires ["
1700:                                            + pending_acquires
1701:                                            + "], "
1702:                                            + " attempts_remaining: "
1703:                                            + attempts_remaining);
1704:                    }
1705:                }
1706:
1707:                public void run() {
1708:                    try {
1709:                        boolean fkap = isForceKillAcquiresPending();
1710:                        if (!fkap) {
1711:                            //we don't want this call to be sync'd
1712:                            //on the pool, so that resource acquisition
1713:                            //does not interfere with other pool clients.
1714:                            BasicResourcePool.this .doAcquire();
1715:                        }
1716:                        decrementPendingAcquires();
1717:                        if (logger.isLoggable(MLevel.FINEST))
1718:                            logger
1719:                                    .finest("Acquisition series terminated "
1720:                                            + (fkap ? "because force-kill-acquires is pending"
1721:                                                    : "successfully")
1722:                                            + ". Decremented pending_acquires ["
1723:                                            + pending_acquires + "], "
1724:                                            + " attempts_remaining: "
1725:                                            + attempts_remaining);
1726:                    } catch (Exception e) {
1727:                        BasicResourcePool.this .setLastAcquisitionFailure(e);
1728:
1729:                        if (attempts_remaining == 0) //last try in a round...
1730:                        {
1731:                            decrementPendingAcquires();
1732:                            if (logger.isLoggable(MLevel.WARNING)) {
1733:                                logger
1734:                                        .log(
1735:                                                MLevel.WARNING,
1736:                                                this 
1737:                                                        + " -- Acquisition Attempt Failed!!! Clearing pending acquires. "
1738:                                                        + "While trying to acquire a needed new resource, we failed "
1739:                                                        + "to succeed more than the maximum number of allowed "
1740:                                                        + "acquisition attempts ("
1741:                                                        + num_acq_attempts
1742:                                                        + "). "
1743:                                                        + "Last acquisition attempt exception: ",
1744:                                                e);
1745:                            }
1746:                            if (break_on_acquisition_failure) {
1747:                                //System.err.println("\tTHE RESOURCE POOL IS PERMANENTLY BROKEN!");
1748:                                if (logger.isLoggable(MLevel.SEVERE))
1749:                                    logger
1750:                                            .severe("A RESOURCE POOL IS PERMANENTLY BROKEN! ["
1751:                                                    + this 
1752:                                                    + "] "
1753:                                                    + "(because a series of "
1754:                                                    + num_acq_attempts
1755:                                                    + " acquisition attempts "
1756:                                                    + "failed.)");
1757:                                unexpectedBreak();
1758:                            } else {
1759:                                try {
1760:                                    forceKillAcquires();
1761:                                } catch (InterruptedException ie) {
1762:                                    if (logger.isLoggable(MLevel.WARNING))
1763:                                        logger
1764:                                                .log(
1765:                                                        MLevel.WARNING,
1766:                                                        "Failed to force-kill pending acquisition attempts after acquisition failue, "
1767:                                                                + " due to an InterruptedException!",
1768:                                                        ie);
1769:
1770:                                    // we might still have clients waiting, so we should try
1771:                                    // to ensure there are sufficient connections to serve
1772:                                    recheckResizePool();
1773:                                }
1774:                            }
1775:                            if (logger.isLoggable(MLevel.FINEST))
1776:                                logger
1777:                                        .finest("Acquisition series terminated unsuccessfully. Decremented pending_acquires ["
1778:                                                + pending_acquires
1779:                                                + "], "
1780:                                                + " attempts_remaining: "
1781:                                                + attempts_remaining);
1782:                        } else {
1783:                            // if attempts_remaining < 0, we try to acquire forever, so the end-of-batch
1784:                            // log message below will never be triggered if there is a persistent problem
1785:                            // so in this case, it's better flag a higher-than-debug-level message for
1786:                            // each failed attempt. (Thanks to Eric Crahen for calling attention to this
1787:                            // issue.)
1788:                            MLevel logLevel = (attempts_remaining > 0 ? MLevel.FINE
1789:                                    : MLevel.INFO);
1790:                            if (logger.isLoggable(logLevel))
1791:                                logger
1792:                                        .log(
1793:                                                logLevel,
1794:                                                "An exception occurred while acquiring a poolable resource. Will retry.",
1795:                                                e);
1796:
1797:                            TimerTask doNextAcquire = new TimerTask() {
1798:                                public void run() {
1799:                                    taskRunner
1800:                                            .postRunnable(new ScatteredAcquireTask(
1801:                                                    attempts_remaining - 1,
1802:                                                    false));
1803:                                }
1804:                            };
1805:                            cullAndIdleRefurbishTimer.schedule(doNextAcquire,
1806:                                    acq_attempt_delay);
1807:                        }
1808:                    }
1809:                }
1810:
1811:            }
1812:
1813:            /*
1814:             *  task we post to separate thread to acquire
1815:             *  pooled resources
1816:             */
1817:            class AcquireTask implements  Runnable {
1818:                boolean success = false;
1819:
1820:                public AcquireTask() {
1821:                    incrementPendingAcquires();
1822:                }
1823:
1824:                public void run() {
1825:                    try {
1826:                        Exception lastException = null;
1827:                        for (int i = 0; shouldTry(i); ++i) {
1828:                            try {
1829:                                if (i > 0)
1830:                                    Thread.sleep(acq_attempt_delay);
1831:
1832:                                //we don't want this call to be sync'd
1833:                                //on the pool, so that resource acquisition
1834:                                //does not interfere with other pool clients.
1835:                                BasicResourcePool.this .doAcquire();
1836:
1837:                                success = true;
1838:                            } catch (InterruptedException e) {
1839:                                // end the whole task on interrupt, regardless of success
1840:                                // or failure
1841:                                throw e;
1842:                            } catch (Exception e) {
1843:                                //e.printStackTrace();
1844:
1845:                                // if num_acq_attempts <= 0, we try to acquire forever, so the end-of-batch
1846:                                // log message below will never be triggered if there is a persistent problem
1847:                                // so in this case, it's better flag a higher-than-debug-level message for
1848:                                // each failed attempt. (Thanks to Eric Crahen for calling attention to this
1849:                                // issue.)
1850:                                MLevel logLevel = (num_acq_attempts > 0 ? MLevel.FINE
1851:                                        : MLevel.INFO);
1852:                                if (logger.isLoggable(logLevel))
1853:                                    logger
1854:                                            .log(
1855:                                                    logLevel,
1856:                                                    "An exception occurred while acquiring a poolable resource. Will retry.",
1857:                                                    e);
1858:
1859:                                lastException = e;
1860:                                setLastAcquisitionFailure(e);
1861:                            }
1862:                        }
1863:                        if (!success) {
1864:                            if (logger.isLoggable(MLevel.WARNING)) {
1865:                                logger
1866:                                        .log(
1867:                                                MLevel.WARNING,
1868:                                                this 
1869:                                                        + " -- Acquisition Attempt Failed!!! Clearing pending acquires. "
1870:                                                        + "While trying to acquire a needed new resource, we failed "
1871:                                                        + "to succeed more than the maximum number of allowed "
1872:                                                        + "acquisition attempts ("
1873:                                                        + num_acq_attempts
1874:                                                        + "). "
1875:                                                        + (lastException == null ? ""
1876:                                                                : "Last acquisition attempt exception: "),
1877:                                                lastException);
1878:                            }
1879:                            if (break_on_acquisition_failure) {
1880:                                //System.err.println("\tTHE RESOURCE POOL IS PERMANENTLY BROKEN!");
1881:                                if (logger.isLoggable(MLevel.SEVERE))
1882:                                    logger
1883:                                            .severe("A RESOURCE POOL IS PERMANENTLY BROKEN! ["
1884:                                                    + this  + "]");
1885:                                unexpectedBreak();
1886:                            } else
1887:                                forceKillAcquires();
1888:                        } else
1889:                            recheckResizePool();
1890:                    } catch (ResourceClosedException e) // one of our async threads died
1891:                    {
1892:                        //e.printStackTrace();
1893:                        if (Debug.DEBUG) {
1894:                            if (logger.isLoggable(MLevel.FINE))
1895:                                logger
1896:                                        .log(
1897:                                                MLevel.FINE,
1898:                                                "a resource pool async thread died.",
1899:                                                e);
1900:                        }
1901:                        unexpectedBreak();
1902:                    } catch (InterruptedException e) //from force kill acquires, or by the thread pool during the long task...
1903:                    {
1904:                        if (logger.isLoggable(MLevel.WARNING)) {
1905:                            logger
1906:                                    .log(
1907:                                            MLevel.WARNING,
1908:                                            BasicResourcePool.this 
1909:                                                    + " -- Thread unexpectedly interrupted while performing an acquisition attempt.",
1910:                                            e);
1911:                        }
1912:
1913:                        //              System.err.println(BasicResourcePool.this + " -- Thread unexpectedly interrupted while waiting for stale acquisition attempts to die.");
1914:                        //              e.printStackTrace();
1915:
1916:                        recheckResizePool();
1917:                    } finally {
1918:                        decrementPendingAcquires();
1919:                    }
1920:                }
1921:
1922:                private boolean shouldTry(int attempt_num) {
1923:                    //try if we haven't already succeeded
1924:                    //and someone hasn't signalled that our resource source is down
1925:                    //and not max attempts is set,
1926:                    //or we are less than the set limit
1927:                    return !success
1928:                            && !isForceKillAcquiresPending()
1929:                            && (num_acq_attempts <= 0 || attempt_num < num_acq_attempts);
1930:                }
1931:            }
1932:
1933:            /*
1934:             *  task we post to separate thread to remove
1935:             *  unspecified pooled resources
1936:             *
1937:             *  TODO: do removal and destruction synchronously
1938:             *        but carefully not synchronized during the
1939:             *        destruction of the resource.
1940:             */
1941:            class RemoveTask implements  Runnable {
1942:                public RemoveTask() {
1943:                    incrementPendingRemoves();
1944:                }
1945:
1946:                public void run() {
1947:                    try {
1948:                        synchronousRemoveArbitraryResource();
1949:                        recheckResizePool();
1950:                    } finally {
1951:                        decrementPendingRemoves();
1952:                    }
1953:                }
1954:            }
1955:
1956:            class CullTask extends TimerTask {
1957:                public void run() {
1958:                    try {
1959:                        if (Debug.DEBUG && Debug.TRACE >= Debug.TRACE_MED
1960:                                && logger.isLoggable(MLevel.FINER))
1961:                            logger.log(MLevel.FINER,
1962:                                    "Checking for expired resources - "
1963:                                            + new Date() + " ["
1964:                                            + BasicResourcePool.this  + "]");
1965:                        synchronized (BasicResourcePool.this ) {
1966:                            cullExpired();
1967:                        }
1968:                    } catch (ResourceClosedException e) // one of our async threads died
1969:                    {
1970:                        if (Debug.DEBUG) {
1971:                            if (logger.isLoggable(MLevel.FINE))
1972:                                logger
1973:                                        .log(
1974:                                                MLevel.FINE,
1975:                                                "a resource pool async thread died.",
1976:                                                e);
1977:                        }
1978:                        unexpectedBreak();
1979:                    }
1980:                }
1981:            }
1982:
1983:            // this is run by a single-threaded timer, so we don't have
1984:            // to worry about multiple threads executing the task at the same 
1985:            // time 
1986:            class CheckIdleResourcesTask extends TimerTask {
1987:                public void run() {
1988:                    try {
1989:                        //System.err.println("c3p0-JENNIFER: refurbishing idle resources - " + new Date() + " [" + BasicResourcePool.this + "]");
1990:                        if (Debug.DEBUG && Debug.TRACE >= Debug.TRACE_MED
1991:                                && logger.isLoggable(MLevel.FINER))
1992:                            logger.log(MLevel.FINER,
1993:                                    "Refurbishing idle resources - "
1994:                                            + new Date() + " ["
1995:                                            + BasicResourcePool.this  + "]");
1996:                        synchronized (BasicResourcePool.this ) {
1997:                            checkIdleResources();
1998:                        }
1999:                    } catch (ResourceClosedException e) // one of our async threads died
2000:                    {
2001:                        //e.printStackTrace();
2002:                        if (Debug.DEBUG) {
2003:                            if (logger.isLoggable(MLevel.FINE))
2004:                                logger
2005:                                        .log(
2006:                                                MLevel.FINE,
2007:                                                "a resource pool async thread died.",
2008:                                                e);
2009:                        }
2010:                        unexpectedBreak();
2011:                    }
2012:                }
2013:            }
2014:
2015:            class AsyncTestIdleResourceTask implements  Runnable {
2016:                // unchanging after ctor
2017:                Object resc;
2018:
2019:                // protected by this' lock
2020:                boolean pending = true;
2021:                boolean failed;
2022:
2023:                AsyncTestIdleResourceTask(Object resc) {
2024:                    this .resc = resc;
2025:                }
2026:
2027:                public void run() {
2028:                    assert !Thread.holdsLock(BasicResourcePool.this );
2029:
2030:                    try {
2031:                        try {
2032:                            mgr.refurbishIdleResource(resc);
2033:                        } catch (Exception e) {
2034:                            if (logger.isLoggable(MLevel.FINE))
2035:                                logger.log(MLevel.FINE,
2036:                                        "BasicResourcePool: An idle resource is broken and will be purged. ["
2037:                                                + resc + ']', e);
2038:
2039:                            synchronized (BasicResourcePool.this ) {
2040:                                if (managed.keySet().contains(resc)) //resc might have been culled as expired while we tested
2041:                                {
2042:                                    removeResource(resc);
2043:                                    ensureMinResources();
2044:                                }
2045:
2046:                                ++failed_idle_tests;
2047:                                setLastIdleCheckFailure(e);
2048:                            }
2049:                        }
2050:                    } finally {
2051:                        synchronized (BasicResourcePool.this ) {
2052:                            idleCheckResources.remove(resc);
2053:                            BasicResourcePool.this .notifyAll();
2054:                        }
2055:                    }
2056:                }
2057:            }
2058:
2059:            final static class PunchCard {
2060:                long acquisition_time;
2061:                long last_checkin_time;
2062:                long checkout_time;
2063:                Exception checkoutStackTraceException;
2064:
2065:                PunchCard() {
2066:                    this .acquisition_time = System.currentTimeMillis();
2067:                    this .last_checkin_time = acquisition_time;
2068:                    this .checkout_time = -1;
2069:                    this .checkoutStackTraceException = null;
2070:                }
2071:            }
2072:
2073:            //  static class CheckInProgressResourceHolder
2074:            //  {
2075:            //  Object checkResource;
2076:
2077:            //  public synchronized void setCheckResource( Object resc )
2078:            //  { 
2079:            //  this.checkResource = resc; 
2080:            //  this.notifyAll();
2081:            //  }
2082:
2083:            //  public void unsetCheckResource()
2084:            //  { setCheckResource( null ); }
2085:
2086:            //  /**
2087:            //  * @return true if we actually had to wait
2088:            //  */
2089:            //  public synchronized boolean awaitNotInCheck( Object resc )
2090:            //  {
2091:            //  boolean had_to_wait = false;
2092:            //  boolean set_interrupt = false;
2093:            //  while ( checkResource == resc )
2094:            //  {
2095:            //  try
2096:            //  {
2097:            //  had_to_wait = true;
2098:            //  this.wait(); 
2099:            //  }
2100:            //  catch ( InterruptedException e )
2101:            //  { 
2102:            //  e.printStackTrace();
2103:            //  set_interrupt = true;
2104:            //  }
2105:            //  }
2106:            //  if ( set_interrupt )
2107:            //  Thread.currentThread().interrupt();
2108:            //  return had_to_wait;
2109:            //  }
2110:            //  }
2111:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.