package jef.database.innerpool;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicLong;
import javax.sql.DataSource;
import jef.common.Callback;
import jef.common.pool.PoolStatus;
import jef.database.ConnectInfo;
import jef.database.DbMetaData;
import jef.database.DbUtils;
import jef.database.ORMConfig;
import jef.database.datasource.IRoutingDataSource;
import jef.database.dialect.DatabaseDialect;
import org.easyframe.enterprise.spring.TransactionMode;
import com.google.common.collect.MapMaker;
/**
* 启用了外部连接池后的路由伪连接池。
* 实际上所有真正的连接都是从外部连接池中获取的。每次释放的时候这些连接都被关闭(即释放回外部连接池)
*
*
* @author jiyi
*
*/
public class RoutingDummyConnectionPool implements IRoutingConnectionPool{
protected IRoutingDataSource datasource;
final Map<Object, RoutingConnection> usedConnection=new MapMaker().concurrencyLevel(12).weakKeys().makeMap();
private final AtomicLong pollCount=new AtomicLong();
private final AtomicLong offerCount=new AtomicLong();
private final Map<String,DbMetaData> metadatas=new HashMap<String,DbMetaData>(8,0.5f);
public RoutingDummyConnectionPool(IRoutingDataSource ds){
this.datasource=ds;
}
public RoutingConnection getConnection(Object transaction) throws SQLException {
pollCount.incrementAndGet();
RoutingConnection conn=usedConnection.get(transaction);
if(conn==null){
conn=new RoutingConnection(this,ORMConfig.getInstance().isJpaContinueCommitIfError());
conn.ensureOpen();//对于Routing连接来说,监测是否有效是没有意义的
usedConnection.put(transaction, conn);
conn.setUsedByObject(transaction);
}else{
conn.addUsedByObject();
}
return conn;
}
public RoutingConnection poll() throws SQLException {
return getConnection(Thread.currentThread());
}
public void offer(ReentrantConnection conn){
offerCount.incrementAndGet();
if(conn!=null){
//处理内部的记录数据
Object o=conn.popUsedByObject();
if(o==null)return;//不是真正的归还
IConnection conn1=usedConnection.remove(o);
conn.closePhysical();
if(conn1!=conn){
throw new IllegalStateException("The connection returned not match.");
}
}
}
public void close() throws SQLException {
for(IConnection conn: usedConnection.values()){
conn.closePhysical();
}
usedConnection.clear();
PoolService.logPoolStatic(getClass().getSimpleName(),pollCount.get(), offerCount.get());
}
public DataSource getDatasource() {
throw new UnsupportedOperationException();
}
public PoolStatus getStatus() {
int size=usedConnection.size();
return new PoolStatus(0,0,size,size,0);
}
public Collection<String> getAllDatasourceNames() {
return datasource.getDataSourceNames();
}
public IRoutingDataSource getRoutingDataSource() {
return datasource;
}
/**
* 默认实现,从不缓存连接
* @throws SQLException
*/
public Connection getCachedConnection(String ds) throws SQLException {
return datasource.getDataSource(ds).getConnection();
}
/**
* 默认实现,从不缓存连接,连接直接关闭(使用外部连接池的场景)
*/
public void putback(String ds, Connection conn) {
DbUtils.closeConnection(conn);
}
public void closeConnectionTillMin() {
//无需任何功能
}
public DbMetaData getMetadata(String dbkey) {
dbkey=wrapNullKey(dbkey);
DbMetaData meta=metadatas.get(dbkey);
if(meta!=null)return meta;
meta=createMetadata(dbkey);
return meta;
}
private String wrapNullKey(String dbkey) {
if(dbkey!=null){
return dbkey;
}
Entry<String,DataSource> e=datasource.getDefaultDatasource();
if(e!=null){
return e.getKey();
}else{
throw new IllegalArgumentException("No default datasource found in "+datasource+"!");
}
}
private synchronized DbMetaData createMetadata(String key) {
DataSource ds=datasource.getDataSource(key);//必须放在双重检查锁定逻辑的外面,否则会因为回调对象的存在而造成元数据对象初始化两遍。。。
DbMetaData meta=metadatas.get(key);
if(meta==null){
meta=new DbMetaData(ds,this,key);
metadatas.put(key, meta);
}
// 反向修正
meta.getProfile().accept(meta);
return meta;
}
public DatabaseDialect getProfile(String dbkey) {
return getMetadata(dbkey).getProfile();
}
public ConnectInfo getInfo(String dbkey) {
return getMetadata(dbkey).getInfo();
}
public boolean isRouting() {
return true;
}
public void registeDbInitCallback(Callback<String, SQLException> callback) {
this.datasource.setCallback(callback);
}
public boolean isDummy() {
return true;
}
private TransactionMode txMode;
@Override
public IUserManagedPool setTransactionMode(TransactionMode txMode) {
this.txMode=txMode;
return this;
}
@Override
public TransactionMode getTransactionMode() {
return txMode;
}
}