package com.ctrip.platform.dal.dao.configure;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.ctrip.platform.dal.common.enums.DatabaseCategory;
import com.ctrip.platform.dal.dao.DalHints;
import com.ctrip.platform.dal.dao.strategy.DalShardingStrategy;
import com.ctrip.platform.dal.exceptions.DalException;
public class DatabaseSet {
private static final String CLASS = "class";
private static final String ENTRY_SEPARATOR = ";";
private static final String KEY_VALUE_SEPARATOR = "=";
private String name;
private String provider;
private DatabaseCategory dbCategory;
private DalShardingStrategy strategy;
private Map<String, DataBase> databases;
// Key is shard id, value is all database under in this shard
private Map<String, List<DataBase>> masterDbByShard = new HashMap<String, List<DataBase>>();
private Map<String, List<DataBase>> slaveDbByShard = new HashMap<String, List<DataBase>>();
private List<DataBase> masterDbs = new ArrayList<DataBase>();
private List<DataBase> slaveDbs = new ArrayList<DataBase>();
/**
* The target DB set does not support shard
* @param name
* @param provider
* @param databases
* @throws Exception
*/
public DatabaseSet(String name, String provider, Map<String, DataBase> databases) throws Exception {
this(name, provider, null, databases);
}
public DatabaseSet(String name, String provider, String shardStrategy, Map<String, DataBase> databases) throws Exception {
this.name = name;
this.provider = provider;
dbCategory = DatabaseCategory.matchWith(provider);
this.databases = databases;
initStrategy(shardStrategy);
initShards();
}
private void initStrategy(String shardStrategy) throws Exception {
if(shardStrategy == null || shardStrategy.length() == 0)
return;
String[] values = shardStrategy.split(ENTRY_SEPARATOR);
String[] strategyDef = values[0].split(KEY_VALUE_SEPARATOR);
if(strategyDef[0].equals(CLASS))
strategy = (DalShardingStrategy)Class.forName(strategyDef[1]).newInstance();
Map<String, String> settings = new HashMap<String, String>();
for(int i = 1; i < values.length; i++) {
String[] entry = values[i].split(KEY_VALUE_SEPARATOR);
settings.put(entry[0], entry[1]);
}
strategy.initialize(settings);
}
private void initShards() throws Exception {
if(strategy == null || strategy.isShardingByDb() == false){
// Init with no shard support
for(DataBase db: databases.values()) {
if(db.isMaster())
masterDbs.add(db);
else
slaveDbs.add(db);
}
}else{
// Init map by shard
for(DataBase db: databases.values()) {
Map<String, List<DataBase>> dbByShard = db.isMaster() ?
masterDbByShard : slaveDbByShard;
List<DataBase> dbList = dbByShard.get(db.getSharding());
if(dbList == null) {
dbList = new ArrayList<DataBase>();
dbByShard.put(db.getSharding(), dbList);
}
dbList.add(db);
}
}
}
public String getName() {
return name;
}
public String getProvider() {
return provider;
}
public DatabaseCategory getDatabaseCategory() {
return dbCategory;
}
public boolean isShardingSupported() {
return strategy != null && strategy.isShardingByDb();
}
public boolean isTableShardingSupported(String tableName) {
return strategy != null && strategy.isShardingByTable() && strategy.isShardingEnable(tableName);
}
public Map<String, DataBase> getDatabases() {
return databases;
}
public void validate(String shard) throws SQLException {
if(!masterDbByShard.containsKey(shard))
throw new SQLException("No shard defined for id: " + shard);
}
public Set<String> getAllShards() {
return masterDbByShard.keySet();
}
public DalShardingStrategy getStrategy() throws SQLException {
if(strategy == null)
throw new SQLException("No sharding stradegy defined");
return strategy;
}
public List<DataBase> getMasterDbs(String shard) {
return masterDbByShard.get(shard);
}
public List<DataBase> getSlaveDbs(String shard) {
return slaveDbByShard.get(shard);
}
public String getRandomRealDbName(DalHints hints, String shard, boolean isMaster, boolean isSelect) throws DalException {
return getRandomRealDbName(hints, isMaster, isSelect, getMasterDbs(shard), getSlaveDbs(shard));
}
public String getRandomRealDbName(DalHints hints, boolean isMaster, boolean isSelect) throws DalException {
return getRandomRealDbName(hints, isMaster, isSelect, masterDbs, slaveDbs);
}
private String getRandomRealDbName(DalHints hints, boolean isMaster, boolean isSelect, List<DataBase> masterCandidates, List<DataBase> slaveCandidates) throws DalException {
return new DatabaseSelector(hints, masterCandidates, slaveCandidates, isMaster, isSelect).select();
}
}