该算法根据时间分片,热数据存储在索引为 0 的dataNode中,其余数据根据sPartionDay进行分片存储,用户可配置属性 dataFormat、 sLastDay、 sPartionDay。
- dataFormat: 时间解析格式;
- sLastDay:热数据范围,如该值配置为10,则表示从现在往前推10天的数据为热点数据。将存储在第一个dataNode中,需要 注意的是如果插入数据晚于当前时间,如当前2019-03-12,columnValue为 2019-04-15,该数据也是写入第一个dataNode。
- sPartionDay:当不是热数据时的分片间隔天数。
如下配置:
<function name="partition-by-hot-date" class="io.mycat.route.function.PartitionByHotDate">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sLastDay">10</property>
<property name="sPartionDay">10</property>
</function>
当sPartionDay值为10,sLastDay值为10,当前时间是2019-03-12,则分片结果如下 :
- 2019-03-03 (包括)以后的数据,存储在第一个dataNode;
- 2019-02-21(包括)~ 2019-03-02,存储在第二个dataNode;
- 2019-02-11(包括)~2019-02-20,存储在第三个dataNode;
依次类推,如果时间太过久远,计算出来的dataNode索引超出了用户配置的dataNode个数,则抛出异常
“SQLNonTransientException: Can't find a valid data node for specified node index”
PartitionByHotDate的init 和 calculate 方法如下:
@Override
public void init() {
try {
formatter = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(dateFormat);
}
};
sLastTime = Integer.valueOf(sLastDay);
partionTime = Integer.parseInt(sPartionDay) * oneDay;
} catch (Exception e) {
throw new java.lang.IllegalArgumentException(e);
}
}
/**
* 涉及变量说明:
* sLastTime:设置多少天以内的数据是热数据,如该属性配置为10,则表示10天内的数据为热数据,存储在dataNode = 0 的节点中,超过 10 天的进行分片存储
* sPartionDay: 设置多少天数据存储在一个分片中。
* oneDay: 一天的毫秒数 1000 * 60 * 60 * 24
* partionTime: init 方法中初始化 Integer.parseInt(sPartionDay) * oneDay,表示多少天的数据是一个分片。
*/
@Override
public Integer calculate(String columnValue) {
Integer targetPartition = -1;
try {
long targetTime = formatter.get().parse(columnValue).getTime();
Calendar now = Calendar.getInstance();
long nowTime = now.getTimeInMillis();
beginDate = nowTime - sLastTime * oneDay;
long diffDays = (nowTime - targetTime) / (1000 * 60 * 60 * 24) + 1;
if(diffDays-sLastTime <= 0 || diffDays<0 ){
targetPartition = 0;
}else{
targetPartition = (int) ((beginDate - targetTime) / partionTime) + 1;
}
LOGGER.debug("PartitionByHotDate calculate for " + columnValue + " return " + targetPartition);
return targetPartition;
} catch (ParseException e) {
throw new IllegalArgumentException(new StringBuilder().append("columnValue:").append(columnValue).append(" Please check if the format satisfied.").toString(),e);
}
}