Skip to content
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

When a SQL error occurs, clean up all prepared statement. #2936

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

px3303
Copy link
Contributor

@px3303 px3303 commented Mar 15, 2023

As described in #420 , when the prepared statement fails unexpectedly in the database, the program cannot be recovered.

This PR will clear all the prepared statements in the cache when the statement execution error occurs (this is because other prepared statements may also make errors).

@px3303 px3303 requested a review from a team as a code owner March 15, 2023 08:41
@px3303 px3303 requested a review from zkpjedi March 15, 2023 08:41
Copy link
Contributor

@mhutchinson mhutchinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also remove the TODO in getStmt to do this work:

// TODO(al,martin): we'll possibly need to expire Stmts from the cache,

Thanks!

func (m *mySQLTreeStorage) cleanAllStmt() {
m.statementMutex.Lock()
defer m.statementMutex.Unlock()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some kind of logging for this would be really useful. This should be a rare event in an otherwise healthy system:

klog.Info("Clearing all prepared statements")

Actually, for bonus points I think it's worth incrementing a counter whenever we clear statements, which should appear on monitoring dashboards and allow correlation with potential impacts such as increased latency or errors. Take a look at queuedCounter in this class as an example (though we won't need a logID for this as it's effectively global).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


for _, ns := range m.statements {
for _, s := range ns {
s.Close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the error returned from Close. Maybe not much more to do other than log the failure, but I don't like letting errors like this simply disappear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@px3303 px3303 requested review from mhutchinson and removed request for zkpjedi March 15, 2023 10:53
Copy link
Contributor

@mhutchinson mhutchinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM. Would appreciate @AlCutter giving final approval as an original author of this code.

@mhutchinson
Copy link
Contributor

/gcbrun

Copy link
Member

@AlCutter AlCutter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of small naming/readability nits.

@@ -101,6 +102,7 @@ func createMetrics(mf monitoring.MetricFactory) {
queuedCounter = mf.NewCounter("mysql_queued_leaves", "Number of leaves queued", logIDLabel)
queuedDupCounter = mf.NewCounter("mysql_queued_dup_leaves", "Number of duplicate leaves queued", logIDLabel)
dequeuedCounter = mf.NewCounter("mysql_dequeued_leaves", "Number of leaves dequeued", logIDLabel)
clearedAllStmtCounter = mf.NewCounter("mysql_cleared_all_prepared_statements", "Number of all prepared statements cleared")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: -> "number of times the prepared-statement cache has been cleared"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -104,6 +104,25 @@ func expandPlaceholderSQL(sql string, num int, first, rest string) string {
return strings.Replace(sql, placeholderSQL, parameters, 1)
}

// clearAllStmt clean up all sql.Stmt in cache
func (m *mySQLTreeStorage) cleanAllStmt() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would clearStmtCache be a clearer name for this func?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@px3303 px3303 requested a review from AlCutter March 15, 2023 12:31
@AlCutter
Copy link
Member

/gcbrun

@AlCutter
Copy link
Member

@px3303 Would you mind adding a small bit of text to the CHANGELOG to capture this? It's an important change which definitely should be highlighted in the next release's set of release notes.

@AlCutter
Copy link
Member

@px3303 Looks like the metric name needs a tweak, might be the "-": Step #14 - "integration_mariadb": panic: descriptor Desc{fqName: "mysql_cleared_prepared-statement_caches", help: "Number of times the prepared-statement cache has been cleared", constLabels: {}, variableLabels: []} is invalid: "mysql_cleared_prepared-statement_caches" is not a valid metric name

Copy link
Contributor

@Martin2112 Martin2112 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel a bit bad that we never got round to this. The way this works here means some errors will surface but it should recover. Alternatively, it could retry on error but I think this code is probably already complex enough and this isn't something that should happen often.

@@ -101,6 +102,7 @@ func createMetrics(mf monitoring.MetricFactory) {
queuedCounter = mf.NewCounter("mysql_queued_leaves", "Number of leaves queued", logIDLabel)
queuedDupCounter = mf.NewCounter("mysql_queued_dup_leaves", "Number of duplicate leaves queued", logIDLabel)
dequeuedCounter = mf.NewCounter("mysql_dequeued_leaves", "Number of leaves dequeued", logIDLabel)
clearedStmtCacheCounter = mf.NewCounter("mysql_cleared_prepared-statement_caches", "Number of times the prepared-statement cache has been cleared")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth noting in the description that this is an unexpected condition / could indicate a problem.

INNER JOIN Subtree
ON Subtree.SubtreeId = x.SubtreeId
AND Subtree.SubtreeRevision = x.MaxRevision
INNER JOIN Subtree
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume these are gofmt changes. Could be done separately but up to you.

@px3303
Copy link
Contributor Author

px3303 commented Mar 17, 2023

@AlCutter @Martin2112 @mhutchinson

I submitted an improved version #2937 , please review it again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants