Drop IO priority to idle while reading blocks for peer requests and startup verification

This commit is contained in:
Luke Dashjr 2016-11-30 08:27:55 +00:00
parent 1248d0da22
commit cd5fd154a9
8 changed files with 142 additions and 15 deletions

View File

@ -943,6 +943,25 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
[ AC_MSG_RESULT([no])]
)
AC_MSG_CHECKING(for 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);
]])
],[
have_ioprio_syscall=yes
AC_DEFINE(HAVE_IOPRIO_SYSCALL,1,[Define this symbol if you have ioprio syscalls])
],[
have_ioprio_syscall=no
])
AC_MSG_RESULT($have_ioprio_syscall)
AM_CONDITIONAL([HAVE_IOPRIO_SYSCALL], [test "$have_ioprio_syscall" = "yes"])
dnl Check for different ways of gathering OS randomness
AC_MSG_CHECKING([for Linux getrandom function])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[

View File

@ -312,6 +312,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 \
@ -762,6 +763,10 @@ libbitcoin_util_a_SOURCES = \
$(BITCOIN_CORE_H)
#
if HAVE_IOPRIO_SYSCALL
libbitcoin_util_a_SOURCES += util/ioprio.cpp
endif
# cli #
libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)

View File

@ -2516,7 +2516,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 {
@ -2530,7 +2530,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 {
@ -4434,7 +4434,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);
@ -6052,7 +6052,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/signalinterrupt.h>
#include <util/strencodings.h>
#include <util/translation.h>
@ -1034,10 +1035,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()) {
@ -1053,6 +1057,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());
@ -1068,11 +1074,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()) {
@ -1082,7 +1088,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
@ -1092,6 +1098,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

@ -420,9 +420,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;

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

@ -0,0 +1,37 @@
// 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>
#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));
}

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>
#ifdef HAVE_IOPRIO_SYSCALL
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

@ -4742,7 +4742,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;
}
@ -4808,7 +4808,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;
}
@ -4837,7 +4837,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;
}
@ -4895,7 +4895,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;
}