kvstorage: add WAG truncation infrastructure#167533
Conversation
|
😎 Merged successfully - details. |
66d1a39 to
7755a41
Compare
7755a41 to
0b8c355
Compare
0b8c355 to
7150474
Compare
pav-kv
left a comment
There was a problem hiding this comment.
A few quick comments. Will take a closer look tomorrow.
| return truncationResult{}, err | ||
| } | ||
| if deleted == 0 { | ||
| return truncationResult{outcome: TruncatedNone}, nil |
There was a problem hiding this comment.
Is there a difference between TruncatedNone with seen == deleted == 0 and seen == 1 && deleted == 0?
Could you outline for my information how this enum result is going to be used? Alternatively, don't introduce this for now, add later in the PR that would be using it. I'm assuming this would be mainly for the online truncation?
There was a problem hiding this comment.
This was assuming that we will be able to remove all WAG nodes in one shot. My idea was that we could use to perform some assertions. For example, at engine startup, we expect ALL wag nodes to be deleted. But now that we are going to limit the number of WAG nodes that can be deleted in one go, I don't think this field helps much.
There was a problem hiding this comment.
I see. For this assertion, seems like seen == deleted == 0 should be counted as "all" rather than "none", correct? Maybe move the if deleted == seen check up? Meaning an empty WAG is fully applied by definition.
Possibly, the None case is not interesting. We just want to know if the WAG is fully applied or not?
- the startup code cares about WAG being fully applied (not necessarily truncated, btw; maybe in the future we may want to keep it around for a bit, for debuggability)
- the runtime truncation might use this as an optimization to know if it should ignore flushes. Though it's quite possible that it will be implemented in some other way in the end, due to concurrency/gaps/etc. E.g. WAG can be empty but some writes already queued up via the
Seq. More likely we would be watching the last deleted WAG index vsSeqindex for that sort of signal.
There was a problem hiding this comment.
I removed that logic and I am just returning a boolean to say whether a deletion happened or not. The startup truncation assertion can be done without this piece.
And for the periodic truncations, I am thinking of this signal:
- Have a variable that contains the last WAG index that was successfully deleted.
- When we recieve a signal from the state engine that there was a flush, check if the last given seq number is higher than the last deleted WAG node. If not (they are equal), there is no way that there is any WAG node to even check.
- When we run a periodic truncation, we can start from the index right after the last successfully truncated WAG node index. This way we don't need to go through previously deleted WAG nodes.
iskettaneh
left a comment
There was a problem hiding this comment.
@iskettaneh made 1 comment.
Reviewable status:complete! 0 of 0 LGTMs obtained (waiting on pav-kv).
| return truncationResult{}, err | ||
| } | ||
| if deleted == 0 { | ||
| return truncationResult{outcome: TruncatedNone}, nil |
There was a problem hiding this comment.
This was assuming that we will be able to remove all WAG nodes in one shot. My idea was that we could use to perform some assertions. For example, at engine startup, we expect ALL wag nodes to be deleted. But now that we are going to limit the number of WAG nodes that can be deleted in one go, I don't think this field helps much.
7150474 to
f006510
Compare
iskettaneh
left a comment
There was a problem hiding this comment.
@iskettaneh made 2 comments.
Reviewable status:complete! 0 of 0 LGTMs obtained (waiting on pav-kv).
| return truncationResult{}, err | ||
| } | ||
| if deleted == 0 { | ||
| return truncationResult{outcome: TruncatedNone}, nil |
There was a problem hiding this comment.
I see. For this assertion, seems like seen == deleted == 0 should be counted as "all" rather than "none", correct? Maybe move the if deleted == seen check up? Meaning an empty WAG is fully applied by definition.
Possibly, the None case is not interesting. We just want to know if the WAG is fully applied or not?
- the startup code cares about WAG being fully applied (not necessarily truncated, btw; maybe in the future we may want to keep it around for a bit, for debuggability)
- the runtime truncation might use this as an optimization to know if it should ignore flushes. Though it's quite possible that it will be implemented in some other way in the end, due to concurrency/gaps/etc. E.g. WAG can be empty but some writes already queued up via the
Seq. More likely we would be watching the last deleted WAG index vsSeqindex for that sort of signal.
f006510 to
d3de7ff
Compare
iskettaneh
left a comment
There was a problem hiding this comment.
@iskettaneh made 16 comments and resolved 2 discussions.
Reviewable status:complete! 0 of 0 LGTMs obtained (waiting on pav-kv).
| return truncationResult{}, err | ||
| } | ||
| if deleted == 0 { | ||
| return truncationResult{outcome: TruncatedNone}, nil |
There was a problem hiding this comment.
I removed that logic and I am just returning a boolean to say whether a deletion happened or not. The startup truncation assertion can be done without this piece.
And for the periodic truncations, I am thinking of this signal:
- Have a variable that contains the last WAG index that was successfully deleted.
- When we recieve a signal from the state engine that there was a flush, check if the last given seq number is higher than the last deleted WAG node. If not (they are equal), there is no way that there is any WAG node to even check.
- When we run a periodic truncation, we can start from the index right after the last successfully truncated WAG node index. This way we don't need to go through previously deleted WAG nodes.
pav-kv
left a comment
There was a problem hiding this comment.
Looks great, thanks for the cleanups. Probably good to merge after rebasing on Mira's PR, I'll review it soon.
| sl := MakeStateLoader(rangeID) | ||
| prefix := sl.RaftLogPrefix() |
There was a problem hiding this comment.
nit: sl is used only once. Simply use keys.RaftLogPrefix(rangeID) instead?
d3de7ff to
8108b23
Compare
iskettaneh
left a comment
There was a problem hiding this comment.
@iskettaneh made 4 comments and resolved 5 discussions.
Reviewable status:complete! 0 of 0 LGTMs obtained (waiting on pav-kv).
This PR adds the infrastructure that will be used to truncating WAG nodes. It will be used in two places: 1) Truncating all WAG nodes on startup, and 2) Periodically truncating durably applied WAG nodes. A lot of functions are similar to WAG replay, and there are TODOs to reconcile the functions between WAG replay and truncation. There is also some work left for clearing the Raft state, and deleting sideloaded files. Release note: None Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
When deleting a WAG node that has the events destroy or subsume, we also need to delete the raft log (up until and including the addr.index), and any sideloaded files that are part of that raft log prefix. We do this because when a replica delete or subsume is applied, we cannot just yet delete the replica state (log and sideloaded files) because we might crash before the state engine has flushed, and we might need the raft log to replay the event. Release note: None Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
8108b23 to
f121734
Compare
|
TFTR! /trunk merge |
This PR adds the infrastructure that will be used to truncating WAG
nodes. It will be used in two places: 1) Truncating all WAG nodes on
startup, and 2) Periodically truncating durably applied WAG nodes.
Release note: None
References: #167607