package com.taobao.tddl.optimizer.rule;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.taobao.tddl.common.TddlConstants;
import com.taobao.tddl.common.exception.TddlException;
import com.taobao.tddl.common.exception.TddlRuntimeException;
import com.taobao.tddl.common.model.Group;
import com.taobao.tddl.common.model.Matrix;
import com.taobao.tddl.common.model.lifecycle.AbstractLifecycle;
import com.taobao.tddl.optimizer.config.table.RepoSchemaManager;
import com.taobao.tddl.optimizer.config.table.SchemaManager;
import com.taobao.tddl.optimizer.config.table.StaticSchemaManager;
import com.taobao.tddl.optimizer.config.table.TableMeta;
import com.taobao.tddl.optimizer.exceptions.OptimizerException;
import com.taobao.tddl.rule.model.TargetDB;
/**
* 基于Rule获取到物理的group进行查找
*
* @since 5.0.0
*/
public class RuleSchemaManager extends AbstractLifecycle implements SchemaManager {
private OptimizerRule rule;
private final Matrix matrix;
private StaticSchemaManager local;
private boolean useCache = true;
private LoadingCache<Group, RepoSchemaManager> repos = null;
private LoadingCache<String, TableMeta> cache = null;
/**
* default cache expire time, 30000ms
*/
private long cacheExpireTime = TddlConstants.DEFAULT_TABLE_META_EXPIRE_TIME;
public RuleSchemaManager(OptimizerRule rule, Matrix matrix){
this(rule, matrix, null);
}
public RuleSchemaManager(OptimizerRule rule, Matrix matrix, Long cacheExpireTime){
this.rule = rule;
this.matrix = matrix;
if (cacheExpireTime != null && cacheExpireTime != 0) {
this.cacheExpireTime = cacheExpireTime;
}
}
@Override
protected void doInit() throws TddlException {
super.doInit();
if (local != null) {
local.init();
}
repos = CacheBuilder.newBuilder().build(new CacheLoader<Group, RepoSchemaManager>() {
@Override
public RepoSchemaManager load(Group group) throws Exception {
RepoSchemaManager repo = new RepoSchemaManager();
repo.setGroup(group);
repo.setLocal(local);
repo.setRule(rule);
repo.init();
return repo;
}
});
cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(cacheExpireTime, TimeUnit.MILLISECONDS)
.build(new CacheLoader<String, TableMeta>() {
@Override
public TableMeta load(String tableName) throws Exception {
return getTable0(tableName);
}
});
}
@Override
protected void doDestory() throws TddlException {
super.doDestory();
for (RepoSchemaManager repo : repos.asMap().values()) {
repo.destory();
}
if (cache != null) {
cache.cleanUp();
}
}
public TableMeta getTable0(String tableName) {
TargetDB targetDB = rule.shardAny(tableName);
TableMeta ts = null;
if (targetDB.getDbIndex() == null) {
// 没有对应的规则,也没有default group,则可能是一个不存在的表
// 尝试找一下local
ts = local.getTable(tableName);
} else {
Group group = matrix.getGroup(targetDB.getDbIndex()); // 先找到group
try {
ts = repos.get(group).getTable(tableName, targetDB.getTableNames().iterator().next());
} catch (ExecutionException e) {
throw new OptimizerException(e);
}
}
if (ts == null) {
throw new TddlRuntimeException(tableName + " is not found");
}
return ts;
}
@Override
public TableMeta getTable(String tableName) {
TableMeta meta = null;
if (local != null) {// 本地如果开启了,先找本地
meta = local.getTable(tableName);
}
if (meta != null) {
return meta;
}
if (useCache) {
try {
meta = cache.get(tableName);
} catch (Exception e) {
throw new TddlRuntimeException(e);
}
} else {
meta = this.getTable0(tableName);
}
if (meta == null) {
throw new IllegalArgumentException("table : " + tableName + " is not found");
}
return meta;
}
@Override
public void putTable(String tableName, TableMeta tableMeta) {
if (local != null) {
local.putTable(tableName, tableMeta);
} else if (useCache) {
cache.put(tableName, tableMeta);
}
}
@Override
public Collection<TableMeta> getAllTables() {
List<TableMeta> metas = new ArrayList();
if (local != null) {
metas.addAll(local.getAllTables());
}
if (cache != null) {
metas.addAll(cache.asMap().values());
}
return metas;
}
public void setRule(OptimizerRule rule) {
this.rule = rule;
}
public void setLocal(StaticSchemaManager local) {
this.local = local;
}
public void setUseCache(boolean useCache) {
this.useCache = useCache;
}
}