-
Notifications
You must be signed in to change notification settings - Fork 8
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
Dead Page Reference Count Bug Fix #181
base: main
Are you sure you want to change the base?
Conversation
src/llfs/page_recycler_events.hpp
Outdated
@@ -39,6 +39,8 @@ struct PageToRecycle { | |||
// | |||
i32 depth; | |||
|
|||
slot_offset_type offset_as_unique_identifier; |
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.
This is a bit verbose... maybe we can use the same convention as PageAllocator
, which calls this user_slot
?
See: https://github.com/mathworks/llfs/blob/main/src/llfs/page_allocator_events.hpp#L44
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.
sure.. this is all changed now. As discussed will use volume_trim_slot instead.
//+++++++++++-+-+--+----- --- -- - - - - | ||
|
||
static PageCount default_max_buffered_page_count(const PageRecyclerOptions& options); | ||
|
||
static u64 calculate_log_size(const PageRecyclerOptions& options, | ||
Optional<PageCount> max_buffered_page_count = None); | ||
|
||
static u64 calculate_log_size_no_padding(const PageRecyclerOptions& options, |
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.
Would you please add doc comments for this new function? Thanks!
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.
sure...
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.
General comment: on functions that return Status
or StatusOr
, usually it's best to declare as noexcept
. My advice would be to do this on functions whose signature we modify, or newly added functions; as opposed to just going through and changing a bunch of existing signatures.
@@ -55,13 +55,21 @@ class PageRecycler | |||
CountMetric<u64> page_drop_error_count{0}; | |||
}; | |||
|
|||
struct GlobalMetrics { | |||
CountMetric<u32> page_id_deletion_reissue_count{0}; |
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.
Why not u64
here? Not that we expect a lot of these, but why not?
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.
My reasoning was this. Say we do recovery every second and we dedup all these requests then we could do that for next ~50,000 years with a 32-bit counter. Why allocate more space when we are never going to hit the limit.
src/llfs/page_recycler.hpp
Outdated
// recycle_pages. | ||
// | ||
StatusOr<slot_offset_type> recycle_pages_depth_n(const Slice<const PageId>& page_ids_in, | ||
batt::Grant* grant, const i32 depth); |
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.
Now that the grant
param is required for this overload, consider changing the type to batt::Grant&
.
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.
Here's what I have so far... I need to review the page_recycler.cpp changes in more detail. Will post another review later.
src/llfs/page_recycler_events.hpp
Outdated
|
||
// This tracks the page index within recycle_pages request. | ||
// | ||
u16 page_index; |
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 think this should be u32
at least; it's reasonable to expect that we may trim a log multiple MB at a time, in which case we could easily have more than 64k pages.
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.
sure...
src/llfs/page_recycler_events.hpp
Outdated
@@ -132,12 +142,14 @@ struct PackedPageToRecycle { | |||
|
|||
little_page_id_int page_id; | |||
little_u64 batch_slot; | |||
u64 offset_as_unique_identifier; |
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.
Please use little_u64
here.
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.
sure... this part of the code is all changed now.
src/llfs/page_recycler_events.hpp
Outdated
little_i32 depth; | ||
u16 page_index; |
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.
This should be little_u32
.
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.
sure..
@@ -111,13 +113,28 @@ Optional<SlotRange> PageRecyclerRecoveryVisitor::latest_info_refresh_slot() cons | |||
return this->latest_info_refresh_slot_; | |||
} | |||
|
|||
//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - - | |||
// | |||
slot_offset_type PageRecyclerRecoveryVisitor::volume_trim_offset() const |
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.
nit: Maybe have the member function name match the member data name? volume_trim_slot()
?
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.
sure...thats a good point.
// Save the largest unique offset identifier. Note that if offsets are same then we need to only | ||
// update the largest page_index. | ||
// | ||
if (this->volume_trim_slot_ < recovered.offset_as_unique_identifier) { |
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 should always use llfs::slot_less_than
(and friends; see https://github.com/mathworks/llfs/blob/main/src/llfs/slot.hpp#L36) to compare two slot offset values, instead of the built-in comparison operators.
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.
sure.. I will use slot_less_than.
@@ -45,6 +45,9 @@ class PageRecyclerRecoveryVisitor | |||
|
|||
Optional<SlotRange> latest_info_refresh_slot() const; | |||
|
|||
slot_offset_type volume_trim_offset() const; |
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.
Great! Consider grouping these together as a single struct
. The advantages would be:
- Code that calls this API gets a very strong "hint" that the two always need to be called together (and the pair needs to travel around together)
- Can define custom operators for that type, to re-use the
slot_less_than
and lexicographical ordering that is coded inline in a couple places currently.
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.
Will do the change as discussed...
@@ -29,6 +29,8 @@ namespace llfs { | |||
, latest_batch_{} | |||
, recycler_uuid_{boost::uuids::random_generator{}()} | |||
, latest_info_refresh_slot_{} | |||
, volume_trim_slot_{0} |
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.
Consider having these be Optional
so that we can detect that case where no slot/index information could be recovered from the log. It's unlikely the slow will over overflow (being 64-bits), but making this Optional
would also have the benefit of handling integer wrap (like slot_less_than
).
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.
First time when the DB is coming up we will never find a slot/index during recovery. We take them as 0/0. I am not sure if optional will be useful here. Let me know if I missed anything?
This MR is to release the fix for ref count bug in page recycler's dead page recycling flow. This issue crops up when volume trimmer and page recycler retries a dead page recycling task for a page after recovery. The solution is to track largest_slot_offset in recycler which will be checked at the time of receiving any new dead_page recycling request from volume trimmer. Any request having lower or equal slot_offset compare to largest-slot-offset will be ignored.
The MR also adds in a histogram plot to show where all we are hitting the bug over the entire seed range. This is done through an existing page ref count test.
#13