mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-10 22:58:40 +02:00
util: add _GiB for Gibibyte conversions
Introduce `operator""_GiB`, sharing the overflow-checked conversion logic with the existing `operator""_MiB`. Use `1_GiB` in a few existing places where it is a drop-in replacement (e.g. `1024_MiB`, `1<<30`) and extend unit tests to cover boundary behavior.
This commit is contained in:
@@ -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) :
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<size_t>::max() >> 20};
|
||||
BOOST_CHECK_EXCEPTION(operator""_MiB(static_cast<unsigned long long>(max_mib) + 1), std::overflow_error, HasReason("MiB value too large for size_t byte conversion"));
|
||||
constexpr auto max_mib{std::numeric_limits<size_t>::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<size_t>::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()
|
||||
|
||||
@@ -7,16 +7,31 @@
|
||||
|
||||
#include <util/overflow.h>
|
||||
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace util::detail {
|
||||
template <unsigned SHIFT>
|
||||
constexpr size_t ByteUnitsToBytes(unsigned long long units, const char* exception_msg)
|
||||
{
|
||||
const auto bytes{CheckedLeftShift(units, SHIFT)};
|
||||
if (!bytes || *bytes > std::numeric_limits<size_t>::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<size_t>::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
|
||||
|
||||
Reference in New Issue
Block a user