mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
Merge branch 'develop' into mvadari/fix-bad-cast
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Extract a tar archive compressed with lz4
|
||||
|
||||
@@ -17,6 +17,6 @@ extractTarLz4(
|
||||
boost::filesystem::path const& src,
|
||||
boost::filesystem::path const& dst);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
using IniFileSections =
|
||||
std::unordered_map<std::string, std::vector<std::string>>;
|
||||
@@ -380,6 +380,6 @@ get_if_exists<bool>(Section const& section, std::string const& name, bool& v)
|
||||
return stat;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Storage for linear binary data.
|
||||
Blocks of binary data appear often in various idioms and structures.
|
||||
*/
|
||||
using Blob = std::vector<unsigned char>;
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Like std::vector<char> but better.
|
||||
Meets the requirements of BufferFactory.
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
XRPL_ASSERT(
|
||||
s.size() == 0 || size_ == 0 || s.data() < p_.get() ||
|
||||
s.data() >= p_.get() + size_,
|
||||
"ripple::Buffer::operator=(Slice) : input not a subset");
|
||||
"xrpl::Buffer::operator=(Slice) : input not a subset");
|
||||
|
||||
if (auto p = alloc(s.size()))
|
||||
std::memcpy(p, s.data(), s.size());
|
||||
@@ -215,6 +215,6 @@ operator!=(Buffer const& lhs, Buffer const& rhs) noexcept
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef XRPL_BASICS_BYTEUTILITIES_H_INCLUDED
|
||||
#define XRPL_BASICS_BYTEUTILITIES_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
template <class T>
|
||||
constexpr auto
|
||||
@@ -19,6 +19,6 @@ megabytes(T value) noexcept
|
||||
|
||||
static_assert(kilobytes(2) == 2048, "kilobytes(2) == 2048");
|
||||
static_assert(megabytes(3) == 3145728, "megabytes(3) == 3145728");
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace compression_algorithms {
|
||||
|
||||
@@ -144,6 +144,6 @@ lz4Decompress(
|
||||
|
||||
} // namespace compression_algorithms
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_COMPRESSIONALGORITHMS_H_INCLUDED
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Manages all counted object types. */
|
||||
class CountedObjects
|
||||
@@ -133,6 +133,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Sampling function using exponential decay to provide a continuous value.
|
||||
@tparam The number of seconds in the decay window.
|
||||
@@ -131,6 +131,6 @@ private:
|
||||
time_point when_;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Expected is an approximation of std::expected (hoped for in C++23)
|
||||
|
||||
@@ -232,6 +232,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_BASICS_EXPECTED_H_INCLUDED
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
std::string
|
||||
getFileContents(
|
||||
@@ -20,6 +20,6 @@ writeFileContents(
|
||||
boost::filesystem::path const& destPath,
|
||||
std::string const& contents);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -492,5 +492,5 @@ dynamic_pointer_cast(TT const& v)
|
||||
return SharedPtr<T>(DynamicCastTagSharedIntrusive{}, v);
|
||||
}
|
||||
} // namespace intr_ptr
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
template <class T>
|
||||
template <CAdoptTag TAdoptTag>
|
||||
@@ -608,7 +608,7 @@ SharedWeakUnion<T>::convertToStrong()
|
||||
[[maybe_unused]] auto action = p->releaseWeakRef();
|
||||
XRPL_ASSERT(
|
||||
(action == ReleaseWeakRefAction::noop),
|
||||
"ripple::SharedWeakUnion::convertToStrong : "
|
||||
"xrpl::SharedWeakUnion::convertToStrong : "
|
||||
"action is noop");
|
||||
unsafeSetRawPtr(p, RefStrength::strong);
|
||||
return true;
|
||||
@@ -637,7 +637,7 @@ SharedWeakUnion<T>::convertToWeak()
|
||||
// We just added a weak ref. How could we destroy?
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"ripple::SharedWeakUnion::convertToWeak : destroying freshly "
|
||||
"xrpl::SharedWeakUnion::convertToWeak : destroying freshly "
|
||||
"added ref");
|
||||
delete p;
|
||||
unsafeSetRawPtr(nullptr);
|
||||
@@ -719,5 +719,5 @@ SharedWeakUnion<T>::unsafeReleaseNoStore()
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Action to perform when releasing a strong pointer.
|
||||
|
||||
@@ -34,7 +34,7 @@ enum class ReleaseWeakRefAction { noop, destroy };
|
||||
/** Implement the strong count, weak count, and bit flags for an intrusive
|
||||
pointer.
|
||||
|
||||
A class can satisfy the requirements of a ripple::IntrusivePointer by
|
||||
A class can satisfy the requirements of a xrpl::IntrusivePointer by
|
||||
inheriting from this class.
|
||||
*/
|
||||
struct IntrusiveRefCounts
|
||||
@@ -257,7 +257,7 @@ IntrusiveRefCounts::releaseStrongRef() const
|
||||
RefCountPair const prevVal{prevIntVal};
|
||||
XRPL_ASSERT(
|
||||
(prevVal.strong >= strongDelta),
|
||||
"ripple::IntrusiveRefCounts::releaseStrongRef : previous ref "
|
||||
"xrpl::IntrusiveRefCounts::releaseStrongRef : previous ref "
|
||||
"higher than new");
|
||||
auto nextIntVal = prevIntVal - strongDelta;
|
||||
ReleaseStrongRefAction action = noop;
|
||||
@@ -282,7 +282,7 @@ IntrusiveRefCounts::releaseStrongRef() const
|
||||
// twice.
|
||||
XRPL_ASSERT(
|
||||
(action == noop) || !(prevIntVal & partialDestroyStartedMask),
|
||||
"ripple::IntrusiveRefCounts::releaseStrongRef : not in partial "
|
||||
"xrpl::IntrusiveRefCounts::releaseStrongRef : not in partial "
|
||||
"destroy");
|
||||
return action;
|
||||
}
|
||||
@@ -314,7 +314,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
|
||||
// can't happen twice.
|
||||
XRPL_ASSERT(
|
||||
(!prevVal.partialDestroyStartedBit),
|
||||
"ripple::IntrusiveRefCounts::addWeakReleaseStrongRef : not in "
|
||||
"xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not in "
|
||||
"partial destroy");
|
||||
|
||||
auto nextIntVal = prevIntVal + delta;
|
||||
@@ -336,7 +336,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(!(prevIntVal & partialDestroyStartedMask)),
|
||||
"ripple::IntrusiveRefCounts::addWeakReleaseStrongRef : not "
|
||||
"xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not "
|
||||
"started partial destroy");
|
||||
return action;
|
||||
}
|
||||
@@ -408,11 +408,11 @@ inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
|
||||
auto v = refCounts.load(std::memory_order_acquire);
|
||||
XRPL_ASSERT(
|
||||
(!(v & valueMask)),
|
||||
"ripple::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
|
||||
"xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
|
||||
auto t = v & tagMask;
|
||||
XRPL_ASSERT(
|
||||
(!t || t == tagMask),
|
||||
"ripple::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
|
||||
"xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -427,7 +427,7 @@ inline IntrusiveRefCounts::RefCountPair::RefCountPair(
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||
"ripple::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside "
|
||||
"xrpl::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside "
|
||||
"range");
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ inline IntrusiveRefCounts::RefCountPair::RefCountPair(
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||
"ripple::IntrusiveRefCounts::RefCountPair(CountType, CountType) : "
|
||||
"xrpl::IntrusiveRefCounts::RefCountPair(CountType, CountType) : "
|
||||
"inputs inside range");
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||
"ripple::IntrusiveRefCounts::RefCountPair::combinedValue : inputs "
|
||||
"xrpl::IntrusiveRefCounts::RefCountPair::combinedValue : inputs "
|
||||
"inside range");
|
||||
return (static_cast<IntrusiveRefCounts::FieldType>(weak)
|
||||
<< IntrusiveRefCounts::StrongCountNumBits) |
|
||||
@@ -465,7 +465,7 @@ partialDestructorFinished(T** o)
|
||||
XRPL_ASSERT(
|
||||
(!p.partialDestroyFinishedBit && p.partialDestroyStartedBit &&
|
||||
!p.strong),
|
||||
"ripple::partialDestructorFinished : not a weak ref");
|
||||
"xrpl::partialDestructorFinished : not a weak ref");
|
||||
if (!p.weak)
|
||||
{
|
||||
// There was a weak count before the partial destructor ran (or we would
|
||||
@@ -479,5 +479,5 @@ partialDestructorFinished(T** o)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
#endif
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
using KeyCache = TaggedCache<uint256, int, true>;
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_BASICS_KEYCACHE_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -109,6 +109,6 @@ LocalValue<T>::operator*()
|
||||
.emplace(this, std::make_unique<detail::LocalValues::Value<T>>(t_))
|
||||
.first->second->get());
|
||||
}
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
// DEPRECATED use beast::severities::Severity instead
|
||||
enum LogSeverity {
|
||||
@@ -271,6 +271,6 @@ setDebugLogSink(std::unique_ptr<beast::Journal::Sink> sink);
|
||||
beast::Journal
|
||||
debugLog();
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Calculate one number divided by another number in percentage.
|
||||
* The result is rounded up to the next integer, and capped in the range [0,100]
|
||||
@@ -44,6 +44,6 @@ static_assert(calculatePercent(50'000'000, 100'000'000) == 50);
|
||||
static_assert(calculatePercent(50'000'001, 100'000'000) == 51);
|
||||
static_assert(calculatePercent(99'999'999, 100'000'000) == 100);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
class Number;
|
||||
|
||||
@@ -402,6 +402,6 @@ public:
|
||||
operator=(NumberRoundModeGuard const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_BASICS_NUMBER_H_INCLUDED
|
||||
|
||||
@@ -21,11 +21,11 @@ ripple/basic should contain no dependencies on other modules.
|
||||
- `std::set`
|
||||
- For sorted containers.
|
||||
|
||||
- `ripple::hash_set`
|
||||
- `xrpl::hash_set`
|
||||
- Where inserts and contains need to be O(1).
|
||||
- For "small" sets, `std::set` might be faster and smaller.
|
||||
|
||||
- `ripple::hardened_hash_set`
|
||||
- `xrpl::hardened_hash_set`
|
||||
- For data sets where the key could be manipulated by an attacker
|
||||
in an attempt to mount an algorithmic complexity attack: see
|
||||
http://en.wikipedia.org/wiki/Algorithmic_complexity_attack
|
||||
@@ -33,5 +33,5 @@ ripple/basic should contain no dependencies on other modules.
|
||||
The following container is deprecated
|
||||
|
||||
- `std::unordered_set`
|
||||
- Use `ripple::hash_set` instead, which uses a better hashing algorithm.
|
||||
- Or use `ripple::hardened_hash_set` to prevent algorithmic complexity attacks.
|
||||
- Use `xrpl::hash_set` instead, which uses a better hashing algorithm.
|
||||
- Or use `xrpl::hardened_hash_set` to prevent algorithmic complexity attacks.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** A closed interval over the domain T.
|
||||
|
||||
@@ -85,7 +85,7 @@ to_string(RangeSet<T> const& rs)
|
||||
|
||||
std::string s;
|
||||
for (auto const& interval : rs)
|
||||
s += ripple::to_string(interval) + ",";
|
||||
s += xrpl::to_string(interval) + ",";
|
||||
s.pop_back();
|
||||
|
||||
return s;
|
||||
@@ -172,6 +172,6 @@ prevMissing(RangeSet<T> const& rs, T t, T minVal = 0)
|
||||
return boost::icl::last(tgt);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
class Resolver
|
||||
{
|
||||
@@ -47,6 +47,6 @@ public:
|
||||
/** @} */
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
class ResolverAsio : public Resolver
|
||||
{
|
||||
@@ -17,6 +17,6 @@ public:
|
||||
New(boost::asio::io_context&, beast::Journal);
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
// A SHAMapHash is the hash of a node in a SHAMap, and also the
|
||||
// type of the hash of the entire SHAMap.
|
||||
@@ -97,6 +97,6 @@ extract(SHAMapHash const& key)
|
||||
return *reinterpret_cast<std::size_t const*>(key.as_uint256().data());
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_BASICS_SHAMAP_HASH_H_INCLUDED
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <memory>
|
||||
#include <variant>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** A combination of a std::shared_ptr and a std::weak_pointer.
|
||||
|
||||
@@ -112,5 +112,5 @@ public:
|
||||
private:
|
||||
std::variant<std::shared_ptr<T>, std::weak_ptr<T>> combo_;
|
||||
};
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <xrpl/basics/SharedWeakCachePointer.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
template <class T>
|
||||
SharedWeakCachePointer<T>::SharedWeakCachePointer(
|
||||
SharedWeakCachePointer const& rhs) = default;
|
||||
@@ -169,5 +169,5 @@ SharedWeakCachePointer<T>::convertToWeak()
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
template <typename Type>
|
||||
class SlabAllocator
|
||||
@@ -128,7 +128,7 @@ class SlabAllocator
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
own(ptr),
|
||||
"ripple::SlabAllocator::SlabBlock::deallocate : own input");
|
||||
"xrpl::SlabAllocator::SlabBlock::deallocate : own input");
|
||||
|
||||
std::lock_guard l(m_);
|
||||
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(itemAlignment_ & (itemAlignment_ - 1)) == 0,
|
||||
"ripple::SlabAllocator::SlabAllocator : valid alignment");
|
||||
"xrpl::SlabAllocator::SlabAllocator : valid alignment");
|
||||
}
|
||||
|
||||
SlabAllocator(SlabAllocator const& other) = delete;
|
||||
@@ -285,7 +285,7 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
ptr,
|
||||
"ripple::SlabAllocator::SlabAllocator::deallocate : non-null "
|
||||
"xrpl::SlabAllocator::SlabAllocator::deallocate : non-null "
|
||||
"input");
|
||||
|
||||
for (auto slab = slabs_.load(); slab != nullptr; slab = slab->next_)
|
||||
@@ -419,6 +419,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_BASICS_SLABALLOCATOR_H_INCLUDED
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** An immutable linear range of bytes.
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
i < size_,
|
||||
"ripple::Slice::operator[](std::size_t) const : valid input");
|
||||
"xrpl::Slice::operator[](std::size_t) const : valid input");
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
@@ -243,6 +243,6 @@ makeSlice(std::basic_string<char, Traits, Alloc> const& s)
|
||||
return Slice(s.data(), s.size());
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Format arbitrary binary data as an SQLite "blob literal".
|
||||
|
||||
@@ -132,6 +132,6 @@ to_uint64(std::string const& s);
|
||||
bool
|
||||
isProperlyFormedTomlDomain(std::string_view domain);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Map/cache combination.
|
||||
This class implements a cache and a map. The cache keeps objects alive
|
||||
@@ -315,6 +315,6 @@ private:
|
||||
std::uint64_t m_misses;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <xrpl/basics/IntrusivePointer.ipp>
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
@@ -1005,6 +1005,6 @@ TaggedCache<
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** to_string() generalizes std::to_string to handle bools, chars, and strings.
|
||||
|
||||
@@ -43,6 +43,6 @@ to_string(char const* s)
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* what container it is.
|
||||
*/
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
// hash containers
|
||||
|
||||
@@ -102,6 +102,6 @@ template <
|
||||
using hardened_hash_multiset =
|
||||
std::unordered_multiset<Value, Hash, Pred, Allocator>;
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <ratio>
|
||||
#include <thread>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Tracks program uptime to seconds precision.
|
||||
|
||||
@@ -45,6 +45,6 @@ private:
|
||||
start_clock();
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
// Requires: [first1, last1) and [first2, last2) are ordered ranges according to
|
||||
// comp.
|
||||
@@ -95,6 +95,6 @@ remove_if_intersect_or_match(
|
||||
return first1;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
std::string
|
||||
base64_encode(std::uint8_t const* data, std::size_t len);
|
||||
@@ -53,6 +53,6 @@ base64_encode(std::string const& s)
|
||||
std::string
|
||||
base64_decode(std::string_view data);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -275,7 +275,7 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
c.size() * sizeof(typename Container::value_type) == size(),
|
||||
"ripple::base_uint::base_uint(Container auto) : input size match");
|
||||
"xrpl::base_uint::base_uint(Container auto) : input size match");
|
||||
std::memcpy(data_.data(), c.data(), size());
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
c.size() * sizeof(typename Container::value_type) == size(),
|
||||
"ripple::base_uint::operator=(Container auto) : input size match");
|
||||
"xrpl::base_uint::operator=(Container auto) : input size match");
|
||||
std::memcpy(data_.data(), c.data(), size());
|
||||
return *this;
|
||||
}
|
||||
@@ -648,12 +648,12 @@ static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
|
||||
static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
|
||||
#endif
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
struct is_uniquely_represented<ripple::base_uint<Bits, Tag>>
|
||||
struct is_uniquely_represented<xrpl::base_uint<Bits, Tag>>
|
||||
: public std::true_type
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <ratio>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
// A few handy aliases
|
||||
|
||||
@@ -104,6 +104,6 @@ stopwatch()
|
||||
return beast::get_abstract_clock<Facade, Clock>();
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@@ -52,6 +52,6 @@ using equal_to = std::equal_to<T>;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/* Programming By Contract
|
||||
|
||||
@@ -52,6 +52,6 @@ Throw(Args&&... args)
|
||||
[[noreturn]] void
|
||||
LogicError(std::string const& how) noexcept;
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <random>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -92,6 +92,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
template <class Stream, class Iter>
|
||||
Stream&
|
||||
@@ -85,6 +85,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Create a self-signed SSL context that allows anonymous Diffie Hellman. */
|
||||
std::shared_ptr<boost::asio::ssl::context>
|
||||
@@ -19,6 +19,6 @@ make_SSLContextAuthed(
|
||||
std::string const& chainFile,
|
||||
std::string const& cipherList);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
auto constexpr muldiv_max = std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
/** Return value*mul/div accurately.
|
||||
@@ -21,6 +21,6 @@ auto constexpr muldiv_max = std::numeric_limits<std::uint64_t>::max();
|
||||
std::optional<std::uint64_t>
|
||||
mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
template <typename Key>
|
||||
static std::size_t
|
||||
@@ -242,7 +242,7 @@ public:
|
||||
map_.resize(partitions_);
|
||||
XRPL_ASSERT(
|
||||
partitions_,
|
||||
"ripple::partitioned_unordered_map::partitioned_unordered_map : "
|
||||
"xrpl::partitioned_unordered_map::partitioned_unordered_map : "
|
||||
"nonzero partitions");
|
||||
}
|
||||
|
||||
@@ -401,6 +401,6 @@ private:
|
||||
mutable partition_map_type map_{};
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_BASICS_PARTITIONED_UNORDERED_MAP_H
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <random>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
static_assert(
|
||||
@@ -95,7 +95,7 @@ std::enable_if_t<
|
||||
Integral>
|
||||
rand_int(Engine& engine, Integral min, Integral max)
|
||||
{
|
||||
XRPL_ASSERT(max > min, "ripple::rand_int : max over min inputs");
|
||||
XRPL_ASSERT(max > min, "xrpl::rand_int : max over min inputs");
|
||||
|
||||
// This should have no state and constructing it should
|
||||
// be very cheap. If that turns out not to be the case
|
||||
@@ -186,6 +186,6 @@ rand_bool()
|
||||
}
|
||||
/** @} */
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_BASICS_RANDOM_H_INCLUDED
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
// safe_cast adds compile-time checks to a static_cast to ensure that
|
||||
// the destination can hold all values of the source. This is particularly
|
||||
@@ -80,6 +80,6 @@ inline constexpr std::
|
||||
return unsafe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
// RAII scope helpers. As specified in Library Fundamental, Version 3
|
||||
// Basic design of idea: https://www.youtube.com/watch?v=WjTrfoiB0MQ
|
||||
@@ -218,7 +218,7 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
plock->owns_lock(),
|
||||
"ripple::scope_unlock::scope_unlock : mutex must be locked");
|
||||
"xrpl::scope_unlock::scope_unlock : mutex must be locked");
|
||||
plock->unlock();
|
||||
}
|
||||
|
||||
@@ -236,6 +236,6 @@ public:
|
||||
template <class Mutex>
|
||||
scope_unlock(std::unique_lock<Mutex>&) -> scope_unlock<Mutex>;
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
/** Inform the processor that we are in a tight spin-wait loop.
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
index >= 0 && (mask_ != 0),
|
||||
"ripple::packed_spinlock::packed_spinlock : valid index and mask");
|
||||
"xrpl::packed_spinlock::packed_spinlock : valid index and mask");
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
@@ -206,6 +206,6 @@ public:
|
||||
};
|
||||
/** @} */
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
template <class FwdIt>
|
||||
std::string
|
||||
@@ -28,6 +28,6 @@ strHex(T const& from)
|
||||
return strHex(from.begin(), from.end());
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** A type-safe wrap around standard integral types
|
||||
|
||||
@@ -197,11 +197,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
namespace beast {
|
||||
template <class Int, class Tag, class HashAlgorithm>
|
||||
struct is_contiguously_hashable<ripple::tagged_integer<Int, Tag>, HashAlgorithm>
|
||||
struct is_contiguously_hashable<xrpl::tagged_integer<Int, Tag>, HashAlgorithm>
|
||||
: public is_contiguously_hashable<Int, HashAlgorithm>
|
||||
{
|
||||
explicit is_contiguously_hashable() = default;
|
||||
|
||||
207
include/xrpl/core/ClosureCounter.h
Normal file
207
include/xrpl/core/ClosureCounter.h
Normal file
@@ -0,0 +1,207 @@
|
||||
#ifndef XRPL_CORE_CLOSURE_COUNTER_H_INCLUDED
|
||||
#define XRPL_CORE_CLOSURE_COUNTER_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* The role of a `ClosureCounter` is to assist in shutdown by letting callers
|
||||
* wait for the completion of closures (of a specific type signature) that they
|
||||
* previously registered. These closures are typically callbacks for
|
||||
* asynchronous operations. The lifetime of a `ClosureCounter` consists of two
|
||||
* phases: the initial expanding "fork" phase, and the subsequent shrinking
|
||||
* "join" phase.
|
||||
*
|
||||
* In the fork phase, callers register a closure by passing the closure and
|
||||
* receiving a substitute in return. The substitute has the same callable
|
||||
* interface as the closure, and it informs the `ClosureCounter` whenever it
|
||||
* is copied or destroyed, so that it can keep an accurate count of copies.
|
||||
*
|
||||
* The transition to the join phase is made by a call to `join`. In this
|
||||
* phase, every substitute returned going forward will be null, signaling to
|
||||
* the caller that they should drop the closure and cancel their operation.
|
||||
* `join` blocks until all existing closure substitutes are destroyed.
|
||||
*
|
||||
* \tparam Ret_t The return type of the closure.
|
||||
* \tparam Args_t The argument types of the closure.
|
||||
*/
|
||||
template <typename Ret_t, typename... Args_t>
|
||||
class ClosureCounter
|
||||
{
|
||||
private:
|
||||
std::mutex mutable mutex_{};
|
||||
std::condition_variable allClosuresDoneCond_{}; // guard with mutex_
|
||||
bool waitForClosures_{false}; // guard with mutex_
|
||||
std::atomic<int> closureCount_{0};
|
||||
|
||||
// Increment the count.
|
||||
ClosureCounter&
|
||||
operator++()
|
||||
{
|
||||
++closureCount_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Decrement the count. If we're stopping and the count drops to zero
|
||||
// notify allClosuresDoneCond_.
|
||||
ClosureCounter&
|
||||
operator--()
|
||||
{
|
||||
// Even though closureCount_ is atomic, we decrement its value under
|
||||
// a lock. This removes a small timing window that occurs if the
|
||||
// waiting thread is handling a spurious wakeup when closureCount_
|
||||
// drops to zero.
|
||||
std::lock_guard lock{mutex_};
|
||||
|
||||
// Update closureCount_. Notify if stopping and closureCount_ == 0.
|
||||
if ((--closureCount_ == 0) && waitForClosures_)
|
||||
allClosuresDoneCond_.notify_all();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// A private template class that helps count the number of closures
|
||||
// in flight. This allows callers to block until all their postponed
|
||||
// closures are dispatched.
|
||||
template <typename Closure>
|
||||
class Substitute
|
||||
{
|
||||
private:
|
||||
ClosureCounter& counter_;
|
||||
std::remove_reference_t<Closure> closure_;
|
||||
|
||||
static_assert(
|
||||
std::is_same<decltype(closure_(std::declval<Args_t>()...)), Ret_t>::
|
||||
value,
|
||||
"Closure arguments don't match ClosureCounter Ret_t or Args_t");
|
||||
|
||||
public:
|
||||
Substitute() = delete;
|
||||
|
||||
Substitute(Substitute const& rhs)
|
||||
: counter_(rhs.counter_), closure_(rhs.closure_)
|
||||
{
|
||||
++counter_;
|
||||
}
|
||||
|
||||
Substitute(Substitute&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible<Closure>::value)
|
||||
: counter_(rhs.counter_), closure_(std::move(rhs.closure_))
|
||||
{
|
||||
++counter_;
|
||||
}
|
||||
|
||||
Substitute(ClosureCounter& counter, Closure&& closure)
|
||||
: counter_(counter), closure_(std::forward<Closure>(closure))
|
||||
{
|
||||
++counter_;
|
||||
}
|
||||
|
||||
Substitute&
|
||||
operator=(Substitute const& rhs) = delete;
|
||||
Substitute&
|
||||
operator=(Substitute&& rhs) = delete;
|
||||
|
||||
~Substitute()
|
||||
{
|
||||
--counter_;
|
||||
}
|
||||
|
||||
// Note that Args_t is not deduced, it is explicit. So Args_t&&
|
||||
// would be an rvalue reference, not a forwarding reference. We
|
||||
// want to forward exactly what the user declared.
|
||||
Ret_t
|
||||
operator()(Args_t... args)
|
||||
{
|
||||
return closure_(std::forward<Args_t>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
ClosureCounter() = default;
|
||||
// Not copyable or movable. Outstanding counts would be hard to sort out.
|
||||
ClosureCounter(ClosureCounter const&) = delete;
|
||||
|
||||
ClosureCounter&
|
||||
operator=(ClosureCounter const&) = delete;
|
||||
|
||||
/** Destructor verifies all in-flight closures are complete. */
|
||||
~ClosureCounter()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
join("ClosureCounter", 1s, debugLog());
|
||||
}
|
||||
|
||||
/** Returns once all counted in-flight closures are destroyed.
|
||||
|
||||
@param name Name reported if join time exceeds wait.
|
||||
@param wait If join() exceeds this duration report to Journal.
|
||||
@param j Journal written to if wait is exceeded.
|
||||
*/
|
||||
void
|
||||
join(char const* name, std::chrono::milliseconds wait, beast::Journal j)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{mutex_};
|
||||
waitForClosures_ = true;
|
||||
if (closureCount_ > 0)
|
||||
{
|
||||
if (!allClosuresDoneCond_.wait_for(
|
||||
lock, wait, [this] { return closureCount_ == 0; }))
|
||||
{
|
||||
if (auto stream = j.error())
|
||||
stream << name << " waiting for ClosureCounter::join().";
|
||||
allClosuresDoneCond_.wait(
|
||||
lock, [this] { return closureCount_ == 0; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Wrap the passed closure with a reference counter.
|
||||
|
||||
@param closure Closure that accepts Args_t parameters and returns Ret_t.
|
||||
@return If join() has been called returns std::nullopt. Otherwise
|
||||
returns a std::optional that wraps closure with a
|
||||
reference counter.
|
||||
*/
|
||||
template <class Closure>
|
||||
std::optional<Substitute<Closure>>
|
||||
wrap(Closure&& closure)
|
||||
{
|
||||
std::optional<Substitute<Closure>> ret;
|
||||
|
||||
std::lock_guard lock{mutex_};
|
||||
if (!waitForClosures_)
|
||||
ret.emplace(*this, std::forward<Closure>(closure));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Current number of Closures outstanding. Only useful for testing. */
|
||||
int
|
||||
count() const
|
||||
{
|
||||
return closureCount_;
|
||||
}
|
||||
|
||||
/** Returns true if this has been joined.
|
||||
|
||||
Even if true is returned, counted closures may still be in flight.
|
||||
However if (joined() && (count() == 0)) there should be no more
|
||||
counted closures in flight.
|
||||
*/
|
||||
bool
|
||||
joined() const
|
||||
{
|
||||
std::lock_guard lock{mutex_};
|
||||
return waitForClosures_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_CORE_CLOSURE_COUNTER_H_INCLUDED
|
||||
133
include/xrpl/core/Coro.ipp
Normal file
133
include/xrpl/core/Coro.ipp
Normal file
@@ -0,0 +1,133 @@
|
||||
#ifndef XRPL_CORE_COROINL_H_INCLUDED
|
||||
#define XRPL_CORE_COROINL_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <class F>
|
||||
JobQueue::Coro::Coro(
|
||||
Coro_create_t,
|
||||
JobQueue& jq,
|
||||
JobType type,
|
||||
std::string const& name,
|
||||
F&& f)
|
||||
: jq_(jq)
|
||||
, type_(type)
|
||||
, name_(name)
|
||||
, running_(false)
|
||||
, coro_(
|
||||
[this, fn = std::forward<F>(f)](
|
||||
boost::coroutines::asymmetric_coroutine<void>::push_type&
|
||||
do_yield) {
|
||||
yield_ = &do_yield;
|
||||
yield();
|
||||
fn(shared_from_this());
|
||||
#ifndef NDEBUG
|
||||
finished_ = true;
|
||||
#endif
|
||||
},
|
||||
boost::coroutines::attributes(megabytes(1)))
|
||||
{
|
||||
}
|
||||
|
||||
inline JobQueue::Coro::~Coro()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
XRPL_ASSERT(finished_, "xrpl::JobQueue::Coro::~Coro : is finished");
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void
|
||||
JobQueue::Coro::yield() const
|
||||
{
|
||||
{
|
||||
std::lock_guard lock(jq_.m_mutex);
|
||||
++jq_.nSuspend_;
|
||||
}
|
||||
(*yield_)();
|
||||
}
|
||||
|
||||
inline bool
|
||||
JobQueue::Coro::post()
|
||||
{
|
||||
{
|
||||
std::lock_guard lk(mutex_run_);
|
||||
running_ = true;
|
||||
}
|
||||
|
||||
// sp keeps 'this' alive
|
||||
if (jq_.addJob(
|
||||
type_, name_, [this, sp = shared_from_this()]() { resume(); }))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// The coroutine will not run. Clean up running_.
|
||||
std::lock_guard lk(mutex_run_);
|
||||
running_ = false;
|
||||
cv_.notify_all();
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void
|
||||
JobQueue::Coro::resume()
|
||||
{
|
||||
{
|
||||
std::lock_guard lk(mutex_run_);
|
||||
running_ = true;
|
||||
}
|
||||
{
|
||||
std::lock_guard lock(jq_.m_mutex);
|
||||
--jq_.nSuspend_;
|
||||
}
|
||||
auto saved = detail::getLocalValues().release();
|
||||
detail::getLocalValues().reset(&lvs_);
|
||||
std::lock_guard lock(mutex_);
|
||||
XRPL_ASSERT(
|
||||
static_cast<bool>(coro_), "xrpl::JobQueue::Coro::resume : is runnable");
|
||||
coro_();
|
||||
detail::getLocalValues().release();
|
||||
detail::getLocalValues().reset(saved);
|
||||
std::lock_guard lk(mutex_run_);
|
||||
running_ = false;
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
inline bool
|
||||
JobQueue::Coro::runnable() const
|
||||
{
|
||||
return static_cast<bool>(coro_);
|
||||
}
|
||||
|
||||
inline void
|
||||
JobQueue::Coro::expectEarlyExit()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (!finished_)
|
||||
#endif
|
||||
{
|
||||
// expectEarlyExit() must only ever be called from outside the
|
||||
// Coro's stack. It you're inside the stack you can simply return
|
||||
// and be done.
|
||||
//
|
||||
// That said, since we're outside the Coro's stack, we need to
|
||||
// decrement the nSuspend that the Coro's call to yield caused.
|
||||
std::lock_guard lock(jq_.m_mutex);
|
||||
--jq_.nSuspend_;
|
||||
#ifndef NDEBUG
|
||||
finished_ = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
JobQueue::Coro::join()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutex_run_);
|
||||
cv_.wait(lk, [this]() { return running_ == false; });
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
136
include/xrpl/core/Job.h
Normal file
136
include/xrpl/core/Job.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef XRPL_CORE_JOB_H_INCLUDED
|
||||
#define XRPL_CORE_JOB_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/core/ClosureCounter.h>
|
||||
#include <xrpl/core/LoadMonitor.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Note that this queue should only be used for CPU-bound jobs
|
||||
// It is primarily intended for signature checking
|
||||
|
||||
enum JobType {
|
||||
// Special type indicating an invalid job - will go away soon.
|
||||
jtINVALID = -1,
|
||||
|
||||
// Job types - the position in this enum indicates the job priority with
|
||||
// earlier jobs having lower priority than later jobs. If you wish to
|
||||
// insert a job at a specific priority, simply add it at the right location.
|
||||
|
||||
jtPACK, // Make a fetch pack for a peer
|
||||
jtPUBOLDLEDGER, // An old ledger has been accepted
|
||||
jtCLIENT, // A placeholder for the priority of all jtCLIENT jobs
|
||||
jtCLIENT_SUBSCRIBE, // A websocket subscription by a client
|
||||
jtCLIENT_FEE_CHANGE, // Subscription for fee change by a client
|
||||
jtCLIENT_CONSENSUS, // Subscription for consensus state change by a client
|
||||
jtCLIENT_ACCT_HIST, // Subscription for account history by a client
|
||||
jtCLIENT_RPC, // Client RPC request
|
||||
jtCLIENT_WEBSOCKET, // Client websocket request
|
||||
jtRPC, // A websocket command from the client
|
||||
jtSWEEP, // Sweep for stale structures
|
||||
jtVALIDATION_ut, // A validation from an untrusted source
|
||||
jtMANIFEST, // A validator's manifest
|
||||
jtUPDATE_PF, // Update pathfinding requests
|
||||
jtTRANSACTION_l, // A local transaction
|
||||
jtREPLAY_REQ, // Peer request a ledger delta or a skip list
|
||||
jtLEDGER_REQ, // Peer request ledger/txnset data
|
||||
jtPROPOSAL_ut, // A proposal from an untrusted source
|
||||
jtREPLAY_TASK, // A Ledger replay task/subtask
|
||||
jtTRANSACTION, // A transaction received from the network
|
||||
jtMISSING_TXN, // Request missing transactions
|
||||
jtREQUESTED_TXN, // Reply with requested transactions
|
||||
jtBATCH, // Apply batched transactions
|
||||
jtLEDGER_DATA, // Received data for a ledger we're acquiring
|
||||
jtADVANCE, // Advance validated/acquired ledgers
|
||||
jtPUBLEDGER, // Publish a fully-accepted ledger
|
||||
jtTXN_DATA, // Fetch a proposed set
|
||||
jtWAL, // Write-ahead logging
|
||||
jtVALIDATION_t, // A validation from a trusted source
|
||||
jtWRITE, // Write out hashed objects
|
||||
jtACCEPT, // Accept a consensus ledger
|
||||
jtPROPOSAL_t, // A proposal from a trusted source
|
||||
jtNETOP_CLUSTER, // NetworkOPs cluster peer report
|
||||
jtNETOP_TIMER, // NetworkOPs net timer processing
|
||||
jtADMIN, // An administrative operation
|
||||
|
||||
// Special job types which are not dispatched by the job pool
|
||||
jtPEER,
|
||||
jtDISK,
|
||||
jtTXN_PROC,
|
||||
jtOB_SETUP,
|
||||
jtPATH_FIND,
|
||||
jtHO_READ,
|
||||
jtHO_WRITE,
|
||||
jtGENERIC, // Used just to measure time
|
||||
|
||||
// Node store monitoring
|
||||
jtNS_SYNC_READ,
|
||||
jtNS_ASYNC_READ,
|
||||
jtNS_WRITE,
|
||||
};
|
||||
|
||||
class Job : public CountedObject<Job>
|
||||
{
|
||||
public:
|
||||
using clock_type = std::chrono::steady_clock;
|
||||
|
||||
/** Default constructor.
|
||||
|
||||
Allows Job to be used as a container type.
|
||||
|
||||
This is used to allow things like jobMap [key] = value.
|
||||
*/
|
||||
// VFALCO NOTE I'd prefer not to have a default constructed object.
|
||||
// What is the semantic meaning of a Job with no associated
|
||||
// function? Having the invariant "all Job objects refer to
|
||||
// a job" would reduce the number of states.
|
||||
//
|
||||
Job();
|
||||
|
||||
Job(JobType type, std::uint64_t index);
|
||||
|
||||
// VFALCO TODO try to remove the dependency on LoadMonitor.
|
||||
Job(JobType type,
|
||||
std::string const& name,
|
||||
std::uint64_t index,
|
||||
LoadMonitor& lm,
|
||||
std::function<void()> const& job);
|
||||
|
||||
JobType
|
||||
getType() const;
|
||||
|
||||
/** Returns the time when the job was queued. */
|
||||
clock_type::time_point const&
|
||||
queue_time() const;
|
||||
|
||||
void
|
||||
doJob();
|
||||
|
||||
// These comparison operators make the jobs sort in priority order
|
||||
// in the job set
|
||||
bool
|
||||
operator<(Job const& j) const;
|
||||
bool
|
||||
operator>(Job const& j) const;
|
||||
bool
|
||||
operator<=(Job const& j) const;
|
||||
bool
|
||||
operator>=(Job const& j) const;
|
||||
|
||||
private:
|
||||
JobType mType;
|
||||
std::uint64_t mJobIndex;
|
||||
std::function<void()> mJob;
|
||||
std::shared_ptr<LoadEvent> m_loadEvent;
|
||||
std::string mName;
|
||||
clock_type::time_point m_queue_time;
|
||||
};
|
||||
|
||||
using JobCounter = ClosureCounter<void>;
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
413
include/xrpl/core/JobQueue.h
Normal file
413
include/xrpl/core/JobQueue.h
Normal file
@@ -0,0 +1,413 @@
|
||||
#ifndef XRPL_CORE_JOBQUEUE_H_INCLUDED
|
||||
#define XRPL_CORE_JOBQUEUE_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/LocalValue.h>
|
||||
#include <xrpl/core/ClosureCounter.h>
|
||||
#include <xrpl/core/JobTypeData.h>
|
||||
#include <xrpl/core/JobTypes.h>
|
||||
#include <xrpl/core/detail/Workers.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <boost/coroutine/all.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace perf {
|
||||
class PerfLog;
|
||||
}
|
||||
|
||||
class Logs;
|
||||
struct Coro_create_t
|
||||
{
|
||||
explicit Coro_create_t() = default;
|
||||
};
|
||||
|
||||
/** A pool of threads to perform work.
|
||||
|
||||
A job posted will always run to completion.
|
||||
|
||||
Coroutines that are suspended must be resumed,
|
||||
and run to completion.
|
||||
|
||||
When the JobQueue stops, it waits for all jobs
|
||||
and coroutines to finish.
|
||||
*/
|
||||
class JobQueue : private Workers::Callback
|
||||
{
|
||||
public:
|
||||
/** Coroutines must run to completion. */
|
||||
class Coro : public std::enable_shared_from_this<Coro>
|
||||
{
|
||||
private:
|
||||
detail::LocalValues lvs_;
|
||||
JobQueue& jq_;
|
||||
JobType type_;
|
||||
std::string name_;
|
||||
bool running_;
|
||||
std::mutex mutex_;
|
||||
std::mutex mutex_run_;
|
||||
std::condition_variable cv_;
|
||||
boost::coroutines::asymmetric_coroutine<void>::pull_type coro_;
|
||||
boost::coroutines::asymmetric_coroutine<void>::push_type* yield_;
|
||||
#ifndef NDEBUG
|
||||
bool finished_ = false;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Private: Used in the implementation
|
||||
template <class F>
|
||||
Coro(Coro_create_t, JobQueue&, JobType, std::string const&, F&&);
|
||||
|
||||
// Not copy-constructible or assignable
|
||||
Coro(Coro const&) = delete;
|
||||
Coro&
|
||||
operator=(Coro const&) = delete;
|
||||
|
||||
~Coro();
|
||||
|
||||
/** Suspend coroutine execution.
|
||||
Effects:
|
||||
The coroutine's stack is saved.
|
||||
The associated Job thread is released.
|
||||
Note:
|
||||
The associated Job function returns.
|
||||
Undefined behavior if called consecutively without a corresponding
|
||||
post.
|
||||
*/
|
||||
void
|
||||
yield() const;
|
||||
|
||||
/** Schedule coroutine execution.
|
||||
Effects:
|
||||
Returns immediately.
|
||||
A new job is scheduled to resume the execution of the coroutine.
|
||||
When the job runs, the coroutine's stack is restored and execution
|
||||
continues at the beginning of coroutine function or the
|
||||
statement after the previous call to yield. Undefined behavior if
|
||||
called after the coroutine has completed with a return (as opposed to
|
||||
a yield()). Undefined behavior if post() or resume() called
|
||||
consecutively without a corresponding yield.
|
||||
|
||||
@return true if the Coro's job is added to the JobQueue.
|
||||
*/
|
||||
bool
|
||||
post();
|
||||
|
||||
/** Resume coroutine execution.
|
||||
Effects:
|
||||
The coroutine continues execution from where it last left off
|
||||
using this same thread.
|
||||
Undefined behavior if called after the coroutine has completed
|
||||
with a return (as opposed to a yield()).
|
||||
Undefined behavior if resume() or post() called consecutively
|
||||
without a corresponding yield.
|
||||
*/
|
||||
void
|
||||
resume();
|
||||
|
||||
/** Returns true if the Coro is still runnable (has not returned). */
|
||||
bool
|
||||
runnable() const;
|
||||
|
||||
/** Once called, the Coro allows early exit without an assert. */
|
||||
void
|
||||
expectEarlyExit();
|
||||
|
||||
/** Waits until coroutine returns from the user function. */
|
||||
void
|
||||
join();
|
||||
};
|
||||
|
||||
using JobFunction = std::function<void()>;
|
||||
|
||||
JobQueue(
|
||||
int threadCount,
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
beast::Journal journal,
|
||||
Logs& logs,
|
||||
perf::PerfLog& perfLog);
|
||||
~JobQueue();
|
||||
|
||||
/** Adds a job to the JobQueue.
|
||||
|
||||
@param type The type of job.
|
||||
@param name Name of the job.
|
||||
@param jobHandler Lambda with signature void (Job&). Called when the
|
||||
job is executed.
|
||||
|
||||
@return true if jobHandler added to queue.
|
||||
*/
|
||||
template <
|
||||
typename JobHandler,
|
||||
typename = std::enable_if_t<std::is_same<
|
||||
decltype(std::declval<JobHandler&&>()()),
|
||||
void>::value>>
|
||||
bool
|
||||
addJob(JobType type, std::string const& name, JobHandler&& jobHandler)
|
||||
{
|
||||
if (auto optionalCountedJob =
|
||||
jobCounter_.wrap(std::forward<JobHandler>(jobHandler)))
|
||||
{
|
||||
return addRefCountedJob(type, name, std::move(*optionalCountedJob));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Creates a coroutine and adds a job to the queue which will run it.
|
||||
|
||||
@param t The type of job.
|
||||
@param name Name of the job.
|
||||
@param f Has a signature of void(std::shared_ptr<Coro>). Called when the
|
||||
job executes.
|
||||
|
||||
@return shared_ptr to posted Coro. nullptr if post was not successful.
|
||||
*/
|
||||
template <class F>
|
||||
std::shared_ptr<Coro>
|
||||
postCoro(JobType t, std::string const& name, F&& f);
|
||||
|
||||
/** Jobs waiting at this priority.
|
||||
*/
|
||||
int
|
||||
getJobCount(JobType t) const;
|
||||
|
||||
/** Jobs waiting plus running at this priority.
|
||||
*/
|
||||
int
|
||||
getJobCountTotal(JobType t) const;
|
||||
|
||||
/** All waiting jobs at or greater than this priority.
|
||||
*/
|
||||
int
|
||||
getJobCountGE(JobType t) const;
|
||||
|
||||
/** Return a scoped LoadEvent.
|
||||
*/
|
||||
std::unique_ptr<LoadEvent>
|
||||
makeLoadEvent(JobType t, std::string const& name);
|
||||
|
||||
/** Add multiple load events.
|
||||
*/
|
||||
void
|
||||
addLoadEvents(JobType t, int count, std::chrono::milliseconds elapsed);
|
||||
|
||||
// Cannot be const because LoadMonitor has no const methods.
|
||||
bool
|
||||
isOverloaded();
|
||||
|
||||
// Cannot be const because LoadMonitor has no const methods.
|
||||
Json::Value
|
||||
getJson(int c = 0);
|
||||
|
||||
/** Block until no jobs running. */
|
||||
void
|
||||
rendezvous();
|
||||
|
||||
void
|
||||
stop();
|
||||
|
||||
bool
|
||||
isStopping() const
|
||||
{
|
||||
return stopping_;
|
||||
}
|
||||
|
||||
// We may be able to move away from this, but we can keep it during the
|
||||
// transition.
|
||||
bool
|
||||
isStopped() const;
|
||||
|
||||
private:
|
||||
friend class Coro;
|
||||
|
||||
using JobDataMap = std::map<JobType, JobTypeData>;
|
||||
|
||||
beast::Journal m_journal;
|
||||
mutable std::mutex m_mutex;
|
||||
std::uint64_t m_lastJob;
|
||||
std::set<Job> m_jobSet;
|
||||
JobCounter jobCounter_;
|
||||
std::atomic_bool stopping_{false};
|
||||
std::atomic_bool stopped_{false};
|
||||
JobDataMap m_jobData;
|
||||
JobTypeData m_invalidJobData;
|
||||
|
||||
// The number of jobs currently in processTask()
|
||||
int m_processCount;
|
||||
|
||||
// The number of suspended coroutines
|
||||
int nSuspend_ = 0;
|
||||
|
||||
Workers m_workers;
|
||||
|
||||
// Statistics tracking
|
||||
perf::PerfLog& perfLog_;
|
||||
beast::insight::Collector::ptr m_collector;
|
||||
beast::insight::Gauge job_count;
|
||||
beast::insight::Hook hook;
|
||||
|
||||
std::condition_variable cv_;
|
||||
|
||||
void
|
||||
collect();
|
||||
JobTypeData&
|
||||
getJobTypeData(JobType type);
|
||||
|
||||
// Adds a reference counted job to the JobQueue.
|
||||
//
|
||||
// param type The type of job.
|
||||
// param name Name of the job.
|
||||
// param func std::function with signature void (Job&). Called when the
|
||||
// job is executed.
|
||||
//
|
||||
// return true if func added to queue.
|
||||
bool
|
||||
addRefCountedJob(
|
||||
JobType type,
|
||||
std::string const& name,
|
||||
JobFunction const& func);
|
||||
|
||||
// Returns the next Job we should run now.
|
||||
//
|
||||
// RunnableJob:
|
||||
// A Job in the JobSet whose slots count for its type is greater than zero.
|
||||
//
|
||||
// Pre-conditions:
|
||||
// mJobSet must not be empty.
|
||||
// mJobSet holds at least one RunnableJob
|
||||
//
|
||||
// Post-conditions:
|
||||
// job is a valid Job object.
|
||||
// job is removed from mJobQueue.
|
||||
// Waiting job count of its type is decremented
|
||||
// Running job count of its type is incremented
|
||||
//
|
||||
// Invariants:
|
||||
// The calling thread owns the JobLock
|
||||
void
|
||||
getNextJob(Job& job);
|
||||
|
||||
// Indicates that a running Job has completed its task.
|
||||
//
|
||||
// Pre-conditions:
|
||||
// Job must not exist in mJobSet.
|
||||
// The JobType must not be invalid.
|
||||
//
|
||||
// Post-conditions:
|
||||
// The running count of that JobType is decremented
|
||||
// A new task is signaled if there are more waiting Jobs than the limit, if
|
||||
// any.
|
||||
//
|
||||
// Invariants:
|
||||
// <none>
|
||||
void
|
||||
finishJob(JobType type);
|
||||
|
||||
// Runs the next appropriate waiting Job.
|
||||
//
|
||||
// Pre-conditions:
|
||||
// A RunnableJob must exist in the JobSet
|
||||
//
|
||||
// Post-conditions:
|
||||
// The chosen RunnableJob will have Job::doJob() called.
|
||||
//
|
||||
// Invariants:
|
||||
// <none>
|
||||
void
|
||||
processTask(int instance) override;
|
||||
|
||||
// Returns the limit of running jobs for the given job type.
|
||||
// For jobs with no limit, we return the largest int. Hopefully that
|
||||
// will be enough.
|
||||
int
|
||||
getJobLimit(JobType type);
|
||||
};
|
||||
|
||||
/*
|
||||
An RPC command is received and is handled via ServerHandler(HTTP) or
|
||||
Handler(websocket), depending on the connection type. The handler then calls
|
||||
the JobQueue::postCoro() method to create a coroutine and run it at a later
|
||||
point. This frees up the handler thread and allows it to continue handling
|
||||
other requests while the RPC command completes its work asynchronously.
|
||||
|
||||
postCoro() creates a Coro object. When the Coro ctor is called, and its
|
||||
coro_ member is initialized (a boost::coroutines::pull_type), execution
|
||||
automatically passes to the coroutine, which we don't want at this point,
|
||||
since we are still in the handler thread context. It's important to note
|
||||
here that construction of a boost pull_type automatically passes execution to
|
||||
the coroutine. A pull_type object automatically generates a push_type that is
|
||||
passed as a parameter (do_yield) in the signature of the function the
|
||||
pull_type was created with. This function is immediately called during coro_
|
||||
construction and within it, Coro::yield_ is assigned the push_type
|
||||
parameter (do_yield) address and called (yield()) so we can return execution
|
||||
back to the caller's stack.
|
||||
|
||||
postCoro() then calls Coro::post(), which schedules a job on the job
|
||||
queue to continue execution of the coroutine in a JobQueue worker thread at
|
||||
some later time. When the job runs, we lock on the Coro::mutex_ and call
|
||||
coro_ which continues where we had left off. Since we the last thing we did
|
||||
in coro_ was call yield(), the next thing we continue with is calling the
|
||||
function param f, that was passed into Coro ctor. It is within this
|
||||
function body that the caller specifies what he would like to do while
|
||||
running in the coroutine and allow them to suspend and resume execution.
|
||||
A task that relies on other events to complete, such as path finding, calls
|
||||
Coro::yield() to suspend its execution while waiting on those events to
|
||||
complete and continue when signaled via the Coro::post() method.
|
||||
|
||||
There is a potential race condition that exists here where post() can get
|
||||
called before yield() after f is called. Technically the problem only occurs
|
||||
if the job that post() scheduled is executed before yield() is called.
|
||||
If the post() job were to be executed before yield(), undefined behavior
|
||||
would occur. The lock ensures that coro_ is not called again until we exit
|
||||
the coroutine. At which point a scheduled resume() job waiting on the lock
|
||||
would gain entry, harmlessly call coro_ and immediately return as we have
|
||||
already completed the coroutine.
|
||||
|
||||
The race condition occurs as follows:
|
||||
|
||||
1- The coroutine is running.
|
||||
2- The coroutine is about to suspend, but before it can do so, it must
|
||||
arrange for some event to wake it up.
|
||||
3- The coroutine arranges for some event to wake it up.
|
||||
4- Before the coroutine can suspend, that event occurs and the
|
||||
resumption of the coroutine is scheduled on the job queue. 5- Again, before
|
||||
the coroutine can suspend, the resumption of the coroutine is dispatched. 6-
|
||||
Again, before the coroutine can suspend, the resumption code runs the
|
||||
coroutine.
|
||||
The coroutine is now running in two threads.
|
||||
|
||||
The lock prevents this from happening as step 6 will block until the
|
||||
lock is released which only happens after the coroutine completes.
|
||||
*/
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#include <xrpl/core/Coro.ipp>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <class F>
|
||||
std::shared_ptr<JobQueue::Coro>
|
||||
JobQueue::postCoro(JobType t, std::string const& name, F&& f)
|
||||
{
|
||||
/* First param is a detail type to make construction private.
|
||||
Last param is the function the coroutine runs. Signature of
|
||||
void(std::shared_ptr<Coro>).
|
||||
*/
|
||||
auto coro = std::make_shared<Coro>(
|
||||
Coro_create_t{}, *this, t, name, std::forward<F>(f));
|
||||
if (!coro->post())
|
||||
{
|
||||
// The Coro was not successfully posted. Disable it so it's destructor
|
||||
// can run with no negative side effects. Then destroy it.
|
||||
coro->expectEarlyExit();
|
||||
coro.reset();
|
||||
}
|
||||
return coro;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
88
include/xrpl/core/JobTypeData.h
Normal file
88
include/xrpl/core/JobTypeData.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef XRPL_CORE_JOBTYPEDATA_H_INCLUDED
|
||||
#define XRPL_CORE_JOBTYPEDATA_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/insight/Collector.h>
|
||||
#include <xrpl/core/JobTypeInfo.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
struct JobTypeData
|
||||
{
|
||||
private:
|
||||
LoadMonitor m_load;
|
||||
|
||||
/* Support for insight */
|
||||
beast::insight::Collector::ptr m_collector;
|
||||
|
||||
public:
|
||||
/* The job category which we represent */
|
||||
JobTypeInfo const& info;
|
||||
|
||||
/* The number of jobs waiting */
|
||||
int waiting;
|
||||
|
||||
/* The number presently running */
|
||||
int running;
|
||||
|
||||
/* And the number we deferred executing because of job limits */
|
||||
int deferred;
|
||||
|
||||
/* Notification callbacks */
|
||||
beast::insight::Event dequeue;
|
||||
beast::insight::Event execute;
|
||||
|
||||
JobTypeData(
|
||||
JobTypeInfo const& info_,
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
Logs& logs) noexcept
|
||||
: m_load(logs.journal("LoadMonitor"))
|
||||
, m_collector(collector)
|
||||
, info(info_)
|
||||
, waiting(0)
|
||||
, running(0)
|
||||
, deferred(0)
|
||||
{
|
||||
m_load.setTargetLatency(
|
||||
info.getAverageLatency(), info.getPeakLatency());
|
||||
|
||||
if (!info.special())
|
||||
{
|
||||
dequeue = m_collector->make_event(info.name() + "_q");
|
||||
execute = m_collector->make_event(info.name());
|
||||
}
|
||||
}
|
||||
|
||||
/* Not copy-constructible or assignable */
|
||||
JobTypeData(JobTypeData const& other) = delete;
|
||||
JobTypeData&
|
||||
operator=(JobTypeData const& other) = delete;
|
||||
|
||||
std::string
|
||||
name() const
|
||||
{
|
||||
return info.name();
|
||||
}
|
||||
|
||||
JobType
|
||||
type() const
|
||||
{
|
||||
return info.type();
|
||||
}
|
||||
|
||||
LoadMonitor&
|
||||
load()
|
||||
{
|
||||
return m_load;
|
||||
}
|
||||
|
||||
LoadMonitor::Stats
|
||||
stats()
|
||||
{
|
||||
return m_load.getStats();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
83
include/xrpl/core/JobTypeInfo.h
Normal file
83
include/xrpl/core/JobTypeInfo.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef XRPL_CORE_JOBTYPEINFO_H_INCLUDED
|
||||
#define XRPL_CORE_JOBTYPEINFO_H_INCLUDED
|
||||
|
||||
#include <xrpl/core/Job.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/** Holds all the 'static' information about a job, which does not change */
|
||||
class JobTypeInfo
|
||||
{
|
||||
private:
|
||||
JobType const m_type;
|
||||
std::string const m_name;
|
||||
|
||||
/** The limit on the number of running jobs for this job type.
|
||||
|
||||
A limit of 0 marks this as a "special job" which is not
|
||||
dispatched via the job queue.
|
||||
*/
|
||||
int const m_limit;
|
||||
|
||||
/** Average and peak latencies for this job type. 0 is none specified */
|
||||
std::chrono::milliseconds const m_avgLatency;
|
||||
std::chrono::milliseconds const m_peakLatency;
|
||||
|
||||
public:
|
||||
// Not default constructible
|
||||
JobTypeInfo() = delete;
|
||||
|
||||
JobTypeInfo(
|
||||
JobType type,
|
||||
std::string name,
|
||||
int limit,
|
||||
std::chrono::milliseconds avgLatency,
|
||||
std::chrono::milliseconds peakLatency)
|
||||
: m_type(type)
|
||||
, m_name(std::move(name))
|
||||
, m_limit(limit)
|
||||
, m_avgLatency(avgLatency)
|
||||
, m_peakLatency(peakLatency)
|
||||
{
|
||||
}
|
||||
|
||||
JobType
|
||||
type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
std::string const&
|
||||
name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
int
|
||||
limit() const
|
||||
{
|
||||
return m_limit;
|
||||
}
|
||||
|
||||
bool
|
||||
special() const
|
||||
{
|
||||
return m_limit == 0;
|
||||
}
|
||||
|
||||
std::chrono::milliseconds
|
||||
getAverageLatency() const
|
||||
{
|
||||
return m_avgLatency;
|
||||
}
|
||||
|
||||
std::chrono::milliseconds
|
||||
getPeakLatency() const
|
||||
{
|
||||
return m_peakLatency;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
175
include/xrpl/core/JobTypes.h
Normal file
175
include/xrpl/core/JobTypes.h
Normal file
@@ -0,0 +1,175 @@
|
||||
#ifndef XRPL_CORE_JOBTYPES_H_INCLUDED
|
||||
#define XRPL_CORE_JOBTYPES_H_INCLUDED
|
||||
|
||||
#include <xrpl/core/Job.h>
|
||||
#include <xrpl/core/JobTypeInfo.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class JobTypes
|
||||
{
|
||||
public:
|
||||
using Map = std::map<JobType, JobTypeInfo>;
|
||||
using const_iterator = Map::const_iterator;
|
||||
|
||||
private:
|
||||
JobTypes()
|
||||
: m_unknown(
|
||||
jtINVALID,
|
||||
"invalid",
|
||||
0,
|
||||
std::chrono::milliseconds{0},
|
||||
std::chrono::milliseconds{0})
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
int maxLimit = std::numeric_limits<int>::max();
|
||||
|
||||
auto add = [this](
|
||||
JobType jt,
|
||||
std::string name,
|
||||
int limit,
|
||||
std::chrono::milliseconds avgLatency,
|
||||
std::chrono::milliseconds peakLatency) {
|
||||
XRPL_ASSERT(
|
||||
m_map.find(jt) == m_map.end(),
|
||||
"xrpl::JobTypes::JobTypes::add : unique job type input");
|
||||
|
||||
[[maybe_unused]] auto const inserted =
|
||||
m_map
|
||||
.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(jt),
|
||||
std::forward_as_tuple(
|
||||
jt, name, limit, avgLatency, peakLatency))
|
||||
.second;
|
||||
|
||||
XRPL_ASSERT(
|
||||
inserted == true,
|
||||
"xrpl::JobTypes::JobTypes::add : input is inserted");
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
// avg peak
|
||||
// JobType name limit latency latency
|
||||
add(jtPACK, "makeFetchPack", 1, 0ms, 0ms);
|
||||
add(jtPUBOLDLEDGER, "publishAcqLedger", 2, 10000ms, 15000ms);
|
||||
add(jtVALIDATION_ut, "untrustedValidation", maxLimit, 2000ms, 5000ms);
|
||||
add(jtMANIFEST, "manifest", maxLimit, 2000ms, 5000ms);
|
||||
add(jtTRANSACTION_l, "localTransaction", maxLimit, 100ms, 500ms);
|
||||
add(jtREPLAY_REQ, "ledgerReplayRequest", 10, 250ms, 1000ms);
|
||||
add(jtLEDGER_REQ, "ledgerRequest", 3, 0ms, 0ms);
|
||||
add(jtPROPOSAL_ut, "untrustedProposal", maxLimit, 500ms, 1250ms);
|
||||
add(jtREPLAY_TASK, "ledgerReplayTask", maxLimit, 0ms, 0ms);
|
||||
add(jtLEDGER_DATA, "ledgerData", 3, 0ms, 0ms);
|
||||
add(jtCLIENT, "clientCommand", maxLimit, 2000ms, 5000ms);
|
||||
add(jtCLIENT_SUBSCRIBE, "clientSubscribe", maxLimit, 2000ms, 5000ms);
|
||||
add(jtCLIENT_FEE_CHANGE, "clientFeeChange", maxLimit, 2000ms, 5000ms);
|
||||
add(jtCLIENT_CONSENSUS, "clientConsensus", maxLimit, 2000ms, 5000ms);
|
||||
add(jtCLIENT_ACCT_HIST, "clientAccountHistory", maxLimit, 2000ms, 5000ms);
|
||||
add(jtCLIENT_RPC, "clientRPC", maxLimit, 2000ms, 5000ms);
|
||||
add(jtCLIENT_WEBSOCKET, "clientWebsocket", maxLimit, 2000ms, 5000ms);
|
||||
add(jtRPC, "RPC", maxLimit, 0ms, 0ms);
|
||||
add(jtUPDATE_PF, "updatePaths", 1, 0ms, 0ms);
|
||||
add(jtTRANSACTION, "transaction", maxLimit, 250ms, 1000ms);
|
||||
add(jtBATCH, "batch", maxLimit, 250ms, 1000ms);
|
||||
add(jtADVANCE, "advanceLedger", maxLimit, 0ms, 0ms);
|
||||
add(jtPUBLEDGER, "publishNewLedger", maxLimit, 3000ms, 4500ms);
|
||||
add(jtTXN_DATA, "fetchTxnData", 5, 0ms, 0ms);
|
||||
add(jtWAL, "writeAhead", maxLimit, 1000ms, 2500ms);
|
||||
add(jtVALIDATION_t, "trustedValidation", maxLimit, 500ms, 1500ms);
|
||||
add(jtWRITE, "writeObjects", maxLimit, 1750ms, 2500ms);
|
||||
add(jtACCEPT, "acceptLedger", maxLimit, 0ms, 0ms);
|
||||
add(jtPROPOSAL_t, "trustedProposal", maxLimit, 100ms, 500ms);
|
||||
add(jtSWEEP, "sweep", 1, 0ms, 0ms);
|
||||
add(jtNETOP_CLUSTER, "clusterReport", 1, 9999ms, 9999ms);
|
||||
add(jtNETOP_TIMER, "heartbeat", 1, 999ms, 999ms);
|
||||
add(jtADMIN, "administration", maxLimit, 0ms, 0ms);
|
||||
add(jtMISSING_TXN, "handleHaveTransactions", 1200, 0ms, 0ms);
|
||||
add(jtREQUESTED_TXN, "doTransactions", 1200, 0ms, 0ms);
|
||||
|
||||
add(jtPEER, "peerCommand", 0, 200ms, 2500ms);
|
||||
add(jtDISK, "diskAccess", 0, 500ms, 1000ms);
|
||||
add(jtTXN_PROC, "processTransaction", 0, 0ms, 0ms);
|
||||
add(jtOB_SETUP, "orderBookSetup", 0, 0ms, 0ms);
|
||||
add(jtPATH_FIND, "pathFind", 0, 0ms, 0ms);
|
||||
add(jtHO_READ, "nodeRead", 0, 0ms, 0ms);
|
||||
add(jtHO_WRITE, "nodeWrite", 0, 0ms, 0ms);
|
||||
add(jtGENERIC, "generic", 0, 0ms, 0ms);
|
||||
add(jtNS_SYNC_READ, "SyncReadNode", 0, 0ms, 0ms);
|
||||
add(jtNS_ASYNC_READ, "AsyncReadNode", 0, 0ms, 0ms);
|
||||
add(jtNS_WRITE, "WriteNode", 0, 0ms, 0ms);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
public:
|
||||
static JobTypes const&
|
||||
instance()
|
||||
{
|
||||
static JobTypes const types;
|
||||
return types;
|
||||
}
|
||||
|
||||
static std::string const&
|
||||
name(JobType jt)
|
||||
{
|
||||
return instance().get(jt).name();
|
||||
}
|
||||
|
||||
JobTypeInfo const&
|
||||
get(JobType jt) const
|
||||
{
|
||||
Map::const_iterator const iter(m_map.find(jt));
|
||||
XRPL_ASSERT(iter != m_map.end(), "xrpl::JobTypes::get : valid input");
|
||||
|
||||
if (iter != m_map.end())
|
||||
return iter->second;
|
||||
|
||||
return m_unknown;
|
||||
}
|
||||
|
||||
JobTypeInfo const&
|
||||
getInvalid() const
|
||||
{
|
||||
return m_unknown;
|
||||
}
|
||||
|
||||
Map::size_type
|
||||
size() const
|
||||
{
|
||||
return m_map.size();
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return m_map.cbegin();
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cbegin() const
|
||||
{
|
||||
return m_map.cbegin();
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return m_map.cend();
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cend() const
|
||||
{
|
||||
return m_map.cend();
|
||||
}
|
||||
|
||||
JobTypeInfo m_unknown;
|
||||
Map m_map;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
70
include/xrpl/core/LoadEvent.h
Normal file
70
include/xrpl/core/LoadEvent.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef XRPL_CORE_LOADEVENT_H_INCLUDED
|
||||
#define XRPL_CORE_LOADEVENT_H_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class LoadMonitor;
|
||||
|
||||
// VFALCO NOTE What is the difference between a LoadEvent and a LoadMonitor?
|
||||
// VFALCO TODO Rename LoadEvent to ScopedLoadSample
|
||||
//
|
||||
// This looks like a scoped elapsed time measuring class
|
||||
//
|
||||
class LoadEvent
|
||||
{
|
||||
public:
|
||||
// VFALCO TODO remove the dependency on LoadMonitor. Is that possible?
|
||||
LoadEvent(LoadMonitor& monitor, std::string const& name, bool shouldStart);
|
||||
LoadEvent(LoadEvent const&) = delete;
|
||||
|
||||
~LoadEvent();
|
||||
|
||||
std::string const&
|
||||
name() const;
|
||||
|
||||
// The time spent waiting.
|
||||
std::chrono::steady_clock::duration
|
||||
waitTime() const;
|
||||
|
||||
// The time spent running.
|
||||
std::chrono::steady_clock::duration
|
||||
runTime() const;
|
||||
|
||||
void
|
||||
setName(std::string const& name);
|
||||
|
||||
// Start the measurement. If already started, then
|
||||
// restart, assigning the elapsed time to the "waiting"
|
||||
// state.
|
||||
void
|
||||
start();
|
||||
|
||||
// Stop the measurement and report the results. The
|
||||
// time reported is measured from the last call to
|
||||
// start.
|
||||
void
|
||||
stop();
|
||||
|
||||
private:
|
||||
LoadMonitor& monitor_;
|
||||
|
||||
// Represents our current state
|
||||
bool running_;
|
||||
|
||||
// The name associated with this event, if any.
|
||||
std::string name_;
|
||||
|
||||
// Represents the time we last transitioned states
|
||||
std::chrono::steady_clock::time_point mark_;
|
||||
|
||||
// The time we spent waiting and running respectively
|
||||
std::chrono::steady_clock::duration timeWaiting_;
|
||||
std::chrono::steady_clock::duration timeRunning_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
72
include/xrpl/core/LoadMonitor.h
Normal file
72
include/xrpl/core/LoadMonitor.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef XRPL_CORE_LOADMONITOR_H_INCLUDED
|
||||
#define XRPL_CORE_LOADMONITOR_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/UptimeClock.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/core/LoadEvent.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Monitors load levels and response times
|
||||
|
||||
// VFALCO TODO Rename this. Having both LoadManager and LoadMonitor is
|
||||
// confusing.
|
||||
//
|
||||
class LoadMonitor
|
||||
{
|
||||
public:
|
||||
explicit LoadMonitor(beast::Journal j);
|
||||
|
||||
void
|
||||
addLoadSample(LoadEvent const& sample);
|
||||
|
||||
void
|
||||
addSamples(int count, std::chrono::milliseconds latency);
|
||||
|
||||
void
|
||||
setTargetLatency(
|
||||
std::chrono::milliseconds avg,
|
||||
std::chrono::milliseconds pk);
|
||||
|
||||
bool
|
||||
isOverTarget(std::chrono::milliseconds avg, std::chrono::milliseconds peak);
|
||||
|
||||
// VFALCO TODO make this return the values in a struct.
|
||||
struct Stats
|
||||
{
|
||||
Stats();
|
||||
|
||||
std::uint64_t count;
|
||||
std::chrono::milliseconds latencyAvg;
|
||||
std::chrono::milliseconds latencyPeak;
|
||||
bool isOverloaded;
|
||||
};
|
||||
|
||||
Stats
|
||||
getStats();
|
||||
|
||||
bool
|
||||
isOver();
|
||||
|
||||
private:
|
||||
void
|
||||
update();
|
||||
|
||||
std::mutex mutex_;
|
||||
|
||||
std::uint64_t mCounts;
|
||||
int mLatencyEvents;
|
||||
std::chrono::milliseconds mLatencyMSAvg;
|
||||
std::chrono::milliseconds mLatencyMSPeak;
|
||||
std::chrono::milliseconds mTargetLatencyAvg;
|
||||
std::chrono::milliseconds mTargetLatencyPk;
|
||||
UptimeClock::time_point mLastUpdate;
|
||||
beast::Journal const j_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
192
include/xrpl/core/PerfLog.h
Normal file
192
include/xrpl/core/PerfLog.h
Normal file
@@ -0,0 +1,192 @@
|
||||
#ifndef XRPL_CORE_PERFLOG_H
|
||||
#define XRPL_CORE_PERFLOG_H
|
||||
|
||||
#include <xrpl/basics/BasicConfig.h>
|
||||
#include <xrpl/core/JobTypes.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
class Journal;
|
||||
}
|
||||
|
||||
namespace xrpl {
|
||||
class Application;
|
||||
namespace perf {
|
||||
|
||||
/**
|
||||
* Singleton class that maintains performance counters and optionally
|
||||
* writes Json-formatted data to a distinct log. It should exist prior
|
||||
* to other objects launched by Application to make it accessible for
|
||||
* performance logging.
|
||||
*/
|
||||
|
||||
class PerfLog
|
||||
{
|
||||
public:
|
||||
using steady_clock = std::chrono::steady_clock;
|
||||
using system_clock = std::chrono::system_clock;
|
||||
using steady_time_point = std::chrono::time_point<steady_clock>;
|
||||
using system_time_point = std::chrono::time_point<system_clock>;
|
||||
using seconds = std::chrono::seconds;
|
||||
using milliseconds = std::chrono::milliseconds;
|
||||
using microseconds = std::chrono::microseconds;
|
||||
|
||||
/**
|
||||
* Configuration from [perf] section of rippled.cfg.
|
||||
*/
|
||||
struct Setup
|
||||
{
|
||||
boost::filesystem::path perfLog;
|
||||
// log_interval is in milliseconds to support faster testing.
|
||||
milliseconds logInterval{seconds(1)};
|
||||
};
|
||||
|
||||
virtual ~PerfLog() = default;
|
||||
|
||||
virtual void
|
||||
start()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
stop()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Log start of RPC call.
|
||||
*
|
||||
* @param method RPC command
|
||||
* @param requestId Unique identifier to track command
|
||||
*/
|
||||
virtual void
|
||||
rpcStart(std::string const& method, std::uint64_t requestId) = 0;
|
||||
|
||||
/**
|
||||
* Log successful finish of RPC call
|
||||
*
|
||||
* @param method RPC command
|
||||
* @param requestId Unique identifier to track command
|
||||
*/
|
||||
virtual void
|
||||
rpcFinish(std::string const& method, std::uint64_t requestId) = 0;
|
||||
|
||||
/**
|
||||
* Log errored RPC call
|
||||
*
|
||||
* @param method RPC command
|
||||
* @param requestId Unique identifier to track command
|
||||
*/
|
||||
virtual void
|
||||
rpcError(std::string const& method, std::uint64_t requestId) = 0;
|
||||
|
||||
/**
|
||||
* Log queued job
|
||||
*
|
||||
* @param type Job type
|
||||
*/
|
||||
virtual void
|
||||
jobQueue(JobType const type) = 0;
|
||||
|
||||
/**
|
||||
* Log job executing
|
||||
*
|
||||
* @param type Job type
|
||||
* @param dur Duration enqueued in microseconds
|
||||
* @param startTime Time that execution began
|
||||
* @param instance JobQueue worker thread instance
|
||||
*/
|
||||
virtual void
|
||||
jobStart(
|
||||
JobType const type,
|
||||
microseconds dur,
|
||||
steady_time_point startTime,
|
||||
int instance) = 0;
|
||||
|
||||
/**
|
||||
* Log job finishing
|
||||
*
|
||||
* @param type Job type
|
||||
* @param dur Duration running in microseconds
|
||||
* @param instance Jobqueue worker thread instance
|
||||
*/
|
||||
virtual void
|
||||
jobFinish(JobType const type, microseconds dur, int instance) = 0;
|
||||
|
||||
/**
|
||||
* Render performance counters in Json
|
||||
*
|
||||
* @return Counters Json object
|
||||
*/
|
||||
virtual Json::Value
|
||||
countersJson() const = 0;
|
||||
|
||||
/**
|
||||
* Render currently executing jobs and RPC calls and durations in Json
|
||||
*
|
||||
* @return Current executing jobs and RPC calls and durations
|
||||
*/
|
||||
virtual Json::Value
|
||||
currentJson() const = 0;
|
||||
|
||||
/**
|
||||
* Ensure enough room to store each currently executing job
|
||||
*
|
||||
* @param resize Number of JobQueue worker threads
|
||||
*/
|
||||
virtual void
|
||||
resizeJobs(int const resize) = 0;
|
||||
|
||||
/**
|
||||
* Rotate perf log file
|
||||
*/
|
||||
virtual void
|
||||
rotate() = 0;
|
||||
};
|
||||
|
||||
PerfLog::Setup
|
||||
setup_PerfLog(Section const& section, boost::filesystem::path const& configDir);
|
||||
|
||||
std::unique_ptr<PerfLog>
|
||||
make_PerfLog(
|
||||
PerfLog::Setup const& setup,
|
||||
Application& app,
|
||||
beast::Journal journal,
|
||||
std::function<void()>&& signalStop);
|
||||
|
||||
template <typename Func, class Rep, class Period>
|
||||
auto
|
||||
measureDurationAndLog(
|
||||
Func&& func,
|
||||
std::string const& actionDescription,
|
||||
std::chrono::duration<Rep, Period> maxDelay,
|
||||
beast::Journal const& journal)
|
||||
{
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto result = func();
|
||||
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
end_time - start_time);
|
||||
if (duration > maxDelay)
|
||||
{
|
||||
JLOG(journal.warn())
|
||||
<< actionDescription << " took " << duration.count() << " ms";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace perf
|
||||
} // namespace xrpl
|
||||
|
||||
#endif // XRPL_CORE_PERFLOG_H
|
||||
219
include/xrpl/core/detail/Workers.h
Normal file
219
include/xrpl/core/detail/Workers.h
Normal file
@@ -0,0 +1,219 @@
|
||||
#ifndef XRPL_CORE_WORKERS_H_INCLUDED
|
||||
#define XRPL_CORE_WORKERS_H_INCLUDED
|
||||
|
||||
#include <xrpl/beast/core/LockFreeStack.h>
|
||||
#include <xrpl/core/detail/semaphore.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace perf {
|
||||
class PerfLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* `Workers` is effectively a thread pool. The constructor takes a "callback"
|
||||
* that has a `void processTask(int instance)` method, and a number of
|
||||
* workers. It creates that many `Worker`s and then waits for calls to
|
||||
* `Workers::addTask()`. It holds a semaphore that counts the number of
|
||||
* pending "tasks", and a condition variable for the event when the last
|
||||
* worker pauses itself.
|
||||
*
|
||||
* A "task" is just a call to the callback's `processTask` method.
|
||||
* "Adding a task" means calling that method now, or remembering to call it in
|
||||
* the future.
|
||||
* This is implemented with a semaphore.
|
||||
* If there are any workers waiting when a task is added, then one will be
|
||||
* woken to claim the task.
|
||||
* If not, then the next worker to wait on the semaphore will claim the task.
|
||||
*
|
||||
* Creating a `Worker` creates a thread that calls `Worker::run()`. When that
|
||||
* thread enters `Worker::run`, it increments the count of active workers in
|
||||
* the parent `Workers` object and then tries to claim a task, which blocks if
|
||||
* there are none pending.
|
||||
* It will be unblocked whenever the semaphore is notified (i.e. when the
|
||||
* number of pending tasks is incremented).
|
||||
* That only happens in two circumstances: (1) when
|
||||
* `Workers::addTask` is called and (2) when `Workers` wants to pause some
|
||||
* workers ("pause one worker" is considered one task), which happens when
|
||||
* someone wants to stop the workers or shrink the threadpool. No worker
|
||||
* threads are ever destroyed until `Workers` is destroyed; it merely pauses
|
||||
* workers until then.
|
||||
*
|
||||
* When a waiting worker is woken, it checks whether `Workers` is trying to
|
||||
* pause workers. If so, it changes its status from active to paused and
|
||||
* blocks on
|
||||
* its own condition variable. If not, then it calls `processTask` on the
|
||||
* "callback" held by `Workers`.
|
||||
*
|
||||
* When a paused worker is woken, it checks whether it should exit. The signal
|
||||
* to exit is only set in the destructor of `Worker`, which unblocks the
|
||||
* paused thread and waits for it to exit. A `Worker::run` thread checks
|
||||
* whether it needs to exit only when it is woken from a pause (not when it is
|
||||
* woken from waiting). This is why the destructor for `Workers` pauses all
|
||||
* the workers before destroying them.
|
||||
*/
|
||||
class Workers
|
||||
{
|
||||
public:
|
||||
/** Called to perform tasks as needed. */
|
||||
struct Callback
|
||||
{
|
||||
virtual ~Callback() = default;
|
||||
Callback() = default;
|
||||
Callback(Callback const&) = delete;
|
||||
Callback&
|
||||
operator=(Callback const&) = delete;
|
||||
|
||||
/** Perform a task.
|
||||
|
||||
The call is made on a thread owned by Workers. It is important
|
||||
that you only process one task from inside your callback. Each
|
||||
call to addTask will result in exactly one call to processTask.
|
||||
|
||||
@param instance The worker thread instance.
|
||||
|
||||
@see Workers::addTask
|
||||
*/
|
||||
virtual void
|
||||
processTask(int instance) = 0;
|
||||
};
|
||||
|
||||
/** Create the object.
|
||||
|
||||
A number of initial threads may be optionally specified. The
|
||||
default is to create one thread per CPU.
|
||||
|
||||
@param threadNames The name given to each created worker thread.
|
||||
*/
|
||||
explicit Workers(
|
||||
Callback& callback,
|
||||
perf::PerfLog* perfLog,
|
||||
std::string const& threadNames = "Worker",
|
||||
int numberOfThreads =
|
||||
static_cast<int>(std::thread::hardware_concurrency()));
|
||||
|
||||
~Workers();
|
||||
|
||||
/** Retrieve the desired number of threads.
|
||||
|
||||
This just returns the number of active threads that were requested. If
|
||||
there was a recent call to setNumberOfThreads, the actual number of
|
||||
active threads may be temporarily different from what was last requested.
|
||||
|
||||
@note This function is not thread-safe.
|
||||
*/
|
||||
int
|
||||
getNumberOfThreads() const noexcept;
|
||||
|
||||
/** Set the desired number of threads.
|
||||
@note This function is not thread-safe.
|
||||
*/
|
||||
void
|
||||
setNumberOfThreads(int numberOfThreads);
|
||||
|
||||
/** Pause all threads and wait until they are paused.
|
||||
|
||||
If a thread is processing a task it will pause as soon as the task
|
||||
completes. There may still be tasks signaled even after all threads
|
||||
have paused.
|
||||
|
||||
@note This function is not thread-safe.
|
||||
*/
|
||||
void
|
||||
stop();
|
||||
|
||||
/** Add a task to be performed.
|
||||
|
||||
Every call to addTask will eventually result in a call to
|
||||
Callback::processTask unless the Workers object is destroyed or
|
||||
the number of threads is never set above zero.
|
||||
|
||||
@note This function is thread-safe.
|
||||
*/
|
||||
void
|
||||
addTask();
|
||||
|
||||
/** Get the number of currently executing calls of Callback::processTask.
|
||||
While this function is thread-safe, the value may not stay
|
||||
accurate for very long. It's mainly for diagnostic purposes.
|
||||
*/
|
||||
int
|
||||
numberOfCurrentlyRunningTasks() const noexcept;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
struct PausedTag
|
||||
{
|
||||
explicit PausedTag() = default;
|
||||
};
|
||||
|
||||
/* A Worker executes tasks on its provided thread.
|
||||
|
||||
These are the states:
|
||||
|
||||
Active: Running the task processing loop.
|
||||
Idle: Active, but blocked on waiting for a task.
|
||||
Paused: Blocked waiting to exit or become active.
|
||||
*/
|
||||
class Worker : public beast::LockFreeStack<Worker>::Node,
|
||||
public beast::LockFreeStack<Worker, PausedTag>::Node
|
||||
{
|
||||
public:
|
||||
Worker(
|
||||
Workers& workers,
|
||||
std::string const& threadName,
|
||||
int const instance);
|
||||
|
||||
~Worker();
|
||||
|
||||
void
|
||||
notify();
|
||||
|
||||
private:
|
||||
void
|
||||
run();
|
||||
|
||||
private:
|
||||
Workers& m_workers;
|
||||
std::string const threadName_;
|
||||
int const instance_;
|
||||
|
||||
std::thread thread_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable wakeup_;
|
||||
int wakeCount_; // how many times to un-pause
|
||||
bool shouldExit_;
|
||||
};
|
||||
|
||||
private:
|
||||
static void
|
||||
deleteWorkers(beast::LockFreeStack<Worker>& stack);
|
||||
|
||||
private:
|
||||
Callback& m_callback;
|
||||
perf::PerfLog* perfLog_;
|
||||
std::string m_threadNames; // The name to give each thread
|
||||
std::condition_variable m_cv; // signaled when all threads paused
|
||||
std::mutex m_mut;
|
||||
bool m_allPaused;
|
||||
semaphore m_semaphore; // each pending task is 1 resource
|
||||
int m_numberOfThreads; // how many we want active now
|
||||
std::atomic<int> m_activeCount; // to know when all are paused
|
||||
std::atomic<int> m_pauseCount; // how many threads need to pause now
|
||||
std::atomic<int>
|
||||
m_runningTaskCount; // how many calls to processTask() active
|
||||
beast::LockFreeStack<Worker> m_everyone; // holds all created workers
|
||||
beast::LockFreeStack<Worker, PausedTag>
|
||||
m_paused; // holds just paused workers
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
92
include/xrpl/core/detail/semaphore.h
Normal file
92
include/xrpl/core/detail/semaphore.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
*
|
||||
* TODO: Remove xrpl::basic_semaphore (and this file) and use
|
||||
* std::counting_semaphore.
|
||||
*
|
||||
* Background:
|
||||
* - PR: https://github.com/XRPLF/rippled/pull/5512/files
|
||||
* - std::counting_semaphore had a bug fixed in both GCC and Clang:
|
||||
* * GCC PR 104928: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104928
|
||||
* * LLVM PR 79265: https://github.com/llvm/llvm-project/pull/79265
|
||||
*
|
||||
* GCC:
|
||||
* According to GCC Bugzilla PR104928
|
||||
* (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104928#c15), the fix is
|
||||
* scheduled for inclusion in GCC 16.0 (see comment #15, Target
|
||||
* Milestone: 16.0). It is not included in GCC 14.x or earlier, and there is no
|
||||
* indication that it will be backported to GCC 13.x or 14.x branches.
|
||||
*
|
||||
* Clang:
|
||||
* The fix for is included in Clang 19.1.0+
|
||||
*
|
||||
* Once the minimum compiler version is updated to > GCC 16.0 or Clang 19.1.0,
|
||||
* we can remove this file.
|
||||
*
|
||||
* WARNING: Avoid using std::counting_semaphore until the minimum compiler
|
||||
* version is updated.
|
||||
*/
|
||||
|
||||
#ifndef XRPL_CORE_SEMAPHORE_H_INCLUDED
|
||||
#define XRPL_CORE_SEMAPHORE_H_INCLUDED
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <class Mutex, class CondVar>
|
||||
class basic_semaphore
|
||||
{
|
||||
private:
|
||||
Mutex m_mutex;
|
||||
CondVar m_cond;
|
||||
std::size_t m_count;
|
||||
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
|
||||
/** Create the semaphore, with an optional initial count.
|
||||
If unspecified, the initial count is zero.
|
||||
*/
|
||||
explicit basic_semaphore(size_type count = 0) : m_count(count)
|
||||
{
|
||||
}
|
||||
|
||||
/** Increment the count and unblock one waiting thread. */
|
||||
void
|
||||
notify()
|
||||
{
|
||||
std::lock_guard lock{m_mutex};
|
||||
++m_count;
|
||||
m_cond.notify_one();
|
||||
}
|
||||
|
||||
/** Block until notify is called. */
|
||||
void
|
||||
wait()
|
||||
{
|
||||
std::unique_lock lock{m_mutex};
|
||||
while (m_count == 0)
|
||||
m_cond.wait(lock);
|
||||
--m_count;
|
||||
}
|
||||
|
||||
/** Perform a non-blocking wait.
|
||||
@return `true` If the wait would be satisfied.
|
||||
*/
|
||||
bool
|
||||
try_wait()
|
||||
{
|
||||
std::lock_guard lock{m_mutex};
|
||||
if (m_count == 0)
|
||||
return false;
|
||||
--m_count;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
using semaphore = basic_semaphore<std::mutex, std::condition_variable>;
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
class RFC1751
|
||||
{
|
||||
@@ -42,6 +42,6 @@ private:
|
||||
static char const* s_dictionary[];
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** A cryptographically secure random number engine
|
||||
|
||||
@@ -70,6 +70,6 @@ public:
|
||||
csprng_engine&
|
||||
crypto_prng();
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Attempts to clear the given blob of memory.
|
||||
|
||||
@@ -22,6 +22,6 @@ namespace ripple {
|
||||
void
|
||||
secure_erase(void* dest, std::size_t bytes);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <xrpl/beast/utility/PropertyStream.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** A PropertyStream::Sink which produces a Json::Value of type objectValue. */
|
||||
class JsonPropertyStream : public beast::PropertyStream
|
||||
@@ -66,6 +66,6 @@ protected:
|
||||
add(std::string const& v) override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,445 +0,0 @@
|
||||
#ifndef XRPL_JSON_OBJECT_H_INCLUDED
|
||||
#define XRPL_JSON_OBJECT_H_INCLUDED
|
||||
|
||||
#include <xrpl/json/Writer.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Json {
|
||||
|
||||
/**
|
||||
Collection is a base class for Array and Object, classes which provide the
|
||||
facade of JSON collections for the O(1) JSON writer, while still using no
|
||||
heap memory and only a very small amount of stack.
|
||||
|
||||
From http://json.org, JSON has two types of collection: array, and object.
|
||||
Everything else is a *scalar* - a number, a string, a boolean, the special
|
||||
value null, or a legacy Json::Value.
|
||||
|
||||
Collections must write JSON "as-it-goes" in order to get the strong
|
||||
performance guarantees. This puts restrictions upon API users:
|
||||
|
||||
1. Only one collection can be open for change at any one time.
|
||||
|
||||
This condition is enforced automatically and a std::logic_error thrown if
|
||||
it is violated.
|
||||
|
||||
2. A tag may only be used once in an Object.
|
||||
|
||||
Some objects have many tags, so this condition might be a little
|
||||
expensive. Enforcement of this condition is turned on in debug builds and
|
||||
a std::logic_error is thrown when the tag is added for a second time.
|
||||
|
||||
Code samples:
|
||||
|
||||
Writer writer;
|
||||
|
||||
// An empty object.
|
||||
{
|
||||
Object::Root (writer);
|
||||
}
|
||||
// Outputs {}
|
||||
|
||||
// An object with one scalar value.
|
||||
{
|
||||
Object::Root root (writer);
|
||||
write["hello"] = "world";
|
||||
}
|
||||
// Outputs {"hello":"world"}
|
||||
|
||||
// Same, using chaining.
|
||||
{
|
||||
Object::Root (writer)["hello"] = "world";
|
||||
}
|
||||
// Output is the same.
|
||||
|
||||
// Add several scalars, with chaining.
|
||||
{
|
||||
Object::Root (writer)
|
||||
.set ("hello", "world")
|
||||
.set ("flag", false)
|
||||
.set ("x", 42);
|
||||
}
|
||||
// Outputs {"hello":"world","flag":false,"x":42}
|
||||
|
||||
// Add an array.
|
||||
{
|
||||
Object::Root root (writer);
|
||||
{
|
||||
auto array = root.setArray ("hands");
|
||||
array.append ("left");
|
||||
array.append ("right");
|
||||
}
|
||||
}
|
||||
// Outputs {"hands":["left", "right"]}
|
||||
|
||||
// Same, using chaining.
|
||||
{
|
||||
Object::Root (writer)
|
||||
.setArray ("hands")
|
||||
.append ("left")
|
||||
.append ("right");
|
||||
}
|
||||
// Output is the same.
|
||||
|
||||
// Add an object.
|
||||
{
|
||||
Object::Root root (writer);
|
||||
{
|
||||
auto object = root.setObject ("hands");
|
||||
object["left"] = false;
|
||||
object["right"] = true;
|
||||
}
|
||||
}
|
||||
// Outputs {"hands":{"left":false,"right":true}}
|
||||
|
||||
// Same, using chaining.
|
||||
{
|
||||
Object::Root (writer)
|
||||
.setObject ("hands")
|
||||
.set ("left", false)
|
||||
.set ("right", true);
|
||||
}
|
||||
}
|
||||
// Outputs {"hands":{"left":false,"right":true}}
|
||||
|
||||
|
||||
Typical ways to make mistakes and get a std::logic_error:
|
||||
|
||||
Writer writer;
|
||||
Object::Root root (writer);
|
||||
|
||||
// Repeat a tag.
|
||||
{
|
||||
root ["hello"] = "world";
|
||||
root ["hello"] = "there"; // THROWS! in a debug build.
|
||||
}
|
||||
|
||||
// Open a subcollection, then set something else.
|
||||
{
|
||||
auto object = root.setObject ("foo");
|
||||
root ["hello"] = "world"; // THROWS!
|
||||
}
|
||||
|
||||
// Open two subcollections at a time.
|
||||
{
|
||||
auto object = root.setObject ("foo");
|
||||
auto array = root.setArray ("bar"); // THROWS!!
|
||||
}
|
||||
|
||||
For more examples, check the unit tests.
|
||||
*/
|
||||
|
||||
class Collection
|
||||
{
|
||||
public:
|
||||
Collection(Collection&& c) noexcept;
|
||||
Collection&
|
||||
operator=(Collection&& c) noexcept;
|
||||
Collection() = delete;
|
||||
|
||||
~Collection();
|
||||
|
||||
protected:
|
||||
// A null parent means "no parent at all".
|
||||
// Writers cannot be null.
|
||||
Collection(Collection* parent, Writer*);
|
||||
void
|
||||
checkWritable(std::string const& label);
|
||||
|
||||
Collection* parent_;
|
||||
Writer* writer_;
|
||||
bool enabled_;
|
||||
};
|
||||
|
||||
class Array;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Represents a JSON object being written to a Writer. */
|
||||
class Object : protected Collection
|
||||
{
|
||||
public:
|
||||
/** Object::Root is the only Collection that has a public constructor. */
|
||||
class Root;
|
||||
|
||||
/** Set a scalar value in the Object for a key.
|
||||
|
||||
A JSON scalar is a single value - a number, string, boolean, nullptr or
|
||||
a Json::Value.
|
||||
|
||||
`set()` throws an exception if this object is disabled (which means that
|
||||
one of its children is enabled).
|
||||
|
||||
In a debug build, `set()` also throws an exception if the key has
|
||||
already been set() before.
|
||||
|
||||
An operator[] is provided to allow writing `object["key"] = scalar;`.
|
||||
*/
|
||||
template <typename Scalar>
|
||||
void
|
||||
set(std::string const& key, Scalar const&);
|
||||
|
||||
void
|
||||
set(std::string const& key, Json::Value const&);
|
||||
|
||||
// Detail class and method used to implement operator[].
|
||||
class Proxy;
|
||||
|
||||
Proxy
|
||||
operator[](std::string const& key);
|
||||
Proxy
|
||||
operator[](Json::StaticString const& key);
|
||||
|
||||
/** Make a new Object at a key and return it.
|
||||
|
||||
This Object is disabled until that sub-object is destroyed.
|
||||
Throws an exception if this Object was already disabled.
|
||||
*/
|
||||
Object
|
||||
setObject(std::string const& key);
|
||||
|
||||
/** Make a new Array at a key and return it.
|
||||
|
||||
This Object is disabled until that sub-array is destroyed.
|
||||
Throws an exception if this Object was already disabled.
|
||||
*/
|
||||
Array
|
||||
setArray(std::string const& key);
|
||||
|
||||
protected:
|
||||
friend class Array;
|
||||
Object(Collection* parent, Writer* w) : Collection(parent, w)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Object::Root : public Object
|
||||
{
|
||||
public:
|
||||
/** Each Object::Root must be constructed with its own unique Writer. */
|
||||
Root(Writer&);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Represents a JSON array being written to a Writer. */
|
||||
class Array : private Collection
|
||||
{
|
||||
public:
|
||||
/** Append a scalar to the Arrary.
|
||||
|
||||
Throws an exception if this array is disabled (which means that one of
|
||||
its sub-collections is enabled).
|
||||
*/
|
||||
template <typename Scalar>
|
||||
void
|
||||
append(Scalar const&);
|
||||
|
||||
/**
|
||||
Appends a Json::Value to an array.
|
||||
Throws an exception if this Array was disabled.
|
||||
*/
|
||||
void
|
||||
append(Json::Value const&);
|
||||
|
||||
/** Append a new Object and return it.
|
||||
|
||||
This Array is disabled until that sub-object is destroyed.
|
||||
Throws an exception if this Array was disabled.
|
||||
*/
|
||||
Object
|
||||
appendObject();
|
||||
|
||||
/** Append a new Array and return it.
|
||||
|
||||
This Array is disabled until that sub-array is destroyed.
|
||||
Throws an exception if this Array was already disabled.
|
||||
*/
|
||||
Array
|
||||
appendArray();
|
||||
|
||||
protected:
|
||||
friend class Object;
|
||||
Array(Collection* parent, Writer* w) : Collection(parent, w)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Generic accessor functions to allow Json::Value and Collection to
|
||||
// interoperate.
|
||||
|
||||
/** Add a new subarray at a named key in a Json object. */
|
||||
Json::Value&
|
||||
setArray(Json::Value&, Json::StaticString const& key);
|
||||
|
||||
/** Add a new subarray at a named key in a Json object. */
|
||||
Array
|
||||
setArray(Object&, Json::StaticString const& key);
|
||||
|
||||
/** Add a new subobject at a named key in a Json object. */
|
||||
Json::Value&
|
||||
addObject(Json::Value&, Json::StaticString const& key);
|
||||
|
||||
/** Add a new subobject at a named key in a Json object. */
|
||||
Object
|
||||
addObject(Object&, Json::StaticString const& key);
|
||||
|
||||
/** Append a new subarray to a Json array. */
|
||||
Json::Value&
|
||||
appendArray(Json::Value&);
|
||||
|
||||
/** Append a new subarray to a Json array. */
|
||||
Array
|
||||
appendArray(Array&);
|
||||
|
||||
/** Append a new subobject to a Json object. */
|
||||
Json::Value&
|
||||
appendObject(Json::Value&);
|
||||
|
||||
/** Append a new subobject to a Json object. */
|
||||
Object
|
||||
appendObject(Array&);
|
||||
|
||||
/** Copy all the keys and values from one object into another. */
|
||||
void
|
||||
copyFrom(Json::Value& to, Json::Value const& from);
|
||||
|
||||
/** Copy all the keys and values from one object into another. */
|
||||
void
|
||||
copyFrom(Object& to, Json::Value const& from);
|
||||
|
||||
/** An Object that contains its own Writer. */
|
||||
class WriterObject
|
||||
{
|
||||
public:
|
||||
WriterObject(Output const& output)
|
||||
: writer_(std::make_unique<Writer>(output))
|
||||
, object_(std::make_unique<Object::Root>(*writer_))
|
||||
{
|
||||
}
|
||||
|
||||
WriterObject(WriterObject&& other) = default;
|
||||
|
||||
Object*
|
||||
operator->()
|
||||
{
|
||||
return object_.get();
|
||||
}
|
||||
|
||||
Object&
|
||||
operator*()
|
||||
{
|
||||
return *object_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Writer> writer_;
|
||||
std::unique_ptr<Object::Root> object_;
|
||||
};
|
||||
|
||||
WriterObject
|
||||
stringWriterObject(std::string&);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Implementation details.
|
||||
|
||||
// Detail class for Object::operator[].
|
||||
class Object::Proxy
|
||||
{
|
||||
private:
|
||||
Object& object_;
|
||||
std::string const key_;
|
||||
|
||||
public:
|
||||
Proxy(Object& object, std::string const& key);
|
||||
|
||||
template <class T>
|
||||
void
|
||||
operator=(T const& t)
|
||||
{
|
||||
object_.set(key_, t);
|
||||
// Note: This function shouldn't return *this, because it's a trap.
|
||||
//
|
||||
// In Json::Value, foo[jss::key] returns a reference to a
|
||||
// mutable Json::Value contained _inside_ foo. But in the case of
|
||||
// Json::Object, where we write once only, there isn't any such
|
||||
// reference that can be returned. Returning *this would return an
|
||||
// object "a level higher" than in Json::Value, leading to obscure bugs,
|
||||
// particularly in generic code.
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename Scalar>
|
||||
void
|
||||
Array::append(Scalar const& value)
|
||||
{
|
||||
checkWritable("append");
|
||||
if (writer_)
|
||||
writer_->append(value);
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void
|
||||
Object::set(std::string const& key, Scalar const& value)
|
||||
{
|
||||
checkWritable("set");
|
||||
if (writer_)
|
||||
writer_->set(key, value);
|
||||
}
|
||||
|
||||
inline Json::Value&
|
||||
setArray(Json::Value& json, Json::StaticString const& key)
|
||||
{
|
||||
return (json[key] = Json::arrayValue);
|
||||
}
|
||||
|
||||
inline Array
|
||||
setArray(Object& json, Json::StaticString const& key)
|
||||
{
|
||||
return json.setArray(std::string(key));
|
||||
}
|
||||
|
||||
inline Json::Value&
|
||||
addObject(Json::Value& json, Json::StaticString const& key)
|
||||
{
|
||||
return (json[key] = Json::objectValue);
|
||||
}
|
||||
|
||||
inline Object
|
||||
addObject(Object& object, Json::StaticString const& key)
|
||||
{
|
||||
return object.setObject(std::string(key));
|
||||
}
|
||||
|
||||
inline Json::Value&
|
||||
appendArray(Json::Value& json)
|
||||
{
|
||||
return json.append(Json::arrayValue);
|
||||
}
|
||||
|
||||
inline Array
|
||||
appendArray(Array& json)
|
||||
{
|
||||
return json.appendArray();
|
||||
}
|
||||
|
||||
inline Json::Value&
|
||||
appendObject(Json::Value& json)
|
||||
{
|
||||
return json.append(Json::objectValue);
|
||||
}
|
||||
|
||||
inline Object
|
||||
appendObject(Array& json)
|
||||
{
|
||||
return json.appendObject();
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif
|
||||
@@ -234,7 +234,7 @@ inline void
|
||||
check(bool condition, std::string const& message)
|
||||
{
|
||||
if (!condition)
|
||||
ripple::Throw<std::logic_error>(message);
|
||||
xrpl::Throw<std::logic_error>(message);
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
|
||||
#define JSON_ASSERT_MESSAGE(condition, message) \
|
||||
if (!(condition)) \
|
||||
ripple::Throw<Json::error>(message);
|
||||
xrpl::Throw<Json::error>(message);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -199,7 +199,7 @@ public:
|
||||
Value(UInt value);
|
||||
Value(double value);
|
||||
Value(char const* value);
|
||||
Value(ripple::Number const& value);
|
||||
Value(xrpl::Number const& value);
|
||||
/** \brief Constructs a value from a static string.
|
||||
|
||||
* Like other value string constructor but do not duplicate the string for
|
||||
@@ -430,7 +430,7 @@ private:
|
||||
};
|
||||
|
||||
inline Value
|
||||
to_json(ripple::Number const& number)
|
||||
to_json(xrpl::Number const& number)
|
||||
{
|
||||
return to_string(number);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <xrpl/ledger/RawView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
enum ApplyFlags : std::uint32_t {
|
||||
tapNONE = 0x00,
|
||||
@@ -267,7 +267,7 @@ public:
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"ripple::ApplyView::dirAppend : only Offers are appended to "
|
||||
"xrpl::ApplyView::dirAppend : only Offers are appended to "
|
||||
"book directories");
|
||||
// Only Offers are appended to book directories. Call dirInsert()
|
||||
// instead
|
||||
@@ -407,6 +407,6 @@ insertPage(
|
||||
std::function<void(std::shared_ptr<SLE> const&)> const& describe);
|
||||
|
||||
} // namespace directory
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Editable, discardable view that can build metadata for one tx.
|
||||
|
||||
@@ -75,6 +75,6 @@ private:
|
||||
std::optional<STAmount> deliver_;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
class BookDirs
|
||||
{
|
||||
@@ -89,6 +89,6 @@ private:
|
||||
static beast::Journal j_;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
using CachedSLEs = TaggedCache<uint256, SLE const>;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -47,10 +47,10 @@ public:
|
||||
return base_.open();
|
||||
}
|
||||
|
||||
LedgerInfo const&
|
||||
info() const override
|
||||
LedgerHeader const&
|
||||
header() const override
|
||||
{
|
||||
return base_.info();
|
||||
return base_.header();
|
||||
}
|
||||
|
||||
Fees const&
|
||||
@@ -164,6 +164,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
namespace credentials {
|
||||
|
||||
// These function will be used by the code that use DepositPreauth / Credentials
|
||||
@@ -93,6 +93,6 @@ verifyDepositPreauth(
|
||||
std::shared_ptr<SLE> const& sleDst,
|
||||
beast::Journal j);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** A class that simplifies iterating ledger directory pages
|
||||
|
||||
@@ -108,6 +108,6 @@ private:
|
||||
std::vector<uint256>::const_iterator it_;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Open ledger construction tag.
|
||||
|
||||
@@ -82,7 +82,7 @@ private:
|
||||
monotonic_resource_;
|
||||
txs_map txs_;
|
||||
Rules rules_;
|
||||
LedgerInfo info_;
|
||||
LedgerHeader header_;
|
||||
ReadView const* base_;
|
||||
detail::RawStateTable items_;
|
||||
std::shared_ptr<void const> hold_;
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
|
||||
Effects:
|
||||
|
||||
The LedgerInfo is copied from the base.
|
||||
The LedgerHeader is copied from the base.
|
||||
|
||||
The rules are inherited from the base.
|
||||
|
||||
@@ -188,8 +188,8 @@ public:
|
||||
|
||||
// ReadView
|
||||
|
||||
LedgerInfo const&
|
||||
info() const override;
|
||||
LedgerHeader const&
|
||||
header() const override;
|
||||
|
||||
Fees const&
|
||||
fees() const override;
|
||||
@@ -252,6 +252,6 @@ public:
|
||||
std::shared_ptr<Serializer const> const& metaData) override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -188,6 +188,6 @@ private:
|
||||
PaymentSandbox const* ps_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Interface for ledger entry changes.
|
||||
|
||||
@@ -87,6 +87,6 @@ public:
|
||||
std::shared_ptr<Serializer const> const& metaData) = 0;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <optional>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -80,8 +80,8 @@ public:
|
||||
}
|
||||
|
||||
/** Returns information about the ledger. */
|
||||
virtual LedgerInfo const&
|
||||
info() const = 0;
|
||||
virtual LedgerHeader const&
|
||||
header() const = 0;
|
||||
|
||||
/** Returns true if this reflects an open ledger. */
|
||||
virtual bool
|
||||
@@ -91,14 +91,14 @@ public:
|
||||
NetClock::time_point
|
||||
parentCloseTime() const
|
||||
{
|
||||
return info().parentCloseTime;
|
||||
return header().parentCloseTime;
|
||||
}
|
||||
|
||||
/** Returns the sequence number of the base ledger. */
|
||||
LedgerIndex
|
||||
seq() const
|
||||
{
|
||||
return info().seq;
|
||||
return header().seq;
|
||||
}
|
||||
|
||||
/** Returns the fees for the base ledger. */
|
||||
@@ -258,7 +258,7 @@ makeRulesGivenLedger(
|
||||
DigestAwareReadView const& ledger,
|
||||
std::unordered_set<uint256, beast::uhash<>> const& presets);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#include <xrpl/ledger/detail/ReadViewFwdRange.ipp>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <xrpl/ledger/RawView.h>
|
||||
#include <xrpl/ledger/detail/ApplyViewBase.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Discardable, editable view to a ledger.
|
||||
|
||||
@@ -39,6 +39,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
enum class WaiveTransferFee : bool { No = false, Yes };
|
||||
enum class SkipEntry : bool { No = false, Yes };
|
||||
@@ -1197,6 +1197,6 @@ sharesToAssetsWithdraw(
|
||||
bool
|
||||
after(NetClock::time_point now, std::uint32_t mark);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
namespace detail {
|
||||
|
||||
// Helper class that buffers modifications
|
||||
@@ -139,6 +139,6 @@ private:
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <xrpl/ledger/detail/ApplyStateTable.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
namespace detail {
|
||||
|
||||
class ApplyViewBase : public ApplyView, public RawView
|
||||
@@ -27,8 +27,8 @@ public:
|
||||
bool
|
||||
open() const override;
|
||||
|
||||
LedgerInfo const&
|
||||
info() const override;
|
||||
LedgerHeader const&
|
||||
header() const override;
|
||||
|
||||
Fees const&
|
||||
fees() const override;
|
||||
@@ -106,6 +106,6 @@ protected:
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
namespace detail {
|
||||
|
||||
// Helper class that buffers raw modifications
|
||||
@@ -118,6 +118,6 @@ private:
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
class ReadView;
|
||||
|
||||
@@ -130,6 +130,6 @@ protected:
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef XRPL_LEDGER_READVIEWFWDRANGEINL_H_INCLUDED
|
||||
#define XRPL_LEDGER_READVIEWFWDRANGEINL_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
namespace detail {
|
||||
|
||||
template <class ValueType>
|
||||
@@ -63,7 +63,7 @@ ReadViewFwdRange<ValueType>::iterator::operator==(iterator const& other) const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
view_ == other.view_,
|
||||
"ripple::detail::ReadViewFwdRange::iterator::operator==(iterator) "
|
||||
"xrpl::detail::ReadViewFwdRange::iterator::operator==(iterator) "
|
||||
"const : input view match");
|
||||
|
||||
if (impl_ != nullptr && other.impl_ != nullptr)
|
||||
@@ -115,6 +115,6 @@ ReadViewFwdRange<ValueType>::iterator::operator++(int) -> iterator
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -269,7 +269,7 @@ protected:
|
||||
error_code const& ec,
|
||||
size_t bytesTransferred)
|
||||
{
|
||||
using namespace ripple;
|
||||
using namespace xrpl;
|
||||
|
||||
if (ec)
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** Provides an asynchronous HTTP client implementation with optional SSL.
|
||||
*/
|
||||
@@ -75,6 +75,6 @@ public:
|
||||
beast::Journal& j);
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
class HTTPClientSSLContext
|
||||
{
|
||||
@@ -176,6 +176,6 @@ private:
|
||||
bool const verify_;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <boost/asio/ssl/context.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
/** Register default SSL certificates.
|
||||
|
||||
Register the system default SSL root certificates. On linux/mac,
|
||||
@@ -19,6 +19,6 @@ registerSSLCerts(
|
||||
boost::system::error_code&,
|
||||
beast::Journal j);
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
namespace NodeStore {
|
||||
|
||||
/** A backend used for the NodeStore.
|
||||
@@ -143,6 +143,6 @@ public:
|
||||
};
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace NodeStore {
|
||||
|
||||
@@ -230,7 +230,7 @@ protected:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
count <= sz,
|
||||
"ripple::NodeStore::Database::storeStats : valid inputs");
|
||||
"xrpl::NodeStore::Database::storeStats : valid inputs");
|
||||
storeCount_ += count;
|
||||
storeSz_ += sz;
|
||||
}
|
||||
@@ -291,6 +291,6 @@ private:
|
||||
};
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <xrpl/nodestore/Database.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
namespace NodeStore {
|
||||
|
||||
/* This class has two key-value store Backend objects for persisting SHAMap
|
||||
@@ -39,6 +39,6 @@ public:
|
||||
};
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <xrpl/nodestore/Scheduler.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
namespace NodeStore {
|
||||
|
||||
/** Simple NodeStore Scheduler that just peforms the tasks synchronously. */
|
||||
@@ -21,6 +21,6 @@ public:
|
||||
};
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <nudb/store.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace NodeStore {
|
||||
|
||||
@@ -61,6 +61,6 @@ public:
|
||||
};
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <xrpl/nodestore/DatabaseRotating.h>
|
||||
#include <xrpl/nodestore/Factory.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
namespace NodeStore {
|
||||
|
||||
@@ -83,6 +83,6 @@ public:
|
||||
};
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
// VFALCO NOTE Intentionally not in the NodeStore namespace
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
|
||||
/** The types of node objects. */
|
||||
enum NodeObjectType : std::uint32_t {
|
||||
@@ -81,6 +81,6 @@ private:
|
||||
Blob const mData;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace ripple {
|
||||
namespace xrpl {
|
||||
namespace NodeStore {
|
||||
|
||||
enum class FetchType { synchronous, async };
|
||||
@@ -66,6 +66,6 @@ public:
|
||||
};
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
} // namespace xrpl
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user