From fcd847bbf9c73cfcef86e246a57073d3172799b2 Mon Sep 17 00:00:00 2001 From: Zygo Blaxell Date: Thu, 14 Oct 2021 18:34:49 -0400 Subject: [PATCH] fs: add an item type parameter to next_min When we are searching the btrfs metadata trees, we usually want only one type of item. If the last item in a search result is not of the desired type, we can restart the search at the next possible key with that item type, potentially skipping over some uninteresting items we would otherwise have to fetch, process, and discard. Also remove a bug in the previous next_min code that would skip over items if the offset overflowed and the next objectid in the tree had a lower item type number than the previous objectid. This doesn't seem to be a bug that has ever happened, as it would require a file to roll over in the offset field. Signed-off-by: Zygo Blaxell --- include/crucible/fs.h | 3 +++ lib/fs.cc | 42 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/include/crucible/fs.h b/include/crucible/fs.h index 0cb5275..01bef77 100644 --- a/include/crucible/fs.h +++ b/include/crucible/fs.h @@ -192,6 +192,9 @@ namespace crucible { // Copy objectid/type/offset so we move forward void next_min(const BtrfsIoctlSearchHeader& ref); + // move forward to next object of a single type + void next_min(const BtrfsIoctlSearchHeader& ref, const uint8_t type); + size_t m_buf_size; set m_result; }; diff --git a/lib/fs.cc b/lib/fs.cc index c3ae00f..db10b13 100644 --- a/lib/fs.cc +++ b/lib/fs.cc @@ -823,8 +823,46 @@ namespace crucible { min_type = ref.type; min_offset = ref.offset + 1; if (min_offset < ref.offset) { - // We wrapped, try the next objectid - ++min_objectid; + // We wrapped, try the next type + ++min_type; + assert(min_offset == 0); + if (min_type < ref.type) { + assert(min_type == 0); + // We wrapped, try the next objectid + ++min_objectid; + // no advancement possible at end + THROW_CHECK1(runtime_error, min_type, min_type == 0); + } + } + } + + void + BtrfsIoctlSearchKey::next_min(const BtrfsIoctlSearchHeader &ref, const uint8_t type) + { + if (ref.type < type) { + // forward to type in same object with zero offset + min_objectid = ref.objectid; + min_type = type; + min_offset = 0; + } else if (ref.type > type) { + // skip directly to start of next objectid with target type + min_objectid = ref.objectid + 1; + // no advancement possible at end + THROW_CHECK2(out_of_range, min_objectid, ref.objectid, min_objectid > ref.objectid); + min_type = type; + min_offset = 0; + } else { + // advance within this type + min_objectid = ref.objectid; + min_type = ref.type; + min_offset = ref.offset + 1; + if (min_offset < ref.offset) { + // We wrapped, try the next objectid, same type + ++min_objectid; + THROW_CHECK2(out_of_range, min_objectid, ref.objectid, min_objectid > ref.objectid); + min_type = type; + assert(min_offset == 0); + } } }