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

Cancel any row count queries before attempting to cut over #846

Open
wants to merge 4 commits into
base: master
from

Conversation

@ajm188
Copy link
Contributor

@ajm188 ajm188 commented May 18, 2020

Closes #830. Switches from using QueryRow to QueryRowContext, and
stores a context.CancelFunc in the migration context, which is called to
halt any running row count query before beginning the cut over.

Note: I'm 99% sure database/sql does what I think it should do here. I wanted to open this now in case anyone else happens to know off-hand, but in the meantime I'll keep reading through the go stdlib to convince myself this is right.

Update on the above: I smartened up and read the docs instead of the code, which say go-sql-driver does support cancelling queries via contexts

In case this PR introduced Go code changes:

  • contributed code is using same conventions as original code
  • script/cibuild returns with no formatting errors, build errors or unit test errors.
Closes #830. Switches from using `QueryRow` to `QueryRowContext`, and
stores a context.CancelFunc in the migration context, which is called to
halt any running row count query before beginning the cut over.
Copy link
Contributor

@shlomi-noach shlomi-noach left a comment

Thank you for this important fix! To the best of my understanding the termination of the rowcount query is not fully implemented in this PR, see comments inline.

@@ -401,6 +406,10 @@ func (this *Migrator) Migrate() (err error) {
}
this.printStatus(ForcePrintStatusRule)

if this.migrationContext.CountTableRowsCancelFunc != nil {

This comment has been minimized.

default:
// row count query finished. nil out the cancel func, so the main migration thread
// doesn't bother calling it after row copy is done.
this.migrationContext.CountTableRowsCancelFunc = nil

This comment has been minimized.

atomic.StoreInt64(&this.migrationContext.CountingRowsFlag, 1)
defer atomic.StoreInt64(&this.migrationContext.CountingRowsFlag, 0)

log.Infof("As instructed, I'm issuing a SELECT COUNT(*) on the table. This may take a while")

query := fmt.Sprintf(`select /* gh-ost */ count(*) as rows from %s.%s`, sql.EscapeName(this.migrationContext.DatabaseName), sql.EscapeName(this.migrationContext.OriginalTableName))
var rowsEstimate int64
if err := this.db.QueryRow(query).Scan(&rowsEstimate); err != nil {
if err := this.db.QueryRowContext(ctx, query).Scan(&rowsEstimate); err != nil {

This comment has been minimized.

@shlomi-noach

shlomi-noach Jun 28, 2020
Contributor

To the best of my understanding, the go-sql-driver does not actually kill the query when context is cancelled, it is on the user to issue a KILL query. In which case we should first obtain a Connection so that we can get its connection_id, which we can then use to kill it.

This comment has been minimized.

@ajm188

ajm188 Jun 28, 2020
Author Contributor

You're right! I regret this statement 😅 :

Update on the above: I smartened up and read the docs instead of the code, which say go-sql-driver does support cancelling queries via contexts

I think the row count has to be pushed into a goroutine then, so CountTableRows can simultaneously wait on it and on a signal to kill the count query.

ajm188 added 3 commits Jun 28, 2020
* Explicitly grab a connection to run the count, store its connection id
* When the query context is canceled, run a `KILL QUERY ?` on that connection id
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

2 participants
You can’t perform that action at this time.