Skip to content

Commit 3060f4f

Browse files
authored
Merge pull request ceph#54075 from aclamk/wip-aclamk-bs-nice-print
os/bluestore: Recompression, part 1. Nice debugs.
2 parents 6458f80 + f400cb1 commit 3060f4f

File tree

4 files changed

+346
-4
lines changed

4 files changed

+346
-4
lines changed

src/os/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ if(WITH_BLUESTORE)
1515
bluestore/bluefs_types.cc
1616
bluestore/BlueRocksEnv.cc
1717
bluestore/BlueStore.cc
18+
bluestore/BlueStore_debug.cc
1819
bluestore/simple_bitmap.cc
1920
bluestore/bluestore_types.cc
2021
bluestore/fastbmap_allocator_impl.cc

src/os/bluestore/BlueStore.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,6 @@ const vector<uint64_t> bdev_label_positions = {
143143
100*_1G,
144144
1000*_1G};
145145

146-
#define OBJECT_MAX_SIZE 0xffffffff // 32 bits
147-
148-
149146
/*
150147
* extent map blob encoding
151148
*

src/os/bluestore/BlueStore.h

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,22 @@ class BlueStore : public ObjectStore,
274274
virtual ~AioContext() {}
275275
};
276276

277+
static constexpr uint32_t OBJECT_MAX_SIZE = 0xffffffff; // 32 bits
278+
struct printer {
279+
static constexpr uint16_t PTR = 1; // pointer to Blob
280+
static constexpr uint16_t NICK = 2; // a nickname of this Blob
281+
static constexpr uint16_t DISK = 4; // disk allocations of Blob
282+
static constexpr uint16_t SDISK = 8; // shortened version of disk allocaitons
283+
static constexpr uint16_t USE = 16; // use tracker
284+
static constexpr uint16_t SUSE = 32; // shortened use tracker
285+
static constexpr uint16_t CHK = 64; // checksum, full dump
286+
static constexpr uint16_t SCHK = 128; // only base checksum info
287+
static constexpr uint16_t BUF = 256; // print Blob's buffers (takes cache lock)
288+
static constexpr uint16_t SBUF = 512; // short print Blob's buffers (takes cache lock)
289+
static constexpr uint16_t ATTRS = 1024; // print attrs in onode
290+
static constexpr uint16_t JUSTID = 2048; // used to suppress printing length, spanning and shared blob
291+
};
292+
277293
/// cached buffer
278294
struct Buffer {
279295
MEMPOOL_CLASS_HELPERS();
@@ -291,6 +307,16 @@ class BlueStore : public ObjectStore,
291307
default: return "???";
292308
}
293309
}
310+
// Short version of state name.
311+
// Not print "clean", as it is most frequent.
312+
static const char *get_state_name_short(int s) {
313+
switch (s) {
314+
case STATE_EMPTY: return ",empty";
315+
case STATE_CLEAN: return "";
316+
case STATE_WRITING: return ",writing";
317+
default: return "???";
318+
}
319+
}
294320
enum {
295321
FLAG_NOCACHE = 1, ///< trim when done WRITING (do not become CLEAN)
296322
// NOTE: fix operator<< when you define a second flag
@@ -637,7 +663,16 @@ class BlueStore : public ObjectStore,
637663

638664
void dump(ceph::Formatter* f) const;
639665
friend std::ostream& operator<<(std::ostream& out, const Blob &b);
640-
666+
struct printer : public BlueStore::printer {
667+
const Blob& blob;
668+
uint16_t mode;
669+
printer(const Blob& blob, uint16_t mode)
670+
:blob(blob), mode(mode) {}
671+
};
672+
friend std::ostream& operator<<(std::ostream& out, const printer &p);
673+
printer print(uint16_t mode) const {
674+
return printer(*this, mode);
675+
}
641676
const bluestore_blob_use_tracker_t& get_blob_use_tracker() const {
642677
return used_in_blob;
643678
}
@@ -842,6 +877,16 @@ class BlueStore : public ObjectStore,
842877
blob->get_cache()->rm_extent();
843878
}
844879
}
880+
struct printer : public BlueStore::printer {
881+
const Extent& ext;
882+
uint16_t mode;
883+
printer(const Extent& ext, uint16_t mode)
884+
:ext(ext), mode(mode) {}
885+
};
886+
friend std::ostream& operator<<(std::ostream& out, const printer &p);
887+
printer print(uint16_t mode) const {
888+
return printer(*this, mode);
889+
}
845890

846891
void dump(ceph::Formatter* f) const;
847892

@@ -1404,6 +1449,21 @@ class BlueStore : public ObjectStore,
14041449
void decode_omap_key(const std::string& key, std::string *user_key);
14051450

14061451
void finish_write(TransContext* txc, uint32_t offset, uint32_t length);
1452+
1453+
struct printer : public BlueStore::printer {
1454+
const Onode &onode;
1455+
uint16_t mode;
1456+
uint32_t from = 0;
1457+
uint32_t end = OBJECT_MAX_SIZE;
1458+
printer(const Onode &onode, uint16_t mode) : onode(onode), mode(mode) {}
1459+
printer(const Onode &onode, uint16_t mode, uint32_t from, uint32_t end)
1460+
: onode(onode), mode(mode), from(from), end(end) {}
1461+
};
1462+
friend std::ostream &operator<<(std::ostream &out, const printer &p);
1463+
printer print(uint16_t mode) const { return printer(*this, mode); }
1464+
printer print(uint16_t mode, uint32_t from, uint32_t end) const {
1465+
return printer(*this, mode, from, end);
1466+
}
14071467
};
14081468

14091469
/// A generic Cache Shard
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2+
// vim: ts=8 sw=2 smarttab
3+
/*
4+
* Ceph - scalable distributed file system
5+
*
6+
* Copyright (C) 2023 IBM
7+
*
8+
* This is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License version 2.1, as published by the Free Software
11+
* Foundation. See file COPYING.
12+
*
13+
*/
14+
#include <cstdint>
15+
#include <ostream>
16+
#include "BlueStore.h"
17+
18+
static const std::string transition_table[26] = {
19+
"bcdfghjklmnprstuvxyz", //a
20+
"aeiloruy",//b
21+
"aeiloruvy",//c
22+
"aeilmnoruvy",//d
23+
"bcdfghjklmnprstvxz",//e
24+
25+
"ailou",//f
26+
"aeilnoru",//g
27+
"aeiloru",//h
28+
"dfghklmnpqrstvwx",//i
29+
"aeiou",//j
30+
31+
"aeiloru",//k
32+
"aeimnou",//l
33+
"aeinotuy",//m
34+
"aeiou",//n
35+
"bcdfghjklmnpqrstvwxz",//o
36+
"aehiloruy",//p
37+
38+
"aeiloru",//q
39+
"adefiklmnotuvy",//r
40+
"aehiklmnopqrtuvwy",//s
41+
"acefhiklmnorsuvwy",//t
42+
"bcdfghklmnpqrsvwxyz",//u
43+
44+
"acdeiklmorsu",//v
45+
"aehilnorstu",//w
46+
"aeilnorstuy",//x
47+
"aehinorsuxz",//y
48+
"aeiouy" //z
49+
};
50+
51+
std::string int_to_fancy_name(uint64_t x)
52+
{
53+
std::string result;
54+
uint8_t c = x % 26;
55+
x = x / 26;
56+
result.push_back(c+'a');
57+
while (x > 0) {
58+
uint8_t range = transition_table[c].length();
59+
uint8_t p = x % range;
60+
c = transition_table[c][p] - 'a';
61+
x = x / range;
62+
result.push_back(c+'a');
63+
}
64+
return result;
65+
}
66+
67+
// Use special printing for multiplies of 1024; print K suffix
68+
struct maybe_K {
69+
uint32_t x;
70+
maybe_K(uint32_t x) : x(x) {}
71+
};
72+
std::ostream &operator<<(std::ostream &out, const maybe_K &k) {
73+
if (((k.x & 0x3ff) == 0) && (k.x != 0)) {
74+
if (k.x != 0x400)
75+
out << (k.x / 0x400);
76+
out << "K";
77+
} else {
78+
out << std::hex << k.x << std::dec;
79+
}
80+
return out;
81+
}
82+
// cheap, not very reliable but portable detector where heap starts
83+
static std::unique_ptr<char> heap_begin(new char);
84+
std::ostream& operator<<(std::ostream& out, const BlueStore::Buffer& b);
85+
std::ostream& operator<<(std::ostream& out, const BlueStore::Blob::printer &p)
86+
{
87+
using P = BlueStore::printer;
88+
out << "Blob(";
89+
if (p.mode & P::PTR) {
90+
out << &p.blob;
91+
}
92+
if (p.mode & P::NICK) {
93+
uint64_t v = uint64_t(&p.blob);
94+
//Assume allocated Blobs will be 16 bytes aligned.
95+
v = (v - (uintptr_t)heap_begin.get()) / 16;
96+
out << int_to_fancy_name(v);
97+
}
98+
const bluestore_blob_t& bblob = p.blob.get_blob();
99+
if (p.mode & P::DISK) {
100+
//use default printer for std::vector * bluestore_pextent_t
101+
out << " disk=" << bblob.get_extents();
102+
}
103+
if (p.mode & P::SDISK) {
104+
const PExtentVector& ev = bblob.get_extents();
105+
uint64_t bits = 0;
106+
for (auto i : ev) {
107+
if (i.is_valid()) bits |= i.offset;
108+
bits |= i.length;
109+
}
110+
uint32_t zeros = 0; //zeros to apply to all values
111+
while ((bits & 0xf) == 0) {
112+
bits = bits >> 4;
113+
++zeros;
114+
}
115+
out << " disk=0x[" << std::hex;
116+
for (size_t i = 0; i < ev.size(); ++i) {
117+
if (i != 0) {
118+
out << ",";
119+
}
120+
if (ev[i].is_valid()) {
121+
out << (ev[i].offset >> zeros * 4) << "~";
122+
} else {
123+
out << "!";
124+
}
125+
out << (ev[i].length >> zeros * 4);
126+
}
127+
out << "]" << std::dec;
128+
while (zeros > 0) {
129+
out << "0";
130+
--zeros;
131+
}
132+
}
133+
//always print lengths, if not printing use tracker
134+
if ((!(p.mode & (P::USE | P::SUSE)) || bblob.is_compressed())
135+
&& !(p.mode & P::JUSTID)) {
136+
// Need to print blob logical length, no tracker printing
137+
// + there is no real tracker for compressed blobs
138+
if (bblob.is_compressed()) {
139+
out << " len=" << std::hex << bblob.get_logical_length() << "->"
140+
<< bblob.get_compressed_payload_length() << std::dec;
141+
} else {
142+
out << " len=" << std::hex << bblob.get_logical_length() << std::dec;
143+
}
144+
}
145+
if ((p.mode & P::USE) && !bblob.is_compressed()) {
146+
out << " " << p.blob.get_blob_use_tracker();
147+
}
148+
if (p.mode & P::SUSE) {
149+
auto& tracker = p.blob.get_blob_use_tracker();
150+
if (bblob.is_compressed()) {
151+
out << " [" << std::hex << tracker.get_referenced_bytes() << std::dec << "]";
152+
} else {
153+
const uint32_t* au_array = tracker.get_au_array();
154+
uint16_t zeros = 0;
155+
uint16_t full = 0;
156+
uint16_t num_au = tracker.get_num_au();
157+
uint32_t au_size = tracker.au_size;
158+
uint32_t def = std::numeric_limits<uint32_t>::max();
159+
out << " track=" << tracker.get_num_au() << "*" << maybe_K(tracker.au_size);
160+
for (size_t i = 0; i < num_au; i++) {
161+
if (au_array[i] == 0) ++zeros;
162+
if (au_array[i] == au_size) ++full;
163+
}
164+
if (zeros >= num_au - 3 && num_au > 6) def = 0;
165+
if (full >= num_au - 3 && num_au > 6) def = au_size;
166+
if (def != std::numeric_limits<uint32_t>::max()) {
167+
out << " {" << maybe_K(def) << "}[";
168+
for (size_t i = 0; i < num_au; i++) {
169+
if (au_array[i] != def) {
170+
out << i << "=" << maybe_K(au_array[i]);
171+
++i;
172+
for (; i < num_au; i++) {
173+
if (au_array[i] != def) {
174+
out << "," << i << "=" << maybe_K(au_array[i]);
175+
}
176+
}
177+
}
178+
}
179+
out << "]";
180+
} else {
181+
out << " [";
182+
for (size_t i = 0; i < num_au; i++) {
183+
if (i != 0) out << ",";
184+
out << maybe_K(au_array[i]);
185+
}
186+
out << "]";
187+
}
188+
}
189+
}
190+
if (bblob.has_csum()) {
191+
if (p.mode & (P::SCHK | P::CHK)) {
192+
out << " " << Checksummer::get_csum_type_string(bblob.csum_type) << "/"
193+
<< (int)bblob.csum_chunk_order << "/" << bblob.csum_data.length();
194+
}
195+
if (p.mode & P::CHK) {
196+
std::vector<uint64_t> v;
197+
unsigned n = bblob.get_csum_count();
198+
for (unsigned i = 0; i < n; ++i)
199+
v.push_back(bblob.get_csum_item(i));
200+
out << " " << std::hex << v << std::dec;
201+
}
202+
}
203+
if (!(p.mode & P::JUSTID) && p.blob.is_spanning()) {
204+
out << " spanning.id=" << p.blob.id;
205+
}
206+
if (!(p.mode & P::JUSTID) &&
207+
p.blob.shared_blob &&
208+
(p.blob.shared_blob->get_sbid() != 0)) {
209+
out << " " << *p.blob.shared_blob;
210+
}
211+
out << ")";
212+
return out;
213+
}
214+
215+
std::ostream& operator<<(std::ostream& out, const BlueStore::Extent::printer &p)
216+
{
217+
out << std::hex << "0x" << p.ext.logical_offset << "~" << p.ext.length
218+
<< ": 0x" << p.ext.blob_offset << "~" << p.ext.length << std::dec
219+
<< " " << p.ext.blob->print(p.mode);
220+
return out;
221+
}
222+
223+
std::ostream& operator<<(std::ostream& out, const BlueStore::Onode::printer &p)
224+
{
225+
using P = BlueStore::printer;
226+
const BlueStore::Onode& o = p.onode;
227+
uint16_t mode = p.mode;
228+
out << &o << " " << o.oid
229+
<< " nid " << o.onode.nid
230+
<< " size 0x" << std::hex << o.onode.size
231+
<< " (" << std::dec << o.onode.size << ")"
232+
<< " expected_object_size " << o.onode.expected_object_size
233+
<< " expected_write_size " << o.onode.expected_write_size
234+
<< " in " << o.onode.extent_map_shards.size() << " shards"
235+
<< ", " << o.extent_map.spanning_blob_map.size()
236+
<< " spanning blobs";
237+
const BlueStore::ExtentMap& map = o.extent_map;
238+
std::set<BlueStore::Blob*> visited;
239+
// to make printing extents in-sync with blobs
240+
uint16_t mode_extent = (mode & (P::PTR | P::NICK)) | P::JUSTID;
241+
auto i = map.seek_lextent(p.from);
242+
while (i != map.extent_map.end() && i->logical_offset < p.end) {
243+
BlueStore::Blob* b = i->blob.get();
244+
out << std::endl << i->print(mode_extent);
245+
if (!visited.contains(b)) {
246+
visited.insert(b);
247+
}
248+
++i;
249+
}
250+
for (const auto& i : visited) {
251+
out << std::endl << i->print(mode);
252+
}
253+
// here printing Buffers
254+
if (p.mode & (P::BUF | P::SBUF)) {
255+
std::lock_guard l(o.c->cache->lock);
256+
if (p.mode & P::SBUF) {
257+
// summary buf mode, only print what is mapped what options are, one liner
258+
out << " bufs(";
259+
bool space = false;
260+
for (auto& i : o.bc.buffer_map) {
261+
if (space) out << " ";
262+
out << "0x" << std::hex << i.offset << "~" << i.length << std::dec
263+
<< BlueStore::Buffer::get_state_name_short(i.state);
264+
if (i.flags) {
265+
out << "," << BlueStore::Buffer::get_flag_name(i.flags);
266+
}
267+
space = true;
268+
}
269+
out << ")";
270+
} else {
271+
for (auto& i : o.bc.buffer_map) {
272+
out << std::endl << " 0x" << std::hex << i.offset
273+
<< "~" << i.length << std::dec
274+
<< " " << i;
275+
}
276+
}
277+
}
278+
if (mode & P::ATTRS) {
279+
for (const auto& p : o.onode.attrs) {
280+
out << std::endl << "attr " << p.first << " len " << p.second.length();
281+
}
282+
}
283+
return out;
284+
}

0 commit comments

Comments
 (0)