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

ddl: fix a bug that we miss adding last handle index in some case. #7142

Merged
merged 15 commits into from
Jul 25, 2018
Merged

ddl: fix a bug that we miss adding last handle index in some case. #7142

merged 15 commits into from
Jul 25, 2018

Conversation

winkyao
Copy link
Contributor

@winkyao winkyao commented Jul 24, 2018

What have you changed? (mandatory)

This PR fixes a bug that, when the last remains indices count is just defaultTaskHandleCnt+1, we do not use handleRange.endIncluded outside, so we may miss adding the last index.

In this case, we break fetchRowColVals by len(w.idxRecords) >= w.batchCnt, then the handleOutOfRange is false, so the nextHandle = idxRecords[len(idxRecords)-1].handle + 1, it is exactly equal to endHandle, so in handleBackfillTask, we break the loop byfinishTask = handleRange.startHandle >= handleRange.endHandle mistakenly.

master branch will fail the newly added test case with:

db_integration_test.go:135:
    tk.MustExec("admin check index t b")
/Users/wink/go_dir/src/github.com/pingcap/tidb/util/testkit/testkit.go:160:
    tk.c.Assert(err, check.IsNil, check.Commentf("sql:%s, %v, error stack %v", sql, args, errors.ErrorStack(err)))
... value *errors.Err = &errors.Err{message:"", cause:(*errors.Err)(0xc420877130), previous:(*errors.Err)(0xc4208773b0), file:"/Users/wink/go_dir/src/github.com/pingcap/tidb/util/testkit/testkit.go", line:134} ("table count 129 != index(b) count 128")
... sql:admin check index t b, [], error stack /Users/wink/go_dir/src/github.com/pingcap/tidb/util/admin/admin.go:204: table count 129 != index(b) count 128
/Users/wink/go_dir/src/github.com/pingcap/tidb/executor/executor.go:452:
/Users/wink/go_dir/src/github.com/pingcap/tidb/executor/adapter.go:269:
/Users/wink/go_dir/src/github.com/pingcap/tidb/session/tidb.go:189:
/Users/wink/go_dir/src/github.com/pingcap/tidb/session/session.go:745:
/Users/wink/go_dir/src/github.com/pingcap/tidb/session/session.go:808:
/Users/wink/go_dir/src/github.com/pingcap/tidb/session/session.go:757:
/Users/wink/go_dir/src/github.com/pingcap/tidb/util/testkit/testkit.go:134:

What is the type of the changes? (mandatory)

  • Bug fix (non-breaking change which fixes an issue)

How has this PR been tested? (mandatory)

ut

Does this PR affect documentation (docs/docs-cn) update? (mandatory)

NO

Does this PR affect tidb-ansible update? (mandatory)

NO

Does this PR need to be added to the release notes? (mandatory)

YES

fix a bug that we miss adding last handle index in some case.

Refer to a related PR or issue link (optional)

Benchmark result if necessary (optional)

Add a few positive/negative examples (optional)

@winkyao winkyao added priority/P1 The issue has P1 priority. type/bugfix This PR fixes a bug. priority/release-blocker This issue blocks a release. Please solve it ASAP. component/DDL-need-LGT3 release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Jul 24, 2018
@winkyao
Copy link
Contributor Author

winkyao commented Jul 24, 2018

/run-all-tests

ddl/index.go Outdated
@@ -678,7 +684,19 @@ func (w *addIndexWorker) handleBackfillTask(d *ddlCtx, task *reorgIndexTask) *ad
}

handleRange.startHandle = nextHandle
if handleRange.startHandle >= handleRange.endHandle {
finishTask := false
// if nextHandle is math.Int64, we can only use handleOutOfRange to indicates the nexHandle is handled.
Copy link
Contributor

Choose a reason for hiding this comment

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

s/if/If
s/to indicates/to indicate
s/nexHandle/nextHandle

ddl/index.go Outdated
@@ -678,7 +684,19 @@ func (w *addIndexWorker) handleBackfillTask(d *ddlCtx, task *reorgIndexTask) *ad
}

handleRange.startHandle = nextHandle
if handleRange.startHandle >= handleRange.endHandle {
finishTask := false
Copy link
Contributor

Choose a reason for hiding this comment

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

We can move it to line 692, where it is used.

ddl/index.go Outdated
if handleRange.startHandle >= handleRange.endHandle {
finishTask := false
// if nextHandle is math.Int64, we can only use handleOutOfRange to indicates the nexHandle is handled.
if handleOutOfRange && nextHandle == handleRange.endHandle {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is handleOutOfRange implies nextHandle == handleRange.endHandle?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no. handleOutOfRange just mean current batch is handled out of range.

@winkyao
Copy link
Contributor Author

winkyao commented Jul 24, 2018

@zimulala @lamxTyler PTAL

Copy link
Contributor

@crazycs520 crazycs520 left a comment

Choose a reason for hiding this comment

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

LGTM

ddl/index.go Outdated
@@ -637,6 +642,7 @@ func (w *addIndexWorker) backfillIndexInTxn(handleRange reorgIndexTask) (nextHan

if handleOutOfRange || len(idxRecords) == 0 {
nextHandle = handleRange.endHandle
handleOutOfRange = true
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused why handleOutOfRange = true when len(idxRecords) == 0

Copy link
Contributor

Choose a reason for hiding this comment

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

And nextHandle should not be handleRange.endHandle when handleRange.exclude is false

@winkyao
Copy link
Contributor Author

winkyao commented Jul 24, 2018

/run-all-tests

@winkyao
Copy link
Contributor Author

winkyao commented Jul 25, 2018

/run-all-tests

@winkyao winkyao added the status/LGT1 Indicates that a PR has LGTM 1. label Jul 25, 2018
@winkyao
Copy link
Contributor Author

winkyao commented Jul 25, 2018

/run-integration-common-test -tidb-test=pr/592

@winkyao
Copy link
Contributor Author

winkyao commented Jul 25, 2018

/run-common-test -tidb-test=pr/592

@tiancaiamao
Copy link
Contributor

PTAL @shenli

Copy link
Contributor

@crazycs520 crazycs520 left a comment

Choose a reason for hiding this comment

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

LGTM

ddl/index.go Outdated
// TODO: use tableScan to prune columns.
w.idxRecords = w.idxRecords[:0]
startTime := time.Now()

// handleOutOfRange means that the added handle is out of taskRange.endHandle.
Copy link
Member

Choose a reason for hiding this comment

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

Can we rename the handleOutOfRange to taskDone ?

ddl/index.go Outdated
@@ -549,10 +551,26 @@ func (w *addIndexWorker) getIndexRecord(handle int64, recordKey []byte, rawRecor
return idxRecord, nil
}

func (w *addIndexWorker) fetchRowColVals(txn kv.Transaction, taskRange reorgIndexTask) ([]*indexRecord, bool, error) {
func (w *addIndexWorker) getNextHandle(taskRange reorgIndexTask, handleOutOfRange bool) (nextHandle int64) {
nextHandle = taskRange.startHandle
Copy link
Member

Choose a reason for hiding this comment

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

This line is useless.

Copy link
Member

Choose a reason for hiding this comment

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

if !taskDone {
// The task is not done. So we need to pick the last processed entry's handle and plus one.
return w.idxRecords[len(w.idxRecords)-1].handle + 1
}

// The task is done. So we need to choose a handle out side this range. There are some corner cases should be considered:
// - The end of task range is MaxInt64.
// - The end of the task is excluded in the range.
if taskRange.endHandle == math.MaxInt64 || !taskRange.endIncluded {
return taskRange.endHandle
}
return taskRange.endHandle + 1

ddl/index.go Outdated
return nextHandle
}

func (w *addIndexWorker) fetchRowColVals(txn kv.Transaction, taskRange reorgIndexTask) ([]*indexRecord, int64, bool, error) {
Copy link
Member

Choose a reason for hiding this comment

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

Add comment for the newly added return value.

zimulala
zimulala previously approved these changes Jul 25, 2018
Copy link
Contributor

@zimulala zimulala left a comment

Choose a reason for hiding this comment

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

LGTM

@winkyao
Copy link
Contributor Author

winkyao commented Jul 25, 2018

@shenli PTAL

@shenli
Copy link
Member

shenli commented Jul 25, 2018

LGTM

@winkyao winkyao added status/LGT2 Indicates that a PR has LGTM 2. status/LGT3 The PR has already had 3 LGTM. and removed status/LGT1 Indicates that a PR has LGTM 1. status/LGT2 Indicates that a PR has LGTM 2. labels Jul 25, 2018
shenli
shenli previously approved these changes Jul 25, 2018
@CaitinChen
Copy link
Contributor

Here is a suggestion for your PR description:

This PR fixes a bug that when the last remained index count is just defaultTaskHandleCnt+1, the last index may not be added because the handleRange.endIncluded attribute is not judged in the handleBackfillTask function (the caller of fetchRowColVals).

In this case, fetchRowColVals is broken by len(w.idxRecords) >= w.batchCnt, and then handleOutOfRange will be false and nextHandle = idxRecords[len(idxRecords)-1].handle + 1. The nextHandle value will be exactly equal to the endHandle value. Thus in handleBackfillTask, the loop is mistakenly broken by finishTask = handleRange.startHandle >= handleRange.endHandle.

The newly added test case will fail in the master branch:

db_integration_test.go:135:
    tk.MustExec("admin check index t b")
/Users/wink/go_dir/src/github.com/pingcap/tidb/util/testkit/testkit.go:160:
    tk.c.Assert(err, check.IsNil, check.Commentf("sql:%s, %v, error stack %v", sql, args, errors.ErrorStack(err)))
... value *errors.Err = &errors.Err{message:"", cause:(*errors.Err)(0xc420877130), previous:(*errors.Err)(0xc4208773b0), file:"/Users/wink/go_dir/src/github.com/pingcap/tidb/util/testkit/testkit.go", line:134} ("table count 129 != index(b) count 128")
... sql:admin check index t b, [], error stack /Users/wink/go_dir/src/github.com/pingcap/tidb/util/admin/admin.go:204: table count 129 != index(b) count 128
/Users/wink/go_dir/src/github.com/pingcap/tidb/executor/executor.go:452:
/Users/wink/go_dir/src/github.com/pingcap/tidb/executor/adapter.go:269:
/Users/wink/go_dir/src/github.com/pingcap/tidb/session/tidb.go:189:
/Users/wink/go_dir/src/github.com/pingcap/tidb/session/session.go:745:
/Users/wink/go_dir/src/github.com/pingcap/tidb/session/session.go:808:
/Users/wink/go_dir/src/github.com/pingcap/tidb/session/session.go:757:
/Users/wink/go_dir/src/github.com/pingcap/tidb/util/testkit/testkit.go:134:

@winkyao
Copy link
Contributor Author

winkyao commented Jul 25, 2018

/run-all-tests

@winkyao
Copy link
Contributor Author

winkyao commented Jul 25, 2018

@CaitinChen Thanks for your valuable suggestions.

ddl/index.go Outdated
// getNextHandle gets next handle of entry that we are going to process.
func (w *addIndexWorker) getNextHandle(taskRange reorgIndexTask, taskDone bool) (nextHandle int64) {
if !taskDone {
// The task is not done. So we need to pick the last processed entry's handle and plus one.
Copy link
Contributor

Choose a reason for hiding this comment

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

The task is not done. So we need to pick the last processed entry's handle and add one.

Note: "plus" is a prep, not a verb.

ddl/index.go Outdated
return w.idxRecords[len(w.idxRecords)-1].handle + 1
}

// The task is done. So we need to choose a handle out side this range.
Copy link
Contributor

Choose a reason for hiding this comment

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

The task is done. So we need to choose a handle outside this range.

ddl/index.go Outdated
}

// The task is done. So we need to choose a handle out side this range.
// There are some corner cases should be considered:
Copy link
Contributor

Choose a reason for hiding this comment

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

Some corner cases should be considered:

Copy link
Contributor

Choose a reason for hiding this comment

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

You can also use "There are some corner cases which should be considered:"

@CaitinChen
Copy link
Contributor

@winkyao My pleasure. ^_^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority/release-blocker This issue blocks a release. Please solve it ASAP. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/sql-infra SIG: SQL Infra status/LGT3 The PR has already had 3 LGTM. type/bugfix This PR fixes a bug.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants