-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
txn: Slow txn log #41864
txn: Slow txn log #41864
Changes from 10 commits
6982eef
d111793
730de85
56d59e7
de9e862
568b10f
d9578d5
d00cec6
3be6c30
238dc0b
62f862e
af9d4df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,16 +17,21 @@ package session | |
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/pingcap/errors" | ||
"github.com/pingcap/failpoint" | ||
"github.com/pingcap/tidb/infoschema" | ||
"github.com/pingcap/tidb/kv" | ||
"github.com/pingcap/tidb/parser" | ||
"github.com/pingcap/tidb/parser/ast" | ||
"github.com/pingcap/tidb/sessionctx" | ||
"github.com/pingcap/tidb/sessiontxn" | ||
"github.com/pingcap/tidb/sessiontxn/isolation" | ||
"github.com/pingcap/tidb/sessiontxn/staleread" | ||
"github.com/pingcap/tidb/util/logutil" | ||
"go.uber.org/zap" | ||
"go.uber.org/zap/zapcore" | ||
) | ||
|
||
func init() { | ||
|
@@ -52,6 +57,22 @@ type txnManager struct { | |
|
||
// We always reuse the same OptimisticTxnContextProvider in one session to reduce memory allocation cost for every new txn. | ||
reservedOptimisticProviders [2]isolation.OptimisticTxnContextProvider | ||
|
||
// used for slow transaction logs | ||
events []event | ||
lastInstant time.Time | ||
enterTxnInstant time.Time | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I've considered the alternative. I think they are basically equivalent and either is fine. If you prefer this style I can change it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it’s fine. A field of type time.Time here is not expensive at all. |
||
} | ||
|
||
type event struct { | ||
event string | ||
duration time.Duration | ||
} | ||
|
||
func (s event) MarshalLogObject(enc zapcore.ObjectEncoder) error { | ||
enc.AddString("event", s.event) | ||
enc.AddDuration("gap", s.duration) | ||
return nil | ||
} | ||
|
||
func newTxnManager(sctx sessionctx.Context) *txnManager { | ||
|
@@ -153,12 +174,30 @@ func (m *txnManager) EnterNewTxn(ctx context.Context, r *sessiontxn.EnterNewTxnR | |
if r.Type == sessiontxn.EnterNewTxnWithBeginStmt { | ||
m.sctx.GetSessionVars().SetInTxn(true) | ||
} | ||
|
||
m.resetEvents() | ||
m.recordEvent("enter txn") | ||
return nil | ||
} | ||
|
||
func (m *txnManager) OnTxnEnd() { | ||
m.ctxProvider = nil | ||
m.stmtNode = nil | ||
|
||
m.events = append(m.events, event{event: "txn end", duration: time.Since(m.lastInstant)}) | ||
|
||
duration := time.Since(m.enterTxnInstant) | ||
threshold := m.sctx.GetSessionVars().SlowTxnThreshold | ||
if threshold > 0 && uint64(duration.Milliseconds()) >= threshold { | ||
logutil.BgLogger().Info( | ||
ekexium marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"slow transaction", zap.Duration("duration", duration), | ||
zap.Uint64("conn", m.sctx.GetSessionVars().ConnectionID), | ||
zap.Uint64("txnStartTS", m.sctx.GetSessionVars().TxnCtx.StartTS), | ||
zap.Objects("events", m.events), | ||
) | ||
} | ||
|
||
m.lastInstant = time.Now() | ||
} | ||
|
||
func (m *txnManager) GetCurrentStmt() ast.StmtNode { | ||
|
@@ -172,9 +211,23 @@ func (m *txnManager) OnStmtStart(ctx context.Context, node ast.StmtNode) error { | |
if m.ctxProvider == nil { | ||
return errors.New("context provider not set") | ||
} | ||
|
||
var sql string | ||
if node != nil { | ||
sql = node.OriginalText() | ||
if m.sctx.GetSessionVars().EnableRedactLog { | ||
sql = parser.Normalize(sql) | ||
} | ||
} | ||
m.recordEvent(sql) | ||
return m.ctxProvider.OnStmtStart(ctx, m.stmtNode) | ||
} | ||
|
||
// OnStmtEnd implements the TxnManager interface | ||
func (m *txnManager) OnStmtEnd() { | ||
m.recordEvent("stmt end") | ||
} | ||
|
||
// OnPessimisticStmtStart is the hook that should be called when starts handling a pessimistic DML or | ||
// a pessimistic select-for-update statements. | ||
func (m *txnManager) OnPessimisticStmtStart(ctx context.Context) error { | ||
|
@@ -222,14 +275,33 @@ func (m *txnManager) OnStmtCommit(ctx context.Context) error { | |
if m.ctxProvider == nil { | ||
return errors.New("context provider not set") | ||
} | ||
m.recordEvent("stmt commit") | ||
return m.ctxProvider.OnStmtCommit(ctx) | ||
} | ||
|
||
func (m *txnManager) recordEvent(eventName string) { | ||
if m.events == nil { | ||
m.resetEvents() | ||
} | ||
m.events = append(m.events, event{event: eventName, duration: time.Since(m.lastInstant)}) | ||
m.lastInstant = time.Now() | ||
} | ||
|
||
func (m *txnManager) resetEvents() { | ||
if m.events == nil { | ||
m.events = make([]event, 0, 10) | ||
} else { | ||
m.events = m.events[:0] | ||
} | ||
m.enterTxnInstant = time.Now() | ||
} | ||
|
||
// OnStmtRollback is the hook that should be called when a statement fails to execute. | ||
func (m *txnManager) OnStmtRollback(ctx context.Context, isForPessimisticRetry bool) error { | ||
if m.ctxProvider == nil { | ||
return errors.New("context provider not set") | ||
} | ||
m.recordEvent("stmt rollback") | ||
return m.ctxProvider.OnStmtRollback(ctx, isForPessimisticRetry) | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,8 @@ const ( | |
DefaultLogFormat = "text" | ||
// DefaultSlowThreshold is the default slow log threshold in millisecond. | ||
DefaultSlowThreshold = 300 | ||
// DefaultSlowTxnThreshold is the default slow txn log threshold in ms. | ||
DefaultSlowTxnThreshold = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How to choose a default-enabled value? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Default to 0. It's totally dependent on the application logic to determine what is "slow". And defaulting to 0 will prevent noisy logs from inner transactions. |
||
// DefaultQueryLogMaxLen is the default max length of the query in the log. | ||
DefaultQueryLogMaxLen = 4096 | ||
// DefaultRecordPlanInSlowLog is the default value for whether enable log query plan in the slow log. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to merge the two
OnStmtEnd
into one #41122 but it looks difficult..