?? googoostatementcache.java
字號:
/* non-public methods that MUST be called with this' lock */ abstract boolean prepareAssimilateNewStatement(Connection pcon); abstract void addStatementToDeathmarches( Object pstmt, Connection physicalConnection ); abstract void removeStatementFromDeathmarches( Object pstmt, Connection physicalConnection ); final int countCachedStatements() { return stmtToKey.size(); } private void assimilateNewCheckedOutStatement( StatementCacheKey key, Connection pConn, Object ps ) { stmtToKey.put( ps, key ); HashSet ks = keySet( key ); if (ks == null) keyToKeyRec.put( key, new KeyRec() ); else { //System.err.println("-------> Multiply prepared statement! " + key.stmtText ); if (logger.isLoggable(MLevel.INFO)) logger.info("Multiply prepared statement! " + key.stmtText ); if (Debug.DEBUG && logger.isLoggable(MLevel.FINE)) logger.fine("(The same statement has already been prepared by this Connection, " + "and that other instance has not yet been closed, so the statement pool " + "has to prepare a second PreparedStatement object rather than reusing " + "the previously-cached Statement. The new Statement will be cached, in case " + "you frequently need multiple copies of this Statement.)"); } keySet( key ).add( ps ); cxnStmtMgr.addStatementForConnection( ps, pConn ); if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) {// System.err.println("cxnStmtMgr.statementSet( " + pConn + " ).size(): " + // cxnStmtMgr.statementSet( pConn ).size()); if (logger.isLoggable(MLevel.FINEST)) logger.finest("cxnStmtMgr.statementSet( " + pConn + " ).size(): " + cxnStmtMgr.statementSet( pConn ).size()); } ++stmt_count; checkedOut.add( ps ); } private void removeStatement( Object ps , boolean force_destroy ) { removeStatement( ps, force_destroy, null ); } /* * SIMULTANEOUS CLOSE OF STATEMENT AND CONNECTION BUG WORKAROUND ( counter crap ) -- see closeAll(Connection c) */ private void removeStatement( Object ps , boolean force_destroy, ChangeNotifyingSynchronizedIntHolder counter ) { synchronized (removalPending) { if ( removalPending.contains( ps ) ) return; else removalPending.add(ps); } StatementCacheKey sck = (StatementCacheKey) stmtToKey.remove( ps ); removeFromKeySet( sck, ps ); Connection pConn = sck.physicalConnection; if (! checkedOut.contains( ps ) ) { removeStatementFromDeathmarches( ps, pConn ); removeFromCheckoutQueue( sck , ps ); destroyStatement( ps, counter ); } else { checkedOut.remove( ps ); // usually we let it defer destruction until check-in! if (force_destroy) // but occasionally we want the statement assuredly gone. { destroyStatement( ps, counter ); } } boolean check = cxnStmtMgr.removeStatementForConnection( ps, pConn ); if (Debug.DEBUG && check == false) { //new Exception("WARNING: removed a statement that apparently wasn't in a statement set!!!").printStackTrace(); if (logger.isLoggable(MLevel.WARNING)) logger.log(MLevel.WARNING, this + " removed a statement that apparently wasn't in a statement set!!!", new Exception("LOG STACK TRACE")); } --stmt_count; synchronized (removalPending) { removalPending.remove(ps); } } private Object acquireStatement(final Connection pConn, final Method stmtProducingMethod, final Object[] args ) throws SQLException { try { final Object[] outHolder = new Object[1]; final SQLException[] exceptionHolder = new SQLException[1]; Runnable r = new Runnable() { public void run() { try { outHolder[0] = stmtProducingMethod.invoke( pConn, args ); } catch ( InvocationTargetException e ) { Throwable targetException = e.getTargetException(); if ( targetException instanceof SQLException ) exceptionHolder[0] = (SQLException) targetException; else exceptionHolder[0] = SqlUtils.toSQLException(targetException); } catch ( Exception e ) { exceptionHolder[0] = SqlUtils.toSQLException(e); } finally { synchronized ( GooGooStatementCache.this ) { GooGooStatementCache.this.notifyAll(); } } } }; blockingTaskAsyncRunner.postRunnable(r); while ( outHolder[0] == null && exceptionHolder[0] == null ) this.wait(); //give up our lock while the Statement gets prepared if (exceptionHolder[0] != null) throw exceptionHolder[0]; else { Object out = outHolder[0]; return out; } } catch ( InterruptedException e ) { throw SqlUtils.toSQLException( e ); } } private KeyRec keyRec( StatementCacheKey key ) { return ((KeyRec) keyToKeyRec.get( key )); } private HashSet keySet( StatementCacheKey key ) { KeyRec rec = keyRec( key ); return (rec == null ? null : rec.allStmts); } private boolean removeFromKeySet( StatementCacheKey key, Object pstmt ) { boolean out; HashSet stmtSet = keySet( key ); out = stmtSet.remove( pstmt ); if (stmtSet.isEmpty() && checkoutQueue( key ).isEmpty()) keyToKeyRec.remove( key ); return out; } private LinkedList checkoutQueue( StatementCacheKey key ) { KeyRec rec = keyRec( key ); return ( rec == null ? null : rec.checkoutQueue ); } private boolean removeFromCheckoutQueue( StatementCacheKey key, Object pstmt ) { boolean out; LinkedList q = checkoutQueue( key ); out = q.remove( pstmt ); if (q.isEmpty() && keySet( key ).isEmpty()) keyToKeyRec.remove( key ); return out; } private boolean ourResource( Object ps ) { return stmtToKey.keySet().contains( ps ); } private void refreshStatement( PreparedStatement ps ) throws Exception { ps.clearParameters(); } private void printStats() { //new Exception("printStats()").printStackTrace(); int total_size = this.countCachedStatements(); int checked_out_size = checkedOut.size(); int num_connections = cxnStmtMgr.getNumConnectionsWithCachedStatements(); int num_keys = keyToKeyRec.size(); System.err.print(this.getClass().getName() + " stats -- "); System.err.print("total size: " + total_size); System.err.print("; checked out: " + checked_out_size); System.err.print("; num connections: " + num_connections); System.err.println("; num keys: " + num_keys); } private String statsString() { int total_size = this.countCachedStatements(); int checked_out_size = checkedOut.size(); int num_connections = cxnStmtMgr.getNumConnectionsWithCachedStatements(); int num_keys = keyToKeyRec.size(); StringBuffer sb = new StringBuffer(255); sb.append(this.getClass().getName()); sb.append(" stats -- "); sb.append("total size: "); sb.append(total_size); sb.append("; checked out: "); sb.append(checked_out_size); sb.append("; num connections: "); sb.append(num_connections); sb.append("; num keys: "); sb.append(num_keys); return sb.toString(); } private static class KeyRec { HashSet allStmts = new HashSet(); LinkedList checkoutQueue = new LinkedList(); } protected class Deathmarch { TreeMap longsToStmts = new TreeMap(); HashMap stmtsToLongs = new HashMap(); long last_long = -1; public void deathmarchStatement( Object ps ) { //System.err.println("deathmarchStatement( " + ps + " )"); if (Debug.DEBUG) { Long old = (Long) stmtsToLongs.get( ps ); if (old != null) throw new RuntimeException("Internal inconsistency: " + "A statement is being double-deathmatched. no checked-out statements should be in a deathmarch already; " + "no already checked-in statement should be deathmarched!"); } Long youth = getNextLong(); stmtsToLongs.put( ps, youth ); longsToStmts.put( youth, ps ); } public void undeathmarchStatement( Object ps ) { Long old = (Long) stmtsToLongs.remove( ps ); if (Debug.DEBUG && old == null) throw new RuntimeException("Internal inconsistency: " + "A (not new) checking-out statement is not in deathmarch."); Object check = longsToStmts.remove( old ); if (Debug.DEBUG && old == null) throw new RuntimeException("Internal inconsistency: " + "A (not new) checking-out statement is not in deathmarch."); } public boolean cullNext() { if ( longsToStmts.isEmpty() ) return false; else { Long l = (Long) longsToStmts.firstKey(); Object ps = longsToStmts.get( l ); if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) {// System.err.println("CULLING: " + // ((StatementCacheKey) stmtToKey.get(ps)).stmtText); if (logger.isLoggable(MLevel.FINEST)) logger.finest("CULLING: " + ((StatementCacheKey) stmtToKey.get(ps)).stmtText); } // we do not undeathmarch the statement ourselves, because removeStatement( ... ) // should remove from all deathmarches... removeStatement( ps, true ); if (Debug.DEBUG && this.contains( ps )) throw new RuntimeException("Inconsistency!!! Statement culled from deathmarch failed to be removed by removeStatement( ... )!"); return true; } } public boolean contains( Object ps ) { return stmtsToLongs.keySet().contains( ps ); } public int size() { return longsToStmts.size(); } private Long getNextLong() { return new Long( ++last_long ); } } protected static abstract class ConnectionStatementManager { Map cxnToStmtSets = new HashMap(); public int getNumConnectionsWithCachedStatements() { return cxnToStmtSets.size(); } public Set statementSet( Connection pcon ) { return (Set) cxnToStmtSets.get( pcon ); } public int getNumStatementsForConnection( Connection pcon ) { Set stmtSet = statementSet( pcon ); return (stmtSet == null ? 0 : stmtSet.size()); } public void addStatementForConnection( Object ps, Connection pcon ) { Set stmtSet = statementSet( pcon ); if (stmtSet == null) { stmtSet = new HashSet(); cxnToStmtSets.put( pcon, stmtSet ); } stmtSet.add( ps ); } public boolean removeStatementForConnection( Object ps, Connection pcon ) { boolean out; Set stmtSet = statementSet( pcon ); if ( stmtSet != null ) { out = stmtSet.remove( ps ); if (stmtSet.isEmpty()) cxnToStmtSets.remove( pcon ); } else out = false; return out; } } // i want this as optimized as possible, so i'm adopting the philosophy that all // classes are abstract or final, to help enable compiler inlining... protected static final class SimpleConnectionStatementManager extends ConnectionStatementManager {} protected final class DeathmarchConnectionStatementManager extends ConnectionStatementManager { Map cxnsToDms = new HashMap(); public void addStatementForConnection( Object ps, Connection pcon ) { super.addStatementForConnection( ps, pcon ); Deathmarch dm = (Deathmarch) cxnsToDms.get( pcon ); if (dm == null) { dm = new Deathmarch(); cxnsToDms.put( pcon, dm ); } } public boolean removeStatementForConnection( Object ps, Connection pcon ) { boolean out = super.removeStatementForConnection( ps, pcon ); if (out) { if ( statementSet( pcon ) == null ) cxnsToDms.remove( pcon ); } return out; } public Deathmarch getDeathmarch( Connection pcon ) { return (Deathmarch) cxnsToDms.get( pcon ); } }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -