@@ -49,44 +49,54 @@ func (w *mergeIndexWorker) batchCheckTemporaryUniqueKey(
49
49
}
50
50
51
51
for i , key := range w .originIdxKeys {
52
- if val , found := batchVals [string (key )]; found {
52
+ keyStr := string (key )
53
+ if val , found := batchVals [keyStr ]; found {
53
54
// Found a value in the original index key.
54
- err := checkTempIndexKey (txn , idxRecords [i ], val , w .table )
55
+ matchDeleted , err := checkTempIndexKey (txn , idxRecords [i ], val , w .table )
55
56
if err != nil {
56
57
if kv .ErrKeyExists .Equal (err ) {
57
58
return driver .ExtractKeyExistsErrFromIndex (key , val , w .table .Meta (), w .currentIndex .ID )
58
59
}
59
60
return errors .Trace (err )
60
61
}
62
+ if matchDeleted {
63
+ // Delete from batchVals to prevent false-positive duplicate detection.
64
+ delete (batchVals , keyStr )
65
+ }
61
66
} else if idxRecords [i ].distinct {
62
67
// The keys in w.batchCheckKeys also maybe duplicate,
63
68
// so we need to backfill the not found key into `batchVals` map.
64
- batchVals [string ( key ) ] = idxRecords [i ].vals
69
+ batchVals [keyStr ] = idxRecords [i ].vals
65
70
}
66
71
}
67
72
return nil
68
73
}
69
74
70
- func checkTempIndexKey (txn kv.Transaction , tmpRec * temporaryIndexRecord , originIdxVal []byte , tblInfo table.Table ) error {
75
+ // checkTempIndexKey determines whether there is a duplicated index key entry according to value of temp index.
76
+ // For non-delete temp record, if the index values mismatch, it is duplicated.
77
+ // For delete temp record, we decode the handle from the origin index value and temp index value.
78
+ // - if the handles matche, we can delete the index key.
79
+ // - otherwise, we further check if the row exists in the table.
80
+ func checkTempIndexKey (txn kv.Transaction , tmpRec * temporaryIndexRecord , originIdxVal []byte , tblInfo table.Table ) (matchDelete bool , err error ) {
71
81
if ! tmpRec .delete {
72
82
if tmpRec .distinct && ! bytes .Equal (originIdxVal , tmpRec .vals ) {
73
- return kv .ErrKeyExists
83
+ return false , kv .ErrKeyExists
74
84
}
75
85
// The key has been found in the original index, skip merging it.
76
86
tmpRec .skip = true
77
- return nil
87
+ return false , nil
78
88
}
79
89
// Delete operation.
80
90
distinct := tablecodec .IndexKVIsUnique (originIdxVal )
81
91
if ! distinct {
82
92
// For non-distinct key, it is consist of a null value and the handle.
83
93
// Same as the non-unique indexes, replay the delete operation on non-distinct keys.
84
- return nil
94
+ return false , nil
85
95
}
86
96
// For distinct index key values, prevent deleting an unexpected index KV in original index.
87
97
hdInVal , err := tablecodec .DecodeHandleInUniqueIndexValue (originIdxVal , tblInfo .Meta ().IsCommonHandle )
88
98
if err != nil {
89
- return errors .Trace (err )
99
+ return false , errors .Trace (err )
90
100
}
91
101
if ! tmpRec .handle .Equal (hdInVal ) {
92
102
// The inequality means multiple modifications happened in the same key.
@@ -97,16 +107,16 @@ func checkTempIndexKey(txn kv.Transaction, tmpRec *temporaryIndexRecord, originI
97
107
if kv .IsErrNotFound (err ) {
98
108
// The row is deleted, so we can merge the delete operation to the origin index.
99
109
tmpRec .skip = false
100
- return nil
110
+ return false , nil
101
111
}
102
112
// Unexpected errors.
103
- return errors .Trace (err )
113
+ return false , errors .Trace (err )
104
114
}
105
115
// Don't delete the index key if the row exists.
106
116
tmpRec .skip = true
107
- return nil
117
+ return false , nil
108
118
}
109
- return nil
119
+ return true , nil
110
120
}
111
121
112
122
// temporaryIndexRecord is the record information of an index.
0 commit comments