Skip to content

Commit

Permalink
Merge pull request libbitcoin#406 from evoskuil/master
Browse files Browse the repository at this point in the history
Change race_volume::finish(...) to return true on first sufficient.
  • Loading branch information
evoskuil authored May 22, 2024
2 parents b436284 + fbc67ff commit d787715
Show file tree
Hide file tree
Showing 16 changed files with 452 additions and 33 deletions.
3 changes: 3 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ test_libbitcoin_network_test_SOURCES = \
test/async/enable_shared_from_base.cpp \
test/async/race_quality.cpp \
test/async/race_speed.cpp \
test/async/race_unity.cpp \
test/async/race_volume.cpp \
test/async/subscriber.cpp \
test/async/thread.cpp \
Expand Down Expand Up @@ -235,6 +236,7 @@ include_bitcoin_network_async_HEADERS = \
include/bitcoin/network/async/handlers.hpp \
include/bitcoin/network/async/race_quality.hpp \
include/bitcoin/network/async/race_speed.hpp \
include/bitcoin/network/async/race_unity.hpp \
include/bitcoin/network/async/race_volume.hpp \
include/bitcoin/network/async/subscriber.hpp \
include/bitcoin/network/async/thread.hpp \
Expand All @@ -256,6 +258,7 @@ include_bitcoin_network_impl_async_HEADERS = \
include/bitcoin/network/impl/async/enable_shared_from_base.ipp \
include/bitcoin/network/impl/async/race_quality.ipp \
include/bitcoin/network/impl/async/race_speed.ipp \
include/bitcoin/network/impl/async/race_unity.ipp \
include/bitcoin/network/impl/async/race_volume.ipp \
include/bitcoin/network/impl/async/subscriber.ipp \
include/bitcoin/network/impl/async/unsubscriber.ipp
Expand Down
1 change: 1 addition & 0 deletions builds/cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ if (with-tests)
"../../test/async/enable_shared_from_base.cpp"
"../../test/async/race_quality.cpp"
"../../test/async/race_speed.cpp"
"../../test/async/race_unity.cpp"
"../../test/async/race_volume.cpp"
"../../test/async/subscriber.cpp"
"../../test/async/thread.cpp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<ClCompile Include="..\..\..\..\test\async\enable_shared_from_base.cpp" />
<ClCompile Include="..\..\..\..\test\async\race_quality.cpp" />
<ClCompile Include="..\..\..\..\test\async\race_speed.cpp" />
<ClCompile Include="..\..\..\..\test\async\race_unity.cpp" />
<ClCompile Include="..\..\..\..\test\async\race_volume.cpp" />
<ClCompile Include="..\..\..\..\test\async\subscriber.cpp" />
<ClCompile Include="..\..\..\..\test\async\thread.cpp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
<ClCompile Include="..\..\..\..\test\async\race_speed.cpp">
<Filter>src\async</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\async\race_unity.cpp">
<Filter>src\async</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\async\race_volume.cpp">
<Filter>src\async</Filter>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\handlers.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_quality.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_speed.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_unity.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_volume.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\subscriber.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\thread.hpp" />
Expand Down Expand Up @@ -266,6 +267,7 @@
<None Include="..\..\..\..\include\bitcoin\network\impl\async\enable_shared_from_base.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_quality.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_speed.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_unity.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_volume.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\subscriber.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\unsubscriber.ipp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,9 @@
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_speed.hpp">
<Filter>include\bitcoin\network\async</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_unity.hpp">
<Filter>include\bitcoin\network\async</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_volume.hpp">
<Filter>include\bitcoin\network\async</Filter>
</ClInclude>
Expand Down Expand Up @@ -634,6 +637,9 @@
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_speed.ipp">
<Filter>include\bitcoin\network\impl\async</Filter>
</None>
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_unity.ipp">
<Filter>include\bitcoin\network\impl\async</Filter>
</None>
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_volume.ipp">
<Filter>include\bitcoin\network\impl\async</Filter>
</None>
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/network.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <bitcoin/network/async/handlers.hpp>
#include <bitcoin/network/async/race_quality.hpp>
#include <bitcoin/network/async/race_speed.hpp>
#include <bitcoin/network/async/race_unity.hpp>
#include <bitcoin/network/async/race_volume.hpp>
#include <bitcoin/network/async/subscriber.hpp>
#include <bitcoin/network/async/thread.hpp>
Expand Down
10 changes: 6 additions & 4 deletions include/bitcoin/network/async/race_quality.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ namespace libbitcoin {
namespace network {

/// Not thread safe.
/// Race is a bind that invokes handler with the first set of arguments
/// but only after a preconfigured number of invocations. This assists in
/// synchronizing the results of a set of racing asynchronous operations.
/// Used in outbound session to invoke for first succeesful handshake.
/// race_quality invokes complete(args) provided at start(complete), with
/// args from first successful call to finish(args), with success determined
/// by first argument in 'args', or upon the last expected invocation of
/// finish(...), based on the constructor 'size' parameter.
template <typename... Args>
class race_quality final
{
Expand All @@ -50,7 +52,7 @@ class race_quality final
/// False implies invalid usage.
bool start(handler&& complete) NOEXCEPT;

/// True implies winning finisher (first not failed).
/// True implies winning finisher (first that is not failed).
/// First arg is an 'error code', cast to bool (failed if true).
/// There may be no winner, in which case last finish is invoked.
bool finish(const Args&... args) NOEXCEPT;
Expand Down
9 changes: 5 additions & 4 deletions include/bitcoin/network/async/race_speed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ namespace libbitcoin {
namespace network {

/// Not thread safe.
/// Race is a bind that invokes handler with the first set of arguments
/// but only after a preconfigured number of invocations. This assists in
/// synchronizing the results of a set of racing asynchronous operations.
/// Used in connector to race between timer (connection timeout) and connect.
/// race_speed<Size> invokes complete(args) provided at start(complete), with
/// args from first call to finish(args), upon the last expected invocation of
/// finish(...) based on the templatized Size number of expected calls.
template <size_t Size, typename... Args>
class race_speed final
{
Expand All @@ -53,7 +54,7 @@ class race_speed final
/// False implies invalid usage.
bool start(handler&& complete) NOEXCEPT;

/// True implies winning finisher.
/// True implies winning finisher, there is always exactly one.
bool finish(const Args&... args) NOEXCEPT;

private:
Expand Down
87 changes: 87 additions & 0 deletions include/bitcoin/network/async/race_unity.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS)
*
* This file is part of libbitcoin.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBBITCOIN_NETWORK_ASYNC_RACE_UNITY_HPP
#define LIBBITCOIN_NETWORK_ASYNC_RACE_UNITY_HPP

#include <memory>
#include <tuple>
#include <utility>
#include <bitcoin/system.hpp>
#include <bitcoin/network/define.hpp>

namespace libbitcoin {
namespace network {

/// Not thread safe.
/// Used in node validation chaser to invoke upon complete, with first error.
/// race_unity invokes complete(args) provided at start(complete), with args
/// from first failed call to finish(args), with failure determined by first
/// argument in 'args', at the last expected invocation of finish(...), based
/// on the constructor 'size' parameter.
template <typename... Args>
class race_unity final
{
public:
typedef std::shared_ptr<race_unity> ptr;
typedef std::function<void(Args...)> handler;

DELETE_COPY_MOVE(race_unity);

race_unity(size_t size) NOEXCEPT;
~race_unity() NOEXCEPT;

/// True if the race_unity is running.
inline bool running() const NOEXCEPT;

/// False implies invalid usage.
bool start(handler&& complete) NOEXCEPT;

/// True implies winning finisher (last invocation, none failed).
/// First arg is an 'error code', cast to bool (failed if true).
/// There may be no winner, in which case last finish is invoked.
bool finish(const Args&... args) NOEXCEPT;

private:
template <size_t... Pack>
using unpack = std::index_sequence<Pack...>;
using packed = std::tuple<std::decay_t<Args>...>;
using sequence = std::index_sequence_for<Args...>;

template<size_t... Index>
void invoker(const handler& complete, const packed& args,
unpack<Index...>) NOEXCEPT;
bool invoke() NOEXCEPT;
bool set_failure(bool failure) NOEXCEPT;

// This is thread safe.
const size_t size_;

// These are not thread safe.
packed args_{};
bool failure_{};
size_t runners_{};
std::shared_ptr<handler> complete_{};
};

} // namespace network
} // namespace libbitcoin

#include <bitcoin/network/impl/async/race_unity.ipp>

#endif
12 changes: 8 additions & 4 deletions include/bitcoin/network/async/race_volume.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ namespace libbitcoin {
namespace network {

/// Not thread safe.
/// Race is a bind that invokes handler with the first set of arguments
/// but only after a preconfigured number of invocations. This assists in
/// synchronizing the results of a set of racing asynchronous operations.
/// Used in seed session to continue once sufficient seeding has occurred.
/// race_volume<Success, Fail>(size, required) invokes sufficient(Success)
/// provided at start(sufficient, complete) when the first call to finish(count)
/// is made where count >= required. If no finish is sufficient then the final
/// call to finish, based on the constructor 'size' parameter, invokes
/// sufficient(Fail). The final call also invokes complete(Success), regardless
/// of sufficiency.
template <error::error_t Success, error::error_t Fail>
class race_volume final
{
Expand All @@ -48,7 +52,7 @@ class race_volume final
/// False implies invalid usage.
bool start(handler&& sufficient, handler&& complete) NOEXCEPT;

/// Signal finisher and pass total count.
/// True implies first sufficient count (there may be none).
bool finish(size_t count) NOEXCEPT;

private:
Expand Down
3 changes: 2 additions & 1 deletion include/bitcoin/network/impl/async/race_quality.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ finish(const Args&... args) NOEXCEPT
const auto winner = set_winner(!ec);

// Save args for winner (first success) or last failure.
if (winner || (!success_ && (runners_ == one)))
const auto last = (runners_ == one);
if (winner || (last && !success_))
args_ = std::move(values);

// false invoke implies logic error.
Expand Down
Loading

0 comments on commit d787715

Please sign in to comment.