From 89c211281b0f861d884955b9d239e053bd6a0d4a Mon Sep 17 00:00:00 2001 From: Adam Kupczyk Date: Wed, 18 Oct 2023 12:10:22 +0000 Subject: [PATCH] os/bluestore: Add improved printer for Blob Introduce printer class that allows to select parts of Blob that are to be printed. It severly reduced amount of clutter in output. Usage: using P = Bluestore::Blob::printer; dout << blob->printer(P::ptr + P::sdisk + P::schk); Signed-off-by: Adam Kupczyk --- src/os/CMakeLists.txt | 1 + src/os/bluestore/BlueStore.h | 19 ++- src/os/bluestore/BlueStore_debug.cc | 216 ++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 src/os/bluestore/BlueStore_debug.cc diff --git a/src/os/CMakeLists.txt b/src/os/CMakeLists.txt index 67770933a3d..9353ceaa63f 100644 --- a/src/os/CMakeLists.txt +++ b/src/os/CMakeLists.txt @@ -15,6 +15,7 @@ if(WITH_BLUESTORE) bluestore/bluefs_types.cc bluestore/BlueRocksEnv.cc bluestore/BlueStore.cc + bluestore/BlueStore_debug.cc bluestore/simple_bitmap.cc bluestore/bluestore_types.cc bluestore/fastbmap_allocator_impl.cc diff --git a/src/os/bluestore/BlueStore.h b/src/os/bluestore/BlueStore.h index 8141a7babf7..86961bc1af0 100644 --- a/src/os/bluestore/BlueStore.h +++ b/src/os/bluestore/BlueStore.h @@ -637,7 +637,24 @@ public: void dump(ceph::Formatter* f) const; friend std::ostream& operator<<(std::ostream& out, const Blob &b); - + struct printer { + const Blob& blob; + uint8_t mode; + printer(const Blob& blob, uint8_t mode) + :blob(blob), mode(mode) {} + static constexpr uint8_t ptr = 1; //pointer to Blob + static constexpr uint8_t nick = 2; //a nickname of this Blob + static constexpr uint8_t disk = 4; //disk allocations of Blob + static constexpr uint8_t sdisk = 8; //shortened version of disk allocaitons + static constexpr uint8_t use = 16; //use tracker + static constexpr uint8_t suse = 32; //shortened use tracker + static constexpr uint8_t chk = 64; //checksum, full dump + static constexpr uint8_t schk = 128; //only base checksum info + }; + friend std::ostream& operator<<(std::ostream& out, const printer &p); + printer print(uint8_t mode) const { + return printer(*this, mode); + } const bluestore_blob_use_tracker_t& get_blob_use_tracker() const { return used_in_blob; } diff --git a/src/os/bluestore/BlueStore_debug.cc b/src/os/bluestore/BlueStore_debug.cc new file mode 100644 index 00000000000..77bc04d5bb3 --- /dev/null +++ b/src/os/bluestore/BlueStore_debug.cc @@ -0,0 +1,216 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2023 IBM + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ +#include +#include +#include "BlueStore.h" + +static const std::string transition_table[26] = { +"bcdfghjklmnprstuvxyz", //a +"aeiloruy",//b +"aeiloruvy",//c +"aeilmnoruvy",//d +"bcdfghjklmnprstvxz",//e + +"ailou",//f +"aeilnoru",//g +"aeiloru",//h +"dfghklmnpqrstvwx",//i +"aeiou",//j + +"aeiloru",//k +"aeimnou",//l +"aeinotuy",//m +"aeiou",//n +"bcdfghjklmnpqrstvwxz",//o +"aehiloruy",//p + +"aeiloru",//q +"adefiklmnotuvy",//r +"aehiklmnopqrtuvwy",//s +"acefhiklmnorsuvwy",//t +"bcdfghklmnpqrsvwxyz",//u + +"acdeiklmorsu",//v +"aehilnorstu",//w +"aeilnorstuy",//x +"aehinorsuxz",//y +"aeiouy" //z +}; + +std::string int_to_fancy_name(uint64_t x) +{ + std::string result; + uint8_t c = x % 26; + x = x / 26; + result.push_back(c+'a'); + while (x > 0) { + uint8_t range = transition_table[c].length(); + uint8_t p = x % range; + c = transition_table[c][p] - 'a'; + x = x / range; + result.push_back(c+'a'); + } + return result; +} + +// Use special printing for multiplies of 1024; print K suffix +struct maybe_K { + uint32_t x; + maybe_K(uint32_t x) : x(x) {} +}; +std::ostream &operator<<(std::ostream &out, const maybe_K &k) { + if (((k.x & 0x3ff) == 0) && (k.x != 0)) { + if (k.x != 0x400) + out << (k.x / 0x400); + out << "K"; + } else { + out << std::hex << k.x << std::dec; + } + return out; +} + +std::ostream& operator<<(std::ostream& out, const BlueStore::Blob::printer &p) +{ + using P = BlueStore::Blob::printer; + out << "Blob("; + if (p.mode & P::ptr) { + out << &p.blob << " "; + } + if (p.mode & P::nick) { + uint64_t v = uint64_t(&p.blob); + v = (v - 0x555550000000) / 16; + out << int_to_fancy_name(v) << " "; + } + const bluestore_blob_t& bblob = p.blob.get_blob(); + if (p.mode & P::disk) { + //use default printer for std::vector * bluestore_pextent_t + out << "disk=" << bblob.get_extents() << " "; + } + if (p.mode & P::sdisk) { + const PExtentVector& ev = bblob.get_extents(); + uint64_t bits = 0; + for (auto i : ev) { + if (i.is_valid()) bits |= i.offset; + bits |= i.length; + } + uint32_t zeros = 0; //zeros to apply to all values + while ((bits & 0xf) == 0) { + bits = bits >> 4; + ++zeros; + } + out << "disk=0x[" << std::hex; + for (size_t i = 0; i < ev.size(); ++i) { + if (i != 0) { + out << ","; + } + if (ev[i].is_valid()) { + out << (ev[i].offset >> zeros * 4) << "~"; + } else { + out << "!"; + } + out << (ev[i].length >> zeros * 4); + } + out << "]" << std::dec; + while (zeros > 0) { + out << "0"; + --zeros; + } + out << " "; + } + //always print lengths, if not printing use tracker + if (!(p.mode & (P::use | P::suse)) || bblob.is_compressed()) { + // Need to print blob logical length, no tracker printing + // + there is no real tracker for compressed blobs + if (bblob.is_compressed()) { + out << "len=" << std::hex << bblob.get_logical_length() << "->" + << bblob.get_compressed_payload_length() << " " << std::dec; + } else { + out << "len=" << std::hex << bblob.get_logical_length() << std::dec << " "; + } + } + if ((p.mode & P::use) && !bblob.is_compressed()) { + out << p.blob.get_blob_use_tracker() << " "; + } + if (p.mode & P::suse) { + auto& tracker = p.blob.get_blob_use_tracker(); + if (bblob.is_compressed()) { + out << "[" << std::hex << tracker.get_referenced_bytes() << std::dec << "] "; + } else { + const uint32_t* au_array = tracker.get_au_array(); + uint16_t zeros = 0; + uint16_t full = 0; + uint16_t num_au = tracker.get_num_au(); + uint32_t au_size = tracker.au_size; + uint32_t def = std::numeric_limits::max(); + out << "track=" << tracker.get_num_au() << "*" << maybe_K(tracker.au_size); + for (size_t i = 0; i < num_au; i++) { + if (au_array[i] == 0) ++zeros; + if (au_array[i] == au_size) ++full; + } + if (zeros >= num_au - 3 && num_au > 6) def = 0; + if (full >= num_au - 3 && num_au > 6) def = au_size; + if (def != std::numeric_limits::max()) { + out << "{" << maybe_K(def) << "}["; + for (size_t i = 0; i < num_au; i++) { + if (au_array[i] != def) { + out << i << "=" << maybe_K(au_array[i]); + ++i; + for (; i < num_au; i++) { + if (au_array[i] != def) { + out << "," << i << "=" << maybe_K(au_array[i]); + } + } + } + } + out << "] "; + } else { + out << "["; + for (size_t i = 0; i < num_au; i++) { + if (i != 0) out << ","; + out << maybe_K(au_array[i]); + } + out << "] "; + } + } + } + if (bblob.has_csum()) { + if (p.mode & (P::schk | P::chk)) { + out << Checksummer::get_csum_type_string(bblob.csum_type) << "/" + << (int)bblob.csum_chunk_order << "/" << bblob.csum_data.length(); + } + if (p.mode & P::chk) { + std::vector v; + unsigned n = bblob.get_csum_count(); + for (unsigned i = 0; i < n; ++i) + v.push_back(bblob.get_csum_item(i)); + out << std::hex << v << std::dec; + } + if (p.mode & (P::schk | P::chk)) { + out << " "; + } + } + if (p.blob.is_spanning()) { + out << " spanning.id=" << p.blob.id; + } + if (p.blob.shared_blob) { + if (p.blob.shared_blob->get_sbid() != 0) { + out << " " << *p.blob.shared_blob; + } + } else { + out << " (shared_blob=NULL)"; + } + out << ")"; + return out; +} + -- 2.39.5