Merge 9245 via ionice

This commit is contained in:
Luke Dashjr 2025-03-05 03:27:08 +00:00
commit 20f5b5a056
8 changed files with 183 additions and 15 deletions

View File

@ -1014,6 +1014,46 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
[ AC_MSG_RESULT([no])]
)
AC_MSG_CHECKING(for macOS iopolicy functions)
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[
#include <sys/resource.h>
]],[[
int x = getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD);
setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, x);
]])
],[
AC_MSG_RESULT([yes])
HAVE_IOPOLICY=1
],[
AC_MSG_RESULT([no])
HAVE_IOPOLICY=0
])
AC_DEFINE_UNQUOTED([HAVE_IOPOLICY], [$HAVE_IOPOLICY], [Define to 1 if macOS iopolicy functions are usable.])
if test x$HAVE_IOPOLICY = x0; then
AC_MSG_CHECKING(for Linux ioprio syscalls)
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
]],[[
int x = syscall(SYS_ioprio_get, 1, 0);
syscall(SYS_ioprio_set, 1, 0, x);
]])
],[
AC_MSG_RESULT([yes])
HAVE_IOPRIO_SYSCALL=1
],[
AC_MSG_RESULT([no])
HAVE_IOPRIO_SYSCALL=0
])
else
HAVE_IOPRIO_SYSCALL=0
fi
AC_DEFINE_UNQUOTED([HAVE_IOPRIO_SYSCALL], [$HAVE_IOPRIO_SYSCALL], [Define to 1 if Linux ioprio syscalls are usable.])
dnl Check for different ways of gathering OS randomness
AC_MSG_CHECKING([for Linux getrandom function])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[

View File

@ -319,6 +319,7 @@ BITCOIN_CORE_H = \
util/hash_type.h \
util/hasher.h \
util/insert.h \
util/ioprio.h \
util/macros.h \
util/moneystr.h \
util/overflow.h \
@ -752,6 +753,7 @@ libbitcoin_util_a_SOURCES = \
util/fs.cpp \
util/fs_helpers.cpp \
util/hasher.cpp \
util/ioprio.cpp \
util/sock.cpp \
util/syserror.cpp \
util/moneystr.cpp \

View File

@ -2542,7 +2542,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
// Fast-path: in this case it is possible to serve the block directly from disk,
// as the network format matches the format on disk
std::vector<uint8_t> block_data;
if (!m_chainman.m_blockman.ReadRawBlockFromDisk(block_data, block_pos)) {
if (!m_chainman.m_blockman.ReadRawBlockFromDisk(block_data, block_pos, /*lowprio=*/true)) {
if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) {
LogPrint(BCLog::NET, "Block was pruned before it could be read, disconnect peer=%s\n", pfrom.GetId());
} else {
@ -2556,7 +2556,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
} else {
// Send block from disk
std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
if (!m_chainman.m_blockman.ReadBlockFromDisk(*pblockRead, block_pos)) {
if (!m_chainman.m_blockman.ReadBlockFromDisk(*pblockRead, block_pos, /*lowprio=*/true)) {
if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) {
LogPrint(BCLog::NET, "Block was pruned before it could be read, disconnect peer=%s\n", pfrom.GetId());
} else {
@ -4460,7 +4460,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (!block_pos.IsNull()) {
CBlock block;
const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, block_pos)};
const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, block_pos, /*lowprio=*/true)};
// If height is above MAX_BLOCKTXN_DEPTH then this block cannot get
// pruned after we release cs_main above, so this read should never fail.
assert(ret);
@ -6078,7 +6078,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
PushMessage(*pto, std::move(cached_cmpctblock_msg.value()));
} else {
CBlock block;
const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, *pBestIndex)};
const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, *pBestIndex, /*lowprio=*/true)};
assert(ret);
CBlockHeaderAndShortTxIDs cmpctblock{block, m_rng.rand64()};
MakeAndPushMessage(*pto, NetMsgType::CMPCTBLOCK, cmpctblock);

View File

@ -31,6 +31,7 @@
#include <util/batchpriority.h>
#include <util/check.h>
#include <util/fs.h>
#include <util/ioprio.h>
#include <util/overflow.h>
#include <util/signalinterrupt.h>
#include <util/strencodings.h>
@ -1159,10 +1160,13 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid
return true;
}
bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) const
bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const bool lowprio) const
{
block.SetNull();
{
IOPRIO_IDLER(lowprio);
// Open history file to read
AutoFile filein{OpenBlockFile(pos, true)};
if (filein.IsNull()) {
@ -1178,6 +1182,8 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) cons
return false;
}
} // end IOPRIO_IDLER scope
// Check the header
if (!CheckProofOfWork(block.GetHash(), block.nBits, GetConsensus())) {
LogError("%s: Errors in block header at %s\n", __func__, pos.ToString());
@ -1193,11 +1199,11 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) cons
return true;
}
bool BlockManager::ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) const
bool BlockManager::ReadBlockFromDisk(CBlock& block, const CBlockIndex& index, const bool lowprio) const
{
const FlatFilePos block_pos{WITH_LOCK(cs_main, return index.GetBlockPos())};
if (!ReadBlockFromDisk(block, block_pos)) {
if (!ReadBlockFromDisk(block, block_pos, lowprio)) {
return false;
}
if (block.GetHash() != index.GetBlockHash()) {
@ -1207,7 +1213,7 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) co
return true;
}
bool BlockManager::ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos) const
bool BlockManager::ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const bool lowprio) const
{
FlatFilePos hpos = pos;
// If nPos is less than 8 the pos is null and we don't have the block data
@ -1217,6 +1223,9 @@ bool BlockManager::ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatF
return false;
}
hpos.nPos -= 8; // Seek back 8 bytes for meta header
IOPRIO_IDLER(lowprio);
AutoFile filein{OpenBlockFile(hpos, true)};
if (filein.IsNull()) {
LogError("%s: OpenBlockFile failed for %s\n", __func__, pos.ToString());

View File

@ -444,9 +444,9 @@ public:
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune) const;
/** Functions for disk access for blocks */
bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) const;
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) const;
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos) const;
bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, bool lowprio = false) const;
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex& index, bool lowprio = false) const;
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, bool lowprio = false) const;
bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& index) const;

57
src/util/ioprio.cpp Normal file
View File

@ -0,0 +1,57 @@
// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
#include <util/ioprio.h>
#if HAVE_IOPRIO_SYSCALL
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <sys/syscall.h>
#ifndef IOPRIO_WHO_PROCESS
#define IOPRIO_WHO_PROCESS 1
#endif
#ifndef IOPRIO_CLASS_IDLE
#define IOPRIO_CLASS_IDLE 3
#endif
#ifndef IOPRIO_CLASS_SHIFT
#define IOPRIO_CLASS_SHIFT 13
#endif
int ioprio_get() {
return syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, 0);
}
int ioprio_set(const int ioprio) {
return syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, 0, ioprio);
}
int ioprio_set_idle() {
return ioprio_set(7 | (IOPRIO_CLASS_IDLE << IOPRIO_CLASS_SHIFT));
}
#elif HAVE_IOPOLICY
#include <sys/resource.h>
int ioprio_get() {
return getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD);
}
int ioprio_set(const int ioprio) {
return setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, ioprio);
}
int ioprio_set_idle() {
return ioprio_set(IOPOL_UTILITY);
}
#endif

57
src/util/ioprio.h Normal file
View File

@ -0,0 +1,57 @@
// Copyright (c) 2016 Satoshi Nakamoto
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UTIL_IOPRIO_H
#define BITCOIN_UTIL_IOPRIO_H
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
#include <logging.h>
#if HAVE_IOPRIO_SYSCALL || HAVE_IOPOLICY
int ioprio_get();
int ioprio_set(int ioprio);
int ioprio_set_idle();
class ioprio_idler {
private:
int orig;
public:
ioprio_idler(const bool lowprio) {
if (!lowprio) {
orig = -1;
return;
}
orig = ioprio_get();
if (orig == -1) {
return;
}
if (ioprio_set_idle() == -1) {
orig = -1;
}
}
~ioprio_idler() {
if (orig == -1) {
return;
}
if (ioprio_set(orig) == -1) {
LogPrintf("failed to restore ioprio\n");
}
}
};
#define IOPRIO_IDLER(lowprio) ioprio_idler ioprio_idler_(lowprio)
#else
#define ioprio_get() ((void)-1)
#define ioprio_set(ioprio) ((void)-1)
#define ioprio_set_idle() ((void)-1)
#define IOPRIO_IDLER(lowprio) (void)lowprio;
#endif
#endif // BITCOIN_UTIL_IOPRIO_H

View File

@ -53,6 +53,7 @@
#include <util/fs.h>
#include <util/fs_helpers.h>
#include <util/hasher.h>
#include <util/ioprio.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/result.h>
@ -4746,7 +4747,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
}
CBlock block;
// check level 0: read from disk
if (!chainstate.m_blockman.ReadBlockFromDisk(block, *pindex)) {
if (!chainstate.m_blockman.ReadBlockFromDisk(block, *pindex, /*lowprio=*/true)) {
LogPrintf("Verification error: ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
@ -4812,7 +4813,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
m_notifications.progress(_("Verifying blocks…"), percentageDone, false);
pindex = chainstate.m_chain.Next(pindex);
CBlock block;
if (!chainstate.m_blockman.ReadBlockFromDisk(block, *pindex)) {
if (!chainstate.m_blockman.ReadBlockFromDisk(block, *pindex, /*lowprio=*/true)) {
LogPrintf("Verification error: ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
@ -4841,7 +4842,7 @@ bool Chainstate::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& in
AssertLockHeld(cs_main);
// TODO: merge with ConnectBlock
CBlock block;
if (!m_blockman.ReadBlockFromDisk(block, *pindex)) {
if (!m_blockman.ReadBlockFromDisk(block, *pindex, /*lowprio=*/true)) {
LogError("ReplayBlock(): ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return false;
}
@ -4899,7 +4900,7 @@ bool Chainstate::ReplayBlocks()
while (pindexOld != pindexFork) {
if (pindexOld->nHeight > 0) { // Never disconnect the genesis block.
CBlock block;
if (!m_blockman.ReadBlockFromDisk(block, *pindexOld)) {
if (!m_blockman.ReadBlockFromDisk(block, *pindexOld, /*lowprio=*/true)) {
LogError("RollbackBlock(): ReadBlockFromDisk() failed at %d, hash=%s\n", pindexOld->nHeight, pindexOld->GetBlockHash().ToString());
return false;
}
@ -5039,6 +5040,8 @@ void ChainstateManager::LoadExternalBlockFile(
int nLoaded = 0;
try {
IOPRIO_IDLER(/*lowprio=*/true);
BufferedFile blkdat{file_in, 2 * MAX_BLOCK_SERIALIZED_SIZE, MAX_BLOCK_SERIALIZED_SIZE + 8};
// nRewind indicates where to resume scanning in case something goes wrong,
// such as a block fails to deserialize.