Ejemplo n.º 1
0
 /**
  * 获取第一个节点作为路由
  *
  * @param rrs 数据路由集合
  * @param dataNode 数据库所在节点
  * @param stmt 执行语句
  * @return 数据路由集合
  * @author mycat
  */
 public static RouteResultset routeToSingleNode(RouteResultset rrs, String dataNode, String stmt) {
   if (dataNode == null) {
     return rrs;
   }
   RouteResultsetNode[] nodes = new RouteResultsetNode[1];
   nodes[0] = new RouteResultsetNode(dataNode, rrs.getSqlType(), stmt); // rrs.getStatement()
   rrs.setNodes(nodes);
   rrs.setFinishedRoute(true);
   if (rrs.getCanRunInReadDB() != null) {
     nodes[0].setCanRunInReadDB(rrs.getCanRunInReadDB());
   }
   return rrs;
 }
Ejemplo n.º 2
0
  public static boolean processERChildTable(
      final SchemaConfig schema, final String origSQL, final ServerConnection sc)
      throws SQLNonTransientException {
    String tableName = StringUtil.getTableName(origSQL).toUpperCase();
    final TableConfig tc = schema.getTables().get(tableName);

    if (null != tc && tc.isChildTable()) {
      final RouteResultset rrs = new RouteResultset(origSQL, ServerParse.INSERT);
      String joinKey = tc.getJoinKey();
      MySqlInsertStatement insertStmt =
          (MySqlInsertStatement) (new MySqlStatementParser(origSQL)).parseInsert();
      int joinKeyIndex = getJoinKeyIndex(insertStmt.getColumns(), joinKey);

      if (joinKeyIndex == -1) {
        String inf = "joinKey not provided :" + tc.getJoinKey() + "," + insertStmt;
        LOGGER.warn(inf);
        throw new SQLNonTransientException(inf);
      }
      if (isMultiInsert(insertStmt)) {
        String msg = "ChildTable multi insert not provided";
        LOGGER.warn(msg);
        throw new SQLNonTransientException(msg);
      }

      String joinKeyVal = insertStmt.getValues().getValues().get(joinKeyIndex).toString();

      String sql = insertStmt.toString();

      // try to route by ER parent partion key
      RouteResultset theRrs = RouterUtil.routeByERParentKey(sql, rrs, tc, joinKeyVal);

      if (theRrs != null) {
        rrs.setFinishedRoute(true);
        sc.getSession2().execute(rrs, ServerParse.INSERT);
        return true;
      }

      // route by sql query root parent's datanode
      final String findRootTBSql = tc.getLocateRTableKeySql().toLowerCase() + joinKeyVal;
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("find root parent's node sql " + findRootTBSql);
      }

      ListenableFuture<String> listenableFuture =
          MycatServer.getInstance()
              .getListeningExecutorService()
              .submit(
                  new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                      FetchStoreNodeOfChildTableHandler fetchHandler =
                          new FetchStoreNodeOfChildTableHandler();
                      return fetchHandler.execute(
                          schema.getName(), findRootTBSql, tc.getRootParent().getDataNodes());
                    }
                  });

      Futures.addCallback(
          listenableFuture,
          new FutureCallback<String>() {
            @Override
            public void onSuccess(String result) {
              if (Strings.isNullOrEmpty(result)) {
                StringBuilder s = new StringBuilder();
                LOGGER.warn(
                    s.append(sc.getSession2()).append(origSQL).toString()
                        + " err:"
                        + "can't find (root) parent sharding node for sql:"
                        + origSQL);
                sc.writeErrMessage(
                    ErrorCode.ER_PARSE_ERROR,
                    "can't find (root) parent sharding node for sql:" + origSQL);
                return;
              }

              if (LOGGER.isDebugEnabled()) {
                LOGGER.debug(
                    "found partion node for child table to insert " + result + " sql :" + origSQL);
              }

              RouteResultset executeRrs = RouterUtil.routeToSingleNode(rrs, result, origSQL);
              sc.getSession2().execute(executeRrs, ServerParse.INSERT);
            }

            @Override
            public void onFailure(Throwable t) {
              StringBuilder s = new StringBuilder();
              LOGGER.warn(
                  s.append(sc.getSession2()).append(origSQL).toString() + " err:" + t.getMessage());
              sc.writeErrMessage(ErrorCode.ER_PARSE_ERROR, t.getMessage() + " " + s.toString());
            }
          },
          MycatServer.getInstance().getListeningExecutorService());
      return true;
    }
    return false;
  }
Ejemplo n.º 3
0
  /**
   * 处理分库表路由
   *
   * @param schema
   * @param tablesAndConditions
   * @param tablesRouteMap
   * @throws SQLNonTransientException
   */
  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 {
    // 为分库表找路由
    for (Map.Entry<String, Map<String, Set<ColumnRoutePair>>> entry :
        tablesAndConditions.entrySet()) {
      String tableName = entry.getKey().toUpperCase();
      TableConfig tableConfig = schema.getTables().get(tableName);
      if (tableConfig == null) {
        String msg =
            "can't find table define in schema " + tableName + " schema:" + schema.getName();
        LOGGER.warn(msg);
        throw new SQLNonTransientException(msg);
      }
      // 全局表或者不分库的表略过(全局表后面再计算)
      if (tableConfig.isGlobalTable()
          || schema.getTables().get(tableName).getDataNodes().size() == 1) {
        continue;
      } else { // 非全局表:分库表、childTable、其他
        Map<String, Set<ColumnRoutePair>> columnsMap = entry.getValue();
        String joinKey = tableConfig.getJoinKey();
        String partionCol = tableConfig.getPartitionColumn();
        String primaryKey = tableConfig.getPrimaryKey();
        boolean isFoundPartitionValue =
            partionCol != null && entry.getValue().get(partionCol) != null;
        boolean isLoadData = false;
        if (LOGGER.isDebugEnabled()) {
          if (sql.startsWith(LoadData.loadDataHint)
              || rrs.isLoadData()) { // 由于load data一次会计算很多路由数据,如果输出此日志会极大降低load data的性能
            isLoadData = true;
          }
        }
        if (entry.getValue().get(primaryKey) != null
            && entry.getValue().size() == 1
            && !isLoadData) { // 主键查找
          // try by primary key if found in cache
          Set<ColumnRoutePair> primaryKeyPairs = entry.getValue().get(primaryKey);
          if (primaryKeyPairs != null) {
            if (LOGGER.isDebugEnabled()) {
              LOGGER.debug("try to find cache by primary key ");
            }
            String tableKey = schema.getName() + '_' + tableName;
            boolean allFound = true;
            for (ColumnRoutePair pair : primaryKeyPairs) { // 可能id in(1,2,3)多主键
              String cacheKey = pair.colValue;
              String dataNode = (String) cachePool.get(tableKey, cacheKey);
              if (dataNode == null) {
                allFound = false;
                continue;
              } else {
                if (tablesRouteMap.get(tableName) == null) {
                  tablesRouteMap.put(tableName, new HashSet<String>());
                }
                tablesRouteMap.get(tableName).add(dataNode);
                continue;
              }
            }
            if (!allFound) {
              // need cache primary key ->datanode relation
              if (isSelect && tableConfig.getPrimaryKey() != null) {
                rrs.setPrimaryKey(tableKey + '.' + tableConfig.getPrimaryKey());
              }
            } else { // 主键缓存中找到了就执行循环的下一轮
              continue;
            }
          }
        }
        if (isFoundPartitionValue) { // 分库表
          Set<ColumnRoutePair> partitionValue = columnsMap.get(partionCol);
          if (partitionValue == null || partitionValue.size() == 0) {
            if (tablesRouteMap.get(tableName) == null) {
              tablesRouteMap.put(tableName, new HashSet<String>());
            }
            tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes());
          } else {
            for (ColumnRoutePair pair : partitionValue) {
              if (pair.colValue != null) {
                Integer nodeIndex =
                    tableConfig.getRule().getRuleAlgorithm().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);
                }
                String node = tableConfig.getDataNodes().get(nodeIndex);
                if (node != null) {
                  if (tablesRouteMap.get(tableName) == null) {
                    tablesRouteMap.put(tableName, new HashSet<String>());
                  }
                  tablesRouteMap.get(tableName).add(node);
                }
              }
              if (pair.rangeValue != null) {
                Integer[] nodeIndexs =
                    tableConfig
                        .getRule()
                        .getRuleAlgorithm()
                        .calculateRange(
                            pair.rangeValue.beginValue.toString(),
                            pair.rangeValue.endValue.toString());
                for (Integer idx : nodeIndexs) {
                  String node = tableConfig.getDataNodes().get(idx);
                  if (node != null) {
                    if (tablesRouteMap.get(tableName) == null) {
                      tablesRouteMap.put(tableName, new HashSet<String>());
                    }
                    tablesRouteMap.get(tableName).add(node);
                  }
                }
              }
            }
          }
        } else if (joinKey != null
            && columnsMap.get(joinKey) != null
            && columnsMap.get(joinKey).size()
                != 0) { // childTable  (如果是select 语句的父子表join)之前要找到root table,将childTable移除,只留下root
                        // table
          Set<ColumnRoutePair> joinKeyValue = columnsMap.get(joinKey);

          ColumnRoutePair joinCol = null;

          Set<String> dataNodeSet = ruleByJoinValueCalculate(rrs, tableConfig, joinKeyValue);

          if (dataNodeSet.isEmpty()) {
            throw new SQLNonTransientException("parent key can't find any valid datanode ");
          }
          if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(
                "found partion nodes (using parent partion rule directly) for child table to update  "
                    + Arrays.toString(dataNodeSet.toArray())
                    + " sql :"
                    + sql);
          }
          if (dataNodeSet.size() > 1) {
            routeToMultiNode(rrs.isCacheAble(), rrs, dataNodeSet, sql);
            rrs.setFinishedRoute(true);
            return;
          } else {
            rrs.setCacheAble(true);
            routeToSingleNode(rrs, dataNodeSet.iterator().next(), sql);
            return;
          }

        } else {
          // 没找到拆分字段,该表的所有节点都路由
          if (tablesRouteMap.get(tableName) == null) {
            tablesRouteMap.put(tableName, new HashSet<String>());
          }
          tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes());
        }
      }
    }
  }