diff --git a/src/include/firebird/impl/msg/gstat.h b/src/include/firebird/impl/msg/gstat.h index 6fe4f06209..d3bb536d48 100644 --- a/src/include/firebird/impl/msg/gstat.h +++ b/src/include/firebird/impl/msg/gstat.h @@ -60,3 +60,5 @@ FB_IMPL_MSG_NO_SYMBOL(GSTAT, 59, "Gstat execution time @1") FB_IMPL_MSG_NO_SYMBOL(GSTAT, 60, "Gstat completion time @1") FB_IMPL_MSG_NO_SYMBOL(GSTAT, 61, " Expected page inventory page @1") FB_IMPL_MSG_NO_SYMBOL(GSTAT, 62, "Generator pages: total @1, encrypted @2, non-crypted @3") +FB_IMPL_MSG_NO_SYMBOL(GSTAT, 63, " Table size: @1 bytes") +FB_IMPL_MSG_NO_SYMBOL(GSTAT, 64, " Level @1: @2, total length: @3, blob pages: @4") diff --git a/src/utilities/gstat/dba.epp b/src/utilities/gstat/dba.epp index 5bf89a5d4b..b339dc1861 100644 --- a/src/utilities/gstat/dba.epp +++ b/src/utilities/gstat/dba.epp @@ -123,6 +123,22 @@ struct dba_fmt bool fmt_used; }; +inline constexpr ULONG MAX_BLOB_LEVELS = 3; +struct dba_blob_statistics +{ + FB_UINT64 blob_count = 0; + FB_UINT64 blob_space = 0; + FB_UINT64 blob_pages = 0; + + dba_blob_statistics& operator+=(const dba_blob_statistics& rhs) + { + blob_count += rhs.blob_count; + blob_space += rhs.blob_space; + blob_pages += rhs.blob_pages; + return *this; + } +}; + struct dba_rel { dba_rel* rel_next; @@ -147,10 +163,7 @@ struct dba_rel FB_UINT64 rel_fragments; FB_UINT64 rel_fragment_space; FB_UINT64 rel_max_fragments; - FB_UINT64 rel_blobs_level_0; - FB_UINT64 rel_blobs_level_1; - FB_UINT64 rel_blobs_level_2; - FB_UINT64 rel_blob_space; + dba_blob_statistics rel_blob_statistics[MAX_BLOB_LEVELS]; ULONG rel_fill_distribution[BUCKETS]; FB_UINT64 rel_format_space; FB_UINT64 rel_total_space; @@ -1024,16 +1037,46 @@ int gstat(Firebird::UtilSvc* uSvc) // msg 47: " Big record pages: @1 } - if (relation->rel_blobs_level_0 || relation->rel_blobs_level_1 || relation->rel_blobs_level_2) + // Blobs are analyzing only when the record option is set + if (sw_record) { - dba_print(false, 48, SafeArg() << (relation->rel_blobs_level_0 + relation->rel_blobs_level_1 + - relation->rel_blobs_level_2) << relation->rel_blob_space << - relation->rel_blob_pages); - // msg 48: " Blobs: @1, total length: @2, blob pages: @3 + dba_blob_statistics blobsTotal; + for (ULONG i = 0; i < MAX_BLOB_LEVELS; ++i) + { + blobsTotal += relation->rel_blob_statistics[i]; + } - dba_print(false, 49, SafeArg() << relation->rel_blobs_level_0 << relation->rel_blobs_level_1 << - relation->rel_blobs_level_2); - // msg 49: " Level 0: @1, Level 1: @2, Level 2: @3 + if (blobsTotal.blob_count) + { + dba_print(false, 48, SafeArg() + << blobsTotal.blob_count + << blobsTotal.blob_space + << blobsTotal.blob_pages); + // msg 48: " Blobs: @1, total length: @2, blob pages: @3 + + for (ULONG i = 0; i < MAX_BLOB_LEVELS; ++i) + { + const dba_blob_statistics& blob_level = relation->rel_blob_statistics[i]; + + if (blob_level.blob_count > 0) + { + dba_print(false, 49, SafeArg() + << i + << blob_level.blob_count + << blob_level.blob_space + << blob_level.blob_pages); + // msg 64: " Level @1: @2, total length: @3, blob pages: @4 + } + } + } + + + const FB_SIZE_T tableSize = tddba->page_size * ( + relation->rel_pointer_pages + + relation->rel_data_pages + + blobsTotal.blob_pages); + + dba_print(false, 63, SafeArg() << tableSize); // msg 63: "Table size: @1 bytes } dba_print(false, 13); // msg 13: " Fill distribution:" @@ -1401,32 +1444,31 @@ static bool analyze_data_page( dba_rel* relation, const data_page* page, bool sw static void analyze_blob(dba_rel* relation, const blh* blob, int length) { - relation->rel_blob_space += blob->blh_length; - if (!blob->blh_level) - { - relation->rel_blobs_level_0++; - } - else + fb_assert(blob->blh_level < MAX_BLOB_LEVELS); + dba_blob_statistics& blob_level = relation->rel_blob_statistics[blob->blh_level]; + + ++blob_level.blob_count; + blob_level.blob_space += blob->blh_length; + + if (blob->blh_level != 0) { const int slots = (length - BLH_SIZE) / static_cast(sizeof(SLONG)); - relation->rel_blob_pages += slots; - if (blob->blh_level == 1) - { - relation->rel_blobs_level_1++; - } - else - { - relation->rel_blobs_level_2++; + ULONG blobPages = slots; + if (blob->blh_level == 2) + { SLONG pages[MAX_PAGE_SIZE / sizeof(SLONG)]; memcpy(pages, blob->blh_page, slots * sizeof(SLONG)); for (int i = 0; i < slots; i++) { const blob_page* bpage = (const blob_page*) db_read(pages[i]); - relation->rel_blob_pages += bpage->blp_length / sizeof(SLONG); + blobPages += bpage->blp_length / sizeof(SLONG); } } + + relation->rel_blob_pages += blobPages; + blob_level.blob_pages += blobPages; } }