refactor: switch from detail level to info features

This commit is contained in:
Marcus Holland-Moritz 2024-08-01 01:00:52 +02:00
parent 964a4f49e6
commit 8199919d36
7 changed files with 315 additions and 123 deletions

View File

@ -76,6 +76,8 @@ class filesystem_v2 {
static std::optional<std::span<uint8_t const>>
header(std::shared_ptr<mmif> mm, file_off_t image_offset);
static fsinfo_features features_for_level(int level);
int check(filesystem_check_level level, size_t num_threads = 0) const {
return impl_->check(level, num_threads);
}
@ -90,6 +92,18 @@ class filesystem_v2 {
return impl_->info_as_json(detail_level);
}
void dump(std::ostream& os, fsinfo_options const& opts) const {
impl_->dump(os, opts);
}
std::string dump(fsinfo_options const& opts) const {
return impl_->dump(opts);
}
nlohmann::json info_as_json(fsinfo_options const& opts) const {
return impl_->info_as_json(opts);
}
nlohmann::json metadata_as_json() const { return impl_->metadata_as_json(); }
std::string serialize_metadata_as_json(bool simple) const {
@ -304,6 +318,9 @@ class filesystem_v2 {
virtual void dump(std::ostream& os, int detail_level) const = 0;
virtual std::string dump(int detail_level) const = 0;
virtual nlohmann::json info_as_json(int detail_level) const = 0;
virtual void dump(std::ostream& os, fsinfo_options const& opts) const = 0;
virtual std::string dump(fsinfo_options const& opts) const = 0;
virtual nlohmann::json info_as_json(fsinfo_options const& opts) const = 0;
virtual nlohmann::json metadata_as_json() const = 0;
virtual std::string serialize_metadata_as_json(bool simple) const = 0;
virtual void

View File

@ -45,6 +45,7 @@ class logger;
struct getattr_options;
struct metadata_options;
struct filesystem_info;
struct fsinfo_options;
struct vfs_stat;
class performance_monitor;
@ -69,14 +70,15 @@ class metadata_v2 {
void check_consistency() const { impl_->check_consistency(); }
void
dump(std::ostream& os, int detail_level, filesystem_info const& fsinfo,
dump(std::ostream& os, fsinfo_options const& opts,
filesystem_info const* fsinfo,
std::function<void(const std::string&, uint32_t)> const& icb) const {
impl_->dump(os, detail_level, fsinfo, icb);
impl_->dump(os, opts, fsinfo, icb);
}
nlohmann::json
info_as_json(int detail_level, filesystem_info const& fsinfo) const {
return impl_->info_as_json(detail_level, fsinfo);
nlohmann::json info_as_json(fsinfo_options const& opts,
filesystem_info const* fsinfo) const {
return impl_->info_as_json(opts, fsinfo);
}
nlohmann::json as_json() const { return impl_->as_json(); }
@ -176,11 +178,13 @@ class metadata_v2 {
virtual void check_consistency() const = 0;
virtual void dump(
std::ostream& os, int detail_level, filesystem_info const& fsinfo,
std::ostream& os, fsinfo_options const& opts,
filesystem_info const* fsinfo,
std::function<void(const std::string&, uint32_t)> const& icb) const = 0;
virtual nlohmann::json
info_as_json(int detail_level, filesystem_info const& fsinfo) const = 0;
info_as_json(fsinfo_options const& opts,
filesystem_info const* fsinfo) const = 0;
virtual nlohmann::json as_json() const = 0;
virtual std::string serialize_as_json(bool simple) const = 0;

View File

@ -24,9 +24,14 @@
#include <chrono>
#include <cstddef>
#include <functional>
#include <initializer_list>
#include <iosfwd>
#include <limits>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_set>
#include <vector>
@ -69,6 +74,78 @@ struct getattr_options {
bool no_size{false};
};
enum class block_access_level {
no_access,
no_verify,
unrestricted,
};
inline auto operator<=>(block_access_level lhs, block_access_level rhs) {
return static_cast<std::underlying_type_t<block_access_level>>(lhs) <=>
static_cast<std::underlying_type_t<block_access_level>>(rhs);
}
enum class fsinfo_feature {
version,
history,
metadata_summary,
metadata_details,
metadata_full_dump,
frozen_analysis,
frozen_layout,
directory_tree,
section_details,
chunk_details,
num_fsinfo_feature_bits,
};
class fsinfo_features {
public:
constexpr fsinfo_features() = default;
constexpr fsinfo_features(std::initializer_list<fsinfo_feature> features) {
for (auto f : features) {
set(f);
}
}
constexpr bool has(fsinfo_feature f) const {
return features_ & (1 << static_cast<size_t>(f));
}
constexpr void set(fsinfo_feature f) {
features_ |= (1 << static_cast<size_t>(f));
}
constexpr void clear(fsinfo_feature f) {
features_ &= ~(1 << static_cast<size_t>(f));
}
constexpr void reset() { features_ = 0; }
constexpr fsinfo_features& operator|=(fsinfo_features const& other) {
features_ |= other.features_;
return *this;
}
constexpr fsinfo_features& operator|=(fsinfo_feature f) {
set(f);
return *this;
}
constexpr bool operator&(fsinfo_feature f) const { return has(f); }
private:
// can be upgraded to std::bitset if needed and when it's constexpr
uint64_t features_{0};
static_assert(static_cast<size_t>(fsinfo_feature::num_fsinfo_feature_bits) <=
std::numeric_limits<uint64_t>::digits);
};
struct fsinfo_options {
fsinfo_features features;
block_access_level block_access{block_access_level::unrestricted};
};
struct metadata_options {
bool enable_nlink{false};
bool readonly{false};

View File

@ -61,6 +61,28 @@ namespace internal {
namespace {
constexpr std::array level_features{
/* 0 */ fsinfo_features(),
/* 1 */
fsinfo_features(
{fsinfo_feature::version, fsinfo_feature::metadata_summary}),
/* 2 */
fsinfo_features({fsinfo_feature::frozen_analysis, fsinfo_feature::history}),
/* 3 */
fsinfo_features(
{fsinfo_feature::metadata_details, fsinfo_feature::section_details}),
/* 4 */
fsinfo_features(
{fsinfo_feature::directory_tree, fsinfo_feature::frozen_layout}),
/* 5 */ fsinfo_features({fsinfo_feature::chunk_details}),
/* 6 */ fsinfo_features({fsinfo_feature::metadata_full_dump}),
/* 7 */ fsinfo_features({}),
};
fsinfo_options fsinfo_opts_for_level(int level) {
return fsinfo_options{.features = filesystem_v2::features_for_level(level)};
}
void check_section_logger(logger& lgr, fs_section const& section) {
LOG_PROXY(debug_logger_policy, lgr);
@ -410,6 +432,9 @@ class filesystem_ final : public filesystem_v2::impl {
void dump(std::ostream& os, int detail_level) const override;
std::string dump(int detail_level) const override;
nlohmann::json info_as_json(int detail_level) const override;
void dump(std::ostream& os, fsinfo_options const& opts) const override;
std::string dump(fsinfo_options const& opts) const override;
nlohmann::json info_as_json(fsinfo_options const& opts) const override;
nlohmann::json metadata_as_json() const override;
std::string serialize_metadata_as_json(bool simple) const override;
void walk(std::function<void(dir_entry_view)> const& func) const override;
@ -488,7 +513,7 @@ class filesystem_ final : public filesystem_v2::impl {
rewrite_options const& opts) const override;
private:
filesystem_info const& get_info() const;
filesystem_info const* get_info(fsinfo_options const& opts) const;
void check_section(fs_section const& section) const;
std::string read_string_ec(uint32_t inode, size_t size, file_off_t offset,
std::error_code& ec) const;
@ -508,6 +533,8 @@ class filesystem_ final : public filesystem_v2::impl {
mutable std::mutex mx_;
std::vector<uint8_t> meta_buffer_;
std::optional<std::span<uint8_t const>> header_;
mutable block_access_level fsinfo_block_access_level_{
block_access_level::no_access};
mutable std::unique_ptr<filesystem_info const> fsinfo_;
history history_;
file_off_t const image_offset_;
@ -545,10 +572,11 @@ void filesystem_<LoggerPolicy>::check_section(fs_section const& section) const {
}
template <typename LoggerPolicy>
filesystem_info const& filesystem_<LoggerPolicy>::get_info() const {
filesystem_info const*
filesystem_<LoggerPolicy>::get_info(fsinfo_options const& opts) const {
std::lock_guard lock(mx_);
if (!fsinfo_) {
if (!fsinfo_ || opts.block_access > fsinfo_block_access_level_) {
filesystem_parser parser(mm_, image_offset_);
filesystem_info info;
@ -561,11 +589,17 @@ filesystem_info const& filesystem_<LoggerPolicy>::get_info() const {
++info.block_count;
info.compressed_block_size += s->length();
info.compressed_block_sizes.push_back(s->length());
try {
auto uncompressed_size = get_uncompressed_section_size(mm_, *s);
info.uncompressed_block_size += uncompressed_size;
info.uncompressed_block_sizes.push_back(uncompressed_size);
} catch (std::exception const&) {
if (opts.block_access >= block_access_level::unrestricted) {
try {
auto uncompressed_size = get_uncompressed_section_size(mm_, *s);
info.uncompressed_block_size += uncompressed_size;
info.uncompressed_block_sizes.push_back(uncompressed_size);
} catch (std::exception const&) {
info.uncompressed_block_size += s->length();
info.uncompressed_block_size_is_estimate = true;
info.uncompressed_block_sizes.push_back(std::nullopt);
}
} else {
info.uncompressed_block_size += s->length();
info.uncompressed_block_size_is_estimate = true;
info.uncompressed_block_sizes.push_back(std::nullopt);
@ -583,9 +617,10 @@ filesystem_info const& filesystem_<LoggerPolicy>::get_info() const {
}
fsinfo_ = std::make_unique<filesystem_info>(info);
fsinfo_block_access_level_ = opts.block_access;
}
return *fsinfo_;
return fsinfo_.get();
}
template <typename LoggerPolicy>
@ -921,9 +956,25 @@ int filesystem_<LoggerPolicy>::check(filesystem_check_level level,
template <typename LoggerPolicy>
void filesystem_<LoggerPolicy>::dump(std::ostream& os, int detail_level) const {
dump(os, fsinfo_opts_for_level(detail_level));
}
template <typename LoggerPolicy>
std::string filesystem_<LoggerPolicy>::dump(int detail_level) const {
return dump(fsinfo_opts_for_level(detail_level));
}
template <typename LoggerPolicy>
nlohmann::json filesystem_<LoggerPolicy>::info_as_json(int detail_level) const {
return info_as_json(fsinfo_opts_for_level(detail_level));
}
template <typename LoggerPolicy>
void filesystem_<LoggerPolicy>::dump(std::ostream& os,
fsinfo_options const& opts) const {
filesystem_parser parser(mm_, image_offset_);
if (detail_level > 0) {
if (opts.features.has(fsinfo_feature::version)) {
os << "DwarFS version " << parser.version();
if (auto off = parser.image_offset(); off > 0) {
os << " at offset " << off;
@ -933,7 +984,7 @@ void filesystem_<LoggerPolicy>::dump(std::ostream& os, int detail_level) const {
size_t block_no{0};
if (detail_level > 2) {
if (opts.features.has(fsinfo_feature::section_details)) {
while (auto sp = parser.next_section()) {
auto const& s = *sp;
@ -962,34 +1013,34 @@ void filesystem_<LoggerPolicy>::dump(std::ostream& os, int detail_level) const {
}
}
if (detail_level > 1) {
if (opts.features.has(fsinfo_feature::history)) {
history_.dump(os);
}
meta_.dump(os, detail_level, get_info(),
[&](const std::string& indent, uint32_t inode) {
std::error_code ec;
auto chunks = meta_.get_chunks(inode, ec);
if (!ec) {
os << indent << chunks.size() << " chunks in inode " << inode
<< "\n";
ir_.dump(os, indent + " ", chunks);
} else {
LOG_ERROR << "error reading chunks for inode " << inode << ": "
<< ec.message();
}
});
meta_.dump(
os, opts, get_info(opts), [&](const std::string& indent, uint32_t inode) {
std::error_code ec;
auto chunks = meta_.get_chunks(inode, ec);
if (!ec) {
os << indent << chunks.size() << " chunks in inode " << inode << "\n";
ir_.dump(os, indent + " ", chunks);
} else {
LOG_ERROR << "error reading chunks for inode " << inode << ": "
<< ec.message();
}
});
}
template <typename LoggerPolicy>
std::string filesystem_<LoggerPolicy>::dump(int detail_level) const {
std::string filesystem_<LoggerPolicy>::dump(fsinfo_options const& opts) const {
std::ostringstream oss;
dump(oss, detail_level);
dump(oss, opts);
return oss.str();
}
template <typename LoggerPolicy>
nlohmann::json filesystem_<LoggerPolicy>::info_as_json(int detail_level) const {
nlohmann::json
filesystem_<LoggerPolicy>::info_as_json(fsinfo_options const& opts) const {
filesystem_parser parser(mm_, image_offset_);
nlohmann::json info{
@ -1002,11 +1053,11 @@ nlohmann::json filesystem_<LoggerPolicy>::info_as_json(int detail_level) const {
{"image_offset", parser.image_offset()},
};
if (detail_level > 1) {
if (opts.features.has(fsinfo_feature::history)) {
info["history"] = history_.as_json();
}
if (detail_level > 2) {
if (opts.features.has(fsinfo_feature::section_details)) {
size_t block_no{0};
while (auto sp = parser.next_section()) {
@ -1036,7 +1087,7 @@ nlohmann::json filesystem_<LoggerPolicy>::info_as_json(int detail_level) const {
}
}
info.update(meta_.info_as_json(detail_level, get_info()));
info.update(meta_.info_as_json(opts, get_info(opts)));
return info;
}
@ -1400,4 +1451,16 @@ filesystem_v2::header(std::shared_ptr<mmif> mm, file_off_t image_offset) {
return internal::filesystem_parser(mm, image_offset).header();
}
fsinfo_features filesystem_v2::features_for_level(int level) {
fsinfo_features features;
level = std::min<int>(level, internal::level_features.size() - 1);
for (int i = 0; i <= level; ++i) {
features |= internal::level_features[i];
}
return features;
}
} // namespace dwarfs

View File

@ -140,7 +140,7 @@ check_metadata_consistency(logger& lgr, global_metadata::Meta const& meta,
void analyze_frozen(std::ostream& os,
MappedFrozen<thrift::metadata::metadata> const& meta,
size_t total_size, int detail) {
size_t total_size, fsinfo_options const& opts) {
using namespace ::apache::thrift::frozen;
null_logger lgr;
@ -305,7 +305,7 @@ void analyze_frozen(std::ostream& os,
os << u.second;
}
if (detail > 3) {
if (opts.features.has(fsinfo_feature::frozen_layout)) {
l->print(os, 0);
os << '\n';
}
@ -332,25 +332,31 @@ void parse_metadata_options(
struct category_info {
size_t count{0};
size_t compressed_size{0};
size_t uncompressed_size{0};
std::optional<size_t> compressed_size;
std::optional<size_t> uncompressed_size;
bool uncompressed_size_is_estimate{false};
};
std::map<size_t, category_info>
get_category_info(MappedFrozen<thrift::metadata::metadata> const& meta,
filesystem_info const& fsinfo) {
filesystem_info const* fsinfo) {
std::map<size_t, category_info> catinfo;
if (auto blockcat = meta.block_categories()) {
for (auto [block, category] : ranges::views::enumerate(blockcat.value())) {
auto& ci = catinfo[category];
++ci.count;
ci.compressed_size += fsinfo.compressed_block_sizes.at(block);
if (auto size = fsinfo.uncompressed_block_sizes.at(block)) {
ci.uncompressed_size += *size;
} else {
ci.uncompressed_size_is_estimate = true;
if (fsinfo) {
if (!ci.compressed_size) {
ci.compressed_size = 0;
ci.uncompressed_size = 0;
}
*ci.compressed_size += fsinfo->compressed_block_sizes.at(block);
if (auto size = fsinfo->uncompressed_block_sizes.at(block)) {
*ci.uncompressed_size += *size;
} else {
ci.uncompressed_size_is_estimate = true;
}
}
}
}
@ -457,12 +463,13 @@ class metadata_ final : public metadata_v2::impl {
void check_consistency() const override;
void dump(std::ostream& os, int detail_level, filesystem_info const& fsinfo,
void dump(std::ostream& os, fsinfo_options const& opts,
filesystem_info const* fsinfo,
std::function<void(const std::string&, uint32_t)> const& icb)
const override;
nlohmann::json
info_as_json(int detail_level, filesystem_info const& fsinfo) const override;
nlohmann::json info_as_json(fsinfo_options const& opts,
filesystem_info const* fsinfo) const override;
nlohmann::json as_json() const override;
std::string serialize_as_json(bool simple) const override;
@ -610,10 +617,10 @@ class metadata_ final : public metadata_v2::impl {
// TODO: see if we really need to pass the extra dir_entry_view in
// addition to directory_view
void dump(std::ostream& os, const std::string& indent, dir_entry_view entry,
int detail_level,
fsinfo_options const& opts,
std::function<void(const std::string&, uint32_t)> const& icb) const;
void dump(std::ostream& os, const std::string& indent, directory_view dir,
dir_entry_view entry, int detail_level,
dir_entry_view entry, fsinfo_options const& opts,
std::function<void(const std::string&, uint32_t)> const& icb) const;
nlohmann::json as_json(dir_entry_view entry) const;
@ -913,7 +920,7 @@ void metadata_<LoggerPolicy>::check_consistency() const {
template <typename LoggerPolicy>
void metadata_<LoggerPolicy>::dump(
std::ostream& os, const std::string& indent, dir_entry_view entry,
int detail_level,
fsinfo_options const& opts,
std::function<void(const std::string&, uint32_t)> const& icb) const {
auto iv = entry.inode();
auto mode = iv.mode();
@ -933,14 +940,13 @@ void metadata_<LoggerPolicy>::dump(
fmt::format("get_chunk_range({}): {}", inode, ec.message()));
os << " [" << cr.begin_ << ", " << cr.end_ << "]";
os << " " << file_size(iv, mode) << "\n";
if (detail_level > 4) {
if (opts.features.has(fsinfo_feature::chunk_details)) {
icb(indent + " ", inode);
}
} break;
case posix_file_type::directory:
dump(os, indent + " ", make_directory_view(iv), entry, detail_level,
std::move(icb));
dump(os, indent + " ", make_directory_view(iv), entry, opts, icb);
break;
case posix_file_type::symlink:
@ -967,8 +973,8 @@ void metadata_<LoggerPolicy>::dump(
template <typename LoggerPolicy>
nlohmann::json
metadata_<LoggerPolicy>::info_as_json(int detail_level,
filesystem_info const& fsinfo) const {
metadata_<LoggerPolicy>::info_as_json(fsinfo_options const& opts,
filesystem_info const* fsinfo) const {
nlohmann::json info;
vfs_stat stbuf;
statvfs(&stbuf);
@ -982,21 +988,25 @@ metadata_<LoggerPolicy>::info_as_json(int detail_level,
fmt::format("{:%Y-%m-%dT%H:%M:%S}", fmt::localtime(ts.value()));
}
if (detail_level > 0) {
if (opts.features.has(fsinfo_feature::metadata_summary)) {
info["block_size"] = meta_.block_size();
info["block_count"] = fsinfo.block_count;
if (fsinfo) {
info["block_count"] = fsinfo->block_count;
}
info["inode_count"] = stbuf.files;
if (auto ps = meta_.preferred_path_separator()) {
info["preferred_path_separator"] = std::string(1, static_cast<char>(*ps));
}
info["original_filesystem_size"] = stbuf.blocks;
info["compressed_block_size"] = fsinfo.compressed_block_size;
if (!fsinfo.uncompressed_block_size_is_estimate) {
info["uncompressed_block_size"] = fsinfo.uncompressed_block_size;
}
info["compressed_metadata_size"] = fsinfo.compressed_metadata_size;
if (!fsinfo.uncompressed_metadata_size_is_estimate) {
info["uncompressed_metadata_size"] = fsinfo.uncompressed_metadata_size;
if (fsinfo) {
info["compressed_block_size"] = fsinfo->compressed_block_size;
if (!fsinfo->uncompressed_block_size_is_estimate) {
info["uncompressed_block_size"] = fsinfo->uncompressed_block_size;
}
info["compressed_metadata_size"] = fsinfo->compressed_metadata_size;
if (!fsinfo->uncompressed_metadata_size_is_estimate) {
info["uncompressed_metadata_size"] = fsinfo->uncompressed_metadata_size;
}
}
if (auto opt = meta_.options()) {
@ -1020,16 +1030,18 @@ metadata_<LoggerPolicy>::info_as_json(int detail_level,
std::string name{catnames[category]};
categories[name] = {
{"block_count", ci.count},
{"compressed_size", ci.compressed_size},
};
if (!ci.uncompressed_size_is_estimate) {
categories[name]["uncompressed_size"] = ci.uncompressed_size;
if (ci.compressed_size) {
categories[name]["compressed_size"] = ci.compressed_size.value();
}
if (ci.uncompressed_size && !ci.uncompressed_size_is_estimate) {
categories[name]["uncompressed_size"] = ci.uncompressed_size.value();
}
}
}
}
if (detail_level > 2) {
if (opts.features.has(fsinfo_feature::metadata_details)) {
nlohmann::json meta;
meta["symlink_inode_offset"] = symlink_inode_offset_;
@ -1068,7 +1080,7 @@ metadata_<LoggerPolicy>::info_as_json(int detail_level,
info["meta"] = std::move(meta);
}
if (detail_level > 3) {
if (opts.features.has(fsinfo_feature::directory_tree)) {
info["root"] = as_json(root_);
}
@ -1079,7 +1091,7 @@ metadata_<LoggerPolicy>::info_as_json(int detail_level,
template <typename LoggerPolicy>
void metadata_<LoggerPolicy>::dump(
std::ostream& os, const std::string& indent, directory_view dir,
dir_entry_view entry, int detail_level,
dir_entry_view entry, fsinfo_options const& opts,
std::function<void(const std::string&, uint32_t)> const& icb) const {
auto count = dir.entry_count();
auto first = dir.first_entry();
@ -1087,14 +1099,14 @@ void metadata_<LoggerPolicy>::dump(
os << " (" << count << " entries, parent=" << dir.parent_entry() << ")\n";
for (size_t i = 0; i < count; ++i) {
dump(os, indent, make_dir_entry_view(first + i, entry.self_index()),
detail_level, icb);
dump(os, indent, make_dir_entry_view(first + i, entry.self_index()), opts,
icb);
}
}
template <typename LoggerPolicy>
void metadata_<LoggerPolicy>::dump(
std::ostream& os, int detail_level, filesystem_info const& fsinfo,
std::ostream& os, fsinfo_options const& opts, filesystem_info const* fsinfo,
std::function<void(const std::string&, uint32_t)> const& icb) const {
vfs_stat stbuf;
statvfs(&stbuf);
@ -1111,39 +1123,44 @@ void metadata_<LoggerPolicy>::dump(
os << "created on: " << str << "\n";
}
if (detail_level > 0) {
if (opts.features.has(fsinfo_feature::metadata_summary)) {
os << "block size: " << size_with_unit(stbuf.bsize) << "\n";
os << "block count: " << fsinfo.block_count << "\n";
if (fsinfo) {
os << "block count: " << fsinfo->block_count << "\n";
}
os << "inode count: " << stbuf.files << "\n";
if (auto ps = meta_.preferred_path_separator()) {
os << "preferred path separator: " << static_cast<char>(*ps) << "\n";
}
os << "original filesystem size: " << size_with_unit(stbuf.blocks) << "\n";
os << "compressed block size: "
<< size_with_unit(fsinfo.compressed_block_size);
if (!fsinfo.uncompressed_block_size_is_estimate) {
os << fmt::format(" ({0:.2f}%)", (100.0 * fsinfo.compressed_block_size) /
fsinfo.uncompressed_block_size);
if (fsinfo) {
os << "compressed block size: "
<< size_with_unit(fsinfo->compressed_block_size);
if (!fsinfo->uncompressed_block_size_is_estimate) {
os << fmt::format(" ({0:.2f}%)",
(100.0 * fsinfo->compressed_block_size) /
fsinfo->uncompressed_block_size);
}
os << "\n";
os << "uncompressed block size: ";
if (fsinfo->uncompressed_block_size_is_estimate) {
os << "(at least) ";
}
os << size_with_unit(fsinfo->uncompressed_block_size) << "\n";
os << "compressed metadata size: "
<< size_with_unit(fsinfo->compressed_metadata_size);
if (!fsinfo->uncompressed_metadata_size_is_estimate) {
os << fmt::format(" ({0:.2f}%)",
(100.0 * fsinfo->compressed_metadata_size) /
fsinfo->uncompressed_metadata_size);
}
os << "\n";
os << "uncompressed metadata size: ";
if (fsinfo->uncompressed_metadata_size_is_estimate) {
os << "(at least) ";
}
os << size_with_unit(fsinfo->uncompressed_metadata_size) << "\n";
}
os << "\n";
os << "uncompressed block size: ";
if (fsinfo.uncompressed_block_size_is_estimate) {
os << "(at least) ";
}
os << size_with_unit(fsinfo.uncompressed_block_size) << "\n";
os << "compressed metadata size: "
<< size_with_unit(fsinfo.compressed_metadata_size);
if (!fsinfo.uncompressed_metadata_size_is_estimate) {
os << fmt::format(" ({0:.2f}%)",
(100.0 * fsinfo.compressed_metadata_size) /
fsinfo.uncompressed_metadata_size);
}
os << "\n";
os << "uncompressed metadata size: ";
if (fsinfo.uncompressed_metadata_size_is_estimate) {
os << "(at least) ";
}
os << size_with_unit(fsinfo.uncompressed_metadata_size) << "\n";
if (auto opt = meta_.options()) {
std::vector<std::string> options;
parse_metadata_options(meta_, [&](auto const& name, bool value) {
@ -1163,15 +1180,20 @@ void metadata_<LoggerPolicy>::dump(
os << "categories:\n";
for (auto const& [category, ci] : catinfo) {
os << " " << catnames[category] << ": " << ci.count << " blocks";
if (ci.uncompressed_size_is_estimate ||
ci.uncompressed_size != ci.compressed_size) {
os << ", " << size_with_unit(ci.compressed_size) << " compressed";
}
if (!ci.uncompressed_size_is_estimate) {
os << ", " << size_with_unit(ci.uncompressed_size) << " uncompressed";
if (ci.uncompressed_size != ci.compressed_size) {
os << fmt::format(" ({0:.2f}%)", (100.0 * ci.compressed_size) /
ci.uncompressed_size);
if (ci.compressed_size) {
if (ci.uncompressed_size_is_estimate ||
ci.uncompressed_size.value() != ci.compressed_size.value()) {
os << ", " << size_with_unit(ci.compressed_size.value())
<< " compressed";
}
if (!ci.uncompressed_size_is_estimate) {
os << ", " << size_with_unit(ci.uncompressed_size.value())
<< " uncompressed";
if (ci.uncompressed_size.value() != ci.compressed_size.value()) {
os << fmt::format(" ({0:.2f}%)",
(100.0 * ci.compressed_size.value()) /
ci.uncompressed_size.value());
}
}
}
os << "\n";
@ -1179,11 +1201,11 @@ void metadata_<LoggerPolicy>::dump(
}
}
if (detail_level > 1) {
analyze_frozen(os, meta_, data_.size(), detail_level);
if (opts.features.has(fsinfo_feature::frozen_analysis)) {
analyze_frozen(os, meta_, data_.size(), opts);
}
if (detail_level > 2) {
if (opts.features.has(fsinfo_feature::metadata_details)) {
os << "symlink_inode_offset: " << symlink_inode_offset_ << "\n";
os << "file_inode_offset: " << file_inode_offset_ << "\n";
os << "dev_inode_offset: " << dev_inode_offset_ << "\n";
@ -1216,12 +1238,12 @@ void metadata_<LoggerPolicy>::dump(
analyze_chunks(os);
}
if (detail_level > 5) {
if (opts.features.has(fsinfo_feature::metadata_full_dump)) {
os << ::apache::thrift::debugString(meta_.thaw()) << '\n';
}
if (detail_level > 3) {
dump(os, "", root_, detail_level, icb);
if (opts.features.has(fsinfo_feature::directory_tree)) {
dump(os, "", root_, opts, icb);
}
}

View File

@ -323,10 +323,16 @@ int dwarfsck_main(int argc, sys_char** argv, iolayer const& iol) {
auto errors = no_check ? 0 : fs.check(level, num_workers);
if (!quiet && !list_files && checksum_algo.empty()) {
fsinfo_options opts;
opts.block_access = no_check ? block_access_level::no_verify
: block_access_level::unrestricted;
opts.features = filesystem_v2::features_for_level(detail);
if (output_json) {
iol.out << fs.info_as_json(detail) << "\n";
iol.out << fs.info_as_json(opts) << "\n";
} else {
fs.dump(iol.out, detail);
fs.dump(iol.out, opts);
}
}

View File

@ -1006,8 +1006,10 @@ TEST_P(tools_test, end_to_end) {
for (auto const& [path, ref] : xattr_tests) {
EXPECT_EQ(dwarfs::listxattr(path), ref) << runner.cmdline();
auto info =
nlohmann::json::parse(dwarfs::getxattr(path, kInodeInfoXattr));
auto xattr = dwarfs::getxattr(path, kInodeInfoXattr);
nlohmann::json info;
EXPECT_NO_THROW(info = nlohmann::json::parse(xattr))
<< runner.cmdline() << ", " << xattr;
EXPECT_TRUE(info.count("uid"));
EXPECT_TRUE(info.count("gid"));
EXPECT_TRUE(info.count("mode"));
@ -1556,7 +1558,8 @@ TEST_P(tools_test, categorize) {
image_recompressed, "--json");
ASSERT_TRUE(json_info);
auto info = nlohmann::json::parse(*json_info);
nlohmann::json info;
EXPECT_NO_THROW(info = nlohmann::json::parse(*json_info)) << *json_info;
EXPECT_EQ(info["block_size"], 65'536);
EXPECT_EQ(info["image_offset"], 0);