Mycat 分片算法 PartitionByDate 两点疑问

最近学习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解释清楚。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wyr2018

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值