-
Notifications
You must be signed in to change notification settings - Fork 222
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
memdb: retain old version nodes of ART to satisfy snapshot read #1503
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: you06 <[email protected]>
Signed-off-by: you06 <[email protected]>
Signed-off-by: you06 <[email protected]>
@@ -62,7 +63,8 @@ func (t *ART) SnapshotIterReverse(k, lowerBound []byte) *SnapIter { | |||
Iterator: inner, | |||
cp: t.getSnapshot(), | |||
} | |||
for !it.setValue() && it.valid { | |||
it.tree.allocator.snapshotInc() |
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.
Ditto.
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.
The fix looks OK. I just have some questions:
- In your example, which variable in the iterator is pointing to node-1? Is it
nodes
inbaseIter
? - Why are we only fixing for SnapshotIter? What about the ART Iterator? Is it currently safe in implementation but not guaranteed by design?
- Are there any other inner structure change that could lead to iterator invalidation, other than the free nodes? I don't see other cases at first glance. Have you verified this as well?
Signed-off-by: you06 <[email protected]>
Yes,
The For
Yes, such usage in TiDB is out of my expectation. For long-term, we may deprecate the
I don't see other cases also. |
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.
Rest LGTM
h := db.Staging() | ||
defer db.Release(h) | ||
|
||
iter := db.SnapshotIter([]byte{0, 0}, []byte{0, 255}) |
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 to Close
the iter
following the requirement usage pattern in test.
[LGTM Timeline notifier]Timeline:
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: cfzjywxk The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@you06 |
ref pingcap/tidb#57425
Changes
The snapshot iterators always read from a snapshot of MemBuffer, but writes between
Next
calls can alter the structure of ART (see the "but explanation" section for details), potentially causing the snapshot iterator to read incorrect results.This PR introduces a counter for active snapshots. When the counter is greater than 0, it indicates that old versions need to be retained for snapshot reads. In such cases, we store freed nodes in unused slices and delay the actual free operation to prevent them from being reused.
Add a counter for
Bug explanation
1. The snapshot iterator scans to node (click to expand the figure)
2. The node 1 grows to larger capacity (node 3) due to coming writes, and the node1 is reused (click to expand the figure)
Next
call.