diff --git a/src/init.cpp b/src/init.cpp index 407ee0fefff..4b6e00bdf6f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1972,7 +1972,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // On first startup, warn on low block storage space if (!do_reindex && !do_reindex_chainstate && chain_active_height <= 1) { - uint64_t assumed_chain_bytes{chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024}; + uint64_t assumed_chain_bytes{chainparams.AssumedBlockchainSize() * 1_GiB}; uint64_t additional_bytes_needed{ chainman.m_blockman.IsPruneMode() ? std::min(chainman.m_blockman.GetPruneTarget(), assumed_chain_bytes) : diff --git a/src/node/caches.cpp b/src/node/caches.cpp index cb8afbc967d..3b9e609f367 100644 --- a/src/node/caches.cpp +++ b/src/node/caches.cpp @@ -20,17 +20,17 @@ // Unlike for the UTXO database, for the txindex scenario the leveldb cache make // a meaningful difference: https://github.com/bitcoin/bitcoin/pull/8273#issuecomment-229601991 //! Max memory allocated to tx index DB specific cache in bytes. -static constexpr size_t MAX_TX_INDEX_CACHE{1024_MiB}; +static constexpr size_t MAX_TX_INDEX_CACHE{1_GiB}; //! Max memory allocated to all block filter index caches combined in bytes. -static constexpr size_t MAX_FILTER_INDEX_CACHE{1024_MiB}; +static constexpr size_t MAX_FILTER_INDEX_CACHE{1_GiB}; //! Max memory allocated to tx spenderindex DB specific cache in bytes. -static constexpr size_t MAX_TXOSPENDER_INDEX_CACHE{1024_MiB}; +static constexpr size_t MAX_TXOSPENDER_INDEX_CACHE{1_GiB}; //! Maximum dbcache size on 32-bit systems. -static constexpr size_t MAX_32BIT_DBCACHE{1024_MiB}; +static constexpr size_t MAX_32BIT_DBCACHE{1_GiB}; //! Larger default dbcache on 64-bit systems with enough RAM. -static constexpr size_t HIGH_DEFAULT_DBCACHE{1024_MiB}; +static constexpr size_t HIGH_DEFAULT_DBCACHE{1_GiB}; //! Minimum detected RAM required for HIGH_DEFAULT_DBCACHE. -static constexpr uint64_t HIGH_DEFAULT_DBCACHE_MIN_TOTAL_RAM{4096ULL << 20}; +static constexpr uint64_t HIGH_DEFAULT_DBCACHE_MIN_TOTAL_RAM{uint64_t{4} * 1_GiB}; namespace node { size_t GetDefaultDBCache() diff --git a/src/node/caches.h b/src/node/caches.h index 62f097411ba..483521dfcfc 100644 --- a/src/node/caches.h +++ b/src/node/caches.h @@ -31,7 +31,7 @@ struct CacheSizes { CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes = 0); constexpr bool ShouldWarnOversizedDbCache(size_t dbcache, size_t total_ram) noexcept { - const size_t cap{(total_ram < 2048_MiB) ? DEFAULT_DB_CACHE : (total_ram / 100) * 75}; + const size_t cap{(total_ram < 2_GiB) ? DEFAULT_DB_CACHE : (total_ram / 100) * 75}; return dbcache > cap; } diff --git a/src/test/caches_tests.cpp b/src/test/caches_tests.cpp index f444f1be239..bdca1d40f82 100644 --- a/src/test/caches_tests.cpp +++ b/src/test/caches_tests.cpp @@ -14,30 +14,30 @@ BOOST_AUTO_TEST_SUITE(caches_tests) BOOST_AUTO_TEST_CASE(oversized_dbcache_warning) { // memory restricted setup - cap is DEFAULT_DB_CACHE (450 MiB) - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/4_MiB, /*total_ram=*/1024_MiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/512_MiB, /*total_ram=*/1024_MiB)); // At cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/1500_MiB, /*total_ram=*/1024_MiB)); // Over cap + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/4_MiB, /*total_ram=*/1_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/512_MiB, /*total_ram=*/1_GiB)); // At cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/1500_MiB, /*total_ram=*/1_GiB)); // Over cap // 2 GiB RAM - cap is 75% - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/1500_MiB, /*total_ram=*/2048_MiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/1600_MiB, /*total_ram=*/2048_MiB)); // Over cap + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/1500_MiB, /*total_ram=*/2_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/1600_MiB, /*total_ram=*/2_GiB)); // Over cap if constexpr (SIZE_MAX == UINT64_MAX) { // 4 GiB RAM - cap is 75% - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/2500_MiB, /*total_ram=*/4096_MiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/3500_MiB, /*total_ram=*/4096_MiB)); // Over cap + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/2500_MiB, /*total_ram=*/4_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/3500_MiB, /*total_ram=*/4_GiB)); // Over cap // 8 GiB RAM - cap is 75% - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/6000_MiB, /*total_ram=*/8192_MiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/7000_MiB, /*total_ram=*/8192_MiB)); // Over cap + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/6000_MiB, /*total_ram=*/8_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/7000_MiB, /*total_ram=*/8_GiB)); // Over cap // 16 GiB RAM - cap is 75% - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/10'000_MiB, /*total_ram=*/16384_MiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/15'000_MiB, /*total_ram=*/16384_MiB)); // Over cap + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/10'000_MiB, /*total_ram=*/16_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/15'000_MiB, /*total_ram=*/16_GiB)); // Over cap // 32 GiB RAM - cap is 75% - BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/20'000_MiB, /*total_ram=*/32768_MiB)); // Under cap - BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/30'000_MiB, /*total_ram=*/32768_MiB)); // Over cap + BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/20'000_MiB, /*total_ram=*/32_GiB)); // Under cap + BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/30'000_MiB, /*total_ram=*/32_GiB)); // Over cap } } diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index dc6a5cf3250..796a9debc05 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1636,7 +1636,7 @@ BOOST_AUTO_TEST_CASE(util_ParseByteUnits) BOOST_CHECK_EQUAL(ParseByteUnits("2M", noop).value(), 2ULL << 20); BOOST_CHECK_EQUAL(ParseByteUnits("3g", noop).value(), 3'000'000'000ULL); - BOOST_CHECK_EQUAL(ParseByteUnits("3G", noop).value(), 3ULL << 30); + BOOST_CHECK_EQUAL(ParseByteUnits("3G", noop).value(), 3_GiB); BOOST_CHECK_EQUAL(ParseByteUnits("4t", noop).value(), 4'000'000'000'000ULL); BOOST_CHECK_EQUAL(ParseByteUnits("4T", noop).value(), 4ULL << 40); @@ -1829,10 +1829,11 @@ BOOST_AUTO_TEST_CASE(saturating_left_shift_test) BOOST_AUTO_TEST_CASE(mib_string_literal_test) { + // Basic equivalences and simple arithmetic operations BOOST_CHECK_EQUAL(0_MiB, 0); BOOST_CHECK_EQUAL(1_MiB, 1024 * 1024); - const auto max_mib{std::numeric_limits::max() >> 20}; - BOOST_CHECK_EXCEPTION(operator""_MiB(static_cast(max_mib) + 1), std::overflow_error, HasReason("MiB value too large for size_t byte conversion")); + constexpr auto max_mib{std::numeric_limits::max() >> 20}; + BOOST_CHECK_EXCEPTION(operator""_MiB(max_mib + 1), std::overflow_error, HasReason("MiB value too large for size_t byte conversion")); } BOOST_AUTO_TEST_CASE(ceil_div_test) @@ -1872,4 +1873,37 @@ BOOST_AUTO_TEST_CASE(ceil_div_test) BOOST_CHECK_EQUAL(CeilDiv(sizeof(uint64_t) * 8, 7u), (sizeof(uint64_t) * 8 + 6) / 7); } +BOOST_AUTO_TEST_CASE(gib_string_literal_test) +{ + // Basic equivalences and simple arithmetic operations + BOOST_CHECK_EQUAL(0_GiB, 0); + BOOST_CHECK_EQUAL(1_GiB, 1 << 30); + BOOST_CHECK_EQUAL(1_GiB, 1024 * 1024 * 1024); + BOOST_CHECK_EQUAL(1_GiB, 0x40000000U); + BOOST_CHECK_EQUAL(1_GiB, 1073741824U); + BOOST_CHECK_EQUAL(1_GiB, 1_MiB * 1024); + BOOST_CHECK_EQUAL(1_GiB, 1024_MiB); + BOOST_CHECK_EQUAL((1_GiB + 123) / double(1_GiB), (1_GiB + 123) / 1024.0 / 1024.0 / 1024.0); + BOOST_CHECK_EQUAL(2ULL * 1_GiB, 2ULL << 30); + BOOST_CHECK_EQUAL(4 * uint64_t{1_GiB}, uint64_t{4} << 30); + BOOST_CHECK_EQUAL(2_GiB, 2048_MiB); + BOOST_CHECK_EQUAL(3_GiB / 1_GiB, 3U); + BOOST_CHECK_EQUAL(3_GiB, 3U << 30); + + // Overflow handling and specific codebase values + constexpr auto max_gib{std::numeric_limits::max() >> 30}; + if constexpr (SIZE_MAX == UINT32_MAX) { + BOOST_CHECK_EQUAL(max_gib, 3U); + BOOST_CHECK_EXCEPTION(4_GiB, std::overflow_error, HasReason("GiB value too large for size_t byte conversion")); + } else { + BOOST_CHECK_GT(max_gib, 3U); + BOOST_CHECK_EQUAL(4_GiB, size_t{4} << 30); + BOOST_CHECK_EQUAL(4_GiB, 4096_MiB); + BOOST_CHECK_EQUAL(8_GiB, 8192_MiB); + BOOST_CHECK_EQUAL(16_GiB, 16384_MiB); + BOOST_CHECK_EQUAL(32_GiB, 32768_MiB); + } + BOOST_CHECK_EXCEPTION(operator""_GiB(max_gib + 1), std::overflow_error, HasReason("GiB value too large for size_t byte conversion")); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util/byte_units.h b/src/util/byte_units.h index 3d6a9627d88..b67af5a48e4 100644 --- a/src/util/byte_units.h +++ b/src/util/byte_units.h @@ -7,16 +7,31 @@ #include +#include #include +namespace util::detail { +template +constexpr size_t ByteUnitsToBytes(unsigned long long units, const char* exception_msg) +{ + const auto bytes{CheckedLeftShift(units, SHIFT)}; + if (!bytes || *bytes > std::numeric_limits::max()) { + throw std::overflow_error(exception_msg); + } + return *bytes; +} +} // namespace util::detail + //! Overflow-safe conversion of MiB to bytes. constexpr size_t operator""_MiB(unsigned long long mebibytes) { - auto bytes{CheckedLeftShift(mebibytes, 20)}; - if (!bytes || *bytes > std::numeric_limits::max()) { - throw std::overflow_error("MiB value too large for size_t byte conversion"); - } - return *bytes; + return util::detail::ByteUnitsToBytes<20>(mebibytes, "MiB value too large for size_t byte conversion"); +} + +//! Overflow-safe conversion of GiB to bytes. +constexpr size_t operator""_GiB(unsigned long long gibibytes) +{ + return util::detail::ByteUnitsToBytes<30>(gibibytes, "GiB value too large for size_t byte conversion"); } #endif // BITCOIN_UTIL_BYTE_UNITS_H