kernel: Add flushError method to notifications
This is done in addition with the following commit. Both have the goal of getting rid of direct calls to AbortNode from kernel code. This extra flushError method is added to notify specifically about errors that arrise when flushing (syncing) block data to disk. Unlike other instances, the current calls to AbortNode in the blockstorage flush functions do not report an error to their callers. This commit is part of the libbitcoinkernel project and further removes the shutdown's and, more generally, the kernel library's dependency on interface_ui with a kernel notification method. By removing interface_ui from the kernel library, its dependency on boost is reduced to just boost::multi_index. At the same time it also takes a step towards de-globalising the interrupt infrastructure.
This commit is contained in:
10 files changed
+35
-3
No files matched your search
@@ -97,6 +97,11 @@ int main(int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
std::cout << "Warning: " << warning.original << std::endl;
|
std::cout << "Warning: " << warning.original << std::endl;
|
||||||
}
|
}
|
||||||
|
void flushError(const std::string& debug_message) override
|
||||||
|
{
|
||||||
|
std::cerr << "Error flushing block data to disk: " << debug_message << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
auto notifications = std::make_unique<KernelNotifications>();
|
auto notifications = std::make_unique<KernelNotifications>();
|
||||||
|
|
||||||
@@ -112,6 +117,7 @@ int main(int argc, char* argv[])
|
|||||||
const node::BlockManager::Options blockman_opts{
|
const node::BlockManager::Options blockman_opts{
|
||||||
.chainparams = chainman_opts.chainparams,
|
.chainparams = chainman_opts.chainparams,
|
||||||
.blocks_dir = abs_datadir / "blocks",
|
.blocks_dir = abs_datadir / "blocks",
|
||||||
|
.notifications = chainman_opts.notifications,
|
||||||
};
|
};
|
||||||
ChainstateManager chainman{kernel_context.interrupt, chainman_opts, blockman_opts};
|
ChainstateManager chainman{kernel_context.interrupt, chainman_opts, blockman_opts};
|
||||||
|
|
||||||
|
|||||||
@@ -999,6 +999,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
|
|||||||
BlockManager::Options blockman_opts_dummy{
|
BlockManager::Options blockman_opts_dummy{
|
||||||
.chainparams = chainman_opts_dummy.chainparams,
|
.chainparams = chainman_opts_dummy.chainparams,
|
||||||
.blocks_dir = args.GetBlocksDirPath(),
|
.blocks_dir = args.GetBlocksDirPath(),
|
||||||
|
.notifications = chainman_opts_dummy.notifications,
|
||||||
};
|
};
|
||||||
auto blockman_result{ApplyArgsManOptions(args, blockman_opts_dummy)};
|
auto blockman_result{ApplyArgsManOptions(args, blockman_opts_dummy)};
|
||||||
if (!blockman_result) {
|
if (!blockman_result) {
|
||||||
@@ -1423,6 +1424,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||||||
BlockManager::Options blockman_opts{
|
BlockManager::Options blockman_opts{
|
||||||
.chainparams = chainman_opts.chainparams,
|
.chainparams = chainman_opts.chainparams,
|
||||||
.blocks_dir = args.GetBlocksDirPath(),
|
.blocks_dir = args.GetBlocksDirPath(),
|
||||||
|
.notifications = chainman_opts.notifications,
|
||||||
};
|
};
|
||||||
Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
|
Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#ifndef BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
|
#ifndef BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
|
||||||
#define BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
|
#define BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
|
||||||
|
|
||||||
|
#include <kernel/notifications_interface.h>
|
||||||
#include <util/fs.h>
|
#include <util/fs.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -25,6 +26,7 @@ struct BlockManagerOpts {
|
|||||||
bool fast_prune{false};
|
bool fast_prune{false};
|
||||||
bool stop_after_block_import{DEFAULT_STOPAFTERBLOCKIMPORT};
|
bool stop_after_block_import{DEFAULT_STOPAFTERBLOCKIMPORT};
|
||||||
const fs::path blocks_dir;
|
const fs::path blocks_dir;
|
||||||
|
Notifications& notifications;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|||||||
@@ -27,6 +27,14 @@ public:
|
|||||||
virtual void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) {}
|
virtual void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) {}
|
||||||
virtual void progress(const bilingual_str& title, int progress_percent, bool resume_possible) {}
|
virtual void progress(const bilingual_str& title, int progress_percent, bool resume_possible) {}
|
||||||
virtual void warning(const bilingual_str& warning) {}
|
virtual void warning(const bilingual_str& warning) {}
|
||||||
|
|
||||||
|
//! The flush error notification is sent to notify the user that an error
|
||||||
|
//! occurred while flushing block data to disk. Kernel code may ignore flush
|
||||||
|
//! errors that don't affect the immediate operation it is trying to
|
||||||
|
//! perform. Applications can choose to handle the flush error notification
|
||||||
|
//! by logging the error, or notifying the user, or triggering an early
|
||||||
|
//! shutdown as a precaution against causing more errors.
|
||||||
|
virtual void flushError(const std::string& debug_message) {}
|
||||||
};
|
};
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|
||||||
|
|||||||
@@ -528,7 +528,7 @@ void BlockManager::FlushUndoFile(int block_file, bool finalize)
|
|||||||
{
|
{
|
||||||
FlatFilePos undo_pos_old(block_file, m_blockfile_info[block_file].nUndoSize);
|
FlatFilePos undo_pos_old(block_file, m_blockfile_info[block_file].nUndoSize);
|
||||||
if (!UndoFileSeq().Flush(undo_pos_old, finalize)) {
|
if (!UndoFileSeq().Flush(undo_pos_old, finalize)) {
|
||||||
AbortNode("Flushing undo file to disk failed. This is likely the result of an I/O error.");
|
m_opts.notifications.flushError("Flushing undo file to disk failed. This is likely the result of an I/O error.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,7 +547,7 @@ void BlockManager::FlushBlockFile(bool fFinalize, bool finalize_undo)
|
|||||||
|
|
||||||
FlatFilePos block_pos_old(m_last_blockfile, m_blockfile_info[m_last_blockfile].nSize);
|
FlatFilePos block_pos_old(m_last_blockfile, m_blockfile_info[m_last_blockfile].nSize);
|
||||||
if (!BlockFileSeq().Flush(block_pos_old, fFinalize)) {
|
if (!BlockFileSeq().Flush(block_pos_old, fFinalize)) {
|
||||||
AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error.");
|
m_opts.notifications.flushError("Flushing block file to disk failed. This is likely the result of an I/O error.");
|
||||||
}
|
}
|
||||||
// we do not always flush the undo file, as the chain tip may be lagging behind the incoming blocks,
|
// we do not always flush the undo file, as the chain tip may be lagging behind the incoming blocks,
|
||||||
// e.g. during IBD or a sync after a node going offline
|
// e.g. during IBD or a sync after a node going offline
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <common/args.h>
|
#include <common/args.h>
|
||||||
#include <common/system.h>
|
#include <common/system.h>
|
||||||
#include <node/interface_ui.h>
|
#include <node/interface_ui.h>
|
||||||
|
#include <shutdown.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
@@ -72,4 +73,9 @@ void KernelNotifications::warning(const bilingual_str& warning)
|
|||||||
DoWarning(warning);
|
DoWarning(warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KernelNotifications::flushError(const std::string& debug_message)
|
||||||
|
{
|
||||||
|
AbortNode(debug_message);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
@@ -25,6 +25,8 @@ public:
|
|||||||
void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override;
|
void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override;
|
||||||
|
|
||||||
void warning(const bilingual_str& warning) override;
|
void warning(const bilingual_str& warning) override;
|
||||||
|
|
||||||
|
void flushError(const std::string& debug_message) override;
|
||||||
};
|
};
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,16 @@
|
|||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
#include <node/blockstorage.h>
|
#include <node/blockstorage.h>
|
||||||
#include <node/context.h>
|
#include <node/context.h>
|
||||||
|
#include <node/kernel_notifications.h>
|
||||||
#include <util/chaintype.h>
|
#include <util/chaintype.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <test/util/setup_common.h>
|
#include <test/util/setup_common.h>
|
||||||
|
|
||||||
using node::BlockManager;
|
|
||||||
using node::BLOCK_SERIALIZATION_HEADER_SIZE;
|
using node::BLOCK_SERIALIZATION_HEADER_SIZE;
|
||||||
|
using node::BlockManager;
|
||||||
|
using node::KernelNotifications;
|
||||||
using node::MAX_BLOCKFILE_SIZE;
|
using node::MAX_BLOCKFILE_SIZE;
|
||||||
|
|
||||||
// use BasicTestingSetup here for the data directory configuration, setup, and cleanup
|
// use BasicTestingSetup here for the data directory configuration, setup, and cleanup
|
||||||
@@ -21,9 +23,11 @@ BOOST_FIXTURE_TEST_SUITE(blockmanager_tests, BasicTestingSetup)
|
|||||||
BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
|
BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
|
||||||
{
|
{
|
||||||
const auto params {CreateChainParams(ArgsManager{}, ChainType::MAIN)};
|
const auto params {CreateChainParams(ArgsManager{}, ChainType::MAIN)};
|
||||||
|
KernelNotifications notifications{};
|
||||||
const BlockManager::Options blockman_opts{
|
const BlockManager::Options blockman_opts{
|
||||||
.chainparams = *params,
|
.chainparams = *params,
|
||||||
.blocks_dir = m_args.GetBlocksDirPath(),
|
.blocks_dir = m_args.GetBlocksDirPath(),
|
||||||
|
.notifications = notifications,
|
||||||
};
|
};
|
||||||
BlockManager blockman{m_node.kernel->interrupt, blockman_opts};
|
BlockManager blockman{m_node.kernel->interrupt, blockman_opts};
|
||||||
CChain chain {};
|
CChain chain {};
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto
|
|||||||
const BlockManager::Options blockman_opts{
|
const BlockManager::Options blockman_opts{
|
||||||
.chainparams = chainman_opts.chainparams,
|
.chainparams = chainman_opts.chainparams,
|
||||||
.blocks_dir = m_args.GetBlocksDirPath(),
|
.blocks_dir = m_args.GetBlocksDirPath(),
|
||||||
|
.notifications = chainman_opts.notifications,
|
||||||
};
|
};
|
||||||
m_node.chainman = std::make_unique<ChainstateManager>(m_node.kernel->interrupt, chainman_opts, blockman_opts);
|
m_node.chainman = std::make_unique<ChainstateManager>(m_node.kernel->interrupt, chainman_opts, blockman_opts);
|
||||||
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(DBParams{
|
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(DBParams{
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ struct SnapshotTestSetup : TestChain100Setup {
|
|||||||
const BlockManager::Options blockman_opts{
|
const BlockManager::Options blockman_opts{
|
||||||
.chainparams = chainman_opts.chainparams,
|
.chainparams = chainman_opts.chainparams,
|
||||||
.blocks_dir = m_args.GetBlocksDirPath(),
|
.blocks_dir = m_args.GetBlocksDirPath(),
|
||||||
|
.notifications = chainman_opts.notifications,
|
||||||
};
|
};
|
||||||
// For robustness, ensure the old manager is destroyed before creating a
|
// For robustness, ensure the old manager is destroyed before creating a
|
||||||
// new one.
|
// new one.
|
||||||
|
|||||||
Reference in new issue
Block a user