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); } }
public virtual void TestMapKeyValue() { var map = new Dictionary<RouteResultsetNode, string>(); var rrn = new RouteResultsetNode("test", "select * from t1 limit 1"); var rrn2 = new RouteResultsetNode("test", 1, "select * from t2 limit 1"); map[rrn] = rrn.Statement; map[rrn2] = rrn2.Statement; Assert.AreEqual(2, map.Count); for (var i = 0; i < 100; i++) { Assert.AreEqual("select * from t1 limit 1", map[rrn]); Assert.AreEqual("select * from t2 limit 1", map[rrn2]); } }
public virtual void TestMapKeyValue() { var map = new Dictionary <RouteResultsetNode, string>(); var rrn = new RouteResultsetNode("test", "select * from t1 limit 1"); var rrn2 = new RouteResultsetNode("test", 1, "select * from t2 limit 1"); map[rrn] = rrn.Statement; map[rrn2] = rrn2.Statement; Assert.AreEqual(2, map.Count); for (var i = 0; i < 100; i++) { Assert.AreEqual("select * from t1 limit 1", map[rrn]); Assert.AreEqual("select * from t2 limit 1", map[rrn2]); } }
/// <exception cref="System.SqlSyntaxErrorException" /> public static void RouteFromHint(object frontConn, SchemaConfig schema, RouteResultset rrs, int prefixIndex, string sql) { var hint = CobarHint.ParserCobarHint(sql, prefixIndex); var outputSql = hint.OutputSql; var replica = hint.Replica; var table = hint.Table; var dataNodes = hint.DataNodes; var partitionOperand = hint.PartitionOperand; TableConfig tableConfig = null; if (table == null || schema.Tables == null || (tableConfig = schema.Tables.GetValue(table)) == null) { // table not indicated var nodes = new RouteResultsetNode[1]; rrs.Nodes = nodes; if (dataNodes != null && !dataNodes.IsEmpty()) { var replicaIndex = dataNodes[0].Value; if (replicaIndex >= 0 && RouteResultsetNode.DefaultReplicaIndex != replicaIndex) { // replica index indicated in dataNodes references nodes[0] = new RouteResultsetNode(schema.DataNode, replicaIndex, outputSql); LogExplicitReplicaSet(frontConn, sql, rrs); return; } } nodes[0] = new RouteResultsetNode(schema.DataNode, replica, outputSql); if (replica != RouteResultsetNode.DefaultReplicaIndex) { LogExplicitReplicaSet(frontConn, sql, rrs); } return; } if (dataNodes != null && !dataNodes.IsEmpty()) { var nodes = new RouteResultsetNode[dataNodes.Count]; rrs.Nodes = nodes; var i = 0; var replicaSet = false; foreach (var pair in dataNodes) { var dataNodeName = tableConfig.DataNodes[pair.Key]; var replicaIndex = dataNodes[i].Value; if (replicaIndex >= 0 && RouteResultsetNode.DefaultReplicaIndex != replicaIndex) { replicaSet = true; nodes[i] = new RouteResultsetNode(dataNodeName, replicaIndex, outputSql); } else { replicaSet = replicaSet || (replica != RouteResultsetNode.DefaultReplicaIndex); nodes[i] = new RouteResultsetNode(dataNodeName, replica, outputSql); } ++i; } if (replicaSet) { LogExplicitReplicaSet(frontConn, sql, rrs); } return; } if (partitionOperand == null) { var tableDataNodes = tableConfig.DataNodes; var nodes = new RouteResultsetNode[tableDataNodes.Length]; rrs.Nodes = nodes; for (var i = 0; i < nodes.Length; ++i) { nodes[i] = new RouteResultsetNode(tableDataNodes[i], replica, outputSql); } return; } var cols = partitionOperand.Key; var vals = partitionOperand.Value; if (cols == null || vals == null) { throw new SqlSyntaxErrorException("${partitionOperand} is invalid: " + sql); } RuleConfig rule = null; var tr = tableConfig.Rule; var rules = tr == null ? null : tr.Rules; if (rules != null) { foreach (var r in rules) { var ruleCols = r.Columns; var match = true; foreach (var ruleCol in ruleCols) { match &= cols.Contains(ruleCol); } if (match) { rule = r; break; } } } var tableDataNodes1 = tableConfig.DataNodes; if (rule == null) { var nodes = new RouteResultsetNode[tableDataNodes1.Length]; rrs.Nodes = nodes; var replicaSet = false; for (var i = 0; i < tableDataNodes1.Length; ++i) { replicaSet = replicaSet || (replica != RouteResultsetNode.DefaultReplicaIndex); nodes[i] = new RouteResultsetNode(tableDataNodes1[i], replica, outputSql); } if (replicaSet) { LogExplicitReplicaSet(frontConn, sql, rrs); } return; } var destDataNodes = CalcHintDataNodes(rule, cols, vals, tableDataNodes1); var nodes1 = new RouteResultsetNode[destDataNodes.Count]; rrs.Nodes = nodes1; var i1 = 0; var replicaSet1 = false; foreach (var dataNode in destDataNodes) { replicaSet1 = replicaSet1 || (replica != RouteResultsetNode.DefaultReplicaIndex); nodes1[i1++] = new RouteResultsetNode(dataNode, replica, outputSql); } if (replicaSet1) { LogExplicitReplicaSet(frontConn, sql, rrs); } }
private static void DispatchInsertReplace(RouteResultsetNode[] rn, DmlInsertReplaceStatement stmt, IList <string> ruleColumns, IDictionary <int, IList <object[]> > dataNodeMap, TableConfig matchedTable, string originalSql, PartitionKeyVisitor visitor) { if (stmt.Select != null) { DispatchWhereBasedStmt(rn, stmt, ruleColumns, dataNodeMap, matchedTable, originalSql, visitor); return; } var colsIndex = visitor.GetColumnIndex(stmt.Table.IdTextUpUnescape); if (colsIndex == null || colsIndex.IsEmpty()) { throw new ArgumentException("columns index is empty: " + originalSql); } var colsIndexList = new List <ColumnValueType>(ruleColumns.Count); for (int i = 0, len = ruleColumns.Count; i < len; ++i) { colsIndexList.Add(colsIndex[ruleColumns[i]]); } var dataNodeId = -1; foreach (var en in dataNodeMap) { var tuples = en.Value; var replaceRowList = new HashSet <RowExpression>(); foreach (var tuple in tuples) { ICollection <Pair <IExpression, IAstNode> > tupleExprs = null; for (var i1 = 0; i1 < tuple.Length; ++i1) { var valueMap = colsIndexList[i1]; var value = tuple[i1]; var set = GetExpressionSet(valueMap, value); tupleExprs = CollectionUtil.IntersectSet(tupleExprs, set); } if (tupleExprs == null || tupleExprs.IsEmpty()) { throw new ArgumentException( string.Format("route: empty expression list for insertReplace stmt: {0}", originalSql)); } foreach (var p in tupleExprs) { if (p.Value == stmt && p.Key is RowExpression) { replaceRowList.Add((RowExpression)p.Key); } } } stmt.ReplaceRowList = new List <RowExpression>(replaceRowList); var sql = GenSql(stmt, originalSql); stmt.ClearReplaceRowList(); var dataNodeName = matchedTable.DataNodes[en.Key]; rn[++dataNodeId] = new RouteResultsetNode(dataNodeName, 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(); } } } }
/// <exception cref="System.Exception" /> public virtual void AssertNode(RouteResultsetNode node) { var nodeIndex = _deconstructor.GetNodeIndex(node.Name); _sqlAsserter.AssertSql(node.Statement, nodeIndex); _replicaAsserter.AssertReplica(nodeIndex, node.ReplicaIndex); }