Skip to content

Commit

Permalink
Add io priority to reduce impact of ActivateChain on IBD and impact o…
Browse files Browse the repository at this point in the history
…f historical block serving.

Based on bitcoin#9245
  • Loading branch information
rebroad committed Apr 25, 2020
1 parent f0c45b9 commit f0a14ee
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 8 deletions.
40 changes: 40 additions & 0 deletions configure.ac 100644 → 100755
Expand Up @@ -549,6 +549,44 @@ AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64],,,
#include <byteswap.h>
#endif])

AC_MSG_CHECKING(for 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);
]])
],[
have_iopolicy=yes
AC_DEFINE(HAVE_IOPOLICY,1,[Define this symbol if you have iopolicy functions])
],[
have_iopolicy=no
])
AC_MSG_RESULT($have_iopolicy)

if test x$have_iopolicy = xno; then
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)
else
have_ioprio_syscall=no
fi

dnl Check for MSG_NOSIGNAL
AC_MSG_CHECKING(for MSG_NOSIGNAL)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
Expand Down Expand Up @@ -1063,6 +1101,8 @@ AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes])
AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes])
AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes])
AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes])
AM_CONDITIONAL([HAVE_IOPOLICY],[test x$have_iopolicy = xyes])
AM_CONDITIONAL([HAVE_IOPRIO_SYSCALL],[test x$have_ioprio_syscall = xyes])
AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes])

AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version])
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am 100644 → 100755
Expand Up @@ -149,6 +149,7 @@ BITCOIN_CORE_H = \
ui_interface.h \
undo.h \
util.h \
utilioprio.h \
utilmoneystr.h \
utiltime.h \
validation.h \
Expand Down Expand Up @@ -338,6 +339,7 @@ libbitcoin_util_a_SOURCES = \
sync.cpp \
threadinterrupt.cpp \
util.cpp \
utilioprio.cpp \
utilmoneystr.cpp \
utilstrencodings.cpp \
utiltime.cpp \
Expand Down
3 changes: 2 additions & 1 deletion src/net_processing.cpp
Expand Up @@ -1185,7 +1185,8 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// Send block from disk
CBlock block;
int nSize = 0;
if (!ReadBlockFromDisk(block, (*mi).second, consensusParams))
// Read block with low priority if not recent (i.e. historical)
if (!ReadBlockFromDisk(block, (*mi).second, consensusParams, !fRecent))
assert(!"cannot load block from disk");
if (inv.type == MSG_BLOCK)
nSize += connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block));
Expand Down
57 changes: 57 additions & 0 deletions src/utilioprio.cpp
@@ -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 "utilioprio.h"

#ifdef 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 changes: 57 additions & 0 deletions src/utilioprio.h
@@ -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 "util.h"

#if defined(HAVE_IOPRIO_SYSCALL) || defined(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 actually_idle) {
if (!actually_idle) {
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(actually_idle) ioprio_idler ioprio_idler_(actually_idle)

#else
#define ioprio_get() ((void)-1)
#define ioprio_set(ioprio) ((void)-1)
#define ioprio_set_idle() ((void)-1)
#define IOPRIO_IDLER(actually_idle) (void)actually_idle;
#endif

#endif // BITCOIN_UTIL_IOPRIO_H
18 changes: 13 additions & 5 deletions src/validation.cpp
Expand Up @@ -31,6 +31,7 @@
#include "ui_interface.h"
#include "undo.h"
#include "util.h"
#include "utilioprio.h"
#include "utilmoneystr.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
Expand Down Expand Up @@ -1093,7 +1094,8 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus

if (pindexSlow) {
CBlock block;
if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) {
// Read block with low priority if during IBD
if (ReadBlockFromDisk(block, pindexSlow, consensusParams, IsInitialBlockDownload())) {
for (const auto& tx : block.vtx) {
if (tx->GetHash() == hash) {
txOut = tx;
Expand Down Expand Up @@ -1138,10 +1140,13 @@ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHea
return true;
}

bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams, const bool lowprio /*=false*/)
{
block.SetNull();

{
IOPRIO_IDLER(lowprio);

// Open history file to read
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
Expand All @@ -1155,16 +1160,18 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus:
return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString());
}

} // end IOPRIO_IDLER scope

// Check the header
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());

return true;
}

bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams, const bool lowprio /*=false*/)
{
if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams))
if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams, lowprio))
return false;
if (block.GetHash() != pindex->GetBlockHash())
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s",
Expand Down Expand Up @@ -2352,7 +2359,8 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
if (!pblock) {
std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
connectTrace.blocksConnected.emplace_back(pindexNew, pblockNew);
if (!ReadBlockFromDisk(*pblockNew, pindexNew, chainparams.GetConsensus()))
// Read from disk with low priority during IBD
if (!ReadBlockFromDisk(*pblockNew, pindexNew, chainparams.GetConsensus(), IsInitialBlockDownload()))
return AbortNode(state, "Failed to read block");
} else {
connectTrace.blocksConnected.emplace_back(pindexNew, pblock);
Expand Down
4 changes: 2 additions & 2 deletions src/validation.h
Expand Up @@ -479,8 +479,8 @@ class CScriptCheck

/** Functions for disk access for blocks */
bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams);
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams, bool lowprio = false);
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams, bool lowprio = false);

/** Functions for validating blocks and updating the block tree */

Expand Down

0 comments on commit f0a14ee

Please sign in to comment.