-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
transaction: lock unique key for delete operation (#19220) #20705
transaction: lock unique key for delete operation (#19220) #20705
Conversation
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>
/run-all-tests |
Signed-off-by: you06 <you1474600@gmail.com>
Signed-off-by: you06 <you1474600@gmail.com>
Signed-off-by: you06 <you1474600@gmail.com>
/run-all-tests |
/run-all-tests |
Signed-off-by: you06 <you1474600@gmail.com>
Signed-off-by: you06 <you1474600@gmail.com>
/run-all-tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
session/txn.go
Outdated
@@ -428,7 +434,7 @@ func (st *TxnState) KeysNeedToLock() ([]kv.Key, error) { | |||
} | |||
keys := make([]kv.Key, 0, st.stmtBufLen()) | |||
if err := kv.WalkMemBuffer(st.stmtBuf, func(k kv.Key, v []byte) error { | |||
if !keyNeedToLock(k, v) { | |||
if !st.stmtBuf.IfKeyNeedLock(k) && !keyNeedToLock(k, v) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stmtBuf
shared the same needLockKey
map with txnBuf
. After RollbackStmt
the new keys added into stmtBuf.needLockKey
will not be removed.
But it will not cause correctness issue:
- If the key still existed after retry, it will be locked;
- Otherwise, it will not be collected at here.
Maybe it will lock more keys than need in some scenarios? But this way seems much simpler than implementing a rollbackable needLockKey
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is MemBuffer.Discard
called when rollback? Seems we can move needLockKey
into Sandbox
, then we can rollback it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. I have already done something simliar as a part of #18372.
Lines 32 to 71 in 761a961
type KeyFlags uint8 | |
const ( | |
flagPresumeKeyNotExists KeyFlags = 1 << iota | |
// flagTouched is a internal flag to help `Mark` operation. | |
// The default value of `KeyFlags` is 0 and the flags returned by any operation will set `flagTouched`. | |
// When merge two flags, if the newer one haven't set the `flagTouched`, the newer value will be ignored. | |
flagTouched KeyFlags = 0x80 | |
) | |
// MarkPresumeKeyNotExists marks the existence of the associated key is checked lazily. | |
func (m KeyFlags) MarkPresumeKeyNotExists() KeyFlags { | |
return (m | flagPresumeKeyNotExists) | flagTouched | |
} | |
// UnmarkPresumeKeyNotExists reverts MarkPresumeKeyNotExists. | |
func (m KeyFlags) UnmarkPresumeKeyNotExists() KeyFlags { | |
return (m & ^flagPresumeKeyNotExists) | flagTouched | |
} | |
// HasPresumeKeyNotExists retruns whether the associated key use lazy check. | |
func (m KeyFlags) HasPresumeKeyNotExists() bool { | |
return m&flagPresumeKeyNotExists != 0 | |
} | |
func (m KeyFlags) isTouched() bool { | |
return m&flagTouched != 0 | |
} | |
// Merge used to merge two KeyFlags. | |
func (m KeyFlags) Merge(old KeyFlags) KeyFlags { | |
// Only consider flagPresumeKeyNotExists in merge operation for now. | |
// We should always respect to the older setting, | |
// the delete operation will overwrite flags in root tree instead of invoke merge. | |
if old.isTouched() { | |
return old | |
} | |
return m | |
} |
Line 109 in 761a961
x.flags = flags |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try it following your implementation in the master.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better not to share objects in stmtbuf
with txnBuf
, we need make sure no unwanted keys get locked, or there will be other incompatbile behaviours issues.
session/tidb_test.go
Outdated
@@ -188,7 +188,7 @@ func (s *testMainSuite) TestKeysNeedLock(c *C) { | |||
need bool | |||
}{ | |||
{rowKey, rowVal, true}, | |||
{rowKey, deleteVal, true}, | |||
{rowKey, deleteVal, false}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Old deleted row keys need to be locked.
@@ -214,6 +214,15 @@ func (txn *tikvTxn) Delete(k kv.Key) error { | |||
return txn.us.Delete(k) | |||
} | |||
|
|||
func (txn *tikvTxn) DeleteWithNeedLock(k kv.Key) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems we will not use this path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd better write this method explicitly, otherwise, the txn.dirty
may incorrect.
session/txn.go
Outdated
@@ -428,7 +434,7 @@ func (st *TxnState) KeysNeedToLock() ([]kv.Key, error) { | |||
} | |||
keys := make([]kv.Key, 0, st.stmtBufLen()) | |||
if err := kv.WalkMemBuffer(st.stmtBuf, func(k kv.Key, v []byte) error { | |||
if !keyNeedToLock(k, v) { | |||
if !st.stmtBuf.IfKeyNeedLock(k) && !keyNeedToLock(k, v) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better not to share objects in stmtbuf
with txnBuf
, we need make sure no unwanted keys get locked, or there will be other incompatbile behaviours issues.
executor/delete_test.go
Outdated
tk2.MustExec(t.tk2Stmt) | ||
doneCh <- struct{}{} | ||
}() | ||
time.Sleep(20 * time.Millisecond) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit short, may not be stable.
Signed-off-by: you06 <you1474600@gmail.com>
kv/memdb_buffer.go
Outdated
func (m *memDbBuffer) IfKeyNeedLock(k Key) bool { | ||
_, ok := m.needLockKey[k.String()] | ||
return ok | ||
//m.needLockKey[k.String()] = struct{}{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delete this line.
Signed-off-by: you06 <you1474600@gmail.com>
LGTM |
/run-all-tests |
LGTM |
kv/memdb/memdb.go
Outdated
@@ -475,6 +508,7 @@ func (ms *mergeState) calculateRecomputeHeight(key []byte, sb *Sandbox) int { | |||
} | |||
|
|||
type nodeHeader struct { | |||
flags KeyFlags | |||
height uint16 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we can reduce height to uint8, it'll be more memory friendly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lines 503 to 508 in 761a961
type nodeHeader struct { | |
height uint8 | |
flags KeyFlags | |
keyLen uint16 | |
valLen uint32 | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afraid of the overflow risk.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never overflow. The upper bound is
Line 25 in 761a961
maxHeight = 16 |
Signed-off-by: you06 <you1474600@gmail.com>
/run-all-tests |
@cfzjywxk I think this PR can be merged now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
What's wrong with the action :( |
/merge |
Your auto merge job has been accepted, waiting for:
|
/run-all-tests |
cherry-pick #19220 to release-4.0
What problem does this PR solve?
Issue Number: close #18798, close #20535
Problem Summary:
What is changed and how it works?
What's Changed:
Lock index for delete operation, so that some transactions can be serialized.
Related changes
Check List
Tests
Release note