-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
planner: fix update panic when update in prepare and execute #26759
planner: fix update panic when update in prepare and execute #26759
Conversation
Signed-off-by: ailinkid <[email protected]>
[REVIEW NOTIFICATION] This pull request has been approved by:
To complete the pull request process, please ask the reviewers in the list to review by filling The full list of commands accepted by this bot can be found here. Reviewer can indicate their review by submitting an approval review. |
Signed-off-by: ailinkid <[email protected]>
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 think it is kinda hacky. Maybe we can workaround the panic in another low-impact way.
planner/optimize.go
Outdated
is = domain.GetDomain(sctx).InfoSchema() | ||
sctx.GetSessionVars().TxnCtx.InfoSchema = is |
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.
GetInfoSchema()
is not equavalent to sctx.GetSessionVars().TxnCtx.InfoSchema
, e.g. snapshot and stale infoschema. And it is intended that the schema of session is not always the global latest, it should be session-latest except some special cases like forUpdate
. In fact, I found 2pc relied on this behavior.
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 found 2pc relied on this behavior.
I don't find this? where is it?
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 only find it works on the resolveAccessPaths
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.
you are right. these two information can be different! may be for this sort of forUpdateRead
case, they should be the same.
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.
2pc relied on schema checker and amender. Changing infoschema between optimize
and execute
may bypass the checker and fail the correctness of amender(for most cases? I don't know why forUpdateRead
will ask for the latest exactly, seems it will cause inconsistency frequently if it is not the latest in some parallel cases)
You reminds me that I've suggested to remove these lines, because I have moved the logic of choosing correct infoschema to the outside https://github.com/pingcap/tidb/pull/26759/files#r679868151: these lines should be stub, the correct infoschema has been chosen. But got refused for risks, because the transaction reviewer seems can not track the whole execution path, too.
I've looked more closely, server/conn
will dispatch prepare
and execute
into the one in session, so yes, the correct infoschema will be passed down from session down to here. And chasing a even newer infoschema between two closely coupled optimize
and execute
is non-sense for me.
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.
We need a whole new proposal to define the behavior of concurrent DDL, because sync the latest = use the global latest. So all sessions will share the same infoschema as long as possible. It is been a gray area for a long time. I believe a talk to the transaction and runtime team is must.
Signed-off-by: ailinkid <[email protected]>
Signed-off-by: ailinkid <[email protected]>
Signed-off-by: ailinkid <[email protected]>
Signed-off-by: ailinkid <[email protected]>
Signed-off-by: ailinkid <[email protected]>
Signed-off-by: ailinkid <[email protected]>
Signed-off-by: ailinkid <[email protected]>
Signed-off-by: ailinkid <[email protected]>
@@ -745,7 +755,7 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter | |||
p: dual, | |||
}, cntPlan, nil | |||
} | |||
canConvertPointGet := len(path.Ranges) > 0 && path.StoreType == kv.TiKV | |||
canConvertPointGet := len(path.Ranges) > 0 && path.StoreType == kv.TiKV && ds.isPointGetConvertableSchema() |
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.
What if executing normal statements without prepare-execute model? It affects those statements now.
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.
it's ok, it's is a normal limitation.
@@ -157,6 +170,7 @@ type preprocessor struct { | |||
|
|||
// values that may be returned | |||
*PreprocessorReturn | |||
*PreprocessExecuteISUpdate |
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.
Why not name it Preprocessor like other members?
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.
Why is PreprocessExecuteISUpdate
necessary? How about just call IsExecuteForUpdateRead
in ensureInfoSchema
?
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.
import circle problem, pass function poninter here is trying to do this
planner/optimize.go
Outdated
@@ -77,6 +77,24 @@ func IsReadOnly(node ast.Node, vars *variable.SessionVars) bool { | |||
return ast.IsReadOnly(node) | |||
} | |||
|
|||
// IsExecuteForUpdateRead is used to check whether the statement is `execute` and target statement has a forUpdateRead flag. | |||
// If so, we will return the latest information schema. | |||
func IsExecuteForUpdateRead(node ast.Node, sctx sessionctx.Context) infoschema.InfoSchema { |
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.
This name sounds like a function returning a bool.
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.
good catch
Signed-off-by: ailinkid <[email protected]>
/lgtm |
@you06: Thanks for your review. The bot only counts approvals from reviewers and higher roles in list, but you're still welcome to leave your comments. In response to this: Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the ti-community-infra/tichi repository. |
/approve |
/merge |
This pull request has been accepted and is ready to merge. Commit hash: da070d7
|
/run-unit-tests |
Signed-off-by: ailinkid [email protected]
What problem does this PR solve?
Issue Number: close #25997
What is changed and how it works?
What's Changed:
Background:
prepare and execute may have the difference schema to build the plan and run the statement. When we are in buildExecute, once we found the real statement of Execute is update read, we will substitute information schema with the lasted one. Latter, we use the latested schema to rebuild the plan, and run it.
This pr solved several bad point.
1: do not convert point-table-scan to point-get if there are non-public column exists.
2: change schema in the deep call chain is not necessary and it's risky, since the outer schema is still old.
3: Binary-Protocol Execute
4: Text-Protocol Execute
stmtType
withforUpdateRead
flag as possible. here we choose to do this at the same level of optimize & runstmt.Check List
Tests
Release note