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 void LogExplicitReplicaSet(object frontConn, string sql, RouteResultset rrs) { //LogExplicitReplicaSet //if (frontConn != null && Logger.IsInfoEnabled()) //{ // StringBuilder s = new StringBuilder(); // s.Append(frontConn).Append("Explicit data node replica set from, sql=["); // s.Append(sql).Append(']'); // Logger.Info(s.ToString()); //} }
private static IDictionary<string, RouteResultsetNode> GetNodeMap(RouteResultset rrs, int expectSize) { var routeNodes = rrs.Nodes; Assert.AreEqual(expectSize, routeNodes.Length); var nodeMap = new Dictionary<string, RouteResultsetNode>(expectSize); for (var i = 0; i < expectSize; i++) { var routeNode = routeNodes[i]; nodeMap[routeNode.Name] = routeNode; } Assert.AreEqual(expectSize, nodeMap.Count); return nodeMap; }
private static void SetGroupFlagAndLimit(RouteResultset rrs, PartitionKeyVisitor visitor) { rrs.LimitSize = visitor.GetLimitSize(); switch (visitor.GetGroupFuncType()) { case PartitionKeyVisitor.GroupSum: { rrs.Flag = RouteResultset.SumFlag; break; } case PartitionKeyVisitor.GroupMax: { rrs.Flag = RouteResultset.MaxFlag; break; } case PartitionKeyVisitor.GroupMin: { rrs.Flag = RouteResultset.MinFlag; break; } } }
/// <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 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); }