func (s *Server) onConn(c net.Conn) { conn := s.newClientConn(c) //新建一个conn defer func() { err := recover() if err != nil { const size = 4096 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] //获得当前goroutine的stacktrace golog.Error("server", "onConn", "error", 0, "remoteAddr", c.RemoteAddr().String(), "stack", string(buf), ) } conn.Close() }() if allowConnect := conn.IsAllowConnect(); allowConnect == false { err := mysql.NewError(mysql.ER_ACCESS_DENIED_ERROR, "ip address access denied by kingshard.") conn.writeError(err) conn.Close() return } if err := conn.Handshake(); err != nil { golog.Error("server", "onConn", err.Error(), 0) c.Close() return } conn.Run() }
func (c *ClientConn) Handshake() error { if err := c.writeInitialHandshake(); err != nil { golog.Error("server", "Handshake", err.Error(), c.connectionId, "msg", "send initial handshake error") return err } if err := c.readHandshakeResponse(); err != nil { golog.Error("server", "readHandshakeResponse", err.Error(), c.connectionId, "msg", "read Handshake Response error") c.writeError(err) return err } if err := c.writeOK(nil); err != nil { golog.Error("server", "readHandshakeResponse", "write ok fail", c.connectionId, "error", err.Error()) return err } c.pkg.Sequence = 0 return nil }
func (r *Router) buildDeletePlan(db string, statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} var where *sqlparser.Where var err error stmt := statement.(*sqlparser.Delete) plan.Rule = r.GetRule(db, sqlparser.String(stmt.Table)) where = stmt.Where if where != nil { plan.Criteria = where.Expr //路由条件 err = plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildUpdatePlan", err.Error(), 0) return nil, err } } else { //if shard delete without where,send to all nodes and all tables plan.RouteTableIndexs = plan.Rule.SubTableIndexs plan.RouteNodeIndexs = makeList(0, len(plan.Rule.Nodes)) } if plan.Rule.Type != DefaultRuleType && len(plan.RouteTableIndexs) == 0 { golog.Error("Route", "BuildDeletePlan", errors.ErrNoCriteria.Error(), 0) return nil, errors.ErrNoCriteria } //generate sql,如果routeTableindexs为空则表示不分表,不分表则发default node err = r.generateDeleteSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
/*处理select语句*/ func (c *ClientConn) handleSelect(stmt *sqlparser.Select, sql string, args []interface{}) error { bindVars := makeBindVars(args) //对于select语句,arg为空,不考虑 conns, err := c.getShardConns(true, stmt, bindVars) if err != nil { golog.Error("ClientConn", "handleSelect", err.Error(), c.connectionId) return err } else if conns == nil { r := c.newEmptyResultset(stmt) return c.writeResultset(c.status, r) } var rs []*Result rs, err = c.executeInShard(conns, sql, args) c.closeShardConns(conns, false) if err != nil { golog.Error("ClientConn", "handleSelect", err.Error(), c.connectionId) return err } err = c.mergeSelectResult(rs, stmt) if err != nil { golog.Error("ClientConn", "handleSelect", err.Error(), c.connectionId) } return err }
func (n *Node) checkMaster() { db := n.Master if db == nil { golog.Error("Node", "checkMaster", "Master is no alive", 0) return } if atomic.LoadInt32(&(db.state)) == Down { return } if err := db.Ping(); err != nil { golog.Error("Node", "checkMaster", "Ping", 0, "db.Addr", db.Addr(), "error", err.Error()) } else { n.LastMasterPing = time.Now().Unix() atomic.StoreInt32(&(db.state), Up) return } if int64(n.DownAfterNoAlive) > 0 && time.Now().Unix()-n.LastMasterPing > int64(n.DownAfterNoAlive/time.Second) { golog.Info("Node", "checkMaster", "Master down", 0, "db.Addr", db.Addr(), "Master_down_time", int64(n.DownAfterNoAlive/time.Second)) n.DownMaster(db.addr) } }
func (r *Router) buildDeletePlan(statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} var where *sqlparser.Where stmt := statement.(*sqlparser.Delete) plan.Rule = r.GetRule(sqlparser.String(stmt.Table)) where = stmt.Where if where != nil { plan.Criteria = where.Expr /*路由条件*/ } else { plan.Rule = r.DefaultRule } plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode)) err := plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildDeletePlan", err.Error(), 0) return nil, err } if plan.Rule.Type != DefaultRuleType && len(plan.RouteTableIndexs) == 0 { golog.Error("Route", "BuildDeletePlan", errors.ErrNoCriteria.Error(), 0) return nil, errors.ErrNoCriteria } //generate sql,如果routeTableindexs为空则表示不分表,不分表则发default node err = r.generateDeleteSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
func (c *ClientConn) handlePrepareSelect(stmt *sqlparser.Select, sql string, args []interface{}) error { defaultRule := c.schema.rule.DefaultRule if len(defaultRule.Nodes) == 0 { return ErrNoDefaultNode } defaultNode := c.proxy.GetNode(defaultRule.Nodes[0]) //execute in Master DB conn, err := c.getBackendConn(defaultNode, false) if err != nil { return err } if conn == nil { r := c.newEmptyResultset(stmt) return c.writeResultset(c.status, r) } var rs []*Result rs, err = c.executeInNode(conn, sql, args) c.closeConn(conn, false) if err != nil { golog.Error("ClientConn", "handlePrepareSelect", err.Error(), c.connectionId) return err } err = c.mergeSelectResult(rs, stmt) if err != nil { golog.Error("ClientConn", "handlePrepareSelect", err.Error(), c.connectionId) } return err }
/*处理query语句*/ func (c *ClientConn) handleQuery(sql string) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("execute %s error %v", sql, e) golog.OutputSql("Error", "%s", sql) return } golog.OutputSql("INFO", "%s", sql) }() sql = strings.TrimRight(sql, ";") //删除sql语句最后的分号 hasHandled, err := c.handleUnsupport(sql) if err != nil { golog.Error("server", "parse", err.Error(), 0, "hasHandled", hasHandled) return err } if hasHandled { return nil } var stmt sqlparser.Statement stmt, err = sqlparser.Parse(sql) //解析sql语句,得到的stmt是一个interface if err != nil { golog.Error("server", "parse", err.Error(), 0, "hasHandled", hasHandled) return err } switch v := stmt.(type) { case *sqlparser.Select: return c.handleSelect(v, sql, nil) case *sqlparser.Insert: return c.handleExec(stmt, sql, nil) case *sqlparser.Update: return c.handleExec(stmt, sql, nil) case *sqlparser.Delete: return c.handleExec(stmt, sql, nil) case *sqlparser.Replace: return c.handleExec(stmt, sql, nil) case *sqlparser.Set: return c.handleSet(v) case *sqlparser.Begin: return c.handleBegin() case *sqlparser.Commit: return c.handleCommit() case *sqlparser.Rollback: return c.handleRollback() case *sqlparser.SimpleSelect: return c.handleSimpleSelect(sql, v) case *sqlparser.Show: return c.handleShow(sql, v) case *sqlparser.Admin: return c.handleAdmin(v) default: return fmt.Errorf("statement %T not support now", stmt) } return nil }
func (r *Router) buildSelectPlan(statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} var where *sqlparser.Where var err error var tableName string stmt := statement.(*sqlparser.Select) switch v := (stmt.From[0]).(type) { case *sqlparser.AliasedTableExpr: tableName = sqlparser.String(v.Expr) case *sqlparser.JoinTableExpr: if ate, ok := (v.LeftExpr).(*sqlparser.AliasedTableExpr); ok { tableName = sqlparser.String(ate.Expr) } else { tableName = sqlparser.String(v) } default: tableName = sqlparser.String(v) } plan.Rule = r.GetRule(tableName) //根据表名获得分表规则 where = stmt.Where plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode)) if where != nil { plan.Criteria = where.Expr //路由条件 err = plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildSelectPlan", err.Error(), 0) return nil, err } } else { //if shard select without where,send to all nodes and all tables plan.RouteTableIndexs = plan.TableIndexs plan.RouteNodeIndexs = makeList(0, len(plan.Rule.Nodes)) } if plan.Rule.Type != DefaultRuleType && len(plan.RouteTableIndexs) == 0 { golog.Error("Route", "BuildSelectPlan", errors.ErrNoCriteria.Error(), 0) return nil, errors.ErrNoCriteria } //generate sql,如果routeTableindexs为空则表示不分表,不分表则发default node err = r.generateSelectSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
func (c *ClientConn) handleExec(stmt sqlparser.Statement, args []interface{}) error { plan, err := c.schema.rule.BuildPlan(stmt) conns, err := c.getShardConns(false, plan) if err != nil { golog.Error("ClientConn", "handleExec", err.Error(), c.connectionId) return err } if conns == nil { return c.writeOK(nil) } var rs []*mysql.Result if 1 < len(conns) { return errors.ErrExecInMulti } if 1 < len(plan.RewrittenSqls) { nodeIndex := plan.RouteNodeIndexs[0] nodeName := plan.Rule.Nodes[nodeIndex] txSqls := []string{"begin;"} txSqls = append(txSqls, plan.RewrittenSqls[nodeName]...) txSqls = append(txSqls, "commit;") plan.RewrittenSqls[nodeName] = txSqls } rs, err = c.executeInMultiNodes(conns, plan.RewrittenSqls, args) c.closeShardConns(conns, err != nil) if err == nil { err = c.mergeExecResult(rs) } return err }
func (r *Router) buildReplacePlan(statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} stmt := statement.(*sqlparser.Replace) if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok { panic(sqlparser.NewParserError("select in replace not allowed")) } plan.Rule = r.GetRule(sqlparser.String(stmt.Table)) plan.Criteria = plan.checkValuesType(stmt.Rows.(sqlparser.Values)) plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode)) err := plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildReplacePlan", err.Error(), 0) return nil, err } err = r.generateReplaceSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
func (r *Router) buildInsertPlan(statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} stmt := statement.(*sqlparser.Insert) if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok { return nil, errors.ErrSelectInInsert } /*根据sql语句的表,获得对应的分片规则*/ plan.Rule = r.GetRule(sqlparser.String(stmt.Table)) if stmt.OnDup != nil { err := plan.Rule.checkUpdateExprs(sqlparser.UpdateExprs(stmt.OnDup)) if err != nil { return nil, err } } plan.Criteria = plan.checkValuesType(stmt.Rows.(sqlparser.Values)) plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode)) err := plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildInsertPlan", err.Error(), 0) return nil, err } err = r.generateInsertSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
/*计算表下标和node下标 */ func (plan *Plan) calRouteIndexs() error { nodesCount := len(plan.Rule.Nodes) if plan.Rule.Type == DefaultRuleType { plan.RouteNodeIndexs = []int{0} return nil } if plan.Criteria == nil { //如果没有分表条件,则是全子表扫描 if plan.Rule.Type != DefaultRuleType { golog.Error("Plan", "calRouteIndexs", "plan have no criteria", 0, "type", plan.Rule.Type) return ErrNoCriteria } } switch criteria := plan.Criteria.(type) { case sqlparser.Values: //代表insert中values tindex := plan.getInsertTableIndex(criteria) plan.RouteTableIndexs = []int{tindex} plan.RouteNodeIndexs = plan.TindexsToNindexs([]int{tindex}) return nil case sqlparser.BoolExpr: plan.RouteTableIndexs = plan.getTableIndexByBoolExpr(criteria) plan.RouteNodeIndexs = plan.TindexsToNindexs(plan.RouteTableIndexs) return nil default: plan.RouteTableIndexs = plan.TableIndexs plan.RouteNodeIndexs = makeList(0, nodesCount) return nil } }
func (r *Router) buildReplacePlan(db string, statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} plan.Rows = make(map[int]sqlparser.Values) stmt := statement.(*sqlparser.Replace) if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok { panic(sqlparser.NewParserError("select in replace not allowed")) } if stmt.Columns == nil { return nil, errors.ErrIRNoColumns } plan.Rule = r.GetRule(db, sqlparser.String(stmt.Table)) err := plan.GetIRKeyIndex(stmt.Columns) if err != nil { return nil, err } plan.Criteria = plan.checkValuesType(stmt.Rows.(sqlparser.Values)) err = plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildReplacePlan", err.Error(), 0) return nil, err } err = r.generateReplaceSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
func (n *Node) checkSlave() { n.RLock() if n.Slave == nil { n.RUnlock() return } slaves := make([]*DB, len(n.Slave)) copy(slaves, n.Slave) n.RUnlock() for i := 0; i < len(slaves); i++ { if atomic.LoadInt32(&(slaves[i].state)) == Down { continue } if err := slaves[i].Ping(); err != nil { golog.Error("Node", "checkSlave", "Ping", 0, "db.Addr", slaves[i].Addr(), "error", err.Error()) } else { n.LastSlavePing = time.Now().Unix() atomic.StoreInt32(&(slaves[i].state), Up) continue } if int64(n.DownAfterNoAlive) > 0 && time.Now().Unix()-n.LastSlavePing > int64(n.DownAfterNoAlive/time.Second) { golog.Info("Node", "checkMaster", "Master down", 0, "db.Addr", slaves[i].Addr(), "slave_down_time", int64(n.DownAfterNoAlive/time.Second)) //If can't ping slave after DownAfterNoAlive, set slave Down n.DownSlave(slaves[i].addr) } } }
func (c *ClientConn) readHandshakeResponse() error { data, err := c.readPacket() if err != nil { return err } pos := 0 //capability c.capability = binary.LittleEndian.Uint32(data[:4]) pos += 4 //skip max packet size pos += 4 //charset, skip, if you want to use another charset, use set names //c.collation = CollationId(data[pos]) pos++ //skip reserved 23[00] pos += 23 //user name c.user = string(data[pos : pos+bytes.IndexByte(data[pos:], 0)]) pos += len(c.user) + 1 //auth length and auth authLen := int(data[pos]) pos++ auth := data[pos : pos+authLen] checkAuth := mysql.CalcPassword(c.salt, []byte(c.proxy.cfg.Password)) if c.user != c.proxy.cfg.User || !bytes.Equal(auth, checkAuth) { golog.Error("ClientConn", "readHandshakeResponse", "error", 0, "auth", auth, "checkAuth", checkAuth, "client_user", c.user, "config_set_user", c.proxy.cfg.User, "passworld", c.proxy.cfg.Password) return mysql.NewDefaultError(mysql.ER_ACCESS_DENIED_ERROR, c.user, c.c.RemoteAddr().String(), "Yes") } pos += authLen var db string if c.capability&mysql.CLIENT_CONNECT_WITH_DB > 0 { if len(data[pos:]) == 0 { return nil } db = string(data[pos : pos+bytes.IndexByte(data[pos:], 0)]) pos += len(c.db) + 1 } c.db = db return nil }
func (c *ClientConn) handleAdmin(admin *sqlparser.Admin) error { var err error var result *mysql.Resultset region := sqlparser.String(admin.Region) err = c.checkCmdOrder(region, admin.Columns) if err != nil { return err } switch strings.ToLower(region) { case NodeRegion: err = c.handleNodeCmd(admin.Rows) case ServerRegion: result, err = c.handleServerCmd(admin.Rows) default: return fmt.Errorf("admin %s not supported now", region) } if err != nil { golog.Error("ClientConn", "handleAdmin", err.Error(), c.connectionId, "sql", sqlparser.String(admin)) return err } if result != nil { return c.writeResultset(c.status, result) } return c.writeOK(nil) }
//返回true表示已经处理,false表示未处理 func (c *ClientConn) handleUnsupport(sql string) (bool, error) { var rs []*Result var TK_FROM string = "from" sql = strings.ToLower(sql) tokens := strings.Fields(sql) tokensLen := len(tokens) if 0 < tokensLen { //token is in WHITE_TOKEN_MAP if 0 < WHITE_TOKEN_MAP[tokens[0]] { //select if 1 < WHITE_TOKEN_MAP[tokens[0]] { for i := 1; i < tokensLen; i++ { if tokens[i] == TK_FROM { return false, nil } } } else { return false, nil } } } defaultRule := c.schema.rule.DefaultRule if len(defaultRule.Nodes) == 0 { return false, ErrNoDefaultNode } defaultNode := c.proxy.GetNode(defaultRule.Nodes[0]) //execute in Master DB conn, err := c.getBackendConn(defaultNode, false) if err != nil { return false, err } rs, err = c.executeInNode(conn, sql, nil) if err != nil { return false, err } c.closeConn(conn, false) if len(rs) == 0 { msg := fmt.Sprintf("result is empty") golog.Error("ClientConn", "handleUnsupport", msg, c.connectionId) return false, NewError(ER_UNKNOWN_ERROR, msg) } if rs[0].Resultset != nil { err = c.writeResultset(c.status, rs[0].Resultset) } else { err = c.writeOK(rs[0]) } if err != nil { return false, err } return true, nil }
func (s *Server) parseNode(cfg config.NodeConfig) (*backend.Node, error) { n := new(backend.Node) //n.server = s n.Cfg = cfg n.DownAfterNoAlive = time.Duration(cfg.DownAfterNoAlive) * time.Second if len(cfg.Master) == 0 { return nil, fmt.Errorf("must setting master MySQL node.") } var err error if n.Master, err = n.OpenDB(cfg.Master); err != nil { return nil, err } //n.db = n.Master if len(cfg.Slave) > 0 { if n.Slave, err = n.OpenDB(cfg.Slave); err != nil { golog.Error("ClientConn", "handleShowProxy", err.Error(), 0) n.Slave = nil } } go n.Run() return n, nil }
func (c *ClientConn) handleNodeCmd(rows sqlparser.InsertRows) error { var err error var opt, nodeName, role, addr string vals := rows.(sqlparser.Values) if len(vals) == 0 { return errors.ErrCmdUnsupport } tuple := vals[0].(sqlparser.ValTuple) if len(tuple) != len(cmdNodeOrder) { return errors.ErrCmdUnsupport } opt = sqlparser.String(tuple[0]) opt = strings.Trim(opt, "'") nodeName = sqlparser.String(tuple[1]) nodeName = strings.Trim(nodeName, "'") role = sqlparser.String(tuple[2]) role = strings.Trim(role, "'") addr = sqlparser.String(tuple[3]) addr = strings.Trim(addr, "'") switch strings.ToLower(opt) { case ADMIN_OPT_ADD: err = c.AddDatabase( nodeName, role, addr, ) case ADMIN_OPT_DEL: err = c.DeleteDatabase( nodeName, role, addr, ) case ADMIN_OPT_UP: err = c.UpDatabase( nodeName, role, addr, ) case ADMIN_OPT_DOWN: err = c.DownDatabase( nodeName, role, addr, ) default: err = errors.ErrCmdUnsupport golog.Error("ClientConn", "handleNodeCmd", err.Error(), c.connectionId, "opt", opt) } return err }
func (n *Node) UpMaster(addr string) error { db, err := n.UpDB(addr) if err != nil { golog.Error("Node", "UpMaster", err.Error(), 0) } n.Master = db return err }
//返回true表示已经处理,false表示未处理 func (c *ClientConn) preHandleShard(sql string) (bool, error) { var rs []*mysql.Result var err error var execNode *backend.Node var fromSlave bool = false if len(sql) == 0 { return false, errors.ErrCmdUnsupport } tokens := strings.Fields(sql) if len(tokens) == 0 { return false, errors.ErrCmdUnsupport } if c.needBeginTx() { execNode, err = c.GetTransExecNode(tokens, sql) } else { execNode, fromSlave, err = c.GetExecNode(tokens, sql) } if err != nil { return false, err } //need shard sql if execNode == nil { return false, nil } //execute in Master DB conn, err := c.getBackendConn(execNode, fromSlave) if err != nil { return false, err } rs, err = c.executeInNode(conn, sql, nil) if err != nil { return false, err } c.closeConn(conn, false) if len(rs) == 0 { msg := fmt.Sprintf("result is empty") golog.Error("ClientConn", "handleUnsupport", msg, c.connectionId) return false, mysql.NewError(mysql.ER_UNKNOWN_ERROR, msg) } if rs[0].Resultset != nil { err = c.writeResultset(c.status, rs[0].Resultset) } else { err = c.writeOK(rs[0]) } if err != nil { return false, err } return true, nil }
func (c *ClientConn) executeInMultiNodes(conns map[string]*backend.BackendConn, sqls map[string][]string, args []interface{}) ([]*Result, error) { if len(conns) != len(sqls) { golog.Error("ClientConn", "executeInMultiNodes", ErrConnNotEqual.Error(), c.connectionId, "conns", conns, "sqls", sqls, ) return nil, ErrConnNotEqual } var wg sync.WaitGroup if len(conns) == 0 { return nil, ErrNoPlan } wg.Add(len(conns)) resultCount := 0 for _, sqlSlice := range sqls { resultCount += len(sqlSlice) } rs := make([]interface{}, resultCount) f := func(rs []interface{}, i int, execSqls []string, co *backend.BackendConn) { for _, v := range execSqls { r, err := co.Execute(v, args...) if err != nil { rs[i] = err } else { rs[i] = r } i++ } wg.Done() } offsert := 0 for nodeName, co := range conns { s := sqls[nodeName] //[]string go f(rs, offsert, s, co) offsert += len(s) } wg.Wait() var err error r := make([]*Result, resultCount) for i, v := range rs { if e, ok := v.(error); ok { err = e break } r[i] = rs[i].(*Result) } return r, err }
/*计算表下标和node下标 */ func (plan *Plan) calRouteIndexs() error { defer func() { if e := recover(); e != nil { //如果是下表超过边界的panic则不往上面传递 if err, ok := e.(error); ok && strings.HasPrefix(err.Error(), "Unexpected key") { golog.Error("Router", "calRouteIndexs", err.Error(), 0) } else { panic(err.Error()) } } }() nodesCount := len(plan.Rule.Nodes) if plan.Rule.Type == DefaultRuleType { plan.RouteNodeIndexs = []int{0} return nil } if plan.Criteria == nil { //如果没有分表条件,则是全子表扫描 if plan.Rule.Type != DefaultRuleType { golog.Error("Plan", "calRouteIndexs", "plan have no criteria", 0, "type", plan.Rule.Type) return errors.ErrNoCriteria } } switch criteria := plan.Criteria.(type) { case sqlparser.Values: //代表insert中values tindex := plan.getInsertTableIndex(criteria) plan.RouteTableIndexs = []int{tindex} plan.RouteNodeIndexs = plan.TindexsToNindexs([]int{tindex}) return nil case sqlparser.BoolExpr: plan.RouteTableIndexs = plan.getTableIndexByBoolExpr(criteria) plan.RouteNodeIndexs = plan.TindexsToNindexs(plan.RouteTableIndexs) return nil default: plan.RouteTableIndexs = plan.TableIndexs plan.RouteNodeIndexs = makeList(0, nodesCount) return nil } }
//preprocessing sql before parse sql func (c *ClientConn) preHandleShard(sql string) (bool, error) { var rs []*mysql.Result var err error var executeDB *ExecuteDB if len(sql) == 0 { return false, errors.ErrCmdUnsupport } tokens := strings.Fields(sql) if len(tokens) == 0 { return false, errors.ErrCmdUnsupport } if c.isInTransaction() { executeDB, err = c.GetTransExecDB(tokens, sql) } else { executeDB, err = c.GetExecDB(tokens, sql) } if err != nil { return false, err } //need shard sql if executeDB == nil { return false, nil } //get connection in DB conn, err := c.getBackendConn(executeDB.ExecNode, executeDB.IsSlave) defer c.closeConn(conn, false) if err != nil { return false, err } rs, err = c.executeInNode(conn, sql, nil) if err != nil { return false, err } if len(rs) == 0 { msg := fmt.Sprintf("result is empty") golog.Error("ClientConn", "handleUnsupport", msg, 0, "sql", sql) return false, mysql.NewError(mysql.ER_UNKNOWN_ERROR, msg) } if rs[0].Resultset != nil { err = c.writeResultset(c.status, rs[0].Resultset) } else { err = c.writeOK(rs[0]) } if err != nil { return false, err } return true, nil }
func (c *ClientConn) Run() { defer func() { r := recover() if err, ok := r.(error); ok { const size = 4096 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] golog.Error("ClientConn", "Run", err.Error(), 0, "stack", string(buf)) } c.Close() }() for { data, err := c.readPacket() if err != nil { return } if err := c.dispatch(data); err != nil { c.proxy.counter.IncrErrLogTotal() golog.Error("server", "Run", err.Error(), c.connectionId, ) c.writeError(err) if err == mysql.ErrBadConn { c.Close() } } if c.closed { return } c.pkg.Sequence = 0 } }
/*处理select语句*/ func (c *ClientConn) handleSelect(stmt *sqlparser.Select, args []interface{}) error { var fromSlave bool = true plan, err := c.schema.rule.BuildPlan(stmt) if err != nil { return err } if 0 < len(stmt.Comments) { comment := string(stmt.Comments[0]) if 0 < len(comment) && strings.ToLower(comment) == MasterComment { fromSlave = false } } conns, err := c.getShardConns(fromSlave, plan) if err != nil { golog.Error("ClientConn", "handleSelect", err.Error(), c.connectionId) return err } if conns == nil { r := c.newEmptyResultset(stmt) return c.writeResultset(c.status, r) } var rs []*Result rs, err = c.executeInMultiNodes(conns, plan.RewrittenSqls, args) c.closeShardConns(conns, false) if err != nil { golog.Error("ClientConn", "handleSelect", err.Error(), c.connectionId) return err } err = c.mergeSelectResult(rs, stmt) if err != nil { golog.Error("ClientConn", "handleSelect", err.Error(), c.connectionId) } return err }
func (r *Router) buildSelectPlan(statement sqlparser.Statement) (*Plan, error) { plan := &Plan{} var where *sqlparser.Where var tableName string stmt := statement.(*sqlparser.Select) if ate, ok := (stmt.From[0]).(*sqlparser.AliasedTableExpr); ok { tableName = sqlparser.String(ate.Expr) } else { tableName = sqlparser.String(stmt.From[0]) } plan.Rule = r.GetRule(tableName) //根据表名获得分表规则 where = stmt.Where if where != nil { plan.Criteria = where.Expr /*路由条件*/ } else { plan.Rule = r.DefaultRule } plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode)) err := plan.calRouteIndexs() if err != nil { golog.Error("Route", "BuildSelectPlan", err.Error(), 0) return nil, err } if plan.Rule.Type != DefaultRuleType && len(plan.RouteTableIndexs) == 0 { golog.Error("Route", "BuildSelectPlan", errors.ErrNoCriteria.Error(), 0) return nil, errors.ErrNoCriteria } //generate sql,如果routeTableindexs为空则表示不分表,不分表则发default node err = r.generateSelectSql(plan, stmt) if err != nil { return nil, err } return plan, nil }
func (c *ClientConn) getBackendConn(n *backend.Node, fromSlave bool) (co *backend.BackendConn, err error) { if !c.isInTransaction() { if fromSlave { co, err = n.GetSlaveConn() if err != nil { co, err = n.GetMasterConn() } } else { co, err = n.GetMasterConn() } if err != nil { golog.Error("server", "getBackendConn", err.Error(), 0) return } } else { var ok bool co, ok = c.txConns[n] if !ok { if co, err = n.GetMasterConn(); err != nil { return } if !c.isAutoCommit() { if err = co.SetAutoCommit(0); err != nil { return } } else { if err = co.Begin(); err != nil { return } } c.txConns[n] = co } } if err = co.UseDB(c.db); err != nil { //reset the database to null c.db = "" return } if err = co.SetCharset(c.charset, c.collation); err != nil { return } return }
func (s *Server) Run() error { s.running = true for s.running { conn, err := s.listener.Accept() if err != nil { golog.Error("server", "Run", err.Error(), 0) continue } go s.onConn(conn) } return nil }