mirror of
https://github.com/mhx/dwarfs.git
synced 2025-09-10 04:50:31 -04:00
refactor: switch from detail level to info features
This commit is contained in:
parent
964a4f49e6
commit
8199919d36
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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,6 +589,7 @@ 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());
|
||||
if (opts.block_access >= block_access_level::unrestricted) {
|
||||
try {
|
||||
auto uncompressed_size = get_uncompressed_section_size(mm_, *s);
|
||||
info.uncompressed_block_size += uncompressed_size;
|
||||
@ -570,6 +599,11 @@ filesystem_info const& filesystem_<LoggerPolicy>::get_info() const {
|
||||
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);
|
||||
}
|
||||
} else if (s->type() == section_type::METADATA_V2) {
|
||||
info.compressed_metadata_size += s->length();
|
||||
try {
|
||||
@ -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,17 +1013,16 @@ 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) {
|
||||
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";
|
||||
os << indent << chunks.size() << " chunks in inode " << inode << "\n";
|
||||
ir_.dump(os, indent + " ", chunks);
|
||||
} else {
|
||||
LOG_ERROR << "error reading chunks for inode " << inode << ": "
|
||||
@ -982,14 +1032,15 @@ void filesystem_<LoggerPolicy>::dump(std::ostream& os, int detail_level) const {
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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,28 +332,34 @@ 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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return catinfo;
|
||||
}
|
||||
@ -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;
|
||||
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;
|
||||
}
|
||||
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";
|
||||
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);
|
||||
<< 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) {
|
||||
if (fsinfo->uncompressed_block_size_is_estimate) {
|
||||
os << "(at least) ";
|
||||
}
|
||||
os << size_with_unit(fsinfo.uncompressed_block_size) << "\n";
|
||||
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) {
|
||||
<< 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);
|
||||
(100.0 * fsinfo->compressed_metadata_size) /
|
||||
fsinfo->uncompressed_metadata_size);
|
||||
}
|
||||
os << "\n";
|
||||
os << "uncompressed metadata size: ";
|
||||
if (fsinfo.uncompressed_metadata_size_is_estimate) {
|
||||
if (fsinfo->uncompressed_metadata_size_is_estimate) {
|
||||
os << "(at least) ";
|
||||
}
|
||||
os << size_with_unit(fsinfo.uncompressed_metadata_size) << "\n";
|
||||
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.compressed_size) {
|
||||
if (ci.uncompressed_size_is_estimate ||
|
||||
ci.uncompressed_size != ci.compressed_size) {
|
||||
os << ", " << size_with_unit(ci.compressed_size) << " compressed";
|
||||
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) << " uncompressed";
|
||||
if (ci.uncompressed_size != ci.compressed_size) {
|
||||
os << fmt::format(" ({0:.2f}%)", (100.0 * ci.compressed_size) /
|
||||
ci.uncompressed_size);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user