KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mchange > v2 > c3p0 > stmt > GooGooStatementCache


1 /*
2  * Distributed as part of c3p0 v.0.9.1
3  *
4  * Copyright (C) 2005 Machinery For Change, Inc.
5  *
6  * Author: Steve Waldman <swaldman@mchange.com>
7  *
8  * This library is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License version 2.1, as
10  * published by the Free Software Foundation.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this software; see the file LICENSE. If not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */

22
23
24 package com.mchange.v2.c3p0.stmt;
25
26 import java.util.*;
27 import java.sql.*;
28 import java.lang.reflect.*;
29 import com.mchange.v2.async.AsynchronousRunner;
30 import com.mchange.v2.sql.SqlUtils;
31 import com.mchange.v2.util.ResourceClosedException;
32 import com.mchange.v2.log.*;
33 import com.mchange.v1.db.sql.StatementUtils;
34
35 import java.io.StringWriter JavaDoc;
36 import java.io.PrintWriter JavaDoc;
37 import java.io.IOException JavaDoc;
38 import com.mchange.v2.io.IndentedWriter;
39
40 public abstract class GooGooStatementCache
41 {
42     private final static MLogger logger = MLog.getLogger( GooGooStatementCache.class );
43
44     private final static int DESTROY_NEVER = 0;
45     private final static int DESTROY_IF_CHECKED_IN = 1 << 0;
46     private final static int DESTROY_IF_CHECKED_OUT = 1 << 1;
47     private final static int DESTROY_ALWAYS = (DESTROY_IF_CHECKED_IN | DESTROY_IF_CHECKED_OUT);
48
49     /* MT: protected by this's lock */
50
51     // contains all statements in the cache,
52
// organized by connection
53
ConnectionStatementManager cxnStmtMgr;
54
55     // contains all statements in the cache,
56
// bound to the keys that produced them
57
HashMap stmtToKey = new HashMap();
58
59     // maps all known keys to their set of statements
60
// and to a queue of statements, if any, available
61
// for checkout
62
HashMap keyToKeyRec = new HashMap();
63
64     // contains all checked out statements -- in the cache,
65
// but not currently available for checkout, nor for
66
// culling in case of overflow
67
HashSet checkedOut = new HashSet();
68
69     /* MT: end protected by this' lock */
70
71     /* MT: protected by its own lock */
72
73     AsynchronousRunner blockingTaskAsyncRunner;
74
75     // This set is used to ensure that multiple threads
76
// do not try to remove the same statement from the
77
// cache, if for example a Statement is both deathmarched
78
// away and its parent Connection is closed.
79
//
80
// ALL ACCESS SHOULD BE EXPLICITLY SYNCHRONIZED
81
// ON removalPending's lock!
82
HashSet removalPending = new HashSet();
83
84     /* MT: end protected by its own lock */
85
86     public GooGooStatementCache(AsynchronousRunner blockingTaskAsyncRunner)
87     {
88         this.blockingTaskAsyncRunner = blockingTaskAsyncRunner;
89         this.cxnStmtMgr = createConnectionStatementManager();
90     }
91
92     public synchronized int getNumStatements()
93     { return this.isClosed() ? -1 : countCachedStatements(); }
94
95     public synchronized int getNumStatementsCheckedOut()
96     { return this.isClosed() ? -1 : checkedOut.size(); }
97
98     public synchronized int getNumConnectionsWithCachedStatements()
99     { return isClosed() ? -1 : cxnStmtMgr.getNumConnectionsWithCachedStatements(); }
100
101     public synchronized String JavaDoc dumpStatementCacheStatus()
102     {
103         if (isClosed())
104             return this + "status: Closed.";
105         else
106         {
107             StringWriter JavaDoc sw = new StringWriter JavaDoc(2048);
108             IndentedWriter iw = new IndentedWriter( sw );
109             try
110             {
111                 iw.print(this);
112                 iw.println(" status:");
113                 iw.upIndent();
114                 iw.println("core stats:");
115                 iw.upIndent();
116                 iw.print("num cached statements: ");
117                 iw.println( this.countCachedStatements() );
118                 iw.print("num cached statements in use: ");
119                 iw.println( checkedOut.size() );
120                 iw.print("num connections with cached statements: ");
121                 iw.println(cxnStmtMgr.getNumConnectionsWithCachedStatements());
122                 iw.downIndent();
123                 iw.println("cached statement dump:");
124                 iw.upIndent();
125                 for (Iterator ii = cxnStmtMgr.connectionSet().iterator(); ii.hasNext();)
126                 {
127                     Connection pcon = (Connection) ii.next();
128                     iw.print(pcon);
129                     iw.println(':');
130                     iw.upIndent();
131                     for (Iterator jj = cxnStmtMgr.statementSet(pcon).iterator(); jj.hasNext();)
132                         iw.println(jj.next());
133                     iw.downIndent();
134                 }
135
136                 iw.downIndent();
137                 iw.downIndent();
138                 return sw.toString();
139             }
140             catch (IOException JavaDoc e)
141             {
142                 if (logger.isLoggable(MLevel.SEVERE))
143                     logger.log(MLevel.SEVERE, "Huh? We've seen an IOException writing to s StringWriter?!", e);
144                 return e.toString();
145             }
146         }
147     }
148
149     abstract ConnectionStatementManager createConnectionStatementManager();
150
151     public synchronized Object JavaDoc checkoutStatement( Connection physicalConnection,
152                     Method stmtProducingMethod,
153                     Object JavaDoc[] args )
154     throws SQLException, ResourceClosedException
155     {
156         try
157         {
158             Object JavaDoc out = null;
159
160             StatementCacheKey key = StatementCacheKey.find( physicalConnection,
161                             stmtProducingMethod,
162                             args );
163             LinkedList l = checkoutQueue( key );
164             if (l == null || l.isEmpty()) //we need a new statement
165
{
166                 // we might wait() here...
167
// don't presume atomicity before and after!
168
out = acquireStatement( physicalConnection, stmtProducingMethod, args );
169
170                 if ( prepareAssimilateNewStatement( physicalConnection ) )
171                     assimilateNewCheckedOutStatement( key, physicalConnection, out );
172                 // else case: we can't assimilate the statement...
173
// so, we just return our newly created statement, without caching it.
174
// on check-in, it will simply be destroyed... this is an "overload statement"
175
}
176             else //okay, we can use an old one
177
{
178                 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
179                     logger.finest(this.getClass().getName() + " ----> CACHE HIT");
180                 //System.err.println("-------------> CACHE HIT!");
181

182                 out = l.get(0);
183                 l.remove(0);
184                 if (! checkedOut.add( out ))
185                     throw new RuntimeException JavaDoc("Internal inconsistency: " +
186                                     "Checking out a statement marked " +
187                     "as already checked out!");
188                 removeStatementFromDeathmarches( out, physicalConnection );
189             }
190
191             if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
192             {
193                 //System.err.print("checkoutStatement(): ");
194
//printStats();
195
if (logger.isLoggable(MLevel.FINEST))
196                     logger.finest("checkoutStatement: " + statsString());
197             }
198
199             return out;
200         }
201         catch (NullPointerException JavaDoc npe)
202         {
203             if (checkedOut == null) //we're closed
204
{
205                 if (logger.isLoggable(MLevel.FINE))
206                     logger.log( MLevel.FINE,
207                                 "A client attempted to work with a closed Statement cache, " + "" +
208                                 "provoking a NullPointerException. c3p0 recovers, but this should be rare.",
209                                 npe);
210                 throw new ResourceClosedException( npe );
211             }
212             else
213                 throw npe;
214         }
215     }
216
217     public synchronized void checkinStatement( Object JavaDoc pstmt )
218     throws SQLException
219     {
220         if (checkedOut == null) //we're closed
221
{
222             synchronousDestroyStatement( pstmt );
223
224             return;
225         }
226         else if (! checkedOut.remove( pstmt ) )
227         {
228             if (! ourResource( pstmt ) ) //this is not our resource, or it is an overload statement
229
destroyStatement( pstmt ); // so we just destroy
230
//in the else case, it's already checked-in, so we ignore
231

232             return;
233         }
234
235         try
236         { refreshStatement( (PreparedStatement) pstmt ); }
237         catch (Exception JavaDoc e)
238         {
239             if (Debug.DEBUG)
240             {
241 // System.err.println("Problem with checked-in Statement, discarding.");
242
// e.printStackTrace();
243
if (logger.isLoggable(MLevel.INFO))
244                     logger.log(MLevel.INFO, "Problem with checked-in Statement, discarding.", e);
245             }
246
247             // swaldman -- 2004-01-31: readd problem statement to checkedOut for consistency
248
// the statement is not yet checked-in, but it is removed from checked out, and this
249
// violates the consistency assumption of removeStatement(). Thanks to Zach Scott for
250
// calling attention to this issue.
251
checkedOut.add( pstmt );
252
253             removeStatement( pstmt, DESTROY_ALWAYS ); //force destruction of the statement even though it appears checked-out
254
return;
255         }
256
257         StatementCacheKey key = (StatementCacheKey) stmtToKey.get( pstmt );
258         if (Debug.DEBUG && key == null)
259             throw new RuntimeException JavaDoc("Internal inconsistency: " +
260             "A checked-out statement has no key associated with it!");
261
262         LinkedList l = checkoutQueue( key );
263         l.add( pstmt );
264         addStatementToDeathmarches( pstmt, key.physicalConnection );
265
266         if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
267         {
268 // System.err.print("checkinStatement(): ");
269
// printStats();
270
if (logger.isLoggable(MLevel.FINEST))
271                 logger.finest("checkinStatement(): " + statsString());
272         }
273     }
274
275
276     public synchronized void checkinAll(Connection pcon)
277     throws SQLException
278     {
279         //new Exception("checkinAll()").printStackTrace();
280

281         Set stmtSet = cxnStmtMgr.statementSet( pcon );
282         if (stmtSet != null)
283         {
284             for (Iterator ii = stmtSet.iterator(); ii.hasNext(); )
285             {
286                 Object JavaDoc stmt = ii.next();
287                 if (checkedOut.contains( stmt ))
288                     checkinStatement( stmt );
289             }
290         }
291
292         if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
293         {
294 // System.err.print("checkinAll(): ");
295
// printStats();
296
if (logger.isLoggable(MLevel.FINEST))
297                 logger.log(MLevel.FINEST, "checkinAll(): " + statsString());
298         }
299     }
300
301     /*
302      * we only selectively sync' parts of this method, because we wish to wait for
303      * Statements we wish to destroy the Statements synchronously, but without
304      * holding the pool's lock.
305      */

306     public void closeAll(Connection pcon) throws SQLException
307     {
308 // System.err.println( this + ": closeAll( " + pcon + " )" );
309
// new Exception("closeAll()").printStackTrace();
310

311 // assert !Thread.holdsLock( this );
312

313         if (! this.isClosed())
314         {
315             if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
316             {
317                 if (logger.isLoggable(MLevel.FINEST))
318                 {
319                     logger.log(MLevel.FINEST, "ENTER METHOD: closeAll( " + pcon + " )! -- num_connections: " +
320                                     cxnStmtMgr.getNumConnectionsWithCachedStatements());
321                     //logger.log(MLevel.FINEST, "Set of statements for connection: " + cSet + (cSet != null ? "; size: " + cSet.size() : ""));
322
}
323             }
324
325             Set stmtSet = null;
326             synchronized (this)
327             {
328                 Set cSet = cxnStmtMgr.statementSet( pcon );
329
330                 if (cSet != null)
331                 {
332                     //the removeStatement(...) removes from cSet, so we can't be iterating over cSet directly
333
stmtSet = new HashSet( cSet );
334                     //System.err.println("SIZE FOR CONNECTION SET: " + stmtSet.size());
335

336                     for (Iterator ii = stmtSet.iterator(); ii.hasNext(); )
337                     {
338                         Object JavaDoc stmt = ii.next();
339                         // we remove without destroying, leaving the destruction
340
// until when we lose the pool's lock
341
removeStatement( stmt, DESTROY_NEVER );
342                     }
343                 }
344             }
345
346             if ( stmtSet != null )
347             {
348                 for (Iterator ii = stmtSet.iterator(); ii.hasNext(); )
349                 {
350                     Object JavaDoc stmt = ii.next();
351                     synchronousDestroyStatement( stmt );
352                 }
353             }
354
355             if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
356             {
357                 if (logger.isLoggable(MLevel.FINEST))
358                     logger.finest("closeAll(): " + statsString());
359             }
360         }
361 // else
362
// {
363
// if (logger.isLoggable(MLevel.FINER))
364
// logger.log(MLevel.FINER,
365
// this + ": call to closeAll() when statment cache is already closed! [not harmful! debug only!]",
366
// new Exception("DUPLICATE CLOSE DEBUG STACK TRACE."));
367
// }
368
}
369
370     public synchronized void close()
371     throws SQLException
372     {
373         //System.err.println( this + ": close()" );
374

375         if (! isClosed())
376         {
377             for (Iterator ii = stmtToKey.keySet().iterator(); ii.hasNext(); )
378                 synchronousDestroyStatement( ii.next() );
379
380             cxnStmtMgr = null;
381             stmtToKey = null;
382             keyToKeyRec = null;
383             checkedOut = null;
384         }
385         else
386         {
387             if (logger.isLoggable(MLevel.FINE))
388                 logger.log(MLevel.FINE, this + ": duplicate call to close() [not harmful! -- debug only!]", new Exception JavaDoc("DUPLICATE CLOSE DEBUG STACK TRACE."));
389         }
390
391     }
392
393
394     public synchronized boolean isClosed()
395     { return cxnStmtMgr == null; }
396
397     /* non-public methods that needn't be called with this' lock below */
398
399     private void destroyStatement( final Object JavaDoc pstmt )
400     {
401         class StatementCloseTask implements Runnable JavaDoc
402         {
403             public void run()
404             { StatementUtils.attemptClose( (PreparedStatement) pstmt ); }
405         }
406
407         Runnable JavaDoc r = new StatementCloseTask();
408
409         blockingTaskAsyncRunner.postRunnable(r);
410     }
411
412     private void synchronousDestroyStatement( final Object JavaDoc pstmt )
413     { StatementUtils.attemptClose( (PreparedStatement) pstmt ); }
414
415     /* end non-public methods that needn't be called with this' lock */
416
417
418
419     /* non-public methods that MUST be called with this' lock */
420
421     abstract boolean prepareAssimilateNewStatement(Connection pcon);
422
423     abstract void addStatementToDeathmarches( Object JavaDoc pstmt, Connection physicalConnection );
424     abstract void removeStatementFromDeathmarches( Object JavaDoc pstmt, Connection physicalConnection );
425
426     final int countCachedStatements()
427     { return stmtToKey.size(); }
428
429     private void assimilateNewCheckedOutStatement( StatementCacheKey key,
430                     Connection pConn,
431                     Object JavaDoc ps )
432     {
433         stmtToKey.put( ps, key );
434         HashSet ks = keySet( key );
435         if (ks == null)
436             keyToKeyRec.put( key, new KeyRec() );
437         else
438         {
439             //System.err.println("-------> Multiply prepared statement! " + key.stmtText );
440
if (logger.isLoggable(MLevel.INFO))
441                 logger.info("Multiply prepared statement! " + key.stmtText );
442             if (Debug.DEBUG && logger.isLoggable(MLevel.FINE))
443                 logger.fine("(The same statement has already been prepared by this Connection, " +
444                                 "and that other instance has not yet been closed, so the statement pool " +
445                                 "has to prepare a second PreparedStatement object rather than reusing " +
446                                 "the previously-cached Statement. The new Statement will be cached, in case " +
447                 "you frequently need multiple copies of this Statement.)");
448         }
449         keySet( key ).add( ps );
450         cxnStmtMgr.addStatementForConnection( ps, pConn );
451
452         if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
453         {
454 // System.err.println("cxnStmtMgr.statementSet( " + pConn + " ).size(): " +
455
// cxnStmtMgr.statementSet( pConn ).size());
456
if (logger.isLoggable(MLevel.FINEST))
457                 logger.finest("cxnStmtMgr.statementSet( " + pConn + " ).size(): " +
458                                 cxnStmtMgr.statementSet( pConn ).size());
459         }
460
461         checkedOut.add( ps );
462     }
463
464     private void removeStatement( Object JavaDoc ps , int destruction_policy )
465     {
466         synchronized (removalPending)
467         {
468             if ( removalPending.contains( ps ) )
469                 return;
470             else
471                 removalPending.add(ps);
472         }
473
474         StatementCacheKey sck = (StatementCacheKey) stmtToKey.remove( ps );
475         removeFromKeySet( sck, ps );
476         Connection pConn = sck.physicalConnection;
477
478         boolean checked_in = !checkedOut.contains( ps );
479
480         if ( checked_in )
481         {
482             removeStatementFromDeathmarches( ps, pConn );
483             removeFromCheckoutQueue( sck , ps );
484             if ((destruction_policy & DESTROY_IF_CHECKED_IN) != 0)
485                 destroyStatement( ps );
486         }
487         else
488         {
489             checkedOut.remove( ps );
490             if ((destruction_policy & DESTROY_IF_CHECKED_OUT) != 0)
491                 destroyStatement( ps );
492         }
493
494
495         boolean check = cxnStmtMgr.removeStatementForConnection( ps, pConn );
496         if (Debug.DEBUG && check == false)
497         {
498             //new Exception("WARNING: removed a statement that apparently wasn't in a statement set!!!").printStackTrace();
499
if (logger.isLoggable(MLevel.WARNING))
500                 logger.log(MLevel.WARNING,
501                                 this + " removed a statement that apparently wasn't in a statement set!!!",
502                                 new Exception JavaDoc("LOG STACK TRACE"));
503         }
504
505         synchronized (removalPending)
506         { removalPending.remove(ps); }
507     }
508
509     private Object JavaDoc acquireStatement(final Connection pConn,
510                     final Method stmtProducingMethod,
511                     final Object JavaDoc[] args )
512     throws SQLException
513     {
514         try
515         {
516             final Object JavaDoc[] outHolder = new Object JavaDoc[1];
517             final SQLException[] exceptionHolder = new SQLException[1];
518
519             class StmtAcquireTask implements Runnable JavaDoc
520             {
521                 public void run()
522                 {
523                     try
524                     {
525                         outHolder[0] =
526                             stmtProducingMethod.invoke( pConn,
527                                             args );
528                     }
529                     catch ( InvocationTargetException e )
530                     {
531                         Throwable JavaDoc targetException = e.getTargetException();
532                         if ( targetException instanceof SQLException )
533                             exceptionHolder[0] = (SQLException) targetException;
534                         else
535                             exceptionHolder[0]
536                                             = SqlUtils.toSQLException(targetException);
537                     }
538                     catch ( Exception JavaDoc e )
539                     { exceptionHolder[0] = SqlUtils.toSQLException(e); }
540                     finally
541                     {
542                         synchronized ( GooGooStatementCache.this )
543                         { GooGooStatementCache.this.notifyAll(); }
544                     }
545                 }
546             }
547
548             Runnable JavaDoc r = new StmtAcquireTask();
549             blockingTaskAsyncRunner.postRunnable(r);
550
551             while ( outHolder[0] == null && exceptionHolder[0] == null )
552                 this.wait(); //give up our lock while the Statement gets prepared
553
if (exceptionHolder[0] != null)
554                 throw exceptionHolder[0];
555             else
556             {
557                 Object JavaDoc out = outHolder[0];
558                 return out;
559             }
560         }
561         catch ( InterruptedException JavaDoc e )
562         { throw SqlUtils.toSQLException( e ); }
563     }
564
565     private KeyRec keyRec( StatementCacheKey key )
566     { return ((KeyRec) keyToKeyRec.get( key )); }
567
568     private HashSet keySet( StatementCacheKey key )
569     {
570         KeyRec rec = keyRec( key );
571         return (rec == null ? null : rec.allStmts);
572     }
573
574     private boolean removeFromKeySet( StatementCacheKey key, Object JavaDoc pstmt )
575     {
576         boolean out;
577         HashSet stmtSet = keySet( key );
578         out = stmtSet.remove( pstmt );
579         if (stmtSet.isEmpty() && checkoutQueue( key ).isEmpty())
580             keyToKeyRec.remove( key );
581         return out;
582     }
583
584     private LinkedList checkoutQueue( StatementCacheKey key )
585     {
586         KeyRec rec = keyRec( key );
587         return ( rec == null ? null : rec.checkoutQueue );
588     }
589
590     private boolean removeFromCheckoutQueue( StatementCacheKey key, Object JavaDoc pstmt )
591     {
592         boolean out;
593         LinkedList q = checkoutQueue( key );
594         out = q.remove( pstmt );
595         if (q.isEmpty() && keySet( key ).isEmpty())
596             keyToKeyRec.remove( key );
597         return out;
598     }
599
600     private boolean ourResource( Object JavaDoc ps )
601     { return stmtToKey.keySet().contains( ps ); }
602
603     private void refreshStatement( PreparedStatement ps ) throws Exception JavaDoc
604     { ps.clearParameters(); }
605
606     private void printStats()
607     {
608         //new Exception("printStats()").printStackTrace();
609
int total_size = this.countCachedStatements();
610         int checked_out_size = checkedOut.size();
611         int num_connections = cxnStmtMgr.getNumConnectionsWithCachedStatements();
612         int num_keys = keyToKeyRec.size();
613         System.err.print(this.getClass().getName() + " stats -- ");
614         System.err.print("total size: " + total_size);
615         System.err.print("; checked out: " + checked_out_size);
616         System.err.print("; num connections: " + num_connections);
617         System.err.println("; num keys: " + num_keys);
618     }
619
620     private String JavaDoc statsString()
621     {
622         int total_size = this.countCachedStatements();
623         int checked_out_size = checkedOut.size();
624         int num_connections = cxnStmtMgr.getNumConnectionsWithCachedStatements();
625         int num_keys = keyToKeyRec.size();
626
627         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(255);
628         sb.append(this.getClass().getName());
629         sb.append(" stats -- ");
630         sb.append("total size: ");
631         sb.append(total_size);
632         sb.append("; checked out: ");
633         sb.append(checked_out_size);
634         sb.append("; num connections: ");
635         sb.append(num_connections);
636         sb.append("; num keys: ");
637         sb.append(num_keys);
638         return sb.toString();
639     }
640
641
642     private static class KeyRec
643     {
644         HashSet allStmts = new HashSet();
645         LinkedList checkoutQueue = new LinkedList();
646     }
647
648     protected class Deathmarch
649     {
650         TreeMap longsToStmts = new TreeMap();
651         HashMap stmtsToLongs = new HashMap();
652
653         long last_long = -1;
654
655         public void deathmarchStatement( Object JavaDoc ps )
656         {
657             //System.err.println("deathmarchStatement( " + ps + " )");
658
if (Debug.DEBUG)
659             {
660                 Long JavaDoc old = (Long JavaDoc) stmtsToLongs.get( ps );
661                 if (old != null)
662                     throw new RuntimeException JavaDoc("Internal inconsistency: " +
663                                     "A statement is being double-deathmatched. no checked-out statements should be in a deathmarch already; " +
664                     "no already checked-in statement should be deathmarched!");
665             }
666
667             Long JavaDoc youth = getNextLong();
668             stmtsToLongs.put( ps, youth );
669             longsToStmts.put( youth, ps );
670         }
671
672         public void undeathmarchStatement( Object JavaDoc ps )
673         {
674             Long JavaDoc old = (Long JavaDoc) stmtsToLongs.remove( ps );
675             if (Debug.DEBUG && old == null)
676                 throw new RuntimeException JavaDoc("Internal inconsistency: " +
677                 "A (not new) checking-out statement is not in deathmarch.");
678             Object JavaDoc check = longsToStmts.remove( old );
679             if (Debug.DEBUG && old == null)
680                 throw new RuntimeException JavaDoc("Internal inconsistency: " +
681                 "A (not new) checking-out statement is not in deathmarch.");
682         }
683
684         public boolean cullNext()
685         {
686             if ( longsToStmts.isEmpty() )
687                 return false;
688             else
689             {
690                 Long JavaDoc l = (Long JavaDoc) longsToStmts.firstKey();
691                 Object JavaDoc ps = longsToStmts.get( l );
692                 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX)
693                 {
694 // System.err.println("CULLING: " +
695
// ((StatementCacheKey) stmtToKey.get(ps)).stmtText);
696
if (logger.isLoggable(MLevel.FINEST))
697                         logger.finest("CULLING: " + ((StatementCacheKey) stmtToKey.get(ps)).stmtText);
698                 }
699                 // we do not undeathmarch the statement ourselves, because removeStatement( ... )
700
// should remove from all deathmarches...
701
removeStatement( ps, DESTROY_ALWAYS );
702                 if (Debug.DEBUG && this.contains( ps ))
703                     throw new RuntimeException JavaDoc("Inconsistency!!! Statement culled from deathmarch failed to be removed by removeStatement( ... )!");
704                 return true;
705             }
706         }
707
708         public boolean contains( Object JavaDoc ps )
709         { return stmtsToLongs.keySet().contains( ps ); }
710
711         public int size()
712         { return longsToStmts.size(); }
713
714         private Long JavaDoc getNextLong()
715         { return new Long JavaDoc( ++last_long ); }
716     }
717
718     protected static abstract class ConnectionStatementManager
719     {
720         Map cxnToStmtSets = new HashMap();
721
722         public int getNumConnectionsWithCachedStatements()
723         { return cxnToStmtSets.size(); }
724
725         public Set connectionSet()
726         { return cxnToStmtSets.keySet(); }
727
728         public Set statementSet( Connection pcon )
729         { return (Set) cxnToStmtSets.get( pcon ); }
730
731         public int getNumStatementsForConnection( Connection pcon )
732         {
733             Set stmtSet = statementSet( pcon );
734             return (stmtSet == null ? 0 : stmtSet.size());
735         }
736
737         public void addStatementForConnection( Object JavaDoc ps, Connection pcon )
738         {
739             Set stmtSet = statementSet( pcon );
740             if (stmtSet == null)
741             {
742                 stmtSet = new HashSet();
743                 cxnToStmtSets.put( pcon, stmtSet );
744             }
745             stmtSet.add( ps );
746         }
747
748         public boolean removeStatementForConnection( Object JavaDoc ps, Connection pcon )
749         {
750             boolean out;
751
752             Set stmtSet = statementSet( pcon );
753             if ( stmtSet != null )
754             {
755                 out = stmtSet.remove( ps );
756                 if (stmtSet.isEmpty())
757                     cxnToStmtSets.remove( pcon );
758             }
759             else
760                 out = false;
761
762             return out;
763         }
764     }
765
766     // i want this as optimized as possible, so i'm adopting the philosophy that all
767
// classes are abstract or final, to help enable compiler inlining...
768
protected static final class SimpleConnectionStatementManager extends ConnectionStatementManager
769     {}
770
771     protected final class DeathmarchConnectionStatementManager extends ConnectionStatementManager
772     {
773         Map cxnsToDms = new HashMap();
774
775         public void addStatementForConnection( Object JavaDoc ps, Connection pcon )
776         {
777             super.addStatementForConnection( ps, pcon );
778             Deathmarch dm = (Deathmarch) cxnsToDms.get( pcon );
779             if (dm == null)
780             {
781                 dm = new Deathmarch();
782                 cxnsToDms.put( pcon, dm );
783             }
784         }
785
786         public boolean removeStatementForConnection( Object JavaDoc ps, Connection pcon )
787         {
788             boolean out = super.removeStatementForConnection( ps, pcon );
789             if (out)
790             {
791                 if ( statementSet( pcon ) == null )
792                     cxnsToDms.remove( pcon );
793             }
794             return out;
795         }
796
797         public Deathmarch getDeathmarch( Connection pcon )
798         { return (Deathmarch) cxnsToDms.get( pcon ); }
799     }
800 }
801
802
Popular Tags