最近学习mycat,关于PartitionByDate有两点疑问,在此记录一下,理解有误的地方还望各位大神指正!
io.mycat.route.function.PartitionByDate,根据时间字端,按天分片
<function name="partition-by-date" class="io.mycat.route.function.PartitionByDate">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2019-03-01</property>
<property name="sEndDate">2019-03-30</property>
<property name="sPartionDay">10</property>
</function>
关于sEndDate参数配置,有两点疑问:
1、columnValue 时间大于 sEndDate时,数据能否存储?能存储的话节点怎么计算;
2、由 1 想到当 columnValue 时间小于 sBeginDate时,时间会怎么处理。
通过阅读源码,mycat每个分片算法都实现了RuleAlgorithm 接口,该接口定义如下:
public interface RuleAlgorithm {
void init();
Integer calculate(String columnValue) ;
Integer[] calculateRange(String beginValue,String endValue) ;
}
此处重点说一下init方法,和calculate方法(calculateRange由于还不清楚什么时候调用,暂时先忽略,后续补上)
init方法是对算法的成员变量进行计算,当mycat启动时再解析rule.xml时调用,该部分代码在 XMLRuleLoader 类 loadFunctions方法中,如下:
private void loadFunctions(Element root) throws ClassNotFoundException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
NodeList list = root.getElementsByTagName("function");
for (int i = 0, n = list.getLength(); i < n; ++i) {
Node node = list.item(i);
if (node instanceof Element) {
Element e = (Element) node;
//获取name标签
String name = e.getAttribute("name");
//如果Map已有,则function重复
if (functions.containsKey(name)) {
throw new ConfigException("rule function " + name
+ " duplicated!");
}
//获取class标签
String clazz = e.getAttribute("class");
//根据class利用反射新建分片算法
AbstractPartitionAlgorithm function = createFunction(name, clazz);
//根据读取参数配置分片算法
ParameterMapping.mapping(function, ConfigUtil.loadElements(e));
//每个AbstractPartitionAlgorithm可能会实现init来初始化
function.init();
//放入functions map
functions.put(name, function);
}
}
}
- calculate 方法在插入数据调用,位于RouterUtil类的 findRouteWithcConditionsForTables(处理分库表路由)方法,用于计算该条数据应该放在哪个节点,PartitionByDate 的calculate方法实现如下:
public Integer calculate(String columnValue) {
try {
//得出columnValue 时间的长整型值
long targetTime = formatter.get().parse(columnValue).getTime();
/*
* 计算存储节点的索引,partionTime 为 sPartionDay * oneDay,及分隔时间的毫秒数,如
* sPartionDay 为 10,表示将10天的数据放到一个节点中,
* 如 beginDate 为 2019-03-01,则 0301–0310的数据存在第一个节点,0311-0320存在
* 第二个节点,依次类推。
* nCount 为 dataNode 的个数,此处为3
*/
int targetPartition = (int) ((targetTime - beginDate) / partionTime);
if(targetTime>endDate && nCount!=0){
targetPartition = targetPartition%nCount;
}
return targetPartition;
} catch (ParseException e) {
throw new IllegalArgumentException(new
StringBuilder().append("columnValue:").append(columnValue).append(" Please
check if the format satisfied.").toString(),e);
}
}
通过上述代码可以看出,当时间大于endDate,targetPartition大于 dataNode时,会做取模运算,如0331算出的targetPartition 为3,与nCount 取模后得出结果为0,则数据插入到第一个节点中。
到此,第一个问题解释清楚。那么如果columnValue的值早于beginDate时,mycat会如何处理呢。
根据上述代码,可以看出如果时间小于beginDate,在计算 targetPartition时,会返回负数(有例外,如果是稍微早于beginDate,那么此处返回0,可以正常插入,感觉此处好像是个bug)。那么,对于dataNode的索引为负数mycat是如何处理的,参看如下代码:
public static void findRouteWithcConditionsForTables(SchemaConfig schema, RouteResultset rrs,
Map<String, Map<String, Set<ColumnRoutePair>>> tablesAndConditions,
Map<String, Set<String>> tablesRouteMap, String sql, LayerCachePool cachePool, boolean isSelect)
throws SQLNonTransientException {
… …
AbstractPartitionAlgorithm algorithm = tableConfig.getRule().getRuleAlgorithm();
if(pair.colValue != null) {
Integer nodeIndex = algorithm.calculate(pair.colValue);
if(nodeIndex == null) {
String msg = "can't find any valid datanode :" + tableConfig.getName()
+ " -> " + tableConfig.getPartitionColumn() + " -> " + pair.colValue;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
ArrayList<String> dataNodes = tableConfig.getDataNodes();
String node;
if (nodeIndex >=0 && nodeIndex < dataNodes.size()) {
node = dataNodes.get(nodeIndex);
} else {
node = null;
String msg = "Can't find a valid data node for specified node index :"
+ tableConfig.getName() + " -> " + tableConfig.getPartitionColumn()
+ " -> " + pair.colValue + " -> " + "Index : " + nodeIndex;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
… …
}
}
可以看出,当索引为负值时,会抛出异常,提示“Can't find a valid data node for specified node index :...”。
问题2解释清楚。。。