package com.ctrip.platform.dal.dao.client;
import java.sql.Connection;
import java.sql.SQLException;
import com.ctrip.platform.dal.dao.DalEventEnum;
import com.ctrip.platform.dal.dao.DalHintEnum;
import com.ctrip.platform.dal.dao.DalHints;
import com.ctrip.platform.dal.dao.configure.DalConfigure;
import com.ctrip.platform.dal.dao.configure.DatabaseSet;
import com.ctrip.platform.dal.dao.markdown.MarkdownManager;
import com.ctrip.platform.dal.dao.status.DalStatusManager;
import com.ctrip.platform.dal.dao.strategy.DalShardingStrategy;
import com.ctrip.platform.dal.exceptions.DalException;
import com.ctrip.platform.dal.exceptions.ErrorCode;
public class DalConnectionManager {
private DalConfigure config;
private String logicDbName;
private DalLogger logger;
private DalConnectionLocator locator;
public DalConnectionManager(String logicDbName, DalConfigure config) {
this.logicDbName = logicDbName;
this.config = config;
this.logger = config.getDalLogger();
this.locator = config.getLocator();
}
public String getLogicDbName() {
return logicDbName;
}
public DalConfigure getConfig() {
return config;
}
public DalLogger getLogger() {
return logger;
}
public DalConnection getNewConnection(DalHints hints, boolean useMaster, DalEventEnum operation)
throws SQLException {
DalConnection connHolder = null;
String realDbName = logicDbName;
try
{
if(DalStatusManager.getDatabaseSetStatus(logicDbName).isMarkdown())
throw new DalException(ErrorCode.MarkdownLogicDb, logicDbName);
boolean isMaster = hints.is(DalHintEnum.masterOnly) || useMaster;
boolean isSelect = operation == DalEventEnum.QUERY;
connHolder = getConnectionFromDSLocator(hints, isMaster, isSelect);
connHolder.setAutoCommit(true);
connHolder.applyHints(hints);
if(hints.getHA() != null){
hints.getHA().setDatabaseCategory(connHolder.getMeta().getDatabaseCategory());
}
realDbName = connHolder.getDatabaseName();
}
catch(SQLException ex)
{
logger.getConnectionFailed(realDbName, ex);
throw ex;
}
return connHolder;
}
private DalConnection getConnectionFromDSLocator(DalHints hints,
boolean isMaster, boolean isSelect) throws SQLException {
Connection conn;
String allInOneKey;
DatabaseSet dbSet = config.getDatabaseSet(logicDbName);
String shardId = null;
if(dbSet.isShardingSupported()){
DalShardingStrategy strategy = dbSet.getStrategy();
// In case the sharding strategy indicate that master shall be used
isMaster |= strategy.isMaster(config, logicDbName, hints);
shardId = hints.getShardId();
if(shardId == null)
shardId = strategy.locateDbShard(config, logicDbName, hints);
if(shardId == null)
throw new DalException(ErrorCode.ShardLocated, logicDbName);
dbSet.validate(shardId);
allInOneKey = dbSet.getRandomRealDbName(hints, shardId, isMaster, isSelect);
} else {
allInOneKey = dbSet.getRandomRealDbName(hints, isMaster, isSelect);
}
try {
conn = locator.getConnection(allInOneKey);
DbMeta meta = DbMeta.createIfAbsent(allInOneKey, dbSet.getDatabaseCategory(), shardId, isMaster, conn);
return new DalConnection(conn, meta);
} catch (Throwable e) {
throw new DalException(ErrorCode.CantGetConnection, e, allInOneKey);
}
}
public <T> T doInConnection(ConnectionAction<T> action, DalHints hints)
throws SQLException {
// If HA disabled or not query, we just directly call _doInConnnection
if(!DalStatusManager.getHaStatus().isEnabled()
|| action.operation != DalEventEnum.QUERY)
return _doInConnection(action, hints);
DalHA highAvalible = new DalHA();
hints.setHA(highAvalible);
do{
try {
return _doInConnection(action, hints);
} catch (SQLException e) {
highAvalible.update(e);
}
}while(highAvalible.needTryAgain());
throw highAvalible.getException();
}
private <T> T _doInConnection(ConnectionAction<T> action, DalHints hints)
throws SQLException {
action.initLogEntry(logicDbName, hints);
action.start();
Throwable ex = null;
T result = null;
try {
result = action.execute();
} catch (Throwable e) {
MarkdownManager.detect(action.connHolder, action.start, e);
ex = e;
} finally {
DalWatcher.endExectue();
action.populateDbMeta();
action.cleanup();
}
action.end(result, ex);
return result;
}
}