Skip to content

Commit b7d2b25

Browse files
committed
test/osd/scrub: scrubber backend test files
introducing the scrubber_generators to create scrubber test data, and the scrubber_test_datasets for pre-prepared test configurations. Signed-off-by: Ronen Friedman <[email protected]>
1 parent 2852ea7 commit b7d2b25

File tree

7 files changed

+1434
-1
lines changed

7 files changed

+1434
-1
lines changed

src/osd/osd_types_fmt.h

Lines changed: 211 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
*/
77

88
#include "common/hobject_fmt.h"
9-
#include "osd/osd_types.h"
109
#include "include/types_fmt.h"
10+
#include "osd/osd_types.h"
11+
#include <fmt/chrono.h>
1112

1213
template <>
1314
struct fmt::formatter<osd_reqid_t> {
@@ -132,3 +133,212 @@ struct fmt::formatter<spg_t> {
132133
}
133134
}
134135
};
136+
137+
template <>
138+
struct fmt::formatter<pg_history_t> {
139+
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
140+
141+
template <typename FormatContext>
142+
auto format(const pg_history_t& pgh, FormatContext& ctx)
143+
{
144+
fmt::format_to(ctx.out(),
145+
"ec={}/{} lis/c={}/{} les/c/f={}/{}/{} sis={}",
146+
pgh.epoch_created,
147+
pgh.epoch_pool_created,
148+
pgh.last_interval_started,
149+
pgh.last_interval_clean,
150+
pgh.last_epoch_started,
151+
pgh.last_epoch_clean,
152+
pgh.last_epoch_marked_full,
153+
pgh.same_interval_since);
154+
155+
if (pgh.prior_readable_until_ub != ceph::timespan::zero()) {
156+
return fmt::format_to(ctx.out(),
157+
" pruub={}",
158+
pgh.prior_readable_until_ub);
159+
} else {
160+
return ctx.out();
161+
}
162+
}
163+
};
164+
165+
template <>
166+
struct fmt::formatter<pg_info_t> {
167+
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
168+
169+
template <typename FormatContext>
170+
auto format(const pg_info_t& pgi, FormatContext& ctx)
171+
{
172+
fmt::format_to(ctx.out(), "{}({}", pgi.pgid, (pgi.dne() ? " DNE" : ""));
173+
if (pgi.is_empty()) {
174+
fmt::format_to(ctx.out(), " empty");
175+
} else {
176+
fmt::format_to(ctx.out(), " v {}", pgi.last_update);
177+
if (pgi.last_complete != pgi.last_update) {
178+
fmt::format_to(ctx.out(), " lc {}", pgi.last_complete);
179+
}
180+
fmt::format_to(ctx.out(), " ({},{}]", pgi.log_tail, pgi.last_update);
181+
}
182+
if (pgi.is_incomplete()) {
183+
fmt::format_to(ctx.out(), " lb {}", pgi.last_backfill);
184+
}
185+
fmt::format_to(ctx.out(),
186+
" local-lis/les={}/{}",
187+
pgi.last_interval_started,
188+
pgi.last_epoch_started);
189+
return fmt::format_to(ctx.out(),
190+
" n={} {})",
191+
pgi.stats.stats.sum.num_objects,
192+
pgi.history);
193+
}
194+
};
195+
196+
// snaps and snap-sets
197+
198+
template <typename T, template <typename, typename, typename...> class C>
199+
struct fmt::formatter<interval_set<T, C>> {
200+
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
201+
202+
template <typename FormatContext>
203+
auto format(const interval_set<T, C>& inter, FormatContext& ctx)
204+
{
205+
bool first = true;
206+
fmt::format_to(ctx.out(), "[");
207+
for (const auto& [start, len] : inter) {
208+
fmt::format_to(ctx.out(), "{}{}~{}", (first ? "" : ","), start, len);
209+
first = false;
210+
}
211+
return fmt::format_to(ctx.out(), "]");
212+
}
213+
};
214+
215+
template <>
216+
struct fmt::formatter<SnapSet> {
217+
template <typename ParseContext>
218+
constexpr auto parse(ParseContext& ctx)
219+
{
220+
auto it = ctx.begin();
221+
if (it != ctx.end() && *it == 'D') {
222+
verbose = true;
223+
++it;
224+
}
225+
return it;
226+
}
227+
228+
template <typename FormatContext>
229+
auto format(const SnapSet& snps, FormatContext& ctx)
230+
{
231+
if (verbose) {
232+
// similar to SnapSet::dump()
233+
fmt::format_to(ctx.out(),
234+
"snaps{{{}: clns ({}): ",
235+
snps.seq,
236+
snps.clones.size());
237+
for (auto cln : snps.clones) {
238+
239+
fmt::format_to(ctx.out(), "[{}: sz:", cln);
240+
241+
auto cs = snps.clone_size.find(cln);
242+
if (cs != snps.clone_size.end()) {
243+
fmt::format_to(ctx.out(), "{} ", cs->second);
244+
} else {
245+
fmt::format_to(ctx.out(), "??");
246+
}
247+
248+
auto co = snps.clone_overlap.find(cln);
249+
if (co != snps.clone_overlap.end()) {
250+
fmt::format_to(ctx.out(), "olp:{} ", co->second);
251+
} else {
252+
fmt::format_to(ctx.out(), "olp:?? ");
253+
}
254+
255+
auto cln_snps = snps.clone_snaps.find(cln);
256+
if (cln_snps != snps.clone_snaps.end()) {
257+
fmt::format_to(ctx.out(), "cl-snps:{} ]", cln_snps->second);
258+
} else {
259+
fmt::format_to(ctx.out(), "cl-snps:?? ]");
260+
}
261+
}
262+
263+
return fmt::format_to(ctx.out(), "}}");
264+
265+
} else {
266+
return fmt::format_to(ctx.out(),
267+
"{}={}:{}",
268+
snps.seq,
269+
snps.snaps,
270+
snps.clone_snaps);
271+
}
272+
}
273+
274+
bool verbose{false};
275+
};
276+
277+
template <>
278+
struct fmt::formatter<ScrubMap::object> {
279+
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
280+
281+
///\todo: consider passing the 'D" flag to control snapset dump
282+
template <typename FormatContext>
283+
auto format(const ScrubMap::object& so, FormatContext& ctx)
284+
{
285+
fmt::format_to(ctx.out(),
286+
"so{{ sz:{} dd:{} od:{} ",
287+
so.size,
288+
so.digest,
289+
so.digest_present);
290+
291+
// note the special handling of (1) OI_ATTR and (2) non-printables
292+
for (auto [k, v] : so.attrs) {
293+
std::string bkstr{v.raw_c_str(), v.raw_length()};
294+
if (k == std::string{OI_ATTR}) {
295+
/// \todo consider parsing the OI args here. Maybe add a specific format
296+
/// specifier
297+
fmt::format_to(ctx.out(), "{{{}:<<OI_ATTR>>({})}} ", k, bkstr.length());
298+
} else if (k == std::string{SS_ATTR}) {
299+
bufferlist bl;
300+
bl.push_back(v);
301+
SnapSet sns{bl};
302+
fmt::format_to(ctx.out(), "{{{}:{:D}}} ", k, sns);
303+
} else {
304+
fmt::format_to(ctx.out(), "{{{}:{}({})}} ", k, bkstr, bkstr.length());
305+
}
306+
}
307+
308+
return fmt::format_to(ctx.out(), "}}");
309+
}
310+
};
311+
312+
template <>
313+
struct fmt::formatter<ScrubMap> {
314+
template <typename ParseContext>
315+
constexpr auto parse(ParseContext& ctx)
316+
{
317+
auto it = ctx.begin();
318+
if (it != ctx.end() && *it == 'D') {
319+
debug_log = true; // list the objects
320+
++it;
321+
}
322+
return it;
323+
}
324+
325+
template <typename FormatContext>
326+
auto format(const ScrubMap& smap, FormatContext& ctx)
327+
{
328+
fmt::format_to(ctx.out(),
329+
"smap{{ valid:{} incr-since:{} #:{}",
330+
smap.valid_through,
331+
smap.incr_since,
332+
smap.objects.size());
333+
if (debug_log) {
334+
fmt::format_to(ctx.out(), " objects:");
335+
for (const auto& [ho, so] : smap.objects) {
336+
fmt::format_to(ctx.out(), "\n\th.o<{}>:<{}> ", ho, so);
337+
}
338+
fmt::format_to(ctx.out(), "\n");
339+
}
340+
return fmt::format_to(ctx.out(), "}}");
341+
}
342+
343+
bool debug_log{false};
344+
};

src/test/osd/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ add_executable(unittest_osdscrub
6767
add_ceph_unittest(unittest_osdscrub)
6868
target_link_libraries(unittest_osdscrub osd os global ${CMAKE_DL_LIBS} mon ${BLKID_LIBRARIES})
6969

70+
# unittest_scrubber_be
71+
add_executable(unittest_scrubber_be
72+
test_scrubber_be.cc
73+
scrubber_generators.cc
74+
scrubber_test_datasets.cc
75+
)
76+
add_ceph_unittest(unittest_scrubber_be)
77+
target_link_libraries(unittest_scrubber_be osd os global ${CMAKE_DL_LIBS} mon ${BLKID_LIBRARIES})
78+
7079
# unittest_pglog
7180
add_executable(unittest_pglog
7281
TestPGLog.cc

0 commit comments

Comments
 (0)