Mercurial Hosting > nabble
diff src/fschmidt/db/pool/Pool.java @ 68:00520880ad02
add fschmidt source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 05 Oct 2025 17:24:15 -0600 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fschmidt/db/pool/Pool.java Sun Oct 05 17:24:15 2025 -0600 @@ -0,0 +1,176 @@ +/* +Copyright (c) 2008 Franklin Schmidt <fschmidt@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +package fschmidt.db.pool; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; +import java.util.ArrayList; +import java.util.Set; +import java.util.HashSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import fschmidt.db.DbDatabase; +import fschmidt.db.DbObject; +import fschmidt.db.DbKey; +import fschmidt.db.DbObjectFactory; +import fschmidt.db.SQLRuntimeException; +import fschmidt.db.extend.DbDatabaseExt; +import fschmidt.db.extend.DbTableExt; +import fschmidt.db.extend.DbTransaction; +import fschmidt.db.extend.DbRecordExt; +import fschmidt.db.extend.FilterDatabase; +import fschmidt.util.java.Stack; +import fschmidt.util.java.ArrayStack; + + +public final class Pool { + private static final Logger logger = LoggerFactory.getLogger(Pool.class); + + final Stack<PooledConnection> stack = new ArrayStack<PooledConnection>(); + private long idleTimeout = 0L; + private long idleExpires; + final ThreadLocal<PooledConnection> localCon = new ThreadLocal<PooledConnection>(); + + public long getIdleTimeout() { + return idleTimeout; + } + + public void setIdleTimeout(long idleTimeout) { + this.idleTimeout = idleTimeout; + } + + boolean isInTransaction() { + PooledConnection con = localCon.get(); + return con!=null && con.isInTransaction(); + } + + void commitTransaction() { + localCon.get().commitTransaction(); + } + + void endTransaction() { + PooledConnection con = localCon.get(); + if( con==null ) + throw new IllegalStateException("endTransaction called without beginTransaction"); + con.endTransaction(); + } + + void runBeforeCommit(Runnable r) { + PooledConnection con = localCon.get(); + if( !con.ignoreRunnablesInThisTransaction ) + con.beforeCommitList.add(r); + } + + void runJustAfterCommit(Runnable r) { + PooledConnection con = localCon.get(); + if( !con.ignoreRunnablesInThisTransaction ) + con.afterCommitList.add(0,r); + } + + void runAfterCommit(Runnable r) { + PooledConnection con = localCon.get(); + if( !con.ignoreRunnablesInThisTransaction ) + con.afterCommitList.add(r); + } + + void ignoreRunnablesInThisTransaction() { + if( !isInTransaction() ) + throw new IllegalStateException("not in transaction"); + localCon.get().ignoreRunnablesInThisTransaction = true; + } + + DbTransaction getTransaction() { + if( isInTransaction() ) { + return localCon.get().dbTrans; + } else { + return null; + } + } + + Connection getConnection(DbDatabaseImpl db) + throws SQLException + { + PooledConnection con = localCon.get(); + if( con==null || con.con().isClosed() ) { + con = getConnection2(db); + localCon.set(con); + pools.get().add(this); + } + return con.nest(db.user); + } + + private static final long timeout = 1000L*60*60; // 1 hour + + private synchronized PooledConnection getConnection2(DbDatabaseImpl db) + throws SQLException + { + long now = System.currentTimeMillis(); + while( !stack.isEmpty() ) { + PooledConnection con = stack.pop(); + Connection realCon = con.con(); + if( realCon.isClosed() ) + continue; + try { + if( now - con.lastUsed > timeout ) { + Statement stmt = realCon.createStatement(); + stmt.executeQuery("select 1"); + stmt.close(); + } + } catch(SQLException e) { + logger.info("corrupt connection dropped from pool"); + continue; + } + return con; + } + idleExpires = now + idleTimeout; + return new PooledConnection(db); + } + + boolean isExpired(long lastUsed) { + return idleTimeout > 0 && lastUsed > idleExpires; + } + + private static ThreadLocal<Set<Pool>> pools = new ThreadLocal<Set<Pool>>() { + protected Set<Pool> initialValue() { + return new HashSet<Pool>(); + } + }; + + public static void threadReset() { + Set<Pool> set = pools.get(); + for( Pool pool : set ) { + PooledConnection con = pool.localCon.get(); + if( con != null ) { + con.forceClose(); + } + } + set.clear(); + } + + public Connection getNativeConnection() { + return localCon.get().con(); + } + +}