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

[DNM] *: add some injections to simulate mutation errors #30666

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a025a6e
check handle consistency
ekexium Sep 28, 2021
f8d3c6a
refactor according to comments
ekexium Oct 8, 2021
ada1f02
refactor according to comments
ekexium Oct 11, 2021
9a23b8f
verify the effectiveness against 24029
ekexium Oct 14, 2021
5c3095e
simplest injections
ekexium Oct 27, 2021
2874f72
assert that the number of index insertions must be a multiple of row …
ekexium Nov 3, 2021
322059e
Merge branch 'check-in-txn' into verify-effectiveness
ekexium Nov 3, 2021
e9fc0de
assert that the number of index insertions must be a multiple of row …
ekexium Nov 3, 2021
b923935
Merge branch 'check-in-txn' into verify-effectiveness
ekexium Nov 3, 2021
4012de4
count for each table
ekexium Nov 4, 2021
f5ed0ae
Merge branch 'check-in-txn' into verify-effectiveness
ekexium Nov 4, 2021
403ced7
Auto stash before merge of "verify-effectiveness" and "check-in-txn"
ekexium Nov 4, 2021
e60abeb
comment CheckTxnConsistency
ekexium Nov 4, 2021
691b50c
add a test for check-in-txn
ekexium Nov 4, 2021
a83c747
only check when InTxn is true
ekexium Nov 4, 2021
dd26e84
Merge branch 'check-in-txn' into verify-effectiveness
ekexium Nov 4, 2021
d027e89
replace dependency
ekexium Nov 16, 2021
dafe8a9
add TestOncall4058
ekexium Nov 18, 2021
d4bf4fc
Merge branch 'ft-data-inconsistency' into verify-effectiveness
ekexium Dec 13, 2021
a9f1cc2
fix the merge
ekexium Dec 13, 2021
91c8c51
remove unnecessary tests and debug code
ekexium Dec 13, 2021
cc7c284
move the injection out of the mutation checker
ekexium Dec 14, 2021
b17b8b8
remove tests
ekexium Dec 15, 2021
fa1dc52
Merge branch 'ft-data-inconsistency' into verify-effectiveness
ekexium Dec 21, 2021
0ff10f9
remove index count check
ekexium Dec 22, 2021
6049add
remove randomness
ekexium Dec 24, 2021
b226ce3
Merge branch 'ft-data-inconsistency' into verify-effectiveness
ekexium Jan 14, 2022
74a51e7
fix imports
ekexium Jan 14, 2022
91d6658
don't skip deletions if possible
ekexium Jan 17, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions kv/kv.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ type MemBuffer interface {

// Size returns sum of keys and values length.
Size() int

// RemoveFromBuffer removes the entry from the buffer. It's used for testing.
RemoveFromBuffer(Key)
}

// LockCtx contains information for LockKeys method.
Expand Down
32 changes: 16 additions & 16 deletions session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,6 @@ import (
"github.com/pingcap/errors"
"github.com/pingcap/failpoint"
"github.com/pingcap/kvproto/pkg/kvrpcpb"
"github.com/pingcap/tidb/parser"
"github.com/pingcap/tidb/parser/ast"
"github.com/pingcap/tidb/parser/auth"
"github.com/pingcap/tidb/parser/charset"
"github.com/pingcap/tidb/parser/model"
"github.com/pingcap/tidb/parser/mysql"
"github.com/pingcap/tidb/parser/terror"
"github.com/pingcap/tidb/sessiontxn"
"github.com/pingcap/tidb/store/driver/txn"
"github.com/pingcap/tidb/table/tables"
"github.com/pingcap/tidb/table/temptable"
"github.com/pingcap/tidb/util/topsql"
topsqlstate "github.com/pingcap/tidb/util/topsql/state"
"github.com/pingcap/tipb/go-binlog"
"go.uber.org/zap"

"github.com/pingcap/tidb/bindinfo"
"github.com/pingcap/tidb/config"
"github.com/pingcap/tidb/ddl"
Expand All @@ -65,6 +49,13 @@ import (
"github.com/pingcap/tidb/meta"
"github.com/pingcap/tidb/metrics"
"github.com/pingcap/tidb/owner"
"github.com/pingcap/tidb/parser"
"github.com/pingcap/tidb/parser/ast"
"github.com/pingcap/tidb/parser/auth"
"github.com/pingcap/tidb/parser/charset"
"github.com/pingcap/tidb/parser/model"
"github.com/pingcap/tidb/parser/mysql"
"github.com/pingcap/tidb/parser/terror"
"github.com/pingcap/tidb/planner"
plannercore "github.com/pingcap/tidb/planner/core"
"github.com/pingcap/tidb/plugin"
Expand All @@ -75,9 +66,13 @@ import (
"github.com/pingcap/tidb/sessionctx/binloginfo"
"github.com/pingcap/tidb/sessionctx/stmtctx"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/sessiontxn"
"github.com/pingcap/tidb/statistics"
"github.com/pingcap/tidb/statistics/handle"
storeerr "github.com/pingcap/tidb/store/driver/error"
"github.com/pingcap/tidb/store/driver/txn"
"github.com/pingcap/tidb/table/tables"
"github.com/pingcap/tidb/table/temptable"
"github.com/pingcap/tidb/tablecodec"
"github.com/pingcap/tidb/telemetry"
"github.com/pingcap/tidb/types"
Expand All @@ -92,10 +87,14 @@ import (
"github.com/pingcap/tidb/util/sqlexec"
"github.com/pingcap/tidb/util/tableutil"
"github.com/pingcap/tidb/util/timeutil"
"github.com/pingcap/tidb/util/topsql"
topsqlstate "github.com/pingcap/tidb/util/topsql/state"
"github.com/pingcap/tipb/go-binlog"
tikvstore "github.com/tikv/client-go/v2/kv"
"github.com/tikv/client-go/v2/oracle"
"github.com/tikv/client-go/v2/tikv"
tikvutil "github.com/tikv/client-go/v2/util"
"go.uber.org/zap"
)

var (
Expand Down Expand Up @@ -679,6 +678,7 @@ func (c *cachedTableRenewLease) commitTSCheck(commitTS uint64) bool {

func (s *session) commitTxnWithTemporaryData(ctx context.Context, txn kv.Transaction) error {
sessVars := s.sessionVars

txnTempTables := sessVars.TxnCtx.TemporaryTables
if len(txnTempTables) == 0 {
return txn.Commit(ctx)
Expand Down
4 changes: 4 additions & 0 deletions store/driver/txn/unionstore_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func (m *memBuffer) Delete(k kv.Key) error {
return m.MemDB.Delete(k)
}

func (m *memBuffer) RemoveFromBuffer(k kv.Key) {
m.MemDB.RemoveFromBuffer(k)
}

func (m *memBuffer) DeleteWithFlags(k kv.Key, ops ...kv.FlagsOp) error {
err := m.MemDB.DeleteWithFlags(k, getTiKVFlagsOps(ops)...)
return derr.ToTiDBErr(err)
Expand Down
101 changes: 101 additions & 0 deletions table/tables/mutation_checker.go
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
package tables

import (
"fmt"
"strings"

"github.com/pingcap/errors"
"github.com/pingcap/failpoint"
"github.com/pingcap/tidb/errno"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/parser/model"
Expand Down Expand Up @@ -381,3 +385,100 @@ func getOrBuildColumnMaps(
}
return maps
}

// only used in tests
// commands is a comma separated string, each representing a type of corruptions to the mutations
// The injection depends on actual encoding rules.
func corruptMutations(t *TableCommon, txn kv.Transaction, sh kv.StagingHandle, cmds string) error {
commands := strings.Split(cmds, ",")
memBuffer := txn.GetMemBuffer()

indexMutations, _, err := collectTableMutationsFromBufferStage(t, memBuffer, sh)
if err != nil {
return errors.Trace(err)
}

for _, cmd := range commands {
switch cmd {
case "extraIndex":
// an extra index mutation
// TODO: distinguish which part to corrupt, value or handle
{
if len(indexMutations) == 0 {
continue
}
indexMutation := indexMutations[0]
key := make([]byte, len(indexMutation.key))
copy(key, indexMutation.key)
key[len(key)-1] += 1
if len(indexMutation.value) == 0 {
if err := memBuffer.Delete(key); err != nil {
return errors.Trace(err)
}
} else {
if err := memBuffer.Set(key, indexMutation.value); err != nil {
return errors.Trace(err)
}
}
}
//case "extraIndexByHandle":
// {
// }
case "missingIndex":
// an index mutation is missing
// "missIndex" should be placed in front of "extraIndex"es,
// in case it removes the mutation that was just added
{
indexMutation := indexMutations[0]
memBuffer.RemoveFromBuffer(indexMutation.key)
}
case "corruptIndexKey":
// a corrupted index mutation.
// TODO: distinguish which part is corrupted, value or handle
{
indexMutation := indexMutations[0]
key := indexMutation.key
memBuffer.RemoveFromBuffer(key)
key[len(key)-1] += 1
if err := memBuffer.Set(key, indexMutation.value); err != nil {
return errors.Trace(err)
}
}
//case "corruptIndexKeyByHandle":
// {
// }
case "corruptIndexValue":
// TODO: distinguish which part to corrupt, int handle, common handle, or restored data?
// It doesn't make much sense to always corrupt the last byte
{
if len(indexMutations) == 0 {
continue
}
indexMutation := indexMutations[0]
value := indexMutation.value
if len(value) > 0 {
value[len(value)-1] += 1
}
if err := memBuffer.Set(indexMutation.key, value); err != nil {
return errors.Trace(err)
}
}
//case "corruptIndexValueCommonHandle":
// {
// }
//case "missIndexValueRestoredData":
// {
// }
default:
return errors.New(fmt.Sprintf("unknown command to corrupt mutation: %s", cmd))
}
}
return nil
}

func injectMutationError(t *TableCommon, txn kv.Transaction, sh kv.StagingHandle) error {
failpoint.Inject("corruptMutations", func(commands failpoint.Value) {
failpoint.Return(corruptMutations(t, txn, sh, commands.(string)))
})
return nil
}
11 changes: 11 additions & 0 deletions table/tables/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,11 +446,16 @@ func (t *TableCommon) UpdateRecord(ctx context.Context, sctx sessionctx.Context,
return err
}


if err = injectMutationError(t, txn, sh); err != nil {
return err
}
if sessVars.EnableMutationChecker {
if err = CheckDataConsistency(txn, sessVars, t, newData, oldData, memBuffer, sh); err != nil {
return errors.Trace(err)
}
}

memBuffer.Release(sh)
if shouldWriteBinlog(sctx, t.meta) {
if !t.meta.PKIsHandle && !t.meta.IsCommonHandle {
Expand Down Expand Up @@ -886,6 +891,9 @@ func (t *TableCommon) AddRecord(sctx sessionctx.Context, r []types.Datum, opts .
return h, err
}

if err = injectMutationError(t, txn, sh); err != nil {
return nil, err
}
if sessVars.EnableMutationChecker {
if err = CheckDataConsistency(txn, sessVars, t, r, nil, memBuffer, sh); err != nil {
return nil, errors.Trace(err)
Expand Down Expand Up @@ -1146,6 +1154,9 @@ func (t *TableCommon) RemoveRecord(ctx sessionctx.Context, h kv.Handle, r []type

sessVars := ctx.GetSessionVars()
sc := sessVars.StmtCtx
if err = injectMutationError(t, txn, sh); err != nil {
return err
}
if sessVars.EnableMutationChecker {
if err = CheckDataConsistency(txn, sessVars, t, nil, r, memBuffer, sh); err != nil {
return errors.Trace(err)
Expand Down