package io.mycat.util.rehasher;
import io.mycat.route.function.AbstractPartitionAlgorithm;
import io.mycat.route.function.PartitionByMod;
import io.mycat.route.function.PartitionByMurmurHash;
import io.mycat.server.exception.RehashException;
import io.mycat.util.CollectionUtil;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.util.JdbcUtils;
/**
* 本工具依赖druid,Mycat已经包含druid,druid配置请查阅相关文档。相关参数请看RehashCmdArgs
* @author wujingrun
*
*/
public class RehashLauncher {
private final class RehashRunner implements Runnable {
private final File output;
private final String table;
private RehashRunner(File output, String table) {
this.output = output;
this.table = table;
}
public void run(){
int pageSize=500;
int page=0;
List<Map<String, Object>> list=null;
int total=0;
int rehashed=0;
String hostWithDatabase=args.getHostWithDatabase();
PrintStream ps=null;
try {
ps=new PrintStream(output);
list = JdbcUtils.executeQuery(dataSource, "select "
+ args.getShardingField() + " from " + table + " limit ?,?", page++ * pageSize,
pageSize);
while (!CollectionUtil.isEmpty(list)) {
for(int i=0,l=list.size();i<l;i++){
Map<String, Object> sf=list.get(i);
Integer hash=alg.calculate(sf.get(args.getShardingField()).toString());
String host=rehashHosts[hash];
total++;
if(host.equals(hostWithDatabase)){
rehashed++;
}
ps.println(sf+"=>"+host);
}
list = JdbcUtils.executeQuery(dataSource, "select "
+ args.getShardingField() + " from " + table + " limit ?,?", page++ * pageSize,
pageSize);
}
ps.println("rehashed ratio:"+(((double)rehashed)/total));
} catch (Exception e) {
throw new RehashException(e);
}finally{
if(ps!=null){
ps.close();
}
latch.countDown();
}
}
}
private RehashCmdArgs args;
private DruidDataSource dataSource;
private String[] rehashHosts;
private AbstractPartitionAlgorithm alg;
private ExecutorService executor;
private CountDownLatch latch;
private static final Logger LOGGER = LoggerFactory.getLogger(RehashLauncher.class);
private RehashLauncher(String[] args) throws IOException{
this.args=new RehashCmdArgs(args);
initDataSource();
this.rehashHosts=this.args.getRehashHosts();
initHashAlg();
executor=Executors.newCachedThreadPool();
}
private void initHashAlg() throws IOException{
if (HashType.MURMUR.equals(args.getHashType())) {
alg=new PartitionByMurmurHash();
PartitionByMurmurHash murmur=(PartitionByMurmurHash)alg;
murmur.setCount(rehashHosts.length);
murmur.setSeed(args.getMurmurHashSeed());
murmur.setVirtualBucketTimes(args.getMurmurHashVirtualBucketTimes());
murmur.init();
} else if (HashType.MOD.equals(args.getHashType())) {
alg=new PartitionByMod();
PartitionByMod mod=(PartitionByMod)alg;
mod.setCount(rehashHosts.length);
mod.init();
}
}
private void initDataSource(){
dataSource=new DruidDataSource();
dataSource.setAsyncCloseConnectionEnable(true);
dataSource.setBreakAfterAcquireFailure(true);
dataSource.setDefaultAutoCommit(true);
dataSource.setDefaultReadOnly(true);
dataSource.setDriverClassName(args.getJdbcDriver());
dataSource.setEnable(true);
dataSource.setPassword(args.getPassword());
dataSource.setTestOnBorrow(true);
dataSource.setTestOnReturn(true);
dataSource.setTestWhileIdle(true);
dataSource.setUrl(args.getJdbcUrl());
dataSource.setUsername(args.getUser());
}
private RehashLauncher execute() throws IOException{
final String[] tables=args.getTables();
final File outputDir=new File(args.getRehashNodeDir());
if(!outputDir.exists()){
outputDir.mkdirs();
}else if(outputDir.isFile()){
throw new IllegalArgumentException("rehashNodeDir must be a directory");
}else if(outputDir.canWrite()){
throw new IllegalArgumentException("rehashNodeDir must be writable");
}
latch=new CountDownLatch(tables.length);
for(int i=0,l=tables.length;i<l;i++){
final int tableIdx=i;
final String table=tables[tableIdx];
final File output=new File(outputDir,table);
if(output.exists()){
output.delete();
}
output.createNewFile();
executor.execute(new RehashRunner(output, table));
}
return this;
}
private void shutdown(){
while(true){
try {
latch.await();
break;
} catch (InterruptedException e) {
LOGGER.error("RehashLauncherError", e);
}
}
executor.shutdown();
if(executor.isTerminated()){
dataSource.close();
}
}
private static void execute(String[] args) throws IOException{
RehashLauncher launcher=null;
try{
launcher=new RehashLauncher(args).execute();
} catch (IOException e) {
LOGGER.error("RehashLauncherError", e);
throw e;
} finally{
if(launcher!=null){
launcher.shutdown();
}
}
}
public static void main(String[] args) throws IOException {
execute(args);
}
}