package io.mycat.route.function; import com.google.common.hash.Hashing; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.ParseException; import java.text.SimpleDateFormat; /** * 先根据日期分组,再根据时间hash使得短期内数据分布的更均匀 * 优点可以避免扩容时的数据迁移,又可以一定程度上避免范围分片的热点问题 * 要求日期格式尽量精确些,不然达不到局部均匀的目的 * * */ public class PartitionByRangeDateHash extends AbstractPartitionAlgorithm implements RuleAlgorithm { private static final Logger LOGGER = LoggerFactory .getLogger(PartitionByRangeDateHash.class); private String sBeginDate; private String sPartionDay; private String dateFormat; private long beginDate; private long partionTime; private static final long oneDay = 86400000; private String groupPartionSize; private int intGroupPartionSize; @Override public void init() { try { beginDate = new SimpleDateFormat(dateFormat).parse(sBeginDate) .getTime(); intGroupPartionSize = Integer.parseInt(groupPartionSize); if (intGroupPartionSize <= 0) { throw new RuntimeException("groupPartionSize must >0,but cur is " + intGroupPartionSize); } } catch (ParseException e) { throw new IllegalArgumentException(e); } partionTime = Integer.parseInt(sPartionDay) * oneDay; } @Override public Integer calculate(String columnValue) { try { long targetTime = new SimpleDateFormat(dateFormat).parse( columnValue).getTime(); int targetPartition = (int) ((targetTime - beginDate) / partionTime); int innerIndex = Hashing.consistentHash(targetTime,intGroupPartionSize); return targetPartition * intGroupPartionSize + innerIndex; } catch (ParseException e) { throw new IllegalArgumentException(e); } } public Integer calculateStart(String columnValue) { try { long targetTime = new SimpleDateFormat(dateFormat).parse( columnValue).getTime(); int targetPartition = (int) ((targetTime - beginDate) / partionTime); return targetPartition * intGroupPartionSize; } catch (ParseException e) { throw new IllegalArgumentException(e); } } public Integer calculateEnd(String columnValue) { try { long targetTime = new SimpleDateFormat(dateFormat).parse( columnValue).getTime(); int targetPartition = (int) ((targetTime - beginDate) / partionTime); return (targetPartition+1) * intGroupPartionSize - 1; } catch (ParseException e) { throw new IllegalArgumentException(e); } } @Override public Integer[] calculateRange(String beginValue, String endValue) { Integer begin = 0, end = 0; begin = calculateStart(beginValue); end = calculateEnd(endValue); if (begin == null || end == null) { return new Integer[0]; } if (end >= begin) { int len = end - begin + 1; Integer[] re = new Integer[len]; for (int i = 0; i < len; i++) { re[i] = begin + i; } return re; } else { return null; } } public long getBeginDate() { return beginDate; } public void setsBeginDate(String sBeginDate) { this.sBeginDate = sBeginDate; } public void setsPartionDay(String sPartionDay) { this.sPartionDay = sPartionDay; } public void setDateFormat(String dateFormat) { this.dateFormat = dateFormat; } public String getGroupPartionSize() { return groupPartionSize; } public void setGroupPartionSize(String groupPartionSize) { this.groupPartionSize = groupPartionSize; } }