Improve build times (#2425)
* Improve compile times * Fix tests * Use loopback address in config * Fix config tests * Hopefully fixes rpc.version test * Fix -DNANO_TIMED_LOCKS build * Formatting * Formatting
This commit is contained in:
parent
270be3c154
commit
27043570d9
209 changed files with 2935 additions and 2200 deletions
|
@ -77,7 +77,8 @@ if (WIN32)
|
|||
-DWINVER=0x0600
|
||||
-DWIN32_LEAN_AND_MEAN
|
||||
-DMINIUPNP_STATICLIB
|
||||
-D_CRT_SECURE_NO_WARNINGS)
|
||||
-D_CRT_SECURE_NO_WARNINGS
|
||||
/EHsc)
|
||||
|
||||
if (${USING_TSAN} OR ${USING_ASAN} OR ${USING_ASAN_INT})
|
||||
message (WARNING "Cannot use TSAN or ASAN on Windows, sanitizers ignored")
|
||||
|
|
|
@ -15,7 +15,7 @@ if [[ $(grep -rl --exclude="*asio.hpp" "asio::async_write" ./nano) ]]; then
|
|||
fi
|
||||
|
||||
# prevent unsolicited use of std::lock_guard & std::unique_lock outside of allowed areas
|
||||
if [[ $(grep -rl --exclude={"*random_pool.cpp","*random_pool.hpp","*locks.hpp","*locks.cpp"} "std::unique_lock\|std::lock_guard\|std::condition_variable" ./nano) ]]; then
|
||||
if [[ $(grep -rl --exclude={"*random_pool.cpp","*random_pool.hpp","*random_pool_shuffle.hpp","*locks.hpp","*locks.cpp"} "std::unique_lock\|std::lock_guard\|std::condition_variable" ./nano) ]]; then
|
||||
echo "using std::unique_lock, std::lock_guard or std::condition_variable is not permitted (except in nano/lib/locks.hpp and non-nano dependent libraries). Use the nano::* versions instead"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4191)
|
||||
#pragma warning(disable : 4242)
|
||||
#endif
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
7
nano/boost/asio/basic_stream_socket.hpp
Normal file
7
nano/boost/asio/basic_stream_socket.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/basic_stream_socket.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/bind_executor.hpp
Normal file
7
nano/boost/asio/bind_executor.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/buffer.hpp
Normal file
7
nano/boost/asio/buffer.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/buffer.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/connect.hpp
Normal file
7
nano/boost/asio/connect.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/connect.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/deadline_timer.hpp
Normal file
7
nano/boost/asio/deadline_timer.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/dispatch.hpp
Normal file
7
nano/boost/asio/dispatch.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/executor_work_guard.hpp
Normal file
7
nano/boost/asio/executor_work_guard.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/io_context.hpp
Normal file
7
nano/boost/asio/io_context.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/io_context.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/ip/address.hpp
Normal file
7
nano/boost/asio/ip/address.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/ip/address_v6.hpp
Normal file
7
nano/boost/asio/ip/address_v6.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/ip/address_v6.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/ip/tcp.hpp
Normal file
7
nano/boost/asio/ip/tcp.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/ip/udp.hpp
Normal file
7
nano/boost/asio/ip/udp.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/local/stream_protocol.hpp
Normal file
7
nano/boost/asio/local/stream_protocol.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/local/stream_protocol.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/post.hpp
Normal file
7
nano/boost/asio/post.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/post.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/read.hpp
Normal file
7
nano/boost/asio/read.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/read.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/strand.hpp
Normal file
7
nano/boost/asio/strand.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/strand.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/thread_pool.hpp
Normal file
7
nano/boost/asio/thread_pool.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/asio/write.hpp
Normal file
7
nano/boost/asio/write.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_ASIO_WARNINGS
|
||||
#include <boost/asio/write.hpp>
|
||||
REENABLE_WARNINGS
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4191)
|
||||
#pragma warning(disable : 4242)
|
||||
#endif
|
||||
|
||||
#include <boost/beast.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
7
nano/boost/beast/core.hpp
Normal file
7
nano/boost/beast/core.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_BEAST_WARNINGS
|
||||
#include <boost/beast/core.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/beast/core/flat_buffer.hpp
Normal file
7
nano/boost/beast/core/flat_buffer.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_BEAST_WARNINGS
|
||||
#include <boost/beast/core/flat_buffer.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/beast/http.hpp
Normal file
7
nano/boost/beast/http.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_BEAST_WARNINGS
|
||||
#include <boost/beast/http.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/beast/http/message.hpp
Normal file
7
nano/boost/beast/http/message.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_BEAST_WARNINGS
|
||||
#include <boost/beast/http/message.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/beast/http/string_body.hpp
Normal file
7
nano/boost/beast/http/string_body.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_BEAST_WARNINGS
|
||||
#include <boost/beast/http/string_body.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/beast/version.hpp
Normal file
7
nano/boost/beast/version.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_BEAST_WARNINGS
|
||||
#include <boost/beast/version.hpp>
|
||||
REENABLE_WARNINGS
|
7
nano/boost/beast/websocket.hpp
Normal file
7
nano/boost/beast/websocket.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_BEAST_WARNINGS
|
||||
#include <boost/beast/websocket.hpp>
|
||||
REENABLE_WARNINGS
|
30
nano/boost/private/macro_warnings.hpp
Normal file
30
nano/boost/private/macro_warnings.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DISABLE_ASIO_WARNINGS \
|
||||
__pragma (warning (push)) \
|
||||
__pragma (warning (disable : 4191)) \
|
||||
__pragma (warning (disable : 4242))
|
||||
|
||||
#else
|
||||
#define DISABLE_ASIO_WARNINGS
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define REENABLE_WARNINGS \
|
||||
__pragma (warning (pop))
|
||||
#else
|
||||
#define REENABLE_WARNINGS
|
||||
#endif
|
||||
|
||||
#define DISABLE_BEAST_WARNINGS DISABLE_ASIO_WARNINGS
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DISABLE_PROCESS_WARNINGS \
|
||||
__pragma (warning (push)) \
|
||||
__pragma (warning (disable : 4191)) \
|
||||
__pragma (warning (disable : 4242)) \
|
||||
__pragma (warning (disable : 4244))
|
||||
#else
|
||||
#define DISABLE_PROCESS_WARNINGS
|
||||
#endif
|
|
@ -1,22 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef BOOST_PROCESS_SUPPORTED
|
||||
#error BOOST_PROCESS_SUPPORTED must be set, check configuration
|
||||
#endif
|
||||
|
||||
#if BOOST_PROCESS_SUPPORTED
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4191)
|
||||
#pragma warning(disable : 4242)
|
||||
#pragma warning(disable : 4244)
|
||||
#endif
|
||||
|
||||
#include <boost/process.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
7
nano/boost/process/child.hpp
Normal file
7
nano/boost/process/child.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/private/macro_warnings.hpp>
|
||||
|
||||
DISABLE_BEAST_WARNINGS
|
||||
#include <boost/process/child.hpp>
|
||||
REENABLE_WARNINGS
|
|
@ -1,5 +1,6 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/node/election.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
@ -544,7 +545,6 @@ TEST (active_transactions, update_difficulty)
|
|||
ASSERT_FALSE (ec);
|
||||
|
||||
auto modify_election = [&node1](auto block) {
|
||||
auto root_l (block->root ());
|
||||
auto hash (block->hash ());
|
||||
nano::lock_guard<std::mutex> active_guard (node1.active.mutex);
|
||||
auto existing (node1.active.roots.find (block->qualified_root ()));
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/node/common.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/secure/buffer.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <crypto/ed25519-donna/ed25519.h>
|
||||
|
||||
TEST (ed25519, signing)
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/lib/stats.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/lib/work.hpp>
|
||||
#include <nano/node/common.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/secure/ledger.hpp>
|
||||
#include <nano/secure/utility.hpp>
|
||||
#include <nano/secure/versioning.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#if NANO_ROCKSDB
|
||||
#include <nano/node/rocksdb/rocksdb.hpp>
|
||||
#endif
|
||||
|
||||
#include <nano/lib/logger_mt.hpp>
|
||||
#include <nano/node/lmdb/lmdb.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -1503,7 +1512,7 @@ TEST (block_store, peers)
|
|||
|
||||
TEST (block_store, endpoint_key_byte_order)
|
||||
{
|
||||
boost::asio::ip::address_v6 address (boost::asio::ip::address_v6::from_string ("::ffff:127.0.0.1"));
|
||||
boost::asio::ip::address_v6 address (boost::asio::ip::make_address_v6 ("::ffff:127.0.0.1"));
|
||||
uint16_t port = 100;
|
||||
nano::endpoint_key endpoint_key (address.to_bytes (), port);
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/node/bootstrap/bootstrap_frontier.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/node/election.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace
|
||||
|
@ -979,7 +982,6 @@ TEST (confirmation_height, callback_confirmed_history)
|
|||
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
|
||||
|
||||
nano::keypair key1;
|
||||
auto & store = node->store;
|
||||
auto send = std::make_shared<nano::send_block> (latest, key1.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (latest));
|
||||
{
|
||||
auto transaction = node->store.tx_begin_write ();
|
||||
|
@ -1058,7 +1060,6 @@ TEST (confirmation_height, dependent_election)
|
|||
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
|
||||
|
||||
nano::keypair key1;
|
||||
auto & store = node->store;
|
||||
auto send = std::make_shared<nano::send_block> (latest, key1.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (latest));
|
||||
auto send1 = std::make_shared<nano::send_block> (send->hash (), key1.pub, nano::genesis_amount - nano::Gxrb_ratio * 2, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send->hash ()));
|
||||
auto send2 = std::make_shared<nano::send_block> (send1->hash (), key1.pub, nano::genesis_amount - nano::Gxrb_ratio * 3, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send1->hash ()));
|
||||
|
@ -1122,7 +1123,6 @@ TEST (confirmation_height, dependent_election_after_already_cemented)
|
|||
nano::block_hash latest (node->latest (nano::test_genesis_key.pub));
|
||||
|
||||
nano::keypair key1;
|
||||
auto & store = node->store;
|
||||
auto send = std::make_shared<nano::send_block> (latest, key1.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (latest));
|
||||
auto send1 = std::make_shared<nano::send_block> (send->hash (), key1.pub, nano::genesis_amount - nano::Gxrb_ratio * 2, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send->hash ()));
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/node/election.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/variant/get.hpp>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST (conflicts, start_stop)
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
#include <nano/node/common.hpp>
|
||||
#include <nano/node/logging.hpp>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
void cleanup_test_directories_on_exit ();
|
||||
void force_nano_test_network ();
|
||||
boost::filesystem::path unique_path ();
|
||||
}
|
||||
|
||||
GTEST_API_ int main (int argc, char ** argv)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/lib/stats.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
#include <nano/node/election.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
|
||||
#include <crypto/cryptopp/filters.h>
|
||||
#include <crypto/cryptopp/randpool.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <future>
|
||||
#include <regex>
|
||||
|
||||
#if NANO_TIMED_LOCKS > 0
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/logger_mt.hpp>
|
||||
#include <nano/node/logging.hpp>
|
||||
#include <nano/secure/utility.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/log/utility/setup/console.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#include <nano/node/common.hpp>
|
||||
#include <nano/secure/buffer.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/variant/get.hpp>
|
||||
|
||||
TEST (message, keepalive_serialization)
|
||||
{
|
||||
nano::keepalive request1;
|
||||
|
|
|
@ -465,7 +465,7 @@ TEST (parse_endpoint, no_colon)
|
|||
|
||||
TEST (network, ipv6)
|
||||
{
|
||||
boost::asio::ip::address_v6 address (boost::asio::ip::address_v6::from_string ("::ffff:127.0.0.1"));
|
||||
boost::asio::ip::address_v6 address (boost::asio::ip::make_address_v6 ("::ffff:127.0.0.1"));
|
||||
ASSERT_TRUE (address.is_v4_mapped ());
|
||||
nano::endpoint endpoint1 (address, 16384);
|
||||
std::vector<uint8_t> bytes1;
|
||||
|
@ -557,12 +557,12 @@ TEST (network, reserved_address)
|
|||
{
|
||||
nano::system system (1);
|
||||
// 0 port test
|
||||
ASSERT_TRUE (nano::transport::reserved_address (nano::endpoint (boost::asio::ip::address_v6::from_string ("2001::"), 0)));
|
||||
ASSERT_TRUE (nano::transport::reserved_address (nano::endpoint (boost::asio::ip::make_address_v6 ("2001::"), 0)));
|
||||
// Valid address test
|
||||
ASSERT_FALSE (nano::transport::reserved_address (nano::endpoint (boost::asio::ip::address_v6::from_string ("2001::"), 1)));
|
||||
nano::endpoint loopback (boost::asio::ip::address_v6::from_string ("::1"), 1);
|
||||
ASSERT_FALSE (nano::transport::reserved_address (nano::endpoint (boost::asio::ip::make_address_v6 ("2001::"), 1)));
|
||||
nano::endpoint loopback (boost::asio::ip::make_address_v6 ("::1"), 1);
|
||||
ASSERT_FALSE (nano::transport::reserved_address (loopback));
|
||||
nano::endpoint private_network_peer (boost::asio::ip::address_v6::from_string ("::ffff:10.0.0.0"), 1);
|
||||
nano::endpoint private_network_peer (boost::asio::ip::make_address_v6 ("::ffff:10.0.0.0"), 1);
|
||||
ASSERT_TRUE (nano::transport::reserved_address (private_network_peer, false));
|
||||
ASSERT_FALSE (nano::transport::reserved_address (private_network_peer, true));
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/node/election.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
#include <nano/node/transport/udp.hpp>
|
||||
#include <nano/secure/working.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/polymorphic_cast.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
|
@ -798,7 +799,7 @@ TEST (node_config, v17_values)
|
|||
ASSERT_FALSE (upgraded);
|
||||
ASSERT_EQ (config.tcp_io_timeout.count (), 1);
|
||||
ASSERT_EQ (config.pow_sleep_interval.count (), 0);
|
||||
ASSERT_EQ (config.external_address, boost::asio::ip::address_v6::from_string ("::1"));
|
||||
ASSERT_EQ (config.external_address, "::1");
|
||||
ASSERT_EQ (config.external_port, 0);
|
||||
ASSERT_EQ (config.tcp_incoming_connections_max, 1);
|
||||
ASSERT_FALSE (config.diagnostics_config.txn_tracking.enable);
|
||||
|
@ -838,7 +839,7 @@ TEST (node_config, v17_values)
|
|||
ASSERT_FALSE (upgraded);
|
||||
ASSERT_EQ (config.tcp_io_timeout.count (), std::numeric_limits<unsigned long>::max () - 100);
|
||||
ASSERT_EQ (config.pow_sleep_interval.count (), std::numeric_limits<unsigned long>::max () - 100);
|
||||
ASSERT_EQ (config.external_address, boost::asio::ip::address_v6::from_string ("::ffff:192.168.1.1"));
|
||||
ASSERT_EQ (config.external_address, "::ffff:192.168.1.1");
|
||||
ASSERT_EQ (config.external_port, std::numeric_limits<uint16_t>::max () - 1);
|
||||
ASSERT_EQ (config.tcp_incoming_connections_max, std::numeric_limits<unsigned>::max ());
|
||||
ASSERT_EQ (config.vote_generator_delay.count (), std::numeric_limits<unsigned long>::max () - 100);
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
#include <nano/boost/asio/io_context.hpp>
|
||||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/lib/alarm.hpp>
|
||||
#include <nano/lib/stats.hpp>
|
||||
#include <nano/lib/work.hpp>
|
||||
#include <nano/secure/blockstore.hpp>
|
||||
#include <nano/secure/ledger.hpp>
|
||||
#include <nano/secure/utility.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
||||
TEST (processor_service, bad_send_signature)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/signatures.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
#include <nano/node/socket.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST (socket, concurrent_writes)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/locks.hpp>
|
||||
#include <nano/lib/timer.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/iostreams/concepts.hpp>
|
||||
#include <boost/log/sources/logger.hpp>
|
||||
#include <boost/log/sinks/text_ostream_backend.hpp>
|
||||
#include <boost/log/utility/setup/console.hpp>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
|
@ -51,7 +51,7 @@ class stringstream_mt_sink : public boost::iostreams::sink
|
|||
{
|
||||
public:
|
||||
stringstream_mt_sink () = default;
|
||||
stringstream_mt_sink (const stringstream_mt_sink & sink)
|
||||
stringstream_mt_sink (stringstream_mt_sink const & sink)
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (mutex);
|
||||
ss << sink.ss.str ();
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
#include <nano/lib/timer.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/lib/worker.hpp>
|
||||
#include <nano/secure/utility.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::atomic<bool> passed_sleep{ false };
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <nano/lib/logger_mt.hpp>
|
||||
#include <nano/node/lmdb/lmdb.hpp>
|
||||
#include <nano/secure/blockstore.hpp>
|
||||
#include <nano/secure/utility.hpp>
|
||||
#include <nano/secure/versioning.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
#include <nano/node/lmdb/wallet_value.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
unsigned constexpr nano::wallet_store::version_current;
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/polymorphic_cast.hpp>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST (wallets, open_create)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include <nano/boost/asio.hpp>
|
||||
#include <nano/boost/beast.hpp>
|
||||
#include <nano/boost/asio/connect.hpp>
|
||||
#include <nano/boost/asio/ip/tcp.hpp>
|
||||
#include <nano/boost/beast/core.hpp>
|
||||
#include <nano/boost/beast/websocket.hpp>
|
||||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
#include <nano/node/websocket.hpp>
|
||||
|
||||
|
@ -10,9 +11,7 @@
|
|||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/logger_mt.hpp>
|
||||
#include <nano/lib/timer.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/wallet.hpp>
|
||||
#include <nano/lib/work.hpp>
|
||||
#include <nano/node/logging.hpp>
|
||||
#include <nano/node/openclconfig.hpp>
|
||||
#include <nano/node/openclwork.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
#include <nano/secure/utility.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <future>
|
||||
|
||||
TEST (work, one)
|
||||
{
|
||||
nano::network_constants network_constants;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
add_library (crypto_lib
|
||||
interface.cpp
|
||||
random_pool.hpp
|
||||
random_pool.cpp
|
||||
random_pool.hpp)
|
||||
random_pool_shuffle.hpp)
|
||||
|
||||
target_link_libraries (crypto_lib
|
||||
blake2
|
||||
|
|
|
@ -1,22 +1,32 @@
|
|||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
|
||||
#include <crypto/cryptopp/osrng.h>
|
||||
|
||||
std::mutex nano::random_pool::mutex;
|
||||
CryptoPP::AutoSeededRandomPool nano::random_pool::pool;
|
||||
|
||||
void nano::random_pool::generate_block (unsigned char * output, size_t size)
|
||||
{
|
||||
auto & pool = get_pool ();
|
||||
std::lock_guard<std::mutex> guard (mutex);
|
||||
pool.GenerateBlock (output, size);
|
||||
}
|
||||
|
||||
unsigned nano::random_pool::generate_word32 (unsigned min, unsigned max)
|
||||
{
|
||||
auto & pool = get_pool ();
|
||||
std::lock_guard<std::mutex> guard (mutex);
|
||||
return pool.GenerateWord32 (min, max);
|
||||
}
|
||||
|
||||
unsigned char nano::random_pool::generate_byte ()
|
||||
{
|
||||
auto & pool = get_pool ();
|
||||
std::lock_guard<std::mutex> guard (mutex);
|
||||
return pool.GenerateByte ();
|
||||
}
|
||||
|
||||
CryptoPP::AutoSeededRandomPool & nano::random_pool::get_pool ()
|
||||
{
|
||||
static CryptoPP::AutoSeededRandomPool pool;
|
||||
return pool;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <crypto/cryptopp/osrng.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace CryptoPP
|
||||
{
|
||||
class AutoSeededRandomPool;
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
/** While this uses CryptoPP do not call any of these functions from global scope, as they depend on global variables inside the CryptoPP library which may not have been initialized yet due to an undefined order for globals in different translation units. To make sure this is not an issue, there should be no ASAN warnings at startup on Mac/Clang in the CryptoPP files. */
|
||||
|
@ -14,19 +17,15 @@ public:
|
|||
static unsigned generate_word32 (unsigned min, unsigned max);
|
||||
static unsigned char generate_byte ();
|
||||
|
||||
template <class Iter>
|
||||
static void shuffle (Iter begin, Iter end)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard (mutex);
|
||||
pool.Shuffle (begin, end);
|
||||
}
|
||||
|
||||
random_pool () = delete;
|
||||
random_pool (random_pool const &) = delete;
|
||||
random_pool & operator= (random_pool const &) = delete;
|
||||
|
||||
private:
|
||||
static std::mutex mutex;
|
||||
static CryptoPP::AutoSeededRandomPool pool;
|
||||
static CryptoPP::AutoSeededRandomPool & get_pool ();
|
||||
|
||||
template <class Iter>
|
||||
friend void random_pool_shuffle (Iter begin, Iter end);
|
||||
};
|
||||
}
|
15
nano/crypto_lib/random_pool_shuffle.hpp
Normal file
15
nano/crypto_lib/random_pool_shuffle.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
|
||||
#include <crypto/cryptopp/osrng.h>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
template <class Iter>
|
||||
void random_pool_shuffle (Iter begin, Iter end)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard (random_pool::mutex);
|
||||
random_pool::get_pool ().Shuffle (begin, end);
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ add_library (nano_lib
|
|||
ipc_client.cpp
|
||||
json_error_response.hpp
|
||||
jsonconfig.hpp
|
||||
jsonconfig.cpp
|
||||
locks.hpp
|
||||
locks.cpp
|
||||
logger_mt.hpp
|
||||
|
@ -49,14 +50,20 @@ add_library (nano_lib
|
|||
rpcconfig.cpp
|
||||
stats.hpp
|
||||
stats.cpp
|
||||
threading.hpp
|
||||
threading.cpp
|
||||
timer.hpp
|
||||
timer.cpp
|
||||
tomlconfig.hpp
|
||||
tomlconfig.cpp
|
||||
utility.hpp
|
||||
utility.cpp
|
||||
walletconfig.hpp
|
||||
walletconfig.cpp
|
||||
work.hpp
|
||||
work.cpp)
|
||||
work.cpp
|
||||
worker.hpp
|
||||
worker.cpp)
|
||||
|
||||
target_link_libraries (nano_lib
|
||||
ed25519
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <nano/lib/alarm.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
|
||||
bool nano::operation::operator> (nano::operation const & other_a) const
|
||||
{
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/locks.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace asio
|
||||
{
|
||||
class io_context;
|
||||
}
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
|
@ -33,7 +40,7 @@ public:
|
|||
std::mutex mutex;
|
||||
nano::condition_variable condition;
|
||||
std::priority_queue<operation, std::vector<operation>, std::greater<operation>> operations;
|
||||
boost::thread thread;
|
||||
std::thread thread;
|
||||
};
|
||||
class seq_con_info_component;
|
||||
std::unique_ptr<seq_con_info_component> collect_seq_con_info (alarm & alarm, const std::string & name);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/asio.hpp>
|
||||
#include <nano/boost/asio/write.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
|
|
|
@ -650,3 +650,64 @@ nano::receive_block_builder & nano::receive_block_builder::source_hex (std::stri
|
|||
build_state |= build_flags::link_present;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename BLOCKTYPE, typename BUILDER>
|
||||
std::unique_ptr<BLOCKTYPE> nano::abstract_builder<BLOCKTYPE, BUILDER>::build ()
|
||||
{
|
||||
if (!ec)
|
||||
{
|
||||
static_cast<BUILDER *> (this)->validate ();
|
||||
}
|
||||
assert (!ec);
|
||||
return std::move (block);
|
||||
}
|
||||
|
||||
template <typename BLOCKTYPE, typename BUILDER>
|
||||
std::unique_ptr<BLOCKTYPE> nano::abstract_builder<BLOCKTYPE, BUILDER>::build (std::error_code & ec)
|
||||
{
|
||||
if (!this->ec)
|
||||
{
|
||||
static_cast<BUILDER *> (this)->validate ();
|
||||
}
|
||||
ec = this->ec;
|
||||
return std::move (block);
|
||||
}
|
||||
|
||||
template <typename BLOCKTYPE, typename BUILDER>
|
||||
nano::abstract_builder<BLOCKTYPE, BUILDER> & nano::abstract_builder<BLOCKTYPE, BUILDER>::work (uint64_t work)
|
||||
{
|
||||
block->work = work;
|
||||
build_state |= build_flags::work_present;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename BLOCKTYPE, typename BUILDER>
|
||||
nano::abstract_builder<BLOCKTYPE, BUILDER> & nano::abstract_builder<BLOCKTYPE, BUILDER>::sign (nano::raw_key const & private_key, nano::public_key const & public_key)
|
||||
{
|
||||
block->signature = nano::sign_message (private_key, public_key, block->hash ());
|
||||
build_state |= build_flags::signature_present;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename BLOCKTYPE, typename BUILDER>
|
||||
nano::abstract_builder<BLOCKTYPE, BUILDER> & nano::abstract_builder<BLOCKTYPE, BUILDER>::sign_zero ()
|
||||
{
|
||||
block->signature.clear ();
|
||||
build_state |= build_flags::signature_present;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename BLOCKTYPE, typename BUILDER>
|
||||
void nano::abstract_builder<BLOCKTYPE, BUILDER>::construct_block ()
|
||||
{
|
||||
block = std::make_unique<BLOCKTYPE> ();
|
||||
ec.clear ();
|
||||
build_state = 0;
|
||||
}
|
||||
|
||||
// Explicit instantiations
|
||||
template class nano::abstract_builder<nano::open_block, nano::open_block_builder>;
|
||||
template class nano::abstract_builder<nano::send_block, nano::send_block_builder>;
|
||||
template class nano::abstract_builder<nano::receive_block, nano::receive_block_builder>;
|
||||
template class nano::abstract_builder<nano::change_block, nano::change_block_builder>;
|
||||
template class nano::abstract_builder<nano::state_block, nano::state_block_builder>;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -46,63 +45,21 @@ class abstract_builder
|
|||
{
|
||||
public:
|
||||
/** Returns the built block as a unique_ptr */
|
||||
inline std::unique_ptr<BLOCKTYPE> build ()
|
||||
{
|
||||
if (!ec)
|
||||
{
|
||||
static_cast<BUILDER *> (this)->validate ();
|
||||
}
|
||||
assert (!ec);
|
||||
return std::move (block);
|
||||
}
|
||||
|
||||
std::unique_ptr<BLOCKTYPE> build ();
|
||||
/** Returns the built block as a unique_ptr. Any errors are placed in \p ec */
|
||||
inline std::unique_ptr<BLOCKTYPE> build (std::error_code & ec)
|
||||
{
|
||||
if (!this->ec)
|
||||
{
|
||||
static_cast<BUILDER *> (this)->validate ();
|
||||
}
|
||||
ec = this->ec;
|
||||
return std::move (block);
|
||||
}
|
||||
|
||||
std::unique_ptr<BLOCKTYPE> build (std::error_code & ec);
|
||||
/** Set work value */
|
||||
inline abstract_builder & work (uint64_t work)
|
||||
{
|
||||
block->work = work;
|
||||
build_state |= build_flags::work_present;
|
||||
return *this;
|
||||
}
|
||||
|
||||
abstract_builder & work (uint64_t work);
|
||||
/** Sign the block using the \p private_key and \p public_key */
|
||||
inline abstract_builder & sign (nano::raw_key const & private_key, nano::public_key const & public_key)
|
||||
{
|
||||
block->signature = nano::sign_message (private_key, public_key, block->hash ());
|
||||
build_state |= build_flags::signature_present;
|
||||
return *this;
|
||||
}
|
||||
|
||||
abstract_builder & sign (nano::raw_key const & private_key, nano::public_key const & public_key);
|
||||
/** Set signature to zero to pass build() validation, allowing block to be signed at a later point. This is mostly useful for tests. */
|
||||
inline abstract_builder & sign_zero ()
|
||||
{
|
||||
block->signature.clear ();
|
||||
build_state |= build_flags::signature_present;
|
||||
return *this;
|
||||
}
|
||||
abstract_builder & sign_zero ();
|
||||
|
||||
protected:
|
||||
abstract_builder ()
|
||||
{
|
||||
}
|
||||
abstract_builder () = default;
|
||||
|
||||
/** Create a new block and resets the internal builder state */
|
||||
inline void construct_block ()
|
||||
{
|
||||
block = std::make_unique<BLOCKTYPE> ();
|
||||
ec.clear ();
|
||||
build_state = 0;
|
||||
}
|
||||
void construct_block ();
|
||||
|
||||
/** The block we're building. Clients can convert this to shared_ptr as needed. */
|
||||
std::unique_ptr<BLOCKTYPE> block;
|
||||
|
@ -290,35 +247,35 @@ class block_builder
|
|||
{
|
||||
public:
|
||||
/** Prepares a new state block and returns a block builder */
|
||||
inline nano::state_block_builder & state ()
|
||||
nano::state_block_builder & state ()
|
||||
{
|
||||
state_builder.make_block ();
|
||||
return state_builder;
|
||||
}
|
||||
|
||||
/** Prepares a new open block and returns a block builder */
|
||||
inline nano::open_block_builder & open ()
|
||||
nano::open_block_builder & open ()
|
||||
{
|
||||
open_builder.make_block ();
|
||||
return open_builder;
|
||||
}
|
||||
|
||||
/** Prepares a new change block and returns a block builder */
|
||||
inline nano::change_block_builder & change ()
|
||||
nano::change_block_builder & change ()
|
||||
{
|
||||
change_builder.make_block ();
|
||||
return change_builder;
|
||||
}
|
||||
|
||||
/** Prepares a new send block and returns a block builder */
|
||||
inline nano::send_block_builder & send ()
|
||||
nano::send_block_builder & send ()
|
||||
{
|
||||
send_builder.make_block ();
|
||||
return send_builder;
|
||||
}
|
||||
|
||||
/** Prepares a new receive block and returns a block builder */
|
||||
inline nano::receive_block_builder & receive ()
|
||||
nano::receive_block_builder & receive ()
|
||||
{
|
||||
receive_builder.make_block ();
|
||||
return receive_builder;
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/memory.hpp>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
|
||||
#include <crypto/cryptopp/words.h>
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/pool/pool_alloc.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
/** Compare blocks, first by type, then content. This is an optimization over dynamic_cast, which is very slow on some platforms. */
|
||||
namespace
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree_fwd.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <streambuf>
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
#include <nano/lib/config.hpp>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <valgrind/valgrind.h>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
const char * network_constants::active_network_err_msg = "Invalid network. Valid values are live, beta and test.";
|
||||
|
||||
void force_nano_test_network ()
|
||||
{
|
||||
nano::network_constants::set_active_network (nano::nano_networks::nano_test_network);
|
||||
|
@ -13,4 +17,29 @@ bool running_within_valgrind ()
|
|||
{
|
||||
return (RUNNING_ON_VALGRIND > 0);
|
||||
}
|
||||
|
||||
std::string get_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return (data_path / "config.json").string ();
|
||||
}
|
||||
|
||||
std::string get_rpc_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return (data_path / "rpc_config.json").string ();
|
||||
}
|
||||
|
||||
std::string get_node_toml_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return (data_path / "config-node.toml").string ();
|
||||
}
|
||||
|
||||
std::string get_rpc_toml_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return (data_path / "config-rpc.toml").string ();
|
||||
}
|
||||
|
||||
std::string get_qtwallet_toml_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return (data_path / "config-qtwallet.toml").string ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
class path;
|
||||
}
|
||||
}
|
||||
|
||||
#define xstr(a) ver_str (a)
|
||||
#define ver_str(a) #a
|
||||
|
||||
|
@ -77,8 +81,11 @@ public:
|
|||
static uint64_t const publish_beta_threshold{ 0xfffffc0000000000 }; // 16x lower than full
|
||||
static uint64_t const publish_test_threshold{ 0xff00000000000000 }; // very low for tests
|
||||
|
||||
/** Error message when an invalid network is specified */
|
||||
static const char * active_network_err_msg;
|
||||
|
||||
/** The network this param object represents. This may differ from the global active network; this is needed for certain --debug... commands */
|
||||
nano_networks current_network;
|
||||
nano_networks current_network{ nano::network_constants::active_network };
|
||||
uint64_t publish_threshold;
|
||||
unsigned principal_weight_factor;
|
||||
uint16_t default_node_port;
|
||||
|
@ -108,9 +115,9 @@ public:
|
|||
* If not called, the compile-time option will be used.
|
||||
* @param network_a The new active network. Valid values are "live", "beta" and "test"
|
||||
*/
|
||||
static nano::error set_active_network (std::string network_a)
|
||||
static bool set_active_network (std::string network_a)
|
||||
{
|
||||
nano::error err;
|
||||
auto error{ false };
|
||||
if (network_a == "live")
|
||||
{
|
||||
active_network = nano::nano_networks::nano_live_network;
|
||||
|
@ -125,9 +132,9 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
err = "Invalid network. Valid values are live, beta and test.";
|
||||
error = true;
|
||||
}
|
||||
return err;
|
||||
return error;
|
||||
}
|
||||
|
||||
const char * get_current_network_as_string () const
|
||||
|
@ -152,30 +159,11 @@ public:
|
|||
static nano::nano_networks active_network;
|
||||
};
|
||||
|
||||
inline boost::filesystem::path get_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return data_path / "config.json";
|
||||
}
|
||||
|
||||
inline boost::filesystem::path get_rpc_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return data_path / "rpc_config.json";
|
||||
}
|
||||
|
||||
inline boost::filesystem::path get_node_toml_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return data_path / "config-node.toml";
|
||||
}
|
||||
|
||||
inline boost::filesystem::path get_rpc_toml_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return data_path / "config-rpc.toml";
|
||||
}
|
||||
|
||||
inline boost::filesystem::path get_qtwallet_toml_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return data_path / "config-qtwallet.toml";
|
||||
}
|
||||
std::string get_config_path (boost::filesystem::path const & data_path);
|
||||
std::string get_rpc_config_path (boost::filesystem::path const & data_path);
|
||||
std::string get_node_toml_config_path (boost::filesystem::path const & data_path);
|
||||
std::string get_rpc_toml_config_path (boost::filesystem::path const & data_path);
|
||||
std::string get_qtwallet_toml_config_path (boost::filesystem::path const & data_path);
|
||||
|
||||
/** Called by gtest_main to enforce test network */
|
||||
void force_nano_test_network ();
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include <nano/lib/errors.hpp>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
#include <istream>
|
||||
|
@ -35,7 +34,6 @@ template <> inline std::string type_desc<double> (void) { return "a double preci
|
|||
template <> inline std::string type_desc<char> (void) { return "a character"; }
|
||||
template <> inline std::string type_desc<std::string> (void) { return "a string"; }
|
||||
template <> inline std::string type_desc<bool> (void) { return "a boolean"; }
|
||||
template <> inline std::string type_desc<boost::asio::ip::address_v6> (void) { return "an IP address"; }
|
||||
// clang-format on
|
||||
|
||||
/** Base type for configuration wrappers */
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#include "nano/lib/errors.hpp"
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
std::string nano::error_common_messages::message (int ev) const
|
||||
{
|
||||
switch (static_cast<nano::error_common> (ev))
|
||||
|
@ -256,3 +260,211 @@ std::string nano::error_config_messages::message (int ev) const
|
|||
|
||||
return "Invalid error code";
|
||||
}
|
||||
|
||||
const char * nano::error_conversion::detail::generic_category::name () const noexcept
|
||||
{
|
||||
return boost::system::generic_category ().name ();
|
||||
}
|
||||
std::string nano::error_conversion::detail::generic_category::message (int value) const
|
||||
{
|
||||
return boost::system::generic_category ().message (value);
|
||||
}
|
||||
|
||||
const std::error_category & nano::error_conversion::generic_category ()
|
||||
{
|
||||
static detail::generic_category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::error_code nano::error_conversion::convert (const boost::system::error_code & error)
|
||||
{
|
||||
if (error.category () == boost::system::generic_category ())
|
||||
{
|
||||
return std::error_code (error.value (),
|
||||
nano::error_conversion::generic_category ());
|
||||
}
|
||||
assert (false);
|
||||
|
||||
return nano::error_common::invalid_type_conversion;
|
||||
}
|
||||
|
||||
nano::error::error (std::error_code code_a)
|
||||
{
|
||||
code = code_a;
|
||||
}
|
||||
|
||||
nano::error::error (boost::system::error_code const & code_a)
|
||||
{
|
||||
code = std::make_error_code (static_cast<std::errc> (code_a.value ()));
|
||||
}
|
||||
|
||||
nano::error::error (std::string message_a)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
message = std::move (message_a);
|
||||
}
|
||||
|
||||
nano::error::error (std::exception const & exception_a)
|
||||
{
|
||||
code = nano::error_common::exception;
|
||||
message = exception_a.what ();
|
||||
}
|
||||
|
||||
nano::error & nano::error::operator= (nano::error const & err_a)
|
||||
{
|
||||
code = err_a.code;
|
||||
message = err_a.message;
|
||||
return *this;
|
||||
}
|
||||
|
||||
nano::error & nano::error::operator= (nano::error && err_a)
|
||||
{
|
||||
code = err_a.code;
|
||||
message = std::move (err_a.message);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign error code */
|
||||
nano::error & nano::error::operator= (const std::error_code code_a)
|
||||
{
|
||||
code = code_a;
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign boost error code (as converted to std::error_code) */
|
||||
nano::error & nano::error::operator= (const boost::system::error_code & code_a)
|
||||
{
|
||||
code = nano::error_conversion::convert (code_a);
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign boost error code (as converted to std::error_code) */
|
||||
nano::error & nano::error::operator= (const boost::system::errc::errc_t & code_a)
|
||||
{
|
||||
code = nano::error_conversion::convert (boost::system::errc::make_error_code (code_a));
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set the error to nano::error_common::generic and the error message to \p message_a */
|
||||
nano::error & nano::error::operator= (const std::string message_a)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
message = std::move (message_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Sets the error to nano::error_common::exception and adopts the exception error message. */
|
||||
nano::error & nano::error::operator= (std::exception const & exception_a)
|
||||
{
|
||||
code = nano::error_common::exception;
|
||||
message = exception_a.what ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Return true if this#error_code equals the parameter */
|
||||
bool nano::error::operator== (const std::error_code code_a) const
|
||||
{
|
||||
return code == code_a;
|
||||
}
|
||||
|
||||
/** Return true if this#error_code equals the parameter */
|
||||
bool nano::error::operator== (const boost::system::error_code code_a) const
|
||||
{
|
||||
return code.value () == code_a.value ();
|
||||
}
|
||||
|
||||
/** Call the function iff the current error is zero */
|
||||
nano::error & nano::error::then (std::function<nano::error &()> next)
|
||||
{
|
||||
return code ? *this : next ();
|
||||
}
|
||||
|
||||
/** Implicit error_code conversion */
|
||||
nano::error::operator std::error_code () const
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
/** Implicit bool conversion; true if there's an error */
|
||||
nano::error::operator bool () const
|
||||
{
|
||||
return code.value () != 0;
|
||||
}
|
||||
|
||||
/** Implicit string conversion; returns the error message or an empty string. */
|
||||
nano::error::operator std::string () const
|
||||
{
|
||||
return get_message ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error message, or an empty string if there's no error. If a custom error message is set,
|
||||
* that will be returned, otherwise the error_code#message() is returned.
|
||||
*/
|
||||
std::string nano::error::get_message () const
|
||||
{
|
||||
std::string res = message;
|
||||
if (code && res.empty ())
|
||||
{
|
||||
res = code.message ();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Set an error message, but only if the error code is already set */
|
||||
nano::error & nano::error::on_error (std::string message_a)
|
||||
{
|
||||
if (code)
|
||||
{
|
||||
message = std::move (message_a);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set an error message if the current error code matches \p code_a */
|
||||
nano::error & nano::error::on_error (std::error_code code_a, std::string message_a)
|
||||
{
|
||||
if (code == code_a)
|
||||
{
|
||||
message = std::move (message_a);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set an error message and an error code */
|
||||
nano::error & nano::error::set (std::string message_a, std::error_code code_a)
|
||||
{
|
||||
message = message_a;
|
||||
code = code_a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set a custom error message. If the error code is not set, it will be set to nano::error_common::generic. */
|
||||
nano::error & nano::error::set_message (std::string message_a)
|
||||
{
|
||||
if (!code)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
}
|
||||
message = std::move (message_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Clear an errors */
|
||||
nano::error & nano::error::clear ()
|
||||
{
|
||||
code.clear ();
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
std::error_code make_error_code (boost::system::errc::errc_t const & e)
|
||||
{
|
||||
return std::error_code (static_cast<int> (e), ::nano::error_conversion::generic_category ());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
@ -202,11 +203,7 @@ struct is_error_code_enum<boost::system::errc::errc_t>
|
|||
{
|
||||
};
|
||||
|
||||
inline std::error_code make_error_code (boost::system::errc::errc_t e)
|
||||
{
|
||||
return std::error_code (static_cast<int> (e),
|
||||
::nano::error_conversion::generic_category ());
|
||||
}
|
||||
std::error_code make_error_code (boost::system::errc::errc_t const & e);
|
||||
}
|
||||
namespace nano
|
||||
{
|
||||
|
@ -217,33 +214,12 @@ namespace error_conversion
|
|||
class generic_category : public std::error_category
|
||||
{
|
||||
public:
|
||||
virtual const char * name () const noexcept override
|
||||
{
|
||||
return boost::system::generic_category ().name ();
|
||||
}
|
||||
virtual std::string message (int value) const override
|
||||
{
|
||||
return boost::system::generic_category ().message (value);
|
||||
}
|
||||
const char * name () const noexcept override;
|
||||
std::string message (int value) const override;
|
||||
};
|
||||
}
|
||||
inline const std::error_category & generic_category ()
|
||||
{
|
||||
static detail::generic_category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
inline std::error_code convert (const boost::system::error_code & error)
|
||||
{
|
||||
if (error.category () == boost::system::generic_category ())
|
||||
{
|
||||
return std::error_code (error.value (),
|
||||
nano::error_conversion::generic_category ());
|
||||
}
|
||||
assert (false);
|
||||
|
||||
return nano::error_common::invalid_type_conversion;
|
||||
}
|
||||
const std::error_category & generic_category ();
|
||||
std::error_code convert (const boost::system::error_code & error);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,101 +233,20 @@ public:
|
|||
error (nano::error const & error_a) = default;
|
||||
error (nano::error && error_a) = default;
|
||||
|
||||
error (std::error_code code_a)
|
||||
{
|
||||
code = code_a;
|
||||
}
|
||||
|
||||
error (boost::system::error_code code_a)
|
||||
{
|
||||
code = std::make_error_code (static_cast<std::errc> (code_a.value ()));
|
||||
}
|
||||
|
||||
error (std::string message_a)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
message = std::move (message_a);
|
||||
}
|
||||
|
||||
error (std::exception const & exception_a)
|
||||
{
|
||||
code = nano::error_common::exception;
|
||||
message = exception_a.what ();
|
||||
}
|
||||
|
||||
error & operator= (nano::error const & err_a)
|
||||
{
|
||||
code = err_a.code;
|
||||
message = err_a.message;
|
||||
return *this;
|
||||
}
|
||||
|
||||
error & operator= (nano::error && err_a)
|
||||
{
|
||||
code = err_a.code;
|
||||
message = std::move (err_a.message);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign error code */
|
||||
error & operator= (const std::error_code code_a)
|
||||
{
|
||||
code = code_a;
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign boost error code (as converted to std::error_code) */
|
||||
error & operator= (const boost::system::error_code & code_a)
|
||||
{
|
||||
code = nano::error_conversion::convert (code_a);
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign boost error code (as converted to std::error_code) */
|
||||
error & operator= (const boost::system::errc::errc_t & code_a)
|
||||
{
|
||||
code = nano::error_conversion::convert (boost::system::errc::make_error_code (code_a));
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set the error to nano::error_common::generic and the error message to \p message_a */
|
||||
error & operator= (const std::string message_a)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
message = std::move (message_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Sets the error to nano::error_common::exception and adopts the exception error message. */
|
||||
error & operator= (std::exception const & exception_a)
|
||||
{
|
||||
code = nano::error_common::exception;
|
||||
message = exception_a.what ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Return true if this#error_code equals the parameter */
|
||||
bool operator== (const std::error_code code_a)
|
||||
{
|
||||
return code == code_a;
|
||||
}
|
||||
|
||||
/** Return true if this#error_code equals the parameter */
|
||||
bool operator== (const boost::system::error_code code_a)
|
||||
{
|
||||
return code.value () == code_a.value ();
|
||||
}
|
||||
|
||||
/** Call the function iff the current error is zero */
|
||||
error & then (std::function<nano::error &()> next)
|
||||
{
|
||||
return code ? *this : next ();
|
||||
}
|
||||
|
||||
/** If the current error is one of the listed codes, reset the error code */
|
||||
error (std::error_code code_a);
|
||||
error (boost::system::error_code const & code_a);
|
||||
error (std::string message_a);
|
||||
error (std::exception const & exception_a);
|
||||
error & operator= (nano::error const & err_a);
|
||||
error & operator= (nano::error && err_a);
|
||||
error & operator= (const std::error_code code_a);
|
||||
error & operator= (const boost::system::error_code & code_a);
|
||||
error & operator= (const boost::system::errc::errc_t & code_a);
|
||||
error & operator= (const std::string message_a);
|
||||
error & operator= (std::exception const & exception_a);
|
||||
bool operator== (const std::error_code code_a) const;
|
||||
bool operator== (const boost::system::error_code code_a) const;
|
||||
error & then (std::function<nano::error &()> next);
|
||||
template <typename... ErrorCode>
|
||||
error & accept (ErrorCode... err)
|
||||
{
|
||||
|
@ -365,84 +260,15 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/** Implicit error_code conversion */
|
||||
explicit operator std::error_code () const
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
/** Implicit bool conversion; true if there's an error */
|
||||
explicit operator bool () const
|
||||
{
|
||||
return code.value () != 0;
|
||||
}
|
||||
|
||||
/** Implicit string conversion; returns the error message or an empty string. */
|
||||
explicit operator std::string () const
|
||||
{
|
||||
return get_message ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error message, or an empty string if there's no error. If a custom error message is set,
|
||||
* that will be returned, otherwise the error_code#message() is returned.
|
||||
*/
|
||||
std::string get_message () const
|
||||
{
|
||||
std::string res = message;
|
||||
if (code && res.empty ())
|
||||
{
|
||||
res = code.message ();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Set an error message, but only if the error code is already set */
|
||||
error & on_error (std::string message_a)
|
||||
{
|
||||
if (code)
|
||||
{
|
||||
message = std::move (message_a);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set an error message if the current error code matches \p code_a */
|
||||
error & on_error (std::error_code code_a, std::string message_a)
|
||||
{
|
||||
if (code == code_a)
|
||||
{
|
||||
message = std::move (message_a);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set an error message and an error code */
|
||||
error & set (std::string message_a, std::error_code code_a = nano::error_common::generic)
|
||||
{
|
||||
message = message_a;
|
||||
code = code_a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set a custom error message. If the error code is not set, it will be set to nano::error_common::generic. */
|
||||
error & set_message (std::string message_a)
|
||||
{
|
||||
if (!code)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
}
|
||||
message = std::move (message_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Clear an errors */
|
||||
error & clear ()
|
||||
{
|
||||
code.clear ();
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
explicit operator std::error_code () const;
|
||||
explicit operator bool () const;
|
||||
explicit operator std::string () const;
|
||||
std::string get_message () const;
|
||||
error & on_error (std::string message_a);
|
||||
error & on_error (std::error_code code_a, std::string message_a);
|
||||
error & set (std::string message_a, std::error_code code_a = nano::error_common::generic);
|
||||
error & set_message (std::string message_a);
|
||||
error & clear ();
|
||||
|
||||
private:
|
||||
std::error_code code;
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/asio.hpp>
|
||||
#include <nano/boost/asio/deadline_timer.hpp>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
namespace nano
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
#include <nano/boost/asio/bind_executor.hpp>
|
||||
#include <nano/boost/asio/ip/tcp.hpp>
|
||||
#include <nano/boost/asio/local/stream_protocol.hpp>
|
||||
#include <nano/boost/asio/read.hpp>
|
||||
#include <nano/boost/asio/strand.hpp>
|
||||
#include <nano/lib/asio.hpp>
|
||||
#include <nano/lib/ipc.hpp>
|
||||
#include <nano/lib/ipc_client.hpp>
|
||||
|
@ -5,6 +10,8 @@
|
|||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/polymorphic_cast.hpp>
|
||||
|
||||
#include <future>
|
||||
|
||||
namespace
|
||||
{
|
||||
/** Socket agnostic IO interface */
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/asio.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/ipc.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
|
261
nano/lib/jsonconfig.cpp
Normal file
261
nano/lib/jsonconfig.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
#include <nano/boost/asio/ip/address_v6.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
nano::jsonconfig::jsonconfig () :
|
||||
tree (tree_default)
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
|
||||
nano::jsonconfig::jsonconfig (boost::property_tree::ptree & tree_a, std::shared_ptr<nano::error> error_a) :
|
||||
nano::configbase (error_a), tree (tree_a)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a json object from the stream
|
||||
* @return nano::error&, including a descriptive error message if the config file is malformed.
|
||||
*/
|
||||
nano::error & nano::jsonconfig::read (boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
if (!stream.fail ())
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_json (stream, tree);
|
||||
}
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
auto pos (stream.tellg ());
|
||||
if (pos != std::streampos (0))
|
||||
{
|
||||
*error = ex;
|
||||
}
|
||||
}
|
||||
stream.close ();
|
||||
}
|
||||
return *error;
|
||||
}
|
||||
|
||||
void nano::jsonconfig::write (boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
write (stream);
|
||||
}
|
||||
|
||||
void nano::jsonconfig::write (std::ostream & stream_a) const
|
||||
{
|
||||
boost::property_tree::write_json (stream_a, tree);
|
||||
}
|
||||
|
||||
void nano::jsonconfig::read (std::istream & stream_a)
|
||||
{
|
||||
boost::property_tree::read_json (stream_a, tree);
|
||||
}
|
||||
|
||||
/** Open configuration file, create if necessary */
|
||||
void nano::jsonconfig::open_or_create (std::fstream & stream_a, std::string const & path_a)
|
||||
{
|
||||
if (!boost::filesystem::exists (path_a))
|
||||
{
|
||||
// Create temp stream to first create the file
|
||||
std::ofstream stream (path_a);
|
||||
|
||||
// Set permissions before opening otherwise Windows only has read permissions
|
||||
nano::set_secure_perm_file (path_a);
|
||||
}
|
||||
|
||||
stream_a.open (path_a);
|
||||
}
|
||||
|
||||
/** Takes a filepath, appends '_backup_<timestamp>' to the end (but before any extension) and saves that file in the same directory */
|
||||
void nano::jsonconfig::create_backup_file (boost::filesystem::path const & filepath_a)
|
||||
{
|
||||
auto extension = filepath_a.extension ();
|
||||
auto filename_without_extension = filepath_a.filename ().replace_extension ("");
|
||||
auto orig_filepath = filepath_a;
|
||||
auto & backup_path = orig_filepath.remove_filename ();
|
||||
auto backup_filename = filename_without_extension;
|
||||
backup_filename += "_backup_";
|
||||
backup_filename += std::to_string (std::chrono::system_clock::now ().time_since_epoch ().count ());
|
||||
backup_filename += extension;
|
||||
auto backup_filepath = backup_path / backup_filename;
|
||||
|
||||
boost::filesystem::copy_file (filepath_a, backup_filepath);
|
||||
}
|
||||
|
||||
/** Returns the boost property node managed by this instance */
|
||||
boost::property_tree::ptree const & nano::jsonconfig::get_tree ()
|
||||
{
|
||||
return tree;
|
||||
}
|
||||
|
||||
/** Returns true if the property tree node is empty */
|
||||
bool nano::jsonconfig::empty () const
|
||||
{
|
||||
return tree.empty ();
|
||||
}
|
||||
|
||||
boost::optional<nano::jsonconfig> nano::jsonconfig::get_optional_child (std::string const & key_a)
|
||||
{
|
||||
boost::optional<jsonconfig> child_config;
|
||||
auto child = tree.get_child_optional (key_a);
|
||||
if (child)
|
||||
{
|
||||
return jsonconfig (child.get (), error);
|
||||
}
|
||||
return child_config;
|
||||
}
|
||||
|
||||
nano::jsonconfig nano::jsonconfig::get_required_child (std::string const & key_a)
|
||||
{
|
||||
auto child = tree.get_child_optional (key_a);
|
||||
if (!child)
|
||||
{
|
||||
*error = nano::error_config::missing_value;
|
||||
error->set_message ("Missing configuration node: " + key_a);
|
||||
}
|
||||
return child ? jsonconfig (child.get (), error) : *this;
|
||||
}
|
||||
|
||||
nano::jsonconfig & nano::jsonconfig::put_child (std::string const & key_a, nano::jsonconfig & conf_a)
|
||||
{
|
||||
tree.add_child (key_a, conf_a.get_tree ());
|
||||
return *this;
|
||||
}
|
||||
|
||||
nano::jsonconfig & nano::jsonconfig::replace_child (std::string const & key_a, nano::jsonconfig & conf_a)
|
||||
{
|
||||
tree.erase (key_a);
|
||||
put_child (key_a, conf_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns true if \p key_a is present */
|
||||
bool nano::jsonconfig::has_key (std::string const & key_a)
|
||||
{
|
||||
return tree.find (key_a) != tree.not_found ();
|
||||
}
|
||||
|
||||
/** Erase the property of given key */
|
||||
nano::jsonconfig & nano::jsonconfig::erase (std::string const & key_a)
|
||||
{
|
||||
tree.erase (key_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// boost's lexical cast doesn't handle (u)int8_t
|
||||
nano::jsonconfig & nano::jsonconfig::get_config (bool optional, std::string key, uint8_t & target, uint8_t default_value)
|
||||
{
|
||||
int64_t tmp;
|
||||
try
|
||||
{
|
||||
auto val (tree.get<std::string> (key));
|
||||
if (!boost::conversion::try_lexical_convert<int64_t> (val, tmp) || tmp < 0 || tmp > 255)
|
||||
{
|
||||
conditionally_set_error<uint8_t> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = static_cast<uint8_t> (tmp);
|
||||
}
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const &)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<uint8_t> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<uint8_t> (ex, optional, key);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
nano::jsonconfig & nano::jsonconfig::get_config (bool optional, std::string key, bool & target, bool default_value)
|
||||
{
|
||||
auto bool_conv = [this, &target, &key, optional](std::string val) {
|
||||
if (val == "true")
|
||||
{
|
||||
target = true;
|
||||
}
|
||||
else if (val == "false")
|
||||
{
|
||||
target = false;
|
||||
}
|
||||
else if (!*error)
|
||||
{
|
||||
conditionally_set_error<bool> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
auto val (tree.get<std::string> (key));
|
||||
bool_conv (val);
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const &)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<bool> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<bool> (ex, optional, key);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
nano::jsonconfig & nano::jsonconfig::get_config (bool optional, std::string key, boost::asio::ip::address_v6 & target, boost::asio::ip::address_v6 const & default_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto address_l (tree.get<std::string> (key));
|
||||
boost::system::error_code bec;
|
||||
target = boost::asio::ip::make_address_v6 (address_l, bec);
|
||||
if (bec)
|
||||
{
|
||||
conditionally_set_error<boost::asio::ip::address_v6> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const &)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<boost::asio::ip::address_v6> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void nano::jsonconfig::write_json (std::fstream & stream)
|
||||
{
|
||||
boost::property_tree::write_json (stream, tree);
|
||||
}
|
|
@ -1,63 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/asio.hpp>
|
||||
#include <nano/lib/configbase.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace asio
|
||||
{
|
||||
namespace ip
|
||||
{
|
||||
class address_v6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
/** Manages a node in a boost configuration tree. */
|
||||
class jsonconfig : public nano::configbase
|
||||
{
|
||||
public:
|
||||
jsonconfig () :
|
||||
tree (tree_default)
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
|
||||
jsonconfig (boost::property_tree::ptree & tree_a, std::shared_ptr<nano::error> error_a = nullptr) :
|
||||
nano::configbase (error_a), tree (tree_a)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a json object from the stream
|
||||
* @return nano::error&, including a descriptive error message if the config file is malformed.
|
||||
*/
|
||||
nano::error & read (boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
if (!stream.fail ())
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_json (stream, tree);
|
||||
}
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
auto pos (stream.tellg ());
|
||||
if (pos != std::streampos (0))
|
||||
{
|
||||
*error = ex;
|
||||
}
|
||||
}
|
||||
stream.close ();
|
||||
}
|
||||
return *error;
|
||||
}
|
||||
jsonconfig ();
|
||||
jsonconfig (boost::property_tree::ptree & tree_a, std::shared_ptr<nano::error> error_a = nullptr);
|
||||
nano::error & read (boost::filesystem::path const & path_a);
|
||||
|
||||
/**
|
||||
* Reads a json object from the stream and if it was changed, write the object back to the stream.
|
||||
|
@ -83,7 +55,7 @@ public:
|
|||
stream.open (path_a.string (), std::ios_base::out | std::ios_base::trunc);
|
||||
try
|
||||
{
|
||||
boost::property_tree::write_json (stream, tree);
|
||||
write_json (stream);
|
||||
}
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
|
@ -95,100 +67,19 @@ public:
|
|||
return *error;
|
||||
}
|
||||
|
||||
void write (boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
write (stream);
|
||||
}
|
||||
|
||||
void write (std::ostream & stream_a) const
|
||||
{
|
||||
boost::property_tree::write_json (stream_a, tree);
|
||||
}
|
||||
|
||||
void read (std::istream & stream_a)
|
||||
{
|
||||
boost::property_tree::read_json (stream_a, tree);
|
||||
}
|
||||
|
||||
/** Open configuration file, create if necessary */
|
||||
void open_or_create (std::fstream & stream_a, std::string const & path_a)
|
||||
{
|
||||
if (!boost::filesystem::exists (path_a))
|
||||
{
|
||||
// Create temp stream to first create the file
|
||||
std::ofstream stream (path_a);
|
||||
|
||||
// Set permissions before opening otherwise Windows only has read permissions
|
||||
nano::set_secure_perm_file (path_a);
|
||||
}
|
||||
|
||||
stream_a.open (path_a);
|
||||
}
|
||||
|
||||
/** Takes a filepath, appends '_backup_<timestamp>' to the end (but before any extension) and saves that file in the same directory */
|
||||
void create_backup_file (boost::filesystem::path const & filepath_a)
|
||||
{
|
||||
auto extension = filepath_a.extension ();
|
||||
auto filename_without_extension = filepath_a.filename ().replace_extension ("");
|
||||
auto orig_filepath = filepath_a;
|
||||
auto & backup_path = orig_filepath.remove_filename ();
|
||||
auto backup_filename = filename_without_extension;
|
||||
backup_filename += "_backup_";
|
||||
backup_filename += std::to_string (std::chrono::system_clock::now ().time_since_epoch ().count ());
|
||||
backup_filename += extension;
|
||||
auto backup_filepath = backup_path / backup_filename;
|
||||
|
||||
boost::filesystem::copy_file (filepath_a, backup_filepath);
|
||||
}
|
||||
|
||||
/** Returns the boost property node managed by this instance */
|
||||
boost::property_tree::ptree const & get_tree ()
|
||||
{
|
||||
return tree;
|
||||
}
|
||||
|
||||
/** Returns true if the property tree node is empty */
|
||||
bool empty () const
|
||||
{
|
||||
return tree.empty ();
|
||||
}
|
||||
|
||||
boost::optional<jsonconfig> get_optional_child (std::string const & key_a)
|
||||
{
|
||||
boost::optional<jsonconfig> child_config;
|
||||
auto child = tree.get_child_optional (key_a);
|
||||
if (child)
|
||||
{
|
||||
return jsonconfig (child.get (), error);
|
||||
}
|
||||
return child_config;
|
||||
}
|
||||
|
||||
jsonconfig get_required_child (std::string const & key_a)
|
||||
{
|
||||
auto child = tree.get_child_optional (key_a);
|
||||
if (!child)
|
||||
{
|
||||
*error = nano::error_config::missing_value;
|
||||
error->set_message ("Missing configuration node: " + key_a);
|
||||
}
|
||||
return child ? jsonconfig (child.get (), error) : *this;
|
||||
}
|
||||
|
||||
jsonconfig & put_child (std::string const & key_a, nano::jsonconfig & conf_a)
|
||||
{
|
||||
tree.add_child (key_a, conf_a.get_tree ());
|
||||
return *this;
|
||||
}
|
||||
|
||||
jsonconfig & replace_child (std::string const & key_a, nano::jsonconfig & conf_a)
|
||||
{
|
||||
tree.erase (key_a);
|
||||
put_child (key_a, conf_a);
|
||||
return *this;
|
||||
}
|
||||
void write (boost::filesystem::path const & path_a);
|
||||
void write (std::ostream & stream_a) const;
|
||||
void read (std::istream & stream_a);
|
||||
void open_or_create (std::fstream & stream_a, std::string const & path_a);
|
||||
void create_backup_file (boost::filesystem::path const & filepath_a);
|
||||
boost::property_tree::ptree const & get_tree ();
|
||||
bool empty () const;
|
||||
boost::optional<jsonconfig> get_optional_child (std::string const & key_a);
|
||||
jsonconfig get_required_child (std::string const & key_a);
|
||||
jsonconfig & put_child (std::string const & key_a, nano::jsonconfig & conf_a);
|
||||
jsonconfig & replace_child (std::string const & key_a, nano::jsonconfig & conf_a);
|
||||
bool has_key (std::string const & key_a);
|
||||
jsonconfig & erase (std::string const & key_a);
|
||||
|
||||
/** Set value for the given key. Any existing value will be overwritten. */
|
||||
template <typename T>
|
||||
|
@ -208,19 +99,6 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/** Returns true if \p key_a is present */
|
||||
bool has_key (std::string const & key_a)
|
||||
{
|
||||
return tree.find (key_a) != tree.not_found ();
|
||||
}
|
||||
|
||||
/** Erase the property of given key */
|
||||
jsonconfig & erase (std::string const & key_a)
|
||||
{
|
||||
tree.erase (key_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Iterate array entries */
|
||||
template <typename T>
|
||||
jsonconfig & array_entries (std::function<void(T)> callback)
|
||||
|
@ -236,7 +114,7 @@ public:
|
|||
template <typename T>
|
||||
jsonconfig & get_optional (std::string const & key, T & target, T default_value)
|
||||
{
|
||||
get_config<T> (true, key, target, default_value);
|
||||
get_config (true, key, target, default_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -247,7 +125,7 @@ public:
|
|||
template <typename T>
|
||||
jsonconfig & get_optional (std::string const & key, T & target)
|
||||
{
|
||||
get_config<T> (true, key, target, target);
|
||||
get_config (true, key, target, target);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -259,7 +137,7 @@ public:
|
|||
if (has_key (key))
|
||||
{
|
||||
T target{};
|
||||
get_config<T> (true, key, target, target);
|
||||
get_config (true, key, target, target);
|
||||
res = target;
|
||||
}
|
||||
return res;
|
||||
|
@ -269,7 +147,7 @@ public:
|
|||
template <typename T>
|
||||
jsonconfig & get (std::string const & key, T & target)
|
||||
{
|
||||
get_config<T> (true, key, target, target);
|
||||
get_config (true, key, target, target);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -280,7 +158,7 @@ public:
|
|||
T get (std::string const & key)
|
||||
{
|
||||
T target{};
|
||||
get_config<T> (true, key, target, target);
|
||||
get_config (true, key, target, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
@ -291,7 +169,14 @@ public:
|
|||
template <typename T>
|
||||
jsonconfig & get_required (std::string const & key, T & target)
|
||||
{
|
||||
get_config<T> (false, key, target);
|
||||
get_config (false, key, target);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
jsonconfig & get_required (std::string const & key, T & target, T const & default_value)
|
||||
{
|
||||
get_config (false, key, target, default_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -326,110 +211,15 @@ protected:
|
|||
}
|
||||
|
||||
// boost's lexical cast doesn't handle (u)int8_t
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, uint8_t>::value>>
|
||||
jsonconfig & get_config (bool optional, std::string key, uint8_t & target, uint8_t default_value = T ())
|
||||
{
|
||||
int64_t tmp;
|
||||
try
|
||||
{
|
||||
auto val (tree.get<std::string> (key));
|
||||
if (!boost::conversion::try_lexical_convert<int64_t> (val, tmp) || tmp < 0 || tmp > 255)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = static_cast<uint8_t> (tmp);
|
||||
}
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const &)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<T> (ex, optional, key);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, bool>::value>>
|
||||
jsonconfig & get_config (bool optional, std::string key, bool & target, bool default_value = false)
|
||||
{
|
||||
auto bool_conv = [this, &target, &key, optional](std::string val) {
|
||||
if (val == "true")
|
||||
{
|
||||
target = true;
|
||||
}
|
||||
else if (val == "false")
|
||||
{
|
||||
target = false;
|
||||
}
|
||||
else if (!*error)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
auto val (tree.get<std::string> (key));
|
||||
bool_conv (val);
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const &)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<T> (ex, optional, key);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, boost::asio::ip::address_v6>::value>>
|
||||
jsonconfig & get_config (bool optional, std::string key, boost::asio::ip::address_v6 & target, boost::asio::ip::address_v6 default_value = T ())
|
||||
{
|
||||
try
|
||||
{
|
||||
auto address_l (tree.get<std::string> (key));
|
||||
boost::system::error_code bec;
|
||||
target = boost::asio::ip::address_v6::from_string (address_l, bec);
|
||||
if (bec)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const &)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
jsonconfig & get_config (bool optional, std::string key, uint8_t & target, uint8_t default_value = uint8_t ());
|
||||
jsonconfig & get_config (bool optional, std::string key, bool & target, bool default_value = false);
|
||||
jsonconfig & get_config (bool optional, std::string key, boost::asio::ip::address_v6 & target, boost::asio::ip::address_v6 const & default_value);
|
||||
|
||||
private:
|
||||
/** The property node being managed */
|
||||
boost::property_tree::ptree & tree;
|
||||
boost::property_tree::ptree tree_default;
|
||||
|
||||
void write_json (std::fstream & stream);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <nano/lib/locks.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if NANO_TIMED_LOCKS > 0
|
||||
namespace
|
||||
{
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <crypto/cryptopp/osrng.h>
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
namespace nano
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <pthread_np.h>
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
// This creates a file for the load address of an executable or shared library.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
|
||||
#include <cassert>
|
||||
|
||||
// clang-format off
|
||||
// Keep windows.h header at the top
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <processthreadsapi.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
// clang-format on
|
||||
|
||||
void nano::set_umask ()
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
|
||||
#include <processthreadsapi.h>
|
||||
#include <windows.h>
|
||||
|
||||
void nano::thread_role::set_os_name (std::string const & thread_name)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <nano/boost/asio/ip/address_v6.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/rpcconfig.hpp>
|
||||
|
@ -53,7 +54,13 @@ nano::error nano::rpc_secure_config::deserialize_toml (nano::tomlconfig & toml)
|
|||
return toml.get_error ();
|
||||
}
|
||||
|
||||
nano::rpc_config::rpc_config () :
|
||||
address (boost::asio::ip::address_v6::loopback ().to_string ())
|
||||
{
|
||||
}
|
||||
|
||||
nano::rpc_config::rpc_config (uint16_t port_a, bool enable_control_a) :
|
||||
address (boost::asio::ip::address_v6::loopback ().to_string ()),
|
||||
port (port_a),
|
||||
enable_control (enable_control_a)
|
||||
{
|
||||
|
@ -62,7 +69,7 @@ enable_control (enable_control_a)
|
|||
nano::error nano::rpc_config::serialize_json (nano::jsonconfig & json) const
|
||||
{
|
||||
json.put ("version", json_version ());
|
||||
json.put ("address", address.to_string ());
|
||||
json.put ("address", address);
|
||||
json.put ("port", port);
|
||||
json.put ("enable_control", enable_control);
|
||||
json.put ("max_json_depth", max_json_depth);
|
||||
|
@ -107,7 +114,9 @@ nano::error nano::rpc_config::deserialize_json (bool & upgraded_a, nano::jsoncon
|
|||
secure.deserialize_json (*rpc_secure_l);
|
||||
}
|
||||
|
||||
json.get_required<boost::asio::ip::address_v6> ("address", address);
|
||||
boost::asio::ip::address_v6 address_l;
|
||||
json.get_required<boost::asio::ip::address_v6> ("address", address_l, boost::asio::ip::address_v6::loopback ());
|
||||
address = address_l.to_string ();
|
||||
json.get_optional<uint16_t> ("port", port);
|
||||
json.get_optional<bool> ("enable_control", enable_control);
|
||||
json.get_optional<uint8_t> ("max_json_depth", max_json_depth);
|
||||
|
@ -127,7 +136,9 @@ nano::error nano::rpc_config::deserialize_json (bool & upgraded_a, nano::jsoncon
|
|||
|
||||
rpc_process_l->get_optional<unsigned> ("io_threads", rpc_process.io_threads);
|
||||
rpc_process_l->get_optional<uint16_t> ("ipc_port", rpc_process.ipc_port);
|
||||
rpc_process_l->get_optional<boost::asio::ip::address_v6> ("ipc_address", rpc_process.ipc_address);
|
||||
boost::asio::ip::address_v6 ipc_address_l;
|
||||
rpc_process_l->get_optional<boost::asio::ip::address_v6> ("ipc_address", ipc_address_l);
|
||||
rpc_process.ipc_address = ipc_address_l.to_string ();
|
||||
rpc_process_l->get_optional<unsigned> ("num_ipc_connections", rpc_process.num_ipc_connections);
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +153,7 @@ nano::error nano::rpc_config::deserialize_json (bool & upgraded_a, nano::jsoncon
|
|||
|
||||
nano::error nano::rpc_config::serialize_toml (nano::tomlconfig & toml) const
|
||||
{
|
||||
toml.put ("address", address.to_string (), "Bind address for the RPC server.\ntype:string,ip");
|
||||
toml.put ("address", address, "Bind address for the RPC server.\ntype:string,ip");
|
||||
toml.put ("port", port, "Listening port for the RPC server.\ntype:uint16");
|
||||
toml.put ("enable_control", enable_control, "Enable or disable control-level requests.\nWARNING: Enabling this gives anyone with RPC access the ability to stop the node and access wallet funds.\ntype:bool");
|
||||
toml.put ("max_json_depth", max_json_depth, "Maximum number of levels in JSON requests.\ntype:uint8");
|
||||
|
@ -150,7 +161,7 @@ nano::error nano::rpc_config::serialize_toml (nano::tomlconfig & toml) const
|
|||
|
||||
nano::tomlconfig rpc_process_l;
|
||||
rpc_process_l.put ("io_threads", rpc_process.io_threads, "Number of threads used to serve IO.\ntype:uint32");
|
||||
rpc_process_l.put ("ipc_address", rpc_process.ipc_address.to_string (), "Address of IPC server.\ntype:string,ip");
|
||||
rpc_process_l.put ("ipc_address", rpc_process.ipc_address, "Address of IPC server.\ntype:string,ip");
|
||||
rpc_process_l.put ("ipc_port", rpc_process.ipc_port, "Listening port of IPC server.\ntype:uint16");
|
||||
rpc_process_l.put ("num_ipc_connections", rpc_process.num_ipc_connections, "Number of IPC connections to establish.\ntype:uint32");
|
||||
toml.put_child ("process", rpc_process_l);
|
||||
|
@ -167,7 +178,9 @@ nano::error nano::rpc_config::deserialize_toml (nano::tomlconfig & toml)
|
|||
secure.deserialize_toml (*rpc_secure_l);
|
||||
}
|
||||
|
||||
toml.get_optional<boost::asio::ip::address_v6> ("address", address);
|
||||
boost::asio::ip::address_v6 address_l;
|
||||
toml.get_optional<boost::asio::ip::address_v6> ("address", address_l, boost::asio::ip::address_v6::loopback ());
|
||||
address = address_l.to_string ();
|
||||
toml.get_optional<uint16_t> ("port", port);
|
||||
toml.get_optional<bool> ("enable_control", enable_control);
|
||||
toml.get_optional<uint8_t> ("max_json_depth", max_json_depth);
|
||||
|
@ -178,7 +191,9 @@ nano::error nano::rpc_config::deserialize_toml (nano::tomlconfig & toml)
|
|||
{
|
||||
rpc_process_l->get_optional<unsigned> ("io_threads", rpc_process.io_threads);
|
||||
rpc_process_l->get_optional<uint16_t> ("ipc_port", rpc_process.ipc_port);
|
||||
rpc_process_l->get_optional<boost::asio::ip::address_v6> ("ipc_address", rpc_process.ipc_address);
|
||||
boost::asio::ip::address_v6 ipc_address_l;
|
||||
rpc_process_l->get_optional<boost::asio::ip::address_v6> ("ipc_address", ipc_address_l, boost::asio::ip::address_v6::loopback ());
|
||||
rpc_process.ipc_address = address_l.to_string ();
|
||||
rpc_process_l->get_optional<unsigned> ("num_ipc_connections", rpc_process.num_ipc_connections);
|
||||
}
|
||||
}
|
||||
|
@ -186,6 +201,11 @@ nano::error nano::rpc_config::deserialize_toml (nano::tomlconfig & toml)
|
|||
return toml.get_error ();
|
||||
}
|
||||
|
||||
nano::rpc_process_config::rpc_process_config () :
|
||||
ipc_address (boost::asio::ip::address_v6::loopback ().to_string ())
|
||||
{
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
nano::error read_rpc_config_toml (boost::filesystem::path const & data_path_a, nano::rpc_config & config_a, std::vector<std::string> const & config_overrides)
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/asio.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
class path;
|
||||
}
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class jsonconfig;
|
||||
|
@ -43,9 +48,10 @@ public:
|
|||
class rpc_process_config final
|
||||
{
|
||||
public:
|
||||
rpc_process_config ();
|
||||
nano::network_constants network_constants;
|
||||
unsigned io_threads{ std::max<unsigned> (4, boost::thread::hardware_concurrency ()) };
|
||||
boost::asio::ip::address_v6 ipc_address{ boost::asio::ip::address_v6::loopback () };
|
||||
unsigned io_threads{ (4 < std::thread::hardware_concurrency ()) ? std::thread::hardware_concurrency () : 4 };
|
||||
std::string ipc_address;
|
||||
uint16_t ipc_port{ network_constants.default_ipc_port };
|
||||
unsigned num_ipc_connections{ network_constants.is_live_network () ? 8u : network_constants.is_beta_network () ? 4u : 1u };
|
||||
static unsigned json_version ()
|
||||
|
@ -57,7 +63,7 @@ public:
|
|||
class rpc_config final
|
||||
{
|
||||
public:
|
||||
rpc_config () = default;
|
||||
rpc_config ();
|
||||
explicit rpc_config (uint16_t, bool);
|
||||
nano::error serialize_json (nano::jsonconfig &) const;
|
||||
nano::error deserialize_json (bool & upgraded_a, nano::jsonconfig &);
|
||||
|
@ -65,7 +71,7 @@ public:
|
|||
nano::error deserialize_toml (nano::tomlconfig &);
|
||||
|
||||
nano::rpc_process_config rpc_process;
|
||||
boost::asio::ip::address_v6 address{ boost::asio::ip::address_v6::loopback () };
|
||||
std::string address;
|
||||
uint16_t port{ rpc_process.network_constants.default_rpc_port };
|
||||
bool enable_control{ false };
|
||||
rpc_secure_config secure;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <nano/boost/asio.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/locks.hpp>
|
||||
#include <nano/lib/stats.hpp>
|
||||
#include <nano/lib/tomlconfig.hpp>
|
||||
|
||||
|
@ -7,9 +8,7 @@
|
|||
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
|
||||
nano::error nano::stat_config::deserialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
|
@ -655,3 +654,53 @@ std::string nano::stat::dir_to_string (uint32_t key)
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
nano::stat_datapoint::stat_datapoint (stat_datapoint const & other_a)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (other_a.datapoint_mutex);
|
||||
value = other_a.value;
|
||||
timestamp = other_a.timestamp;
|
||||
}
|
||||
|
||||
nano::stat_datapoint & nano::stat_datapoint::operator= (stat_datapoint const & other_a)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (other_a.datapoint_mutex);
|
||||
value = other_a.value;
|
||||
timestamp = other_a.timestamp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t nano::stat_datapoint::get_value () const
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
return value;
|
||||
}
|
||||
|
||||
void nano::stat_datapoint::set_value (uint64_t value_a)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
value = value_a;
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point nano::stat_datapoint::get_timestamp () const
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
void nano::stat_datapoint::set_timestamp (std::chrono::system_clock::time_point timestamp_a)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
timestamp = timestamp_a;
|
||||
}
|
||||
|
||||
/** Add \addend to the current value and optionally update the timestamp */
|
||||
void nano::stat_datapoint::add (uint64_t addend, bool update_timestamp)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
value += addend;
|
||||
if (update_timestamp)
|
||||
{
|
||||
timestamp = std::chrono::system_clock::now ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class node;
|
||||
class tomlconfig;
|
||||
class jsonconfig;
|
||||
/**
|
||||
* Serialize and deserialize the 'statistics' node from config.json
|
||||
* All configuration values have defaults. In particular, file logging of statistics
|
||||
|
@ -65,50 +62,13 @@ class stat_datapoint final
|
|||
{
|
||||
public:
|
||||
stat_datapoint () = default;
|
||||
stat_datapoint (stat_datapoint const & other_a)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (other_a.datapoint_mutex);
|
||||
value = other_a.value;
|
||||
timestamp = other_a.timestamp;
|
||||
}
|
||||
stat_datapoint & operator= (stat_datapoint const & other_a)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (other_a.datapoint_mutex);
|
||||
value = other_a.value;
|
||||
timestamp = other_a.timestamp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t get_value ()
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
return value;
|
||||
}
|
||||
void set_value (uint64_t value_a)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
value = value_a;
|
||||
}
|
||||
std::chrono::system_clock::time_point get_timestamp ()
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
return timestamp;
|
||||
}
|
||||
void set_timestamp (std::chrono::system_clock::time_point timestamp_a)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
timestamp = timestamp_a;
|
||||
}
|
||||
/** Add \addend to the current value and optionally update the timestamp */
|
||||
void add (uint64_t addend, bool update_timestamp = true)
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (datapoint_mutex);
|
||||
value += addend;
|
||||
if (update_timestamp)
|
||||
{
|
||||
timestamp = std::chrono::system_clock::now ();
|
||||
}
|
||||
}
|
||||
stat_datapoint (stat_datapoint const & other_a);
|
||||
stat_datapoint & operator= (stat_datapoint const & other_a);
|
||||
uint64_t get_value () const;
|
||||
void set_value (uint64_t value_a);
|
||||
std::chrono::system_clock::time_point get_timestamp () const;
|
||||
void set_timestamp (std::chrono::system_clock::time_point timestamp_a);
|
||||
void add (uint64_t addend, bool update_timestamp = true);
|
||||
|
||||
private:
|
||||
mutable std::mutex datapoint_mutex;
|
||||
|
|
166
nano/lib/threading.cpp
Normal file
166
nano/lib/threading.cpp
Normal file
|
@ -0,0 +1,166 @@
|
|||
#include <nano/lib/threading.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
namespace thread_role
|
||||
{
|
||||
/*
|
||||
* nano::thread_role namespace
|
||||
*
|
||||
* Manage thread role
|
||||
*/
|
||||
static thread_local nano::thread_role::name current_thread_role = nano::thread_role::name::unknown;
|
||||
nano::thread_role::name get ()
|
||||
{
|
||||
return current_thread_role;
|
||||
}
|
||||
|
||||
std::string get_string (nano::thread_role::name role)
|
||||
{
|
||||
std::string thread_role_name_string;
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case nano::thread_role::name::unknown:
|
||||
thread_role_name_string = "<unknown>";
|
||||
break;
|
||||
case nano::thread_role::name::io:
|
||||
thread_role_name_string = "I/O";
|
||||
break;
|
||||
case nano::thread_role::name::work:
|
||||
thread_role_name_string = "Work pool";
|
||||
break;
|
||||
case nano::thread_role::name::packet_processing:
|
||||
thread_role_name_string = "Pkt processing";
|
||||
break;
|
||||
case nano::thread_role::name::alarm:
|
||||
thread_role_name_string = "Alarm";
|
||||
break;
|
||||
case nano::thread_role::name::vote_processing:
|
||||
thread_role_name_string = "Vote processing";
|
||||
break;
|
||||
case nano::thread_role::name::block_processing:
|
||||
thread_role_name_string = "Blck processing";
|
||||
break;
|
||||
case nano::thread_role::name::request_loop:
|
||||
thread_role_name_string = "Request loop";
|
||||
break;
|
||||
case nano::thread_role::name::wallet_actions:
|
||||
thread_role_name_string = "Wallet actions";
|
||||
break;
|
||||
case nano::thread_role::name::work_watcher:
|
||||
thread_role_name_string = "Work watcher";
|
||||
break;
|
||||
case nano::thread_role::name::bootstrap_initiator:
|
||||
thread_role_name_string = "Bootstrap init";
|
||||
break;
|
||||
case nano::thread_role::name::voting:
|
||||
thread_role_name_string = "Voting";
|
||||
break;
|
||||
case nano::thread_role::name::signature_checking:
|
||||
thread_role_name_string = "Signature check";
|
||||
break;
|
||||
case nano::thread_role::name::rpc_request_processor:
|
||||
thread_role_name_string = "RPC processor";
|
||||
break;
|
||||
case nano::thread_role::name::rpc_process_container:
|
||||
thread_role_name_string = "RPC process";
|
||||
break;
|
||||
case nano::thread_role::name::confirmation_height_processing:
|
||||
thread_role_name_string = "Conf height";
|
||||
break;
|
||||
case nano::thread_role::name::worker:
|
||||
thread_role_name_string = "Worker";
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to constrain the thread names to 15
|
||||
* characters, since this is the smallest maximum
|
||||
* length supported by the platforms we support
|
||||
* (specifically, Linux)
|
||||
*/
|
||||
assert (thread_role_name_string.size () < 16);
|
||||
return (thread_role_name_string);
|
||||
}
|
||||
|
||||
std::string get_string ()
|
||||
{
|
||||
return get_string (current_thread_role);
|
||||
}
|
||||
|
||||
void set (nano::thread_role::name role)
|
||||
{
|
||||
auto thread_role_name_string (get_string (role));
|
||||
|
||||
nano::thread_role::set_os_name (thread_role_name_string);
|
||||
|
||||
nano::thread_role::current_thread_role = role;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nano::thread_attributes::set (boost::thread::attributes & attrs)
|
||||
{
|
||||
auto attrs_l (&attrs);
|
||||
attrs_l->set_stack_size (8000000); //8MB
|
||||
}
|
||||
|
||||
nano::thread_runner::thread_runner (boost::asio::io_context & io_ctx_a, unsigned service_threads_a) :
|
||||
io_guard (boost::asio::make_work_guard (io_ctx_a))
|
||||
{
|
||||
boost::thread::attributes attrs;
|
||||
nano::thread_attributes::set (attrs);
|
||||
for (auto i (0u); i < service_threads_a; ++i)
|
||||
{
|
||||
threads.push_back (boost::thread (attrs, [&io_ctx_a]() {
|
||||
nano::thread_role::set (nano::thread_role::name::io);
|
||||
try
|
||||
{
|
||||
io_ctx_a.run ();
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::cerr << ex.what () << std::endl;
|
||||
#ifndef NDEBUG
|
||||
throw;
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
* In a release build, catch and swallow the
|
||||
* io_context exception, in debug mode pass it
|
||||
* on
|
||||
*/
|
||||
throw;
|
||||
#endif
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
nano::thread_runner::~thread_runner ()
|
||||
{
|
||||
join ();
|
||||
}
|
||||
|
||||
void nano::thread_runner::join ()
|
||||
{
|
||||
io_guard.reset ();
|
||||
for (auto & i : threads)
|
||||
{
|
||||
if (i.joinable ())
|
||||
{
|
||||
i.join ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nano::thread_runner::stop_event_processing ()
|
||||
{
|
||||
io_guard.get_executor ().context ().stop ();
|
||||
}
|
75
nano/lib/threading.hpp
Normal file
75
nano/lib/threading.hpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/asio/executor_work_guard.hpp>
|
||||
#include <nano/boost/asio/io_context.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
/*
|
||||
* Functions for understanding the role of the current thread
|
||||
*/
|
||||
namespace thread_role
|
||||
{
|
||||
enum class name
|
||||
{
|
||||
unknown,
|
||||
io,
|
||||
work,
|
||||
packet_processing,
|
||||
alarm,
|
||||
vote_processing,
|
||||
block_processing,
|
||||
request_loop,
|
||||
wallet_actions,
|
||||
bootstrap_initiator,
|
||||
voting,
|
||||
signature_checking,
|
||||
rpc_request_processor,
|
||||
rpc_process_container,
|
||||
work_watcher,
|
||||
confirmation_height_processing,
|
||||
worker
|
||||
};
|
||||
/*
|
||||
* Get/Set the identifier for the current thread
|
||||
*/
|
||||
nano::thread_role::name get ();
|
||||
void set (nano::thread_role::name);
|
||||
|
||||
/*
|
||||
* Get the thread name as a string from enum
|
||||
*/
|
||||
std::string get_string (nano::thread_role::name);
|
||||
|
||||
/*
|
||||
* Get the current thread's role as a string
|
||||
*/
|
||||
std::string get_string ();
|
||||
|
||||
/*
|
||||
* Internal only, should not be called directly
|
||||
*/
|
||||
void set_os_name (std::string const &);
|
||||
}
|
||||
|
||||
namespace thread_attributes
|
||||
{
|
||||
void set (boost::thread::attributes &);
|
||||
}
|
||||
|
||||
class thread_runner final
|
||||
{
|
||||
public:
|
||||
thread_runner (boost::asio::io_context &, unsigned);
|
||||
~thread_runner ();
|
||||
/** Tells the IO context to stop processing events.*/
|
||||
void stop_event_processing ();
|
||||
/** Wait for IO threads to complete */
|
||||
void join ();
|
||||
std::vector<boost::thread> threads;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> io_guard;
|
||||
};
|
||||
}
|
246
nano/lib/timer.cpp
Normal file
246
nano/lib/timer.cpp
Normal file
|
@ -0,0 +1,246 @@
|
|||
#include <nano/lib/timer.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::nanoseconds>::value> * = nullptr>
|
||||
std::string typed_unit ()
|
||||
{
|
||||
return "nanoseconds";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::microseconds>::value> * = nullptr>
|
||||
std::string typed_unit ()
|
||||
{
|
||||
return "microseconds";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::milliseconds>::value> * = nullptr>
|
||||
std::string typed_unit ()
|
||||
{
|
||||
return "milliseconds";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::seconds>::value> * = nullptr>
|
||||
std::string typed_unit ()
|
||||
{
|
||||
return "seconds";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::minutes>::value> * = nullptr>
|
||||
std::string typed_unit ()
|
||||
{
|
||||
return "minutes";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::hours>::value> * = nullptr>
|
||||
std::string typed_unit ()
|
||||
{
|
||||
return "hours";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename UNIT, typename CLOCK>
|
||||
nano::timer<UNIT, CLOCK>::timer (nano::timer_state state_a, std::string const & description_a) :
|
||||
desc (description_a)
|
||||
{
|
||||
if (state_a == nano::timer_state::started)
|
||||
{
|
||||
start ();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename UNIT, typename CLOCK>
|
||||
nano::timer<UNIT, CLOCK>::timer (std::string const & description_a) :
|
||||
desc (description_a)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename UNIT, typename CLOCK>
|
||||
nano::timer<UNIT, CLOCK>::timer (std::string const & description_a, nano::timer<UNIT, CLOCK> * parent_a) :
|
||||
parent (parent_a),
|
||||
desc (description_a)
|
||||
{
|
||||
}
|
||||
|
||||
/** Do not output if measured time is below the time units threshold in \p minimum_a */
|
||||
template <typename UNIT, typename CLOCK>
|
||||
nano::timer<UNIT, CLOCK> & nano::timer<UNIT, CLOCK>::set_minimum (UNIT minimum_a)
|
||||
{
|
||||
minimum = minimum_a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a child timer without starting it.
|
||||
* Since the timing API needs to have low overhead, this function
|
||||
* does not check if a timer with the same name already exists.
|
||||
*/
|
||||
template <typename UNIT, typename CLOCK>
|
||||
nano::timer<UNIT, CLOCK> & nano::timer<UNIT, CLOCK>::child (std::string const & description_a)
|
||||
{
|
||||
children.emplace_back (description_a, this);
|
||||
return children.back ();
|
||||
}
|
||||
|
||||
/** Create and start a child timer */
|
||||
template <typename UNIT, typename CLOCK>
|
||||
nano::timer<UNIT, CLOCK> & nano::timer<UNIT, CLOCK>::start_child (std::string const & description_a)
|
||||
{
|
||||
auto & child_timer = child (description_a);
|
||||
child_timer.start ();
|
||||
return child_timer;
|
||||
}
|
||||
|
||||
/** Start the timer. This will assert if the timer is already started. */
|
||||
template <typename UNIT, typename CLOCK>
|
||||
void nano::timer<UNIT, CLOCK>::start ()
|
||||
{
|
||||
assert (state == nano::timer_state::stopped);
|
||||
state = nano::timer_state::started;
|
||||
begin = CLOCK::now ();
|
||||
}
|
||||
|
||||
/** Restarts the timer */
|
||||
template <typename UNIT, typename CLOCK>
|
||||
void nano::timer<UNIT, CLOCK>::restart ()
|
||||
{
|
||||
state = nano::timer_state::started;
|
||||
begin = CLOCK::now ();
|
||||
ticks = UNIT::zero ();
|
||||
measurements = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the timer and increases the measurement count. A timer can be started and paused
|
||||
* multiple times (e.g. in a loop).
|
||||
* @return duration
|
||||
*/
|
||||
template <typename UNIT, typename CLOCK>
|
||||
UNIT nano::timer<UNIT, CLOCK>::pause ()
|
||||
{
|
||||
++measurements;
|
||||
return stop ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop timer
|
||||
* @return duration
|
||||
*/
|
||||
template <typename UNIT, typename CLOCK>
|
||||
UNIT nano::timer<UNIT, CLOCK>::stop ()
|
||||
{
|
||||
assert (state == nano::timer_state::started);
|
||||
state = nano::timer_state::stopped;
|
||||
|
||||
auto end = CLOCK::now ();
|
||||
ticks += std::chrono::duration_cast<UNIT> (end - begin);
|
||||
return ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current units.
|
||||
*/
|
||||
template <typename UNIT, typename CLOCK>
|
||||
UNIT nano::timer<UNIT, CLOCK>::value () const
|
||||
{
|
||||
return ticks;
|
||||
}
|
||||
|
||||
/** Returns the duration in UNIT since the timer was last started. */
|
||||
template <typename UNIT, typename CLOCK>
|
||||
UNIT nano::timer<UNIT, CLOCK>::since_start () const
|
||||
{
|
||||
auto end = CLOCK::now ();
|
||||
return std::chrono::duration_cast<UNIT> (end - begin);
|
||||
}
|
||||
|
||||
/** Returns true if the timer was last started longer than \p duration_a units ago*/
|
||||
template <typename UNIT, typename CLOCK>
|
||||
bool nano::timer<UNIT, CLOCK>::after_deadline (UNIT duration_a)
|
||||
{
|
||||
auto end = CLOCK::now ();
|
||||
return std::chrono::duration_cast<UNIT> (end - begin) > duration_a;
|
||||
}
|
||||
|
||||
/** Returns true if the timer was last started shorter than \p duration_a units ago*/
|
||||
template <typename UNIT, typename CLOCK>
|
||||
bool nano::timer<UNIT, CLOCK>::before_deadline (UNIT duration_a)
|
||||
{
|
||||
auto end = CLOCK::now ();
|
||||
return std::chrono::duration_cast<UNIT> (end - begin) < duration_a;
|
||||
}
|
||||
|
||||
/** Stop timer and write measurements to \p stream_a */
|
||||
template <typename UNIT, typename CLOCK>
|
||||
void nano::timer<UNIT, CLOCK>::stop (std::ostream & stream_a)
|
||||
{
|
||||
stop ();
|
||||
print (stream_a);
|
||||
}
|
||||
|
||||
/** Stop timer and write measurements to \p output_a */
|
||||
template <typename UNIT, typename CLOCK>
|
||||
void nano::timer<UNIT, CLOCK>::stop (std::string & output_a)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stop (stream);
|
||||
output_a = stream.str ();
|
||||
}
|
||||
|
||||
/** Print measurements to the \p stream_a */
|
||||
template <typename UNIT, typename CLOCK>
|
||||
void nano::timer<UNIT, CLOCK>::print (std::ostream & stream_a)
|
||||
{
|
||||
if (ticks >= minimum)
|
||||
{
|
||||
// Print cumulative children first. Non-cumulative children prints directly.
|
||||
for (auto & child : children)
|
||||
{
|
||||
if (child.measurements > 0)
|
||||
{
|
||||
child.print (stream_a);
|
||||
}
|
||||
}
|
||||
|
||||
auto current_parent = parent;
|
||||
while (current_parent)
|
||||
{
|
||||
stream_a << parent->desc << ".";
|
||||
current_parent = current_parent->parent;
|
||||
}
|
||||
|
||||
stream_a << desc << ": " << ticks.count () << ' ' << unit ();
|
||||
if (measurements > 0)
|
||||
{
|
||||
stream_a << " (" << measurements << " measurements, " << std::setprecision (2) << std::fixed << static_cast<double> (ticks.count ()) / static_cast<double> (measurements) << ' ' << unit () << " avg)";
|
||||
}
|
||||
stream_a << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the SI unit string */
|
||||
template <typename UNIT, typename CLOCK>
|
||||
std::string nano::timer<UNIT, CLOCK>::unit () const
|
||||
{
|
||||
return typed_unit<UNIT> ();
|
||||
}
|
||||
|
||||
template <typename UNIT, typename CLOCK>
|
||||
nano::timer_state nano::timer<UNIT, CLOCK>::current_state () const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
// Explicitly instantiate all realistically used timers
|
||||
template class nano::timer<std::chrono::milliseconds, std::chrono::steady_clock>;
|
||||
template class nano::timer<std::chrono::microseconds, std::chrono::steady_clock>;
|
||||
template class nano::timer<std::chrono::nanoseconds, std::chrono::steady_clock>;
|
||||
template class nano::timer<std::chrono::seconds, std::chrono::steady_clock>;
|
||||
template class nano::timer<std::chrono::milliseconds, std::chrono::system_clock>;
|
||||
template class nano::timer<std::chrono::microseconds, std::chrono::system_clock>;
|
||||
template class nano::timer<std::chrono::nanoseconds, std::chrono::system_clock>;
|
||||
template class nano::timer<std::chrono::seconds, std::chrono::system_clock>;
|
|
@ -1,10 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -22,179 +19,25 @@ class timer
|
|||
{
|
||||
public:
|
||||
timer () = default;
|
||||
|
||||
timer (nano::timer_state state_a, std::string description_a = "timer") :
|
||||
desc (description_a)
|
||||
{
|
||||
if (state_a == nano::timer_state::started)
|
||||
{
|
||||
start ();
|
||||
}
|
||||
}
|
||||
|
||||
timer (std::string description_a) :
|
||||
desc (description_a)
|
||||
{
|
||||
}
|
||||
|
||||
timer (std::string description_a, timer * parent_a) :
|
||||
parent (parent_a),
|
||||
desc (description_a)
|
||||
{
|
||||
}
|
||||
|
||||
/** Do not output if measured time is below the time units threshold in \p minimum_a */
|
||||
timer & set_minimum (UNIT minimum_a)
|
||||
{
|
||||
minimum = minimum_a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a child timer without starting it.
|
||||
* Since the timing API needs to have low overhead, this function
|
||||
* does not check if a timer with the same name already exists.
|
||||
*/
|
||||
timer & child (std::string description_a = "child timer")
|
||||
{
|
||||
children.emplace_back (description_a, this);
|
||||
return children.back ();
|
||||
}
|
||||
|
||||
/** Create and start a child timer */
|
||||
timer & start_child (std::string description_a = "child timer")
|
||||
{
|
||||
auto & child_timer = child (description_a);
|
||||
child_timer.start ();
|
||||
return child_timer;
|
||||
}
|
||||
|
||||
/** Start the timer. This will assert if the timer is already started. */
|
||||
void start ()
|
||||
{
|
||||
assert (state == nano::timer_state::stopped);
|
||||
state = nano::timer_state::started;
|
||||
begin = CLOCK::now ();
|
||||
}
|
||||
|
||||
/** Restarts the timer */
|
||||
void restart ()
|
||||
{
|
||||
state = nano::timer_state::started;
|
||||
begin = CLOCK::now ();
|
||||
ticks = UNIT::zero ();
|
||||
measurements = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the timer and increases the measurement count. A timer can be started and paused
|
||||
* multiple times (e.g. in a loop).
|
||||
* @return duration
|
||||
*/
|
||||
UNIT pause ()
|
||||
{
|
||||
++measurements;
|
||||
return stop ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop timer
|
||||
* @return duration
|
||||
*/
|
||||
UNIT stop ()
|
||||
{
|
||||
assert (state == nano::timer_state::started);
|
||||
state = nano::timer_state::stopped;
|
||||
|
||||
auto end = CLOCK::now ();
|
||||
ticks += std::chrono::duration_cast<UNIT> (end - begin);
|
||||
return ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current units.
|
||||
*/
|
||||
UNIT value ()
|
||||
{
|
||||
return ticks;
|
||||
}
|
||||
|
||||
/** Returns the duration in UNIT since the timer was last started. */
|
||||
UNIT since_start () const
|
||||
{
|
||||
auto end = CLOCK::now ();
|
||||
return std::chrono::duration_cast<UNIT> (end - begin);
|
||||
}
|
||||
|
||||
/** Returns true if the timer was last started longer than \p duration_a units ago*/
|
||||
bool after_deadline (UNIT duration_a)
|
||||
{
|
||||
auto end = CLOCK::now ();
|
||||
return std::chrono::duration_cast<UNIT> (end - begin) > duration_a;
|
||||
}
|
||||
|
||||
/** Returns true if the timer was last started shorter than \p duration_a units ago*/
|
||||
bool before_deadline (UNIT duration_a)
|
||||
{
|
||||
auto end = CLOCK::now ();
|
||||
return std::chrono::duration_cast<UNIT> (end - begin) < duration_a;
|
||||
}
|
||||
|
||||
/** Stop timer and write measurements to \p output_a */
|
||||
void stop (std::string & output_a)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stop (stream);
|
||||
output_a = stream.str ();
|
||||
}
|
||||
|
||||
/** Stop timer and write measurements to \p stream_a */
|
||||
void stop (std::ostream & stream_a)
|
||||
{
|
||||
stop ();
|
||||
print (stream_a);
|
||||
}
|
||||
|
||||
/** Print measurements to the \p stream_a */
|
||||
void print (std::ostream & stream_a)
|
||||
{
|
||||
if (ticks >= minimum)
|
||||
{
|
||||
// Print cumulative children first. Non-cumulative children prints directly.
|
||||
for (auto & child : children)
|
||||
{
|
||||
if (child.measurements > 0)
|
||||
{
|
||||
child.print (stream_a);
|
||||
}
|
||||
}
|
||||
|
||||
auto current_parent = parent;
|
||||
while (current_parent)
|
||||
{
|
||||
stream_a << parent->desc << ".";
|
||||
current_parent = current_parent->parent;
|
||||
}
|
||||
|
||||
stream_a << desc << ": " << ticks.count () << ' ' << unit ();
|
||||
if (measurements > 0)
|
||||
{
|
||||
stream_a << " (" << measurements << " measurements, " << std::setprecision (2) << std::fixed << static_cast<double> (ticks.count ()) / static_cast<double> (measurements) << ' ' << unit () << " avg)";
|
||||
}
|
||||
stream_a << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the SI unit string */
|
||||
std::string unit () const
|
||||
{
|
||||
return typed_unit<UNIT> ();
|
||||
}
|
||||
|
||||
nano::timer_state current_state () const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
timer (nano::timer_state state_a, std::string const & description_a = "timer");
|
||||
timer (std::string const & description_a);
|
||||
timer (std::string const & description_a, timer * parent_a);
|
||||
timer & set_minimum (UNIT minimum_a);
|
||||
timer & child (std::string const & description_a = "child timer");
|
||||
timer & start_child (std::string const & description_a = "child timer");
|
||||
void start ();
|
||||
void restart ();
|
||||
UNIT pause ();
|
||||
UNIT stop ();
|
||||
UNIT value () const;
|
||||
UNIT since_start () const;
|
||||
bool after_deadline (UNIT duration_a);
|
||||
bool before_deadline (UNIT duration_a);
|
||||
void stop (std::ostream & stream_a);
|
||||
void stop (std::string & output_a);
|
||||
void print (std::ostream & stream_a);
|
||||
std::string unit () const;
|
||||
nano::timer_state current_state () const;
|
||||
|
||||
private:
|
||||
timer * parent{ nullptr };
|
||||
|
@ -205,62 +48,5 @@ private:
|
|||
UNIT ticks{ 0 };
|
||||
UNIT minimum{ UNIT::zero () };
|
||||
unsigned measurements{ 0 };
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::nanoseconds>::value> * = nullptr>
|
||||
std::string typed_unit () const
|
||||
{
|
||||
return "nanoseconds";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::microseconds>::value> * = nullptr>
|
||||
std::string typed_unit () const
|
||||
{
|
||||
return "microseconds";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::milliseconds>::value> * = nullptr>
|
||||
std::string typed_unit () const
|
||||
{
|
||||
return "milliseconds";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::seconds>::value> * = nullptr>
|
||||
std::string typed_unit () const
|
||||
{
|
||||
return "seconds";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::minutes>::value> * = nullptr>
|
||||
std::string typed_unit () const
|
||||
{
|
||||
return "minutes";
|
||||
}
|
||||
|
||||
template <typename U, std::enable_if_t<std::is_same<U, std::chrono::hours>::value> * = nullptr>
|
||||
std::string typed_unit () const
|
||||
{
|
||||
return "hours";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The autotimer starts on construction, and stops and prints on destruction.
|
||||
*/
|
||||
template <typename UNIT = std::chrono::milliseconds>
|
||||
class autotimer : public nano::timer<UNIT>
|
||||
{
|
||||
public:
|
||||
autotimer (std::string description_a, std::ostream & stream_a = std::cout) :
|
||||
nano::timer<UNIT> (description_a), stream (stream_a)
|
||||
{
|
||||
nano::timer<UNIT>::start ();
|
||||
}
|
||||
~autotimer ()
|
||||
{
|
||||
nano::timer<UNIT>::stop (stream);
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream & stream;
|
||||
};
|
||||
}
|
||||
|
|
385
nano/lib/tomlconfig.cpp
Normal file
385
nano/lib/tomlconfig.cpp
Normal file
|
@ -0,0 +1,385 @@
|
|||
#include <nano/boost/asio/ip/address_v6.hpp>
|
||||
#include <nano/lib/tomlconfig.hpp>
|
||||
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
|
||||
nano::tomlconfig::tomlconfig () :
|
||||
tree (cpptoml::make_table ())
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
|
||||
nano::tomlconfig::tomlconfig (std::shared_ptr<cpptoml::table> const & tree_a, std::shared_ptr<nano::error> const & error_a) :
|
||||
nano::configbase (error_a), tree (tree_a)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
}
|
||||
|
||||
void nano::tomlconfig::doc (std::string const & key, std::string const & doc)
|
||||
{
|
||||
tree->document (key, doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a json object from the stream
|
||||
* @return nano::error&, including a descriptive error message if the config file is malformed.
|
||||
*/
|
||||
nano::error & nano::tomlconfig::read (boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::stringstream stream_override_empty;
|
||||
stream_override_empty << std::endl;
|
||||
return read (stream_override_empty, path_a);
|
||||
}
|
||||
|
||||
nano::error & nano::tomlconfig::read (std::istream & stream_overrides, boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
if (!stream.fail ())
|
||||
{
|
||||
try
|
||||
{
|
||||
read (stream_overrides, stream);
|
||||
}
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
auto pos (stream.tellg ());
|
||||
if (pos != std::streampos (0))
|
||||
{
|
||||
*error = ex;
|
||||
}
|
||||
}
|
||||
stream.close ();
|
||||
}
|
||||
return *error;
|
||||
}
|
||||
|
||||
/** Read from two streams where keys in the first will take precedence over those in the second stream. */
|
||||
void nano::tomlconfig::read (std::istream & stream_first_a, std::istream & stream_second_a)
|
||||
{
|
||||
tree = cpptoml::parse_base_and_override_files (stream_first_a, stream_second_a, cpptoml::parser::merge_type::ignore, true);
|
||||
}
|
||||
|
||||
void nano::tomlconfig::read (std::istream & stream_a)
|
||||
{
|
||||
std::stringstream stream_override_empty;
|
||||
stream_override_empty << std::endl;
|
||||
tree = cpptoml::parse_base_and_override_files (stream_override_empty, stream_a, cpptoml::parser::merge_type::ignore, true);
|
||||
}
|
||||
|
||||
void nano::tomlconfig::write (boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
write (stream);
|
||||
}
|
||||
|
||||
void nano::tomlconfig::write (std::ostream & stream_a) const
|
||||
{
|
||||
cpptoml::toml_writer writer{ stream_a, "" };
|
||||
tree->accept (writer);
|
||||
}
|
||||
|
||||
/** Open configuration file, create if necessary */
|
||||
void nano::tomlconfig::open_or_create (std::fstream & stream_a, std::string const & path_a)
|
||||
{
|
||||
if (!boost::filesystem::exists (path_a))
|
||||
{
|
||||
// Create temp stream to first create the file
|
||||
std::ofstream stream (path_a);
|
||||
|
||||
// Set permissions before opening otherwise Windows only has read permissions
|
||||
nano::set_secure_perm_file (path_a);
|
||||
}
|
||||
|
||||
stream_a.open (path_a);
|
||||
}
|
||||
|
||||
/** Returns the table managed by this instance */
|
||||
std::shared_ptr<cpptoml::table> nano::tomlconfig::get_tree ()
|
||||
{
|
||||
return tree;
|
||||
}
|
||||
|
||||
/** Returns true if the toml table is empty */
|
||||
bool nano::tomlconfig::empty () const
|
||||
{
|
||||
return tree->empty ();
|
||||
}
|
||||
|
||||
boost::optional<nano::tomlconfig> nano::tomlconfig::get_optional_child (std::string const & key_a)
|
||||
{
|
||||
boost::optional<tomlconfig> child_config;
|
||||
if (tree->contains (key_a))
|
||||
{
|
||||
return tomlconfig (tree->get_table (key_a), error);
|
||||
}
|
||||
return child_config;
|
||||
}
|
||||
|
||||
nano::tomlconfig nano::tomlconfig::get_required_child (std::string const & key_a)
|
||||
{
|
||||
if (!tree->contains (key_a))
|
||||
{
|
||||
*error = nano::error_config::missing_value;
|
||||
error->set_message ("Missing configuration node: " + key_a);
|
||||
return *this;
|
||||
}
|
||||
else
|
||||
{
|
||||
return tomlconfig (tree->get_table (key_a), error);
|
||||
}
|
||||
}
|
||||
|
||||
nano::tomlconfig & nano::tomlconfig::put_child (std::string const & key_a, nano::tomlconfig & conf_a)
|
||||
{
|
||||
tree->insert (key_a, conf_a.get_tree ());
|
||||
return *this;
|
||||
}
|
||||
|
||||
nano::tomlconfig & nano::tomlconfig::replace_child (std::string const & key_a, nano::tomlconfig & conf_a)
|
||||
{
|
||||
tree->erase (key_a);
|
||||
put_child (key_a, conf_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns true if \p key_a is present */
|
||||
bool nano::tomlconfig::has_key (std::string const & key_a)
|
||||
{
|
||||
return tree->contains (key_a);
|
||||
}
|
||||
|
||||
/** Erase the property of given key */
|
||||
nano::tomlconfig & nano::tomlconfig::erase (std::string const & key_a)
|
||||
{
|
||||
tree->erase (key_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::shared_ptr<cpptoml::array> nano::tomlconfig::create_array (std::string const & key, boost::optional<const char *> documentation_a)
|
||||
{
|
||||
if (!has_key (key))
|
||||
{
|
||||
auto arr = cpptoml::make_array ();
|
||||
tree->insert (key, arr);
|
||||
if (documentation_a)
|
||||
{
|
||||
doc (key, *documentation_a);
|
||||
}
|
||||
}
|
||||
|
||||
return tree->get_qualified (key)->as_array ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase keys whose values are equal to the one in \p defaults
|
||||
*/
|
||||
void nano::tomlconfig::erase_default_values (tomlconfig & defaults_a)
|
||||
{
|
||||
std::shared_ptr<cpptoml::table> clone = std::dynamic_pointer_cast<cpptoml::table> (tree->clone ());
|
||||
tomlconfig self (clone);
|
||||
|
||||
// The toml library doesn't offer a general way to compare values, so let the diff run on a stringified parse
|
||||
std::stringstream ss_self;
|
||||
write (ss_self);
|
||||
self.read (ss_self);
|
||||
|
||||
tomlconfig defaults_l;
|
||||
std::stringstream ss;
|
||||
defaults_a.write (ss);
|
||||
defaults_l.read (ss);
|
||||
|
||||
erase_defaults (defaults_l.get_tree (), self.get_tree (), get_tree ());
|
||||
}
|
||||
|
||||
std::string nano::tomlconfig::to_string ()
|
||||
{
|
||||
std::stringstream ss;
|
||||
cpptoml::toml_writer writer{ ss, "" };
|
||||
tree->accept (writer);
|
||||
return ss.str ();
|
||||
}
|
||||
|
||||
std::string nano::tomlconfig::to_string_commented_entries ()
|
||||
{
|
||||
std::stringstream ss, ss_processed;
|
||||
cpptoml::toml_writer writer{ ss, "" };
|
||||
tree->accept (writer);
|
||||
std::string line;
|
||||
while (std::getline (ss, line, '\n'))
|
||||
{
|
||||
if (!line.empty () && line[0] != '#' && line[0] != '[')
|
||||
{
|
||||
line = "#" + line;
|
||||
}
|
||||
ss_processed << line << std::endl;
|
||||
}
|
||||
return ss_processed.str ();
|
||||
}
|
||||
|
||||
// boost's lexical cast doesn't handle (u)int8_t
|
||||
nano::tomlconfig & nano::tomlconfig::get_config (bool optional, std::string const & key, uint8_t & target, uint8_t default_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tree->contains_qualified (key))
|
||||
{
|
||||
int64_t tmp;
|
||||
auto val (tree->get_qualified_as<std::string> (key));
|
||||
if (!boost::conversion::try_lexical_convert<int64_t> (*val, tmp) || tmp < 0 || tmp > 255)
|
||||
{
|
||||
conditionally_set_error<uint8_t> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = static_cast<uint8_t> (tmp);
|
||||
}
|
||||
}
|
||||
else if (!optional)
|
||||
{
|
||||
conditionally_set_error<uint8_t> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<uint8_t> (ex, optional, key);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
nano::tomlconfig & nano::tomlconfig::get_config (bool optional, std::string const & key, bool & target, bool default_value)
|
||||
{
|
||||
auto bool_conv = [this, &target, &key, optional](std::string val) {
|
||||
if (val == "true")
|
||||
{
|
||||
target = true;
|
||||
}
|
||||
else if (val == "false")
|
||||
{
|
||||
target = false;
|
||||
}
|
||||
else if (!*error)
|
||||
{
|
||||
conditionally_set_error<bool> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
if (tree->contains_qualified (key))
|
||||
{
|
||||
auto val (tree->get_qualified_as<std::string> (key));
|
||||
bool_conv (*val);
|
||||
}
|
||||
else if (!optional)
|
||||
{
|
||||
conditionally_set_error<bool> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<bool> (ex, optional, key);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Compare two stringified configs, remove keys where values are equal */
|
||||
void nano::tomlconfig::erase_defaults (std::shared_ptr<cpptoml::table> base, std::shared_ptr<cpptoml::table> other, std::shared_ptr<cpptoml::table> update_target)
|
||||
{
|
||||
std::vector<std::string> erased;
|
||||
assert (other != nullptr);
|
||||
for (auto & item : *other)
|
||||
{
|
||||
std::string const & key = item.first;
|
||||
if (other->contains (key) && base->contains (key))
|
||||
{
|
||||
auto value = item.second;
|
||||
if (value->is_table ())
|
||||
{
|
||||
auto child_base = base->get_table (key);
|
||||
auto child_other = other->get_table (key);
|
||||
auto child_target = update_target->get_table (key);
|
||||
erase_defaults (child_base, child_other, child_target);
|
||||
if (child_target->empty ())
|
||||
{
|
||||
erased.push_back (key);
|
||||
}
|
||||
}
|
||||
else if (value->is_array ())
|
||||
{
|
||||
auto arr_other = other->get_array (key)->get ();
|
||||
auto arr_base = base->get_array (key)->get ();
|
||||
|
||||
if (arr_other.size () == arr_base.size ())
|
||||
{
|
||||
bool equal = std::equal (arr_other.begin (), arr_other.end (), arr_base.begin (),
|
||||
[](auto const & item1, auto const & item2) -> bool {
|
||||
return (item1->template as<std::string> ()->get () == item2->template as<std::string> ()->get ());
|
||||
});
|
||||
|
||||
if (equal)
|
||||
{
|
||||
erased.push_back (key);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (value->is_value ())
|
||||
{
|
||||
auto val_other = std::dynamic_pointer_cast<cpptoml::value<std::string>> (other->get (key));
|
||||
auto val_base = std::dynamic_pointer_cast<cpptoml::value<std::string>> (base->get (key));
|
||||
|
||||
if (val_other->get () == val_base->get ())
|
||||
{
|
||||
erased.push_back (key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto & key : erased)
|
||||
{
|
||||
update_target->erase (key);
|
||||
}
|
||||
}
|
||||
|
||||
nano::tomlconfig & nano::tomlconfig::get_config (bool optional, std::string key, boost::asio::ip::address_v6 & target, boost::asio::ip::address_v6 const & default_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tree->contains_qualified (key))
|
||||
{
|
||||
auto address_l (tree->get_qualified_as<std::string> (key));
|
||||
boost::system::error_code bec;
|
||||
target = boost::asio::ip::make_address_v6 (address_l.value_or (""), bec);
|
||||
if (bec)
|
||||
{
|
||||
conditionally_set_error<boost::asio::ip::address_v6> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
}
|
||||
else if (!optional)
|
||||
{
|
||||
conditionally_set_error<boost::asio::ip::address_v6> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<boost::asio::ip::address_v6> (ex, optional, key);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
|
@ -1,169 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/asio.hpp>
|
||||
#include <nano/lib/configbase.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <cpptoml.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace asio
|
||||
{
|
||||
namespace ip
|
||||
{
|
||||
class address_v6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class error;
|
||||
|
||||
/** Manages a table in a toml configuration table hierarchy */
|
||||
class tomlconfig : public nano::configbase
|
||||
{
|
||||
public:
|
||||
tomlconfig () :
|
||||
tree (cpptoml::make_table ())
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
|
||||
tomlconfig (std::shared_ptr<cpptoml::table> const & tree_a, std::shared_ptr<nano::error> const & error_a = nullptr) :
|
||||
nano::configbase (error_a), tree (tree_a)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
}
|
||||
|
||||
void doc (std::string const & key, std::string const & doc)
|
||||
{
|
||||
tree->document (key, doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a json object from the stream
|
||||
* @return nano::error&, including a descriptive error message if the config file is malformed.
|
||||
*/
|
||||
nano::error & read (boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::stringstream stream_override_empty;
|
||||
stream_override_empty << std::endl;
|
||||
return read (stream_override_empty, path_a);
|
||||
}
|
||||
|
||||
nano::error & read (std::istream & stream_overrides, boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
if (!stream.fail ())
|
||||
{
|
||||
try
|
||||
{
|
||||
read (stream_overrides, stream);
|
||||
}
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
auto pos (stream.tellg ());
|
||||
if (pos != std::streampos (0))
|
||||
{
|
||||
*error = ex;
|
||||
}
|
||||
}
|
||||
stream.close ();
|
||||
}
|
||||
return *error;
|
||||
}
|
||||
|
||||
/** Read from two streams where keys in the first will take precedence over those in the second stream. */
|
||||
void read (std::istream & stream_first_a, std::istream & stream_second_a)
|
||||
{
|
||||
tree = cpptoml::parse_base_and_override_files (stream_first_a, stream_second_a, cpptoml::parser::merge_type::ignore, true);
|
||||
}
|
||||
|
||||
void read (std::istream & stream_a)
|
||||
{
|
||||
std::stringstream stream_override_empty;
|
||||
stream_override_empty << std::endl;
|
||||
tree = cpptoml::parse_base_and_override_files (stream_override_empty, stream_a, cpptoml::parser::merge_type::ignore, true);
|
||||
}
|
||||
|
||||
void write (boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
write (stream);
|
||||
}
|
||||
|
||||
void write (std::ostream & stream_a) const
|
||||
{
|
||||
cpptoml::toml_writer writer{ stream_a, "" };
|
||||
tree->accept (writer);
|
||||
}
|
||||
|
||||
/** Open configuration file, create if necessary */
|
||||
void open_or_create (std::fstream & stream_a, std::string const & path_a)
|
||||
{
|
||||
if (!boost::filesystem::exists (path_a))
|
||||
{
|
||||
// Create temp stream to first create the file
|
||||
std::ofstream stream (path_a);
|
||||
|
||||
// Set permissions before opening otherwise Windows only has read permissions
|
||||
nano::set_secure_perm_file (path_a);
|
||||
}
|
||||
|
||||
stream_a.open (path_a);
|
||||
}
|
||||
|
||||
/** Returns the table managed by this instance */
|
||||
std::shared_ptr<cpptoml::table> get_tree ()
|
||||
{
|
||||
return tree;
|
||||
}
|
||||
|
||||
/** Returns true if the toml table is empty */
|
||||
bool empty () const
|
||||
{
|
||||
return tree->empty ();
|
||||
}
|
||||
|
||||
boost::optional<tomlconfig> get_optional_child (std::string const & key_a)
|
||||
{
|
||||
boost::optional<tomlconfig> child_config;
|
||||
if (tree->contains (key_a))
|
||||
{
|
||||
return tomlconfig (tree->get_table (key_a), error);
|
||||
}
|
||||
return child_config;
|
||||
}
|
||||
|
||||
tomlconfig get_required_child (std::string const & key_a)
|
||||
{
|
||||
if (!tree->contains (key_a))
|
||||
{
|
||||
*error = nano::error_config::missing_value;
|
||||
error->set_message ("Missing configuration node: " + key_a);
|
||||
return *this;
|
||||
}
|
||||
else
|
||||
{
|
||||
return tomlconfig (tree->get_table (key_a), error);
|
||||
}
|
||||
}
|
||||
|
||||
tomlconfig & put_child (std::string const & key_a, nano::tomlconfig & conf_a)
|
||||
{
|
||||
tree->insert (key_a, conf_a.get_tree ());
|
||||
return *this;
|
||||
}
|
||||
|
||||
tomlconfig & replace_child (std::string const & key_a, nano::tomlconfig & conf_a)
|
||||
{
|
||||
tree->erase (key_a);
|
||||
put_child (key_a, conf_a);
|
||||
return *this;
|
||||
}
|
||||
tomlconfig ();
|
||||
tomlconfig (std::shared_ptr<cpptoml::table> const & tree_a, std::shared_ptr<nano::error> const & error_a = nullptr);
|
||||
void doc (std::string const & key, std::string const & doc);
|
||||
nano::error & read (boost::filesystem::path const & path_a);
|
||||
nano::error & read (std::istream & stream_overrides, boost::filesystem::path const & path_a);
|
||||
void read (std::istream & stream_first_a, std::istream & stream_second_a);
|
||||
void read (std::istream & stream_a);
|
||||
void write (boost::filesystem::path const & path_a);
|
||||
void write (std::ostream & stream_a) const;
|
||||
void open_or_create (std::fstream & stream_a, std::string const & path_a);
|
||||
std::shared_ptr<cpptoml::table> get_tree ();
|
||||
bool empty () const;
|
||||
boost::optional<tomlconfig> get_optional_child (std::string const & key_a);
|
||||
tomlconfig get_required_child (std::string const & key_a);
|
||||
tomlconfig & put_child (std::string const & key_a, nano::tomlconfig & conf_a);
|
||||
tomlconfig & replace_child (std::string const & key_a, nano::tomlconfig & conf_a);
|
||||
bool has_key (std::string const & key_a);
|
||||
tomlconfig & erase (std::string const & key_a);
|
||||
std::shared_ptr<cpptoml::array> create_array (std::string const & key, boost::optional<const char *> documentation_a);
|
||||
void erase_default_values (tomlconfig & defaults_a);
|
||||
std::string to_string ();
|
||||
std::string to_string_commented_entries ();
|
||||
|
||||
/** Set value for the given key. Any existing value will be overwritten. */
|
||||
template <typename T>
|
||||
|
@ -177,19 +63,6 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/** Returns true if \p key_a is present */
|
||||
bool has_key (std::string const & key_a)
|
||||
{
|
||||
return tree->contains (key_a);
|
||||
}
|
||||
|
||||
/** Erase the property of given key */
|
||||
tomlconfig & erase (std::string const & key_a)
|
||||
{
|
||||
tree->erase (key_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push array element
|
||||
* @param key Array element key. Qualified (dotted) keys are not supported for arrays so this must be called on the correct tomlconfig node.
|
||||
|
@ -207,21 +80,6 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto create_array (std::string const & key, boost::optional<const char *> documentation_a)
|
||||
{
|
||||
if (!has_key (key))
|
||||
{
|
||||
auto arr = cpptoml::make_array ();
|
||||
tree->insert (key, arr);
|
||||
if (documentation_a)
|
||||
{
|
||||
doc (key, *documentation_a);
|
||||
}
|
||||
}
|
||||
|
||||
return tree->get_qualified (key)->as_array ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate array entries.
|
||||
* @param key Array element key. Qualified (dotted) keys are not supported for arrays so this must be called on the correct tomlconfig node.
|
||||
|
@ -248,7 +106,7 @@ public:
|
|||
template <typename T>
|
||||
tomlconfig & get_optional (std::string const & key, T & target, T default_value)
|
||||
{
|
||||
get_config<T> (true, key, target, default_value);
|
||||
get_config (true, key, target, default_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -259,7 +117,7 @@ public:
|
|||
template <typename T>
|
||||
tomlconfig & get_optional (std::string const & key, T & target)
|
||||
{
|
||||
get_config<T> (true, key, target, target);
|
||||
get_config (true, key, target, target);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -271,7 +129,7 @@ public:
|
|||
if (has_key (key))
|
||||
{
|
||||
T target{};
|
||||
get_config<T> (true, key, target, target);
|
||||
get_config (true, key, target, target);
|
||||
res = target;
|
||||
}
|
||||
return res;
|
||||
|
@ -281,7 +139,7 @@ public:
|
|||
template <typename T>
|
||||
tomlconfig & get (std::string const & key, T & target)
|
||||
{
|
||||
get_config<T> (true, key, target, target);
|
||||
get_config (true, key, target, target);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -292,7 +150,7 @@ public:
|
|||
T get (std::string const & key)
|
||||
{
|
||||
T target{};
|
||||
get_config<T> (true, key, target, target);
|
||||
get_config (true, key, target, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
@ -303,54 +161,15 @@ public:
|
|||
template <typename T>
|
||||
tomlconfig & get_required (std::string const & key, T & target)
|
||||
{
|
||||
get_config<T> (false, key, target);
|
||||
get_config (false, key, target);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase keys whose values are equal to the one in \p defaults
|
||||
*/
|
||||
void erase_default_values (tomlconfig & defaults_a)
|
||||
template <typename T>
|
||||
tomlconfig & get_required (std::string const & key, T & target, T const & default_value)
|
||||
{
|
||||
std::shared_ptr<cpptoml::table> clone = std::dynamic_pointer_cast<cpptoml::table> (tree->clone ());
|
||||
tomlconfig self (clone);
|
||||
|
||||
// The toml library doesn't offer a general way to compare values, so let the diff run on a stringified parse
|
||||
std::stringstream ss_self;
|
||||
write (ss_self);
|
||||
self.read (ss_self);
|
||||
|
||||
tomlconfig defaults_l;
|
||||
std::stringstream ss;
|
||||
defaults_a.write (ss);
|
||||
defaults_l.read (ss);
|
||||
|
||||
erase_defaults (defaults_l.get_tree (), self.get_tree (), get_tree ());
|
||||
}
|
||||
|
||||
std::string to_string ()
|
||||
{
|
||||
std::stringstream ss;
|
||||
cpptoml::toml_writer writer{ ss, "" };
|
||||
tree->accept (writer);
|
||||
return ss.str ();
|
||||
}
|
||||
|
||||
std::string to_string_commented_entries ()
|
||||
{
|
||||
std::stringstream ss, ss_processed;
|
||||
cpptoml::toml_writer writer{ ss, "" };
|
||||
tree->accept (writer);
|
||||
std::string line;
|
||||
while (std::getline (ss, line, '\n'))
|
||||
{
|
||||
if (!line.empty () && line[0] != '#' && line[0] != '[')
|
||||
{
|
||||
line = "#" + line;
|
||||
}
|
||||
ss_processed << line << std::endl;
|
||||
}
|
||||
return ss_processed.str ();
|
||||
get_config (false, key, target, default_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -384,174 +203,15 @@ protected:
|
|||
return *this;
|
||||
}
|
||||
|
||||
// boost's lexical cast doesn't handle (u)int8_t
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, uint8_t>::value>>
|
||||
tomlconfig & get_config (bool optional, std::string const & key, uint8_t & target, uint8_t default_value = T ())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tree->contains_qualified (key))
|
||||
{
|
||||
int64_t tmp;
|
||||
auto val (tree->get_qualified_as<std::string> (key));
|
||||
if (!boost::conversion::try_lexical_convert<int64_t> (*val, tmp) || tmp < 0 || tmp > 255)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = static_cast<uint8_t> (tmp);
|
||||
}
|
||||
}
|
||||
else if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<T> (ex, optional, key);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, bool>::value>>
|
||||
tomlconfig & get_config (bool optional, std::string const & key, bool & target, bool default_value = false)
|
||||
{
|
||||
auto bool_conv = [this, &target, &key, optional](std::string val) {
|
||||
if (val == "true")
|
||||
{
|
||||
target = true;
|
||||
}
|
||||
else if (val == "false")
|
||||
{
|
||||
target = false;
|
||||
}
|
||||
else if (!*error)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
if (tree->contains_qualified (key))
|
||||
{
|
||||
auto val (tree->get_qualified_as<std::string> (key));
|
||||
bool_conv (*val);
|
||||
}
|
||||
else if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<T> (ex, optional, key);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, boost::asio::ip::address_v6>::value>>
|
||||
tomlconfig & get_config (bool optional, std::string key, boost::asio::ip::address_v6 & target, boost::asio::ip::address_v6 default_value = T ())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tree->contains_qualified (key))
|
||||
{
|
||||
auto address_l (tree->get_qualified_as<std::string> (key));
|
||||
boost::system::error_code bec;
|
||||
target = boost::asio::ip::address_v6::from_string (address_l.value_or (""), bec);
|
||||
if (bec)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
}
|
||||
else if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<T> (ex, optional, key);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
tomlconfig & get_config (bool optional, std::string const & key, uint8_t & target, uint8_t default_value = uint8_t ());
|
||||
tomlconfig & get_config (bool optional, std::string const & key, bool & target, bool default_value = false);
|
||||
tomlconfig & get_config (bool optional, std::string key, boost::asio::ip::address_v6 & target, boost::asio::ip::address_v6 const & default_value);
|
||||
|
||||
private:
|
||||
/** The config node being managed */
|
||||
std::shared_ptr<cpptoml::table> tree;
|
||||
|
||||
/** Compare two stringified configs, remove keys where values are equal */
|
||||
void erase_defaults (std::shared_ptr<cpptoml::table> base, std::shared_ptr<cpptoml::table> other, std::shared_ptr<cpptoml::table> update_target)
|
||||
{
|
||||
std::vector<std::string> erased;
|
||||
assert (other != nullptr);
|
||||
for (auto & item : *other)
|
||||
{
|
||||
std::string const & key = item.first;
|
||||
if (other->contains (key) && base->contains (key))
|
||||
{
|
||||
auto value = item.second;
|
||||
if (value->is_table ())
|
||||
{
|
||||
auto child_base = base->get_table (key);
|
||||
auto child_other = other->get_table (key);
|
||||
auto child_target = update_target->get_table (key);
|
||||
erase_defaults (child_base, child_other, child_target);
|
||||
if (child_target->empty ())
|
||||
{
|
||||
erased.push_back (key);
|
||||
}
|
||||
}
|
||||
else if (value->is_array ())
|
||||
{
|
||||
auto arr_other = other->get_array (key)->get ();
|
||||
auto arr_base = base->get_array (key)->get ();
|
||||
|
||||
if (arr_other.size () == arr_base.size ())
|
||||
{
|
||||
bool equal = std::equal (arr_other.begin (), arr_other.end (), arr_base.begin (),
|
||||
[](auto const & item1, auto const & item2) -> bool {
|
||||
return (item1->template as<std::string> ()->get () == item2->template as<std::string> ()->get ());
|
||||
});
|
||||
|
||||
if (equal)
|
||||
{
|
||||
erased.push_back (key);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (value->is_value ())
|
||||
{
|
||||
auto val_other = std::dynamic_pointer_cast<cpptoml::value<std::string>> (other->get (key));
|
||||
auto val_base = std::dynamic_pointer_cast<cpptoml::value<std::string>> (base->get (key));
|
||||
|
||||
if (val_other->get () == val_base->get ())
|
||||
{
|
||||
erased.push_back (key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto & key : erased)
|
||||
{
|
||||
update_target->erase (key);
|
||||
}
|
||||
}
|
||||
void erase_defaults (std::shared_ptr<cpptoml::table> base, std::shared_ptr<cpptoml::table> other, std::shared_ptr<cpptoml::table> update_target);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <boost/dll/runtime_symbol_info.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
// Some builds (mac) fail due to "Boost.Stacktrace requires `_Unwind_Backtrace` function".
|
||||
#ifndef _WIN32
|
||||
|
@ -79,243 +81,6 @@ std::string generate_stacktrace ()
|
|||
ss << stacktrace;
|
||||
return ss.str ();
|
||||
}
|
||||
|
||||
namespace thread_role
|
||||
{
|
||||
/*
|
||||
* nano::thread_role namespace
|
||||
*
|
||||
* Manage thread role
|
||||
*/
|
||||
static thread_local nano::thread_role::name current_thread_role = nano::thread_role::name::unknown;
|
||||
nano::thread_role::name get ()
|
||||
{
|
||||
return current_thread_role;
|
||||
}
|
||||
|
||||
std::string get_string (nano::thread_role::name role)
|
||||
{
|
||||
std::string thread_role_name_string;
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case nano::thread_role::name::unknown:
|
||||
thread_role_name_string = "<unknown>";
|
||||
break;
|
||||
case nano::thread_role::name::io:
|
||||
thread_role_name_string = "I/O";
|
||||
break;
|
||||
case nano::thread_role::name::work:
|
||||
thread_role_name_string = "Work pool";
|
||||
break;
|
||||
case nano::thread_role::name::packet_processing:
|
||||
thread_role_name_string = "Pkt processing";
|
||||
break;
|
||||
case nano::thread_role::name::alarm:
|
||||
thread_role_name_string = "Alarm";
|
||||
break;
|
||||
case nano::thread_role::name::vote_processing:
|
||||
thread_role_name_string = "Vote processing";
|
||||
break;
|
||||
case nano::thread_role::name::block_processing:
|
||||
thread_role_name_string = "Blck processing";
|
||||
break;
|
||||
case nano::thread_role::name::request_loop:
|
||||
thread_role_name_string = "Request loop";
|
||||
break;
|
||||
case nano::thread_role::name::wallet_actions:
|
||||
thread_role_name_string = "Wallet actions";
|
||||
break;
|
||||
case nano::thread_role::name::work_watcher:
|
||||
thread_role_name_string = "Work watcher";
|
||||
break;
|
||||
case nano::thread_role::name::bootstrap_initiator:
|
||||
thread_role_name_string = "Bootstrap init";
|
||||
break;
|
||||
case nano::thread_role::name::voting:
|
||||
thread_role_name_string = "Voting";
|
||||
break;
|
||||
case nano::thread_role::name::signature_checking:
|
||||
thread_role_name_string = "Signature check";
|
||||
break;
|
||||
case nano::thread_role::name::rpc_request_processor:
|
||||
thread_role_name_string = "RPC processor";
|
||||
break;
|
||||
case nano::thread_role::name::rpc_process_container:
|
||||
thread_role_name_string = "RPC process";
|
||||
break;
|
||||
case nano::thread_role::name::confirmation_height_processing:
|
||||
thread_role_name_string = "Conf height";
|
||||
break;
|
||||
case nano::thread_role::name::worker:
|
||||
thread_role_name_string = "Worker";
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to constrain the thread names to 15
|
||||
* characters, since this is the smallest maximum
|
||||
* length supported by the platforms we support
|
||||
* (specifically, Linux)
|
||||
*/
|
||||
assert (thread_role_name_string.size () < 16);
|
||||
return (thread_role_name_string);
|
||||
}
|
||||
|
||||
std::string get_string ()
|
||||
{
|
||||
return get_string (current_thread_role);
|
||||
}
|
||||
|
||||
void set (nano::thread_role::name role)
|
||||
{
|
||||
auto thread_role_name_string (get_string (role));
|
||||
|
||||
nano::thread_role::set_os_name (thread_role_name_string);
|
||||
|
||||
nano::thread_role::current_thread_role = role;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nano::thread_attributes::set (boost::thread::attributes & attrs)
|
||||
{
|
||||
auto attrs_l (&attrs);
|
||||
attrs_l->set_stack_size (8000000); //8MB
|
||||
}
|
||||
|
||||
nano::thread_runner::thread_runner (boost::asio::io_context & io_ctx_a, unsigned service_threads_a) :
|
||||
io_guard (boost::asio::make_work_guard (io_ctx_a))
|
||||
{
|
||||
boost::thread::attributes attrs;
|
||||
nano::thread_attributes::set (attrs);
|
||||
for (auto i (0u); i < service_threads_a; ++i)
|
||||
{
|
||||
threads.push_back (boost::thread (attrs, [&io_ctx_a]() {
|
||||
nano::thread_role::set (nano::thread_role::name::io);
|
||||
try
|
||||
{
|
||||
io_ctx_a.run ();
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::cerr << ex.what () << std::endl;
|
||||
#ifndef NDEBUG
|
||||
throw;
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
* In a release build, catch and swallow the
|
||||
* io_context exception, in debug mode pass it
|
||||
* on
|
||||
*/
|
||||
throw;
|
||||
#endif
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
nano::thread_runner::~thread_runner ()
|
||||
{
|
||||
join ();
|
||||
}
|
||||
|
||||
void nano::thread_runner::join ()
|
||||
{
|
||||
io_guard.reset ();
|
||||
for (auto & i : threads)
|
||||
{
|
||||
if (i.joinable ())
|
||||
{
|
||||
i.join ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nano::thread_runner::stop_event_processing ()
|
||||
{
|
||||
io_guard.get_executor ().context ().stop ();
|
||||
}
|
||||
|
||||
nano::worker::worker () :
|
||||
thread ([this]() {
|
||||
nano::thread_role::set (nano::thread_role::name::worker);
|
||||
this->run ();
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
void nano::worker::run ()
|
||||
{
|
||||
nano::unique_lock<std::mutex> lk (mutex);
|
||||
while (!stopped)
|
||||
{
|
||||
if (!queue.empty ())
|
||||
{
|
||||
auto func = queue.front ();
|
||||
queue.pop_front ();
|
||||
lk.unlock ();
|
||||
func ();
|
||||
// So that we reduce locking for anything being pushed as that will
|
||||
// most likely be on an io-thread
|
||||
std::this_thread::yield ();
|
||||
lk.lock ();
|
||||
}
|
||||
else
|
||||
{
|
||||
cv.wait (lk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nano::worker::~worker ()
|
||||
{
|
||||
stop ();
|
||||
}
|
||||
|
||||
void nano::worker::push_task (std::function<void()> func_a)
|
||||
{
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (mutex);
|
||||
if (!stopped)
|
||||
{
|
||||
queue.emplace_back (func_a);
|
||||
}
|
||||
}
|
||||
|
||||
cv.notify_one ();
|
||||
}
|
||||
|
||||
void nano::worker::stop ()
|
||||
{
|
||||
{
|
||||
nano::unique_lock<std::mutex> lk (mutex);
|
||||
stopped = true;
|
||||
queue.clear ();
|
||||
}
|
||||
cv.notify_one ();
|
||||
if (thread.joinable ())
|
||||
{
|
||||
thread.join ();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<nano::seq_con_info_component> nano::collect_seq_con_info (nano::worker & worker, const std::string & name)
|
||||
{
|
||||
auto composite = std::make_unique<seq_con_info_composite> (name);
|
||||
|
||||
size_t count = 0;
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (worker.mutex);
|
||||
count = worker.queue.size ();
|
||||
}
|
||||
auto sizeof_element = sizeof (decltype (worker.queue)::value_type);
|
||||
composite->add_component (std::make_unique<nano::seq_con_info_leaf> (nano::seq_con_info{ "queue", count, sizeof_element }));
|
||||
return composite;
|
||||
}
|
||||
|
||||
void nano::remove_all_files_in_dir (boost::filesystem::path const & dir)
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/boost/asio.hpp>
|
||||
#include <nano/lib/locks.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
class path;
|
||||
}
|
||||
|
||||
namespace system
|
||||
{
|
||||
class error_code;
|
||||
}
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
/* These containers are used to collect information about sequence containers.
|
||||
|
@ -94,92 +101,6 @@ void dump_crash_stacktrace ();
|
|||
*/
|
||||
std::string generate_stacktrace ();
|
||||
|
||||
/*
|
||||
* Functions for understanding the role of the current thread
|
||||
*/
|
||||
namespace thread_role
|
||||
{
|
||||
enum class name
|
||||
{
|
||||
unknown,
|
||||
io,
|
||||
work,
|
||||
packet_processing,
|
||||
alarm,
|
||||
vote_processing,
|
||||
block_processing,
|
||||
request_loop,
|
||||
wallet_actions,
|
||||
bootstrap_initiator,
|
||||
voting,
|
||||
signature_checking,
|
||||
rpc_request_processor,
|
||||
rpc_process_container,
|
||||
work_watcher,
|
||||
confirmation_height_processing,
|
||||
worker
|
||||
};
|
||||
/*
|
||||
* Get/Set the identifier for the current thread
|
||||
*/
|
||||
nano::thread_role::name get ();
|
||||
void set (nano::thread_role::name);
|
||||
|
||||
/*
|
||||
* Get the thread name as a string from enum
|
||||
*/
|
||||
std::string get_string (nano::thread_role::name);
|
||||
|
||||
/*
|
||||
* Get the current thread's role as a string
|
||||
*/
|
||||
std::string get_string ();
|
||||
|
||||
/*
|
||||
* Internal only, should not be called directly
|
||||
*/
|
||||
void set_os_name (std::string const &);
|
||||
}
|
||||
|
||||
namespace thread_attributes
|
||||
{
|
||||
void set (boost::thread::attributes &);
|
||||
}
|
||||
|
||||
class thread_runner final
|
||||
{
|
||||
public:
|
||||
thread_runner (boost::asio::io_context &, unsigned);
|
||||
~thread_runner ();
|
||||
/** Tells the IO context to stop processing events.*/
|
||||
void stop_event_processing ();
|
||||
/** Wait for IO threads to complete */
|
||||
void join ();
|
||||
std::vector<boost::thread> threads;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> io_guard;
|
||||
};
|
||||
|
||||
class worker final
|
||||
{
|
||||
public:
|
||||
worker ();
|
||||
~worker ();
|
||||
void run ();
|
||||
void push_task (std::function<void()> func);
|
||||
void stop ();
|
||||
|
||||
private:
|
||||
nano::condition_variable cv;
|
||||
std::deque<std::function<void()>> queue;
|
||||
std::mutex mutex;
|
||||
bool stopped{ false };
|
||||
std::thread thread;
|
||||
|
||||
friend std::unique_ptr<seq_con_info_component> collect_seq_con_info (worker &, const std::string &);
|
||||
};
|
||||
|
||||
std::unique_ptr<seq_con_info_component> collect_seq_con_info (worker & worker, const std::string & name);
|
||||
|
||||
/**
|
||||
* Returns seconds passed since unix epoch (posix time)
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
#include <nano/lib/work.hpp>
|
||||
#include <nano/node/xorshift.hpp>
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/locks.hpp>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
|
@ -8,13 +9,12 @@
|
|||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class block;
|
||||
|
||||
bool work_validate (nano::root const &, uint64_t, uint64_t * = nullptr);
|
||||
bool work_validate (nano::block const &, uint64_t * = nullptr);
|
||||
uint64_t work_value (nano::root const &, uint64_t);
|
||||
|
|
79
nano/lib/worker.cpp
Normal file
79
nano/lib/worker.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include <nano/lib/threading.hpp>
|
||||
#include <nano/lib/worker.hpp>
|
||||
|
||||
nano::worker::worker () :
|
||||
thread ([this]() {
|
||||
nano::thread_role::set (nano::thread_role::name::worker);
|
||||
this->run ();
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
void nano::worker::run ()
|
||||
{
|
||||
nano::unique_lock<std::mutex> lk (mutex);
|
||||
while (!stopped)
|
||||
{
|
||||
if (!queue.empty ())
|
||||
{
|
||||
auto func = queue.front ();
|
||||
queue.pop_front ();
|
||||
lk.unlock ();
|
||||
func ();
|
||||
// So that we reduce locking for anything being pushed as that will
|
||||
// most likely be on an io-thread
|
||||
std::this_thread::yield ();
|
||||
lk.lock ();
|
||||
}
|
||||
else
|
||||
{
|
||||
cv.wait (lk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nano::worker::~worker ()
|
||||
{
|
||||
stop ();
|
||||
}
|
||||
|
||||
void nano::worker::push_task (std::function<void()> func_a)
|
||||
{
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (mutex);
|
||||
if (!stopped)
|
||||
{
|
||||
queue.emplace_back (func_a);
|
||||
}
|
||||
}
|
||||
|
||||
cv.notify_one ();
|
||||
}
|
||||
|
||||
void nano::worker::stop ()
|
||||
{
|
||||
{
|
||||
nano::unique_lock<std::mutex> lk (mutex);
|
||||
stopped = true;
|
||||
queue.clear ();
|
||||
}
|
||||
cv.notify_one ();
|
||||
if (thread.joinable ())
|
||||
{
|
||||
thread.join ();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<nano::seq_con_info_component> nano::collect_seq_con_info (nano::worker & worker, const std::string & name)
|
||||
{
|
||||
auto composite = std::make_unique<seq_con_info_composite> (name);
|
||||
|
||||
size_t count = 0;
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (worker.mutex);
|
||||
count = worker.queue.size ();
|
||||
}
|
||||
auto sizeof_element = sizeof (decltype (worker.queue)::value_type);
|
||||
composite->add_component (std::make_unique<nano::seq_con_info_leaf> (nano::seq_con_info{ "queue", count, sizeof_element }));
|
||||
return composite;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue