public static void RouteForTableMeta(RouteResultset rrs, SchemaConfig schema, ISqlStatement ast, PartitionKeyVisitor visitor, string stmt) { var sql = stmt; if (visitor.IsSchemaTrimmed()) { sql = GenSql(ast, stmt); } var tables = visitor.GetMetaReadTable(); if (tables == null) { throw new ArgumentException(string.Format("route err: tables[] is null for meta read table: {0}", stmt)); } string[] dataNodes; if (tables.Length <= 0) { dataNodes = schema.MetaDataNodes; } else { if (tables.Length == 1) { dataNodes = new string[1]; dataNodes[0] = GetMetaReadDataNode(schema, tables[0]); } else { ICollection <string> dataNodeSet = new HashSet <string>(); foreach (var table in tables) { var dataNode = GetMetaReadDataNode(schema, table); dataNodeSet.Add(dataNode); } dataNodes = dataNodeSet.ToArray(); //dataNodes = new string[dataNodeSet.Count]; //IEnumerator<string> iter = dataNodeSet.GetEnumerator(); //for (int i = 0; i < dataNodes.Length; ++i) //{ // dataNodes[i] = iter.Current; //} } } var nodes = new RouteResultsetNode[dataNodes.Length]; rrs.Nodes = nodes; for (var i1 = 0; i1 < dataNodes.Length; ++i1) { nodes[i1] = new RouteResultsetNode(dataNodes[i1], sql); } }
//private static readonly Logger Logger = Logger.GetLogger(typeof(ServerRouter)); public static RouteResultset Route(SchemaConfig schema, string stmt, string charset, object info) { var rrs = new RouteResultset(stmt); // 检查是否含有cobar hint var prefixIndex = HintRouter.IndexOfPrefix(stmt); if (prefixIndex >= 0) { HintRouter.RouteFromHint(info, schema, rrs, prefixIndex, stmt); return(rrs); } // 检查schema是否含有拆分库 if (schema.IsNoSharding) { if (schema.IsKeepSqlSchema) { var ast = SqlParserDelegate.Parse(stmt, charset ?? MySqlParser.DefaultCharset); var visitor = new PartitionKeyVisitor(schema.Tables); visitor.SetTrimSchema(schema.Name); ast.Accept(visitor); if (visitor.IsSchemaTrimmed()) { stmt = GenSql(ast, stmt); } } var nodes = new RouteResultsetNode[1]; nodes[0] = new RouteResultsetNode(schema.DataNode, stmt); rrs.Nodes = nodes; return(rrs); } // 生成和展开AST var ast1 = SqlParserDelegate.Parse(stmt, charset ?? MySqlParser.DefaultCharset); var visitor1 = new PartitionKeyVisitor(schema.Tables); visitor1.SetTrimSchema(schema.IsKeepSqlSchema ? schema.Name : null); ast1.Accept(visitor1); // 如果sql包含用户自定义的schema,则路由到default节点 if (schema.IsKeepSqlSchema && visitor1.IsCustomedSchema()) { if (visitor1.IsSchemaTrimmed()) { stmt = GenSql(ast1, stmt); } var nodes = new RouteResultsetNode[1]; nodes[0] = new RouteResultsetNode(schema.DataNode, stmt); rrs.Nodes = nodes; return(rrs); } // 元数据语句路由 if (visitor1.IsTableMetaRead()) { MetaRouter.RouteForTableMeta(rrs, schema, ast1, visitor1, stmt); if (visitor1.IsNeedRewriteField()) { rrs.Flag = RouteResultset.RewriteField; } return(rrs); } // 匹配规则 TableConfig matchedTable = null; RuleConfig rule = null; IDictionary <string, IList <object> > columnValues = null; var astExt = visitor1.GetColumnValue(); var tables = schema.Tables; foreach (var e in astExt) { var col2Val = e.Value; var tc = tables.GetValue(e.Key); if (tc == null) { continue; } if (matchedTable == null) { matchedTable = tc; } if (col2Val == null || col2Val.IsEmpty()) { continue; } var tr = tc.Rule; if (tr != null) { foreach (var rc in tr.Rules) { var match = true; foreach (var ruleColumn in rc.Columns) { match &= col2Val.ContainsKey(ruleColumn); } if (match) { columnValues = col2Val; rule = rc; matchedTable = tc; goto ft_break; } } } } ft_break: ; // 规则匹配处理,表级别和列级别。 if (matchedTable == null) { var sql = visitor1.IsSchemaTrimmed() ? GenSql(ast1, stmt) : stmt; var rn = new RouteResultsetNode[1]; if (string.Empty.Equals(schema.DataNode) && IsSystemReadSql(ast1)) { rn[0] = new RouteResultsetNode(schema.RandomDataNode, sql); } else { rn[0] = new RouteResultsetNode(schema.DataNode, sql); } rrs.Nodes = rn; return(rrs); } if (rule == null) { if (matchedTable.IsRuleRequired) { throw new ArgumentException(string.Format("route rule for table {0} is required: {1}", matchedTable.Name, stmt)); } var dataNodes = matchedTable.DataNodes; var sql = visitor1.IsSchemaTrimmed() ? GenSql(ast1, stmt) : stmt; var rn = new RouteResultsetNode[dataNodes.Length]; for (var i = 0; i < dataNodes.Length; ++i) { rn[i] = new RouteResultsetNode(dataNodes[i], sql); } rrs.Nodes = rn; SetGroupFlagAndLimit(rrs, visitor1); return(rrs); } // 规则计算 ValidateAst(ast1, matchedTable, rule, visitor1); var dnMap = RuleCalculate(matchedTable, rule, columnValues); if (dnMap == null || dnMap.IsEmpty()) { throw new ArgumentException("No target dataNode for rule " + rule); } // 判断路由结果是单库还是多库 if (dnMap.Count == 1) { var dataNode = matchedTable.DataNodes[dnMap.Keys.FirstOrDefault()]; //string dataNode = matchedTable.GetDataNodes()[dnMap.Keys.GetEnumerator().Current]; var sql = visitor1.IsSchemaTrimmed() ? GenSql(ast1, stmt) : stmt; var rn = new RouteResultsetNode[1]; rn[0] = new RouteResultsetNode(dataNode, sql); rrs.Nodes = rn; } else { var rn = new RouteResultsetNode[dnMap.Count]; if (ast1 is DmlInsertReplaceStatement) { var ir = (DmlInsertReplaceStatement)ast1; DispatchInsertReplace(rn, ir, rule.Columns, dnMap, matchedTable, stmt, visitor1); } else { DispatchWhereBasedStmt(rn, ast1, rule.Columns, dnMap, matchedTable, stmt, visitor1); } rrs.Nodes = rn; SetGroupFlagAndLimit(rrs, visitor1); } return(rrs); }
private static void DispatchWhereBasedStmt(RouteResultsetNode[] rn, ISqlStatement stmtAST, IList <string> ruleColumns, IDictionary <int, IList <object[]> > dataNodeMap, TableConfig matchedTable, string originalSQL, PartitionKeyVisitor visitor) { // [perf tag] 11.617 us: sharding multivalue if (ruleColumns.Count > 1) { string sql; if (visitor.IsSchemaTrimmed()) { sql = GenSql(stmtAST, originalSQL); } else { sql = originalSQL; } var i = -1; foreach (var dataNodeId in dataNodeMap.Keys) { var dataNode = matchedTable.DataNodes[dataNodeId]; rn[++i] = new RouteResultsetNode(dataNode, sql); } return; } var table = matchedTable.Name; var columnIndex = visitor.GetColumnIndex(table); var valueMap = columnIndex.GetValue(ruleColumns[0]); ReplacePartitionKeyOperand(columnIndex, ruleColumns); var unreplacedInExpr = new Dictionary <InExpression, ICollection <IExpression> >(1); var unreplacedSingleExprs = new HashSet <IReplacableExpression>(); // [perf tag] 12.2755 us: sharding multivalue var nodeId = -1; foreach (var en in dataNodeMap) { var tuples = en.Value; unreplacedSingleExprs.Clear(); unreplacedInExpr.Clear(); foreach (var tuple in tuples) { var value = tuple[0]; var indexedExpressionPair = GetExpressionSet(valueMap, value); foreach (var pair in indexedExpressionPair) { var expr = pair.Key; var parent = (InExpression)pair.Value; if (PartitionKeyVisitor.IsPartitionKeyOperandSingle(expr, parent)) { unreplacedSingleExprs.Add((IReplacableExpression)expr); } else if (PartitionKeyVisitor.IsPartitionKeyOperandIn(expr, parent)) { var newInSet = unreplacedInExpr.GetValue(parent); if (newInSet == null) { newInSet = new HashSet <IExpression>(); unreplacedInExpr[parent] = newInSet; } newInSet.Add(expr); } } } // [perf tag] 15.3745 us: sharding multivalue foreach (var expr1 in unreplacedSingleExprs) { expr1.ClearReplaceExpr(); } foreach (var entemp in unreplacedInExpr) { var @in = entemp.Key; var set = entemp.Value; if (set == null || set.IsEmpty()) { @in.ReplaceExpr = ReplacableExpressionConstants.BoolFalse; } else { @in.ClearReplaceExpr(); var inlist = @in.GetInExpressionList(); if (inlist != null) { inlist.ReplaceExpr = new List <IExpression>(set); } } } // [perf tag] 16.506 us: sharding multivalue var sql = GenSql(stmtAST, originalSQL); // [perf tag] 21.3425 us: sharding multivalue var dataNodeName = matchedTable.DataNodes[en.Key]; rn[++nodeId] = new RouteResultsetNode(dataNodeName, sql); foreach (var expr2 in unreplacedSingleExprs) { expr2.ReplaceExpr = ReplacableExpressionConstants.BoolFalse; } foreach (var in1 in unreplacedInExpr.Keys) { in1.ReplaceExpr = ReplacableExpressionConstants.BoolFalse; var list = in1.GetInExpressionList(); if (list != null) { list.ClearReplaceExpr(); } } } }