diff --git a/include/dwarfs/fstypes.h b/include/dwarfs/fstypes.h index 1b945aee..616b4c7f 100644 --- a/include/dwarfs/fstypes.h +++ b/include/dwarfs/fstypes.h @@ -114,6 +114,14 @@ struct section_header_v2 { void dump(std::ostream& os) const; }; +struct filesystem_info { + uint64_t block_count{0}; + uint64_t compressed_block_size{0}; + uint64_t uncompressed_block_size{0}; + uint64_t compressed_metadata_size{0}; + uint64_t uncompressed_metadata_size{0}; +}; + bool is_valid_compression_type(compression_type type); bool is_valid_section_type(section_type type); diff --git a/include/dwarfs/metadata_v2.h b/include/dwarfs/metadata_v2.h index 5a75332d..416bcd4b 100644 --- a/include/dwarfs/metadata_v2.h +++ b/include/dwarfs/metadata_v2.h @@ -48,6 +48,8 @@ class logger; struct metadata_options; +struct filesystem_info; + namespace thrift::metadata { class metadata; } @@ -63,9 +65,9 @@ class metadata_v2 { metadata_v2& operator=(metadata_v2&&) = default; void - dump(std::ostream& os, int detail_level, + dump(std::ostream& os, int detail_level, filesystem_info const& fsinfo, std::function const& icb) const { - impl_->dump(os, detail_level, icb); + impl_->dump(os, detail_level, fsinfo, icb); } folly::dynamic as_dynamic() const { return impl_->as_dynamic(); } @@ -141,7 +143,7 @@ class metadata_v2 { virtual ~impl() = default; virtual void dump( - std::ostream& os, int detail_level, + std::ostream& os, int detail_level, filesystem_info const& fsinfo, std::function const& icb) const = 0; virtual folly::dynamic as_dynamic() const = 0; diff --git a/src/dwarfs/filesystem_v2.cpp b/src/dwarfs/filesystem_v2.cpp index ca88f109..4121f8e2 100644 --- a/src/dwarfs/filesystem_v2.cpp +++ b/src/dwarfs/filesystem_v2.cpp @@ -191,6 +191,14 @@ class filesystem_parser { using section_map = std::unordered_map; +size_t +get_uncompressed_section_size(std::shared_ptr mm, fs_section const& sec) { + std::vector tmp; + block_decompressor bd(sec.compression(), mm->as(sec.start()), + sec.length(), tmp); + return bd.uncompressed_size(); +} + folly::ByteRange get_section_data(std::shared_ptr mm, fs_section const& section, std::vector& buffer, bool force_buffer) { @@ -297,6 +305,7 @@ class filesystem_ final : public filesystem_v2::impl { inode_reader_v2 ir_; std::vector meta_buffer_; std::optional header_; + filesystem_info fsinfo_; }; template @@ -317,6 +326,9 @@ filesystem_::filesystem_(logger& lgr, std::shared_ptr mm, << s->length() << " bytes]"; if (s->type() == section_type::BLOCK) { cache.insert(*s); + ++fsinfo_.block_count; + fsinfo_.compressed_block_size += s->length(); + fsinfo_.uncompressed_block_size += get_uncompressed_section_size(mm_, *s); } else { if (!s->check_fast(*mm_)) { DWARFS_THROW(runtime_error, "checksum error in section: " + s->name()); @@ -325,6 +337,12 @@ filesystem_::filesystem_(logger& lgr, std::shared_ptr mm, if (!sections.emplace(s->type(), *s).second) { DWARFS_THROW(runtime_error, "duplicate section: " + s->name()); } + + if (s->type() == section_type::METADATA_V2) { + fsinfo_.compressed_metadata_size += s->length(); + fsinfo_.uncompressed_metadata_size += + get_uncompressed_section_size(mm_, *s); + } } } @@ -344,14 +362,16 @@ filesystem_::filesystem_(logger& lgr, std::shared_ptr mm, template void filesystem_::dump(std::ostream& os, int detail_level) const { - meta_.dump(os, detail_level, [&](const std::string& indent, uint32_t inode) { - if (auto chunks = meta_.get_chunks(inode)) { - os << indent << chunks->size() << " chunks in inode " << inode << "\n"; - ir_.dump(os, indent + " ", *chunks); - } else { - LOG_ERROR << "error reading chunks for inode " << inode; - } - }); + meta_.dump(os, detail_level, fsinfo_, + [&](const std::string& indent, uint32_t inode) { + if (auto chunks = meta_.get_chunks(inode)) { + os << indent << chunks->size() << " chunks in inode " << inode + << "\n"; + ir_.dump(os, indent + " ", *chunks); + } else { + LOG_ERROR << "error reading chunks for inode " << inode; + } + }); } template @@ -612,14 +632,12 @@ int filesystem_v2::identify(logger& lgr, std::shared_ptr mm, try { auto s = sf.get(); - std::vector tmp; - block_decompressor bd(s.compression(), mm->as(s.start()), - s.length(), tmp); - float compression_ratio = float(s.length()) / bd.uncompressed_size(); + auto uncompressed_size = get_uncompressed_section_size(mm, s); + float compression_ratio = float(s.length()) / uncompressed_size; if (detail_level > 2) { os << "SECTION " << s.description() - << ", blocksize=" << bd.uncompressed_size() + << ", blocksize=" << uncompressed_size << ", ratio=" << fmt::format("{:.2f}%", 100.0 * compression_ratio) << std::endl; } diff --git a/src/dwarfs/metadata_v2.cpp b/src/dwarfs/metadata_v2.cpp index badc90a4..08bfce9c 100644 --- a/src/dwarfs/metadata_v2.cpp +++ b/src/dwarfs/metadata_v2.cpp @@ -48,6 +48,7 @@ #include #include "dwarfs/error.h" +#include "dwarfs/fstypes.h" #include "dwarfs/logger.h" #include "dwarfs/metadata_v2.h" #include "dwarfs/options.h" @@ -375,7 +376,7 @@ class metadata_ final : public metadata_v2::impl { } } - void dump(std::ostream& os, int detail_level, + void dump(std::ostream& os, int detail_level, filesystem_info const& fsinfo, std::function const& icb) const override; @@ -795,7 +796,7 @@ void metadata_::dump( template void metadata_::dump( - std::ostream& os, int detail_level, + std::ostream& os, int detail_level, filesystem_info const& fsinfo, std::function const& icb) const { struct ::statvfs stbuf; statvfs(&stbuf); @@ -814,9 +815,24 @@ void metadata_::dump( if (detail_level > 0) { os << "block size: " << size_with_unit(stbuf.f_bsize) << std::endl; + os << "block count: " << fsinfo.block_count << std::endl; os << "inode count: " << stbuf.f_files << std::endl; os << "original filesystem size: " << size_with_unit(stbuf.f_blocks) << std::endl; + os << "compressed block size: " + << size_with_unit(fsinfo.compressed_block_size) + << fmt::format(" ({0:.2f}%)", (100.0 * fsinfo.compressed_block_size) / + fsinfo.uncompressed_block_size) + << std::endl; + os << "uncompressed block size: " + << size_with_unit(fsinfo.uncompressed_block_size) << std::endl; + os << "compressed metadata size: " + << size_with_unit(fsinfo.compressed_metadata_size) + << fmt::format(" ({0:.2f}%)", (100.0 * fsinfo.compressed_metadata_size) / + fsinfo.uncompressed_metadata_size) + << std::endl; + os << "uncompressed metadata size: " + << size_with_unit(fsinfo.uncompressed_metadata_size) << std::endl; if (auto opt = meta_.options()) { std::vector options; auto boolopt = [&](auto const& name, bool value) {