Skip to content

Commit

Permalink
tidb,config: limit statement count in a transaction (#5754)
Browse files Browse the repository at this point in the history
* tidb,config: limit statement count in a transaction
* ast: do statement is read only (#5752)
  • Loading branch information
tiancaiamao authored Jan 30, 2018
1 parent ef9452d commit 16e7e31
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 1 deletion.
2 changes: 1 addition & 1 deletion ast/read_only_checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func IsReadOnly(node Node) bool {

node.Accept(&checker)
return checker.readOnly
case *ExplainStmt:
case *ExplainStmt, *DoStmt:
return true
default:
return false
Expand Down
3 changes: 3 additions & 0 deletions ast/read_only_checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ func (s *testCacheableSuite) TestCacheable(c *C) {

stmt = &ExplainStmt{}
c.Assert(IsReadOnly(stmt), IsTrue)

stmt = &DoStmt{}
c.Assert(IsReadOnly(stmt), IsTrue)
}
2 changes: 2 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type Performance struct {
CrossJoin bool `toml:"cross-join" json:"cross-join"`
StatsLease string `toml:"stats-lease" json:"stats-lease"`
RunAutoAnalyze bool `toml:"run-auto-analyze" json:"run-auto-analyze"`
StmtCountLimit int `toml:"stmt-count-limit" json:"stmt-count-limit"`
}

// XProtocol is the XProtocol section of the config.
Expand Down Expand Up @@ -126,6 +127,7 @@ var defaultConf = Config{
CrossJoin: true,
StatsLease: "3s",
RunAutoAnalyze: true,
StmtCountLimit: 5000,
},
XProtocol: XProtocol{
XHost: "0.0.0.0",
Expand Down
2 changes: 2 additions & 0 deletions config/config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ metrics-interval = 15
[performance]
# Set keep alive option for tcp connection.
tcp-keep-alive = true
# StmtCountLimit limits the max count of statement inside a transaction.
stmt-count-limit = 5000

# The maximum number of retries when commit a transaction.
retry-limit = 10
Expand Down
24 changes: 24 additions & 0 deletions new_session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

. "github.com/pingcap/check"
"github.com/pingcap/tidb"
"github.com/pingcap/tidb/config"
"github.com/pingcap/tidb/context"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/executor"
Expand Down Expand Up @@ -1351,6 +1352,29 @@ type testSchemaSuite struct {
checkLeak func()
}

func (s *testSessionSuite) TestStatementCountLimit(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("create table stmt_count_limit (id int)")
saved := config.GetGlobalConfig().Performance.StmtCountLimit
config.GetGlobalConfig().Performance.StmtCountLimit = 3
defer func() {
config.GetGlobalConfig().Performance.StmtCountLimit = saved
}()
tk.MustExec("begin")
tk.MustExec("insert into stmt_count_limit values (1)")
tk.MustExec("insert into stmt_count_limit values (2)")
_, err := tk.Exec("insert into stmt_count_limit values (3)")
c.Assert(err, NotNil)

// begin is counted into history but this one is not.
tk.MustExec("SET SESSION autocommit = false")
tk.MustExec("insert into stmt_count_limit values (1)")
tk.MustExec("insert into stmt_count_limit values (2)")
tk.MustExec("insert into stmt_count_limit values (3)")
_, err = tk.Exec("insert into stmt_count_limit values (4)")
c.Assert(err, NotNil)
}

func (s *testSchemaSuite) TearDownTest(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
r := tk.MustQuery("show tables")
Expand Down
11 changes: 11 additions & 0 deletions tidb.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/juju/errors"
"github.com/pingcap/tidb/ast"
"github.com/pingcap/tidb/config"
"github.com/pingcap/tidb/context"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/executor"
Expand Down Expand Up @@ -170,6 +171,16 @@ func runStmt(ctx context.Context, s ast.Statement) (ast.RecordSet, error) {
} else {
err = se.CommitTxn()
}
} else {
// If the user insert, insert, insert ... but never commit, TiDB would OOM.
// So we limit the statement count in a transaction here.
history := GetHistory(ctx)
if history.Count() > config.GetGlobalConfig().Performance.StmtCountLimit {
err1 := se.RollbackTxn()
terror.Log(errors.Trace(err1))
return rs, errors.Errorf("statement count %d exceeds the transaction limitation, autocommit = %t",
history.Count(), ctx.GetSessionVars().IsAutocommit())
}
}
return rs, errors.Trace(err)
}
Expand Down

0 comments on commit 16e7e31

Please sign in to comment.