Replace qalloc with boost::pmr

This commit is contained in:
seelabs
2020-09-14 14:48:29 -04:00
committed by manojsdoshi
parent ef53197e1f
commit d89c158a77
12 changed files with 155 additions and 492 deletions

View File

@@ -15,6 +15,7 @@ endif ()
find_dependency (Boost 1.70
COMPONENTS
chrono
container
context
coroutine
date_time

View File

@@ -722,7 +722,6 @@ target_sources (rippled PRIVATE
src/test/basics/FeeUnits_test.cpp
src/test/basics/hardened_hash_test.cpp
src/test/basics/mulDiv_test.cpp
src/test/basics/qalloc_test.cpp
src/test/basics/tagged_integer_test.cpp
#[===============================[
test sources:

View File

@@ -47,6 +47,7 @@ endif ()
find_package (Boost 1.70 REQUIRED
COMPONENTS
chrono
container
context
coroutine
date_time
@@ -69,6 +70,7 @@ target_link_libraries (ripple_boost
INTERFACE
Boost::boost
Boost::chrono
Boost::container
Boost::coroutine
Boost::date_time
Boost::filesystem

View File

@@ -44,6 +44,7 @@ if [[ ${BOOST_BUILD_ALL:-false} == "true" ]]; then
BLDARGS+=(--without-python)
else
BLDARGS+=(--with-chrono)
BLDARGS+=(--with-container)
BLDARGS+=(--with-context)
BLDARGS+=(--with-coroutine)
BLDARGS+=(--with-date_time)

View File

@@ -1,372 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_BASICS_QALLOC_H_INCLUDED
#define RIPPLE_BASICS_QALLOC_H_INCLUDED
#include <ripple/basics/ByteUtilities.h>
#include <ripple/basics/contract.h>
#include <boost/intrusive/list.hpp>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <memory>
#include <new>
#include <sstream>
#include <type_traits>
namespace ripple {
namespace detail {
template <class = void>
class qalloc_impl
{
private:
class block
{
private:
std::size_t count_ = 0;
std::size_t bytes_;
std::size_t remain_;
std::uint8_t* free_;
public:
block* next;
block(block const&) = delete;
block&
operator=(block const&) = delete;
explicit block(std::size_t bytes);
void*
allocate(std::size_t bytes, std::size_t align);
bool
deallocate();
};
block* used_ = nullptr;
block* free_ = nullptr;
public:
static constexpr auto block_size = kilobytes(256);
qalloc_impl() = default;
qalloc_impl(qalloc_impl const&) = delete;
qalloc_impl&
operator=(qalloc_impl const&) = delete;
~qalloc_impl();
void*
allocate(std::size_t bytes, std::size_t align);
void
deallocate(void* p);
};
} // namespace detail
template <class T, bool ShareOnCopy = true>
class qalloc_type
{
private:
template <class, bool>
friend class qalloc_type;
std::shared_ptr<detail::qalloc_impl<>> impl_;
public:
using value_type = T;
using pointer = T*;
using const_pointer = T const*;
using reference = typename std::add_lvalue_reference<T>::type;
using const_reference = typename std::add_lvalue_reference<T const>::type;
using propagate_on_container_move_assignment = std::true_type;
template <class U>
struct rebind
{
explicit rebind() = default;
using other = qalloc_type<U, ShareOnCopy>;
};
qalloc_type(qalloc_type const&) = default;
qalloc_type(qalloc_type&& other) noexcept = default;
qalloc_type&
operator=(qalloc_type const&) = default;
qalloc_type&
operator=(qalloc_type&&) noexcept = default;
qalloc_type();
template <class U>
qalloc_type(qalloc_type<U, ShareOnCopy> const& u);
template <class U>
U*
alloc(std::size_t n);
template <class U>
void
dealloc(U* p, std::size_t n);
T*
allocate(std::size_t n);
void
deallocate(T* p, std::size_t n);
template <class U>
bool
operator==(qalloc_type<U, ShareOnCopy> const& u);
template <class U>
bool
operator!=(qalloc_type<U, ShareOnCopy> const& u);
qalloc_type
select_on_container_copy_construction() const;
private:
qalloc_type select_on_copy(std::true_type) const;
qalloc_type select_on_copy(std::false_type) const;
};
/** Allocator optimized for delete in temporal order.
This allocator is optimized for the case where objects
are deleted in approximately the same order that they
were created.
Thread Safety:
May not be called concurrently.
*/
using qalloc = qalloc_type<int, true>;
//------------------------------------------------------------------------------
namespace detail {
template <class _>
qalloc_impl<_>::block::block(std::size_t bytes)
: bytes_(bytes - sizeof(*this))
, remain_(bytes_)
, free_(reinterpret_cast<std::uint8_t*>(this + 1))
{
}
template <class _>
void*
qalloc_impl<_>::block::allocate(std::size_t bytes, std::size_t align)
{
align = std::max(align, std::alignment_of<block*>::value);
auto pad = [](void const* p, std::size_t a) {
auto const i = reinterpret_cast<std::uintptr_t>(p);
return (a - (i % a)) % a;
};
auto const n0 = pad(free_ + sizeof(block*), align);
auto const n1 = n0 + sizeof(block*) + bytes;
if (remain_ < n1)
return nullptr;
auto p = reinterpret_cast<block**>(free_ + n0 + sizeof(block*));
assert(pad(p - 1, std::alignment_of<block*>::value) == 0);
p[-1] = this;
++count_;
free_ += n1;
remain_ -= n1;
return p;
}
template <class _>
bool
qalloc_impl<_>::block::deallocate()
{
--count_;
if (count_ > 0)
return false;
remain_ = bytes_;
free_ = reinterpret_cast<std::uint8_t*>(this + 1);
return true;
}
template <class _>
qalloc_impl<_>::~qalloc_impl()
{
if (used_)
{
used_->~block();
std::free(used_);
}
while (free_)
{
auto const next = free_->next;
free_->~block();
std::free(free_);
free_ = next;
}
}
template <class _>
void*
qalloc_impl<_>::allocate(std::size_t bytes, std::size_t align)
{
if (used_)
{
auto const p = used_->allocate(bytes, align);
if (p)
return p;
used_ = nullptr;
}
if (free_)
{
auto const p = free_->allocate(bytes, align);
if (p)
{
used_ = free_;
free_ = free_->next;
return p;
}
}
std::size_t const adj_align =
std::max(align, std::alignment_of<block*>::value);
std::size_t const min_alloc = // align up
((sizeof(block) + sizeof(block*) + bytes) + (adj_align - 1)) &
~(adj_align - 1);
auto const n = std::max<std::size_t>(block_size, min_alloc);
block* const b = new (std::malloc(n)) block(n);
if (!b)
Throw<std::bad_alloc>();
used_ = b;
// VFALCO This has to succeed
return used_->allocate(bytes, align);
}
template <class _>
void
qalloc_impl<_>::deallocate(void* p)
{
auto const b = reinterpret_cast<block**>(p)[-1];
if (b->deallocate())
{
if (used_ == b)
used_ = nullptr;
b->next = free_;
free_ = b;
}
}
} // namespace detail
//------------------------------------------------------------------------------
template <class T, bool ShareOnCopy>
qalloc_type<T, ShareOnCopy>::qalloc_type()
: impl_(std::make_shared<detail::qalloc_impl<>>())
{
}
template <class T, bool ShareOnCopy>
template <class U>
qalloc_type<T, ShareOnCopy>::qalloc_type(qalloc_type<U, ShareOnCopy> const& u)
: impl_(u.impl_)
{
}
template <class T, bool ShareOnCopy>
template <class U>
U*
qalloc_type<T, ShareOnCopy>::alloc(std::size_t n)
{
if (n > std::numeric_limits<std::size_t>::max() / sizeof(U))
Throw<std::bad_alloc>();
auto const bytes = n * sizeof(U);
return static_cast<U*>(impl_->allocate(bytes, std::alignment_of<U>::value));
}
template <class T, bool ShareOnCopy>
template <class U>
inline void
qalloc_type<T, ShareOnCopy>::dealloc(U* p, std::size_t n)
{
impl_->deallocate(p);
}
template <class T, bool ShareOnCopy>
T*
qalloc_type<T, ShareOnCopy>::allocate(std::size_t n)
{
return alloc<T>(n);
}
template <class T, bool ShareOnCopy>
inline void
qalloc_type<T, ShareOnCopy>::deallocate(T* p, std::size_t n)
{
dealloc(p, n);
}
template <class T, bool ShareOnCopy>
template <class U>
inline bool
qalloc_type<T, ShareOnCopy>::operator==(qalloc_type<U, ShareOnCopy> const& u)
{
return impl_.get() == u.impl_.get();
}
template <class T, bool ShareOnCopy>
template <class U>
inline bool
qalloc_type<T, ShareOnCopy>::operator!=(qalloc_type<U, ShareOnCopy> const& u)
{
return !(*this == u);
}
template <class T, bool ShareOnCopy>
auto
qalloc_type<T, ShareOnCopy>::select_on_container_copy_construction() const
-> qalloc_type
{
return select_on_copy(std::integral_constant<bool, ShareOnCopy>{});
}
template <class T, bool ShareOnCopy>
auto qalloc_type<T, ShareOnCopy>::select_on_copy(std::true_type) const
-> qalloc_type
{
return *this; // shared arena
}
template <class T, bool ShareOnCopy>
auto qalloc_type<T, ShareOnCopy>::select_on_copy(std::false_type) const
-> qalloc_type
{
return {}; // new arena
}
} // namespace ripple
#endif

View File

@@ -21,10 +21,13 @@
#define RIPPLE_LEDGER_OPENVIEW_H_INCLUDED
#include <ripple/basics/XRPAmount.h>
#include <ripple/basics/qalloc.h>
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/ledger/detail/RawStateTable.h>
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
#include <boost/container/pmr/polymorphic_allocator.hpp>
#include <functional>
#include <utility>
@@ -52,25 +55,43 @@ extern open_ledger_t const open_ledger;
class OpenView final : public ReadView, public TxsRawView
{
private:
// Initial size for the monotonic_buffer_resource used for allocations
// The size was chosen from the old `qalloc` code (which this replaces).
// It is unclear how the size initially chosen in qalloc.
static constexpr size_t initialBufferSize = kilobytes(256);
class txs_iter_impl;
struct txData
{
std::shared_ptr<Serializer const> txn;
std::shared_ptr<Serializer const> meta;
// Constructor needed for emplacement in std::map
txData(
std::shared_ptr<Serializer const> const& txn_,
std::shared_ptr<Serializer const> const& meta_)
: txn(txn_), meta(meta_)
{
}
};
// List of tx, key order
// Use the boost pmr functionality instead of the c++-17 standard pmr
// functions b/c clang does not support pmr yet (as-of 9/2020)
using txs_map = std::map<
key_type,
std::pair<
std::shared_ptr<Serializer const>,
std::shared_ptr<Serializer const>>,
txData,
std::less<key_type>,
qalloc_type<
std::pair<
key_type const,
std::pair<
std::shared_ptr<Serializer const>,
std::shared_ptr<Serializer const>>>,
false>>;
boost::container::pmr::polymorphic_allocator<
std::pair<key_type const, txData>>>;
Rules rules_;
// monotonic_resource_ must outlive `items_`. Make a pointer so it may be
// easily moved.
std::unique_ptr<boost::container::pmr::monotonic_buffer_resource>
monotonic_resource_;
txs_map txs_;
Rules rules_;
LedgerInfo info_;
ReadView const* base_;
detail::RawStateTable items_;
@@ -98,7 +119,7 @@ public:
Since the SLEs are immutable, calls on the
RawView interface cannot break invariants.
*/
OpenView(OpenView const&) = default;
OpenView(OpenView const&);
/** Construct an open ledger view.

View File

@@ -20,9 +20,12 @@
#ifndef RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED
#define RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED
#include <ripple/basics/qalloc.h>
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h>
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
#include <boost/container/pmr/polymorphic_allocator.hpp>
#include <map>
#include <utility>
@@ -34,9 +37,24 @@ class RawStateTable
{
public:
using key_type = ReadView::key_type;
// Initial size for the monotonic_buffer_resource used for allocations
// The size was chosen from the old `qalloc` code (which this replaces).
// It is unclear how the size initially chosen in qalloc.
static constexpr size_t initialBufferSize = kilobytes(256);
RawStateTable()
: monotonic_resource_{std::make_unique<
boost::container::pmr::monotonic_buffer_resource>(
initialBufferSize)}
, items_{monotonic_resource_.get()} {};
RawStateTable(RawStateTable const& rhs)
: monotonic_resource_{std::make_unique<
boost::container::pmr::monotonic_buffer_resource>(
initialBufferSize)}
, items_{rhs.items_, monotonic_resource_.get()}
, dropsDestroyed_{rhs.dropsDestroyed_} {};
RawStateTable() = default;
RawStateTable(RawStateTable const&) = default;
RawStateTable(RawStateTable&&) = default;
RawStateTable&
@@ -89,15 +107,32 @@ private:
class sles_iter_impl;
struct sleAction
{
Action action;
std::shared_ptr<SLE> sle;
// Constructor needed for emplacement in std::map
sleAction(Action action_, std::shared_ptr<SLE> const& sle_)
: action(action_), sle(sle_)
{
}
};
// Use the boost pmr functionality instead of the c++-17 standard pmr
// functions b/c clang does not support pmr yet (as-of 9/2020)
using items_t = std::map<
key_type,
std::pair<Action, std::shared_ptr<SLE>>,
sleAction,
std::less<key_type>,
qalloc_type<
std::pair<key_type const, std::pair<Action, std::shared_ptr<SLE>>>,
false>>;
boost::container::pmr::polymorphic_allocator<
std::pair<const key_type, sleAction>>>;
// monotonic_resource_ must outlive `items_`. Make a pointer so it may be
// easily moved.
std::unique_ptr<boost::container::pmr::monotonic_buffer_resource>
monotonic_resource_;
items_t items_;
XRPAmount dropsDestroyed_{0};
};

View File

@@ -60,12 +60,12 @@ public:
{
value_type result;
{
SerialIter sit(iter_->second.first->slice());
SerialIter sit(iter_->second.txn->slice());
result.first = std::make_shared<STTx const>(sit);
}
if (metadata_)
{
SerialIter sit(iter_->second.second->slice());
SerialIter sit(iter_->second.meta->slice());
result.second = std::make_shared<STObject const>(sit, sfMetadata);
}
return result;
@@ -74,12 +74,31 @@ public:
//------------------------------------------------------------------------------
OpenView::OpenView(OpenView const& rhs)
: ReadView(rhs)
, TxsRawView(rhs)
, monotonic_resource_{std::make_unique<
boost::container::pmr::monotonic_buffer_resource>(initialBufferSize)}
, txs_{rhs.txs_, monotonic_resource_.get()}
, rules_{rhs.rules_}
, info_{rhs.info_}
, base_{rhs.base_}
, items_{rhs.items_}
, hold_{rhs.hold_}
, open_{rhs.open_} {};
OpenView::OpenView(
open_ledger_t,
ReadView const* base,
Rules const& rules,
std::shared_ptr<void const> hold)
: rules_(rules), info_(base->info()), base_(base), hold_(std::move(hold))
: monotonic_resource_{std::make_unique<
boost::container::pmr::monotonic_buffer_resource>(initialBufferSize)}
, txs_{monotonic_resource_.get()}
, rules_(rules)
, info_(base->info())
, base_(base)
, hold_(std::move(hold))
{
info_.validated = false;
info_.accepted = false;
@@ -89,7 +108,10 @@ OpenView::OpenView(
}
OpenView::OpenView(ReadView const* base, std::shared_ptr<void const> hold)
: rules_(base->rules())
: monotonic_resource_{std::make_unique<
boost::container::pmr::monotonic_buffer_resource>(initialBufferSize)}
, txs_{monotonic_resource_.get()}
, rules_(base->rules())
, info_(base->info())
, base_(base)
, hold_(std::move(hold))
@@ -108,7 +130,7 @@ OpenView::apply(TxsRawView& to) const
{
items_.apply(to);
for (auto const& item : txs_)
to.rawTxInsert(item.first, item.second.first, item.second.second);
to.rawTxInsert(item.first, item.second.txn, item.second.meta);
}
//---
@@ -194,11 +216,11 @@ OpenView::txRead(key_type const& key) const -> tx_type
if (iter == txs_.end())
return base_->txRead(key);
auto const& item = iter->second;
auto stx = std::make_shared<STTx const>(SerialIter{item.first->slice()});
auto stx = std::make_shared<STTx const>(SerialIter{item.txn->slice()});
decltype(tx_type::second) sto;
if (item.second)
if (item.meta)
sto = std::make_shared<STObject const>(
SerialIter{item.second->slice()}, sfMetadata);
SerialIter{item.meta->slice()}, sfMetadata);
else
sto = nullptr;
return {std::move(stx), std::move(sto)};
@@ -240,7 +262,10 @@ OpenView::rawTxInsert(
std::shared_ptr<Serializer const> const& txn,
std::shared_ptr<Serializer const> const& metaData)
{
auto const result = txs_.emplace(key, std::make_pair(txn, metaData));
auto const result = txs_.emplace(
std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(txn, metaData));
if (!result.second)
LogicError("rawTxInsert: duplicate TX id" + to_string(key));
}

View File

@@ -47,7 +47,7 @@ public:
sle0_ = *iter0_;
if (iter1_ != end1)
{
sle1_ = iter1_->second.second;
sle1_ = iter1_->second.sle;
skip();
}
}
@@ -129,13 +129,13 @@ private:
if (iter1_ == end1_)
sle1_ = nullptr;
else
sle1_ = iter1_->second.second;
sle1_ = iter1_->second.sle;
}
void
skip()
{
while (iter1_ != end1_ && iter1_->second.first == Action::erase &&
while (iter1_ != end1_ && iter1_->second.action == Action::erase &&
sle0_->key() == sle1_->key())
{
inc1();
@@ -157,16 +157,16 @@ RawStateTable::apply(RawView& to) const
for (auto const& elem : items_)
{
auto const& item = elem.second;
switch (item.first)
switch (item.action)
{
case Action::erase:
to.rawErase(item.second);
to.rawErase(item.sle);
break;
case Action::insert:
to.rawInsert(item.second);
to.rawInsert(item.sle);
break;
case Action::replace:
to.rawReplace(item.second);
to.rawReplace(item.sle);
break;
}
}
@@ -180,9 +180,9 @@ RawStateTable::exists(ReadView const& base, Keylet const& k) const
if (iter == items_.end())
return base.exists(k);
auto const& item = iter->second;
if (item.first == Action::erase)
if (item.action == Action::erase)
return false;
if (!k.check(*item.second))
if (!k.check(*item.sle))
return false;
return true;
}
@@ -207,11 +207,11 @@ RawStateTable::succ(
if (!next)
break;
iter = items_.find(*next);
} while (iter != items_.end() && iter->second.first == Action::erase);
} while (iter != items_.end() && iter->second.action == Action::erase);
// Find non-deleted successor in our list
for (iter = items_.upper_bound(key); iter != items_.end(); ++iter)
{
if (iter->second.first != Action::erase)
if (iter->second.action != Action::erase)
{
// Found both, return the lower key
if (!next || next > iter->first)
@@ -237,7 +237,7 @@ RawStateTable::erase(std::shared_ptr<SLE> const& sle)
if (result.second)
return;
auto& item = result.first->second;
switch (item.first)
switch (item.action)
{
case Action::erase:
LogicError("RawStateTable::erase: already erased");
@@ -246,8 +246,8 @@ RawStateTable::erase(std::shared_ptr<SLE> const& sle)
items_.erase(result.first);
break;
case Action::replace:
item.first = Action::erase;
item.second = sle;
item.action = Action::erase;
item.sle = sle;
break;
}
}
@@ -262,11 +262,11 @@ RawStateTable::insert(std::shared_ptr<SLE> const& sle)
if (result.second)
return;
auto& item = result.first->second;
switch (item.first)
switch (item.action)
{
case Action::erase:
item.first = Action::replace;
item.second = sle;
item.action = Action::replace;
item.sle = sle;
break;
case Action::insert:
LogicError("RawStateTable::insert: already inserted");
@@ -287,14 +287,14 @@ RawStateTable::replace(std::shared_ptr<SLE> const& sle)
if (result.second)
return;
auto& item = result.first->second;
switch (item.first)
switch (item.action)
{
case Action::erase:
LogicError("RawStateTable::replace: was erased");
break;
case Action::insert:
case Action::replace:
item.second = sle;
item.sle = sle;
break;
}
}
@@ -306,10 +306,10 @@ RawStateTable::read(ReadView const& base, Keylet const& k) const
if (iter == items_.end())
return base.read(k);
auto const& item = iter->second;
if (item.first == Action::erase)
if (item.action == Action::erase)
return nullptr;
// Convert to SLE const
std::shared_ptr<SLE const> sle = item.second;
std::shared_ptr<SLE const> sle = item.sle;
if (!k.check(*sle))
return nullptr;
return sle;

View File

@@ -1,47 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2018 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/qalloc.h>
#include <ripple/beast/unit_test.h>
#include <type_traits>
namespace ripple {
struct qalloc_test : beast::unit_test::suite
{
void
testBasicProperties()
{
BEAST_EXPECT(std::is_default_constructible<qalloc>{});
BEAST_EXPECT(std::is_copy_constructible<qalloc>{});
BEAST_EXPECT(std::is_copy_assignable<qalloc>{});
BEAST_EXPECT(std::is_nothrow_move_constructible<qalloc>{});
BEAST_EXPECT(std::is_nothrow_move_assignable<qalloc>{});
}
void
run() override
{
testBasicProperties();
}
};
BEAST_DEFINE_TESTSUITE(qalloc, ripple_basics, ripple);
} // namespace ripple

View File

@@ -20,9 +20,12 @@
#ifndef RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED
#define RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED
#include <ripple/basics/qalloc.h>
#include <ripple/basics/ByteUtilities.h>
#include <ripple/beast/clock/manual_clock.h>
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
#include <boost/intrusive/set.hpp>
#include <type_traits>
#include <utility>
@@ -109,8 +112,8 @@ private:
using by_when_set = typename boost::intrusive::make_multiset<
event,
boost::intrusive::constant_time_size<false>>::type;
qalloc alloc_;
// alloc_ is owned by the scheduler
boost::container::pmr::monotonic_buffer_resource* alloc_;
by_when_set by_when_;
public:
@@ -120,7 +123,8 @@ private:
queue_type&
operator=(queue_type const&) = delete;
explicit queue_type(qalloc const& alloc);
explicit queue_type(
boost::container::pmr::monotonic_buffer_resource* alloc);
~queue_type();
@@ -141,7 +145,7 @@ private:
erase(iterator iter);
};
qalloc alloc_;
boost::container::pmr::monotonic_buffer_resource alloc_{kilobytes(256)};
queue_type queue_;
// Aged containers that rely on this clock take a non-const reference =(
@@ -154,10 +158,6 @@ public:
Scheduler();
/** Return the allocator. */
qalloc const&
alloc() const;
/** Return the clock. (aged_containers want a non-const ref =( */
clock_type&
clock() const;
@@ -275,7 +275,9 @@ public:
//------------------------------------------------------------------------------
inline Scheduler::queue_type::queue_type(qalloc const& alloc) : alloc_(alloc)
inline Scheduler::queue_type::queue_type(
boost::container::pmr::monotonic_buffer_resource* alloc)
: alloc_(alloc)
{
}
@@ -286,7 +288,7 @@ inline Scheduler::queue_type::~queue_type()
auto e = &*iter;
++iter;
e->~event();
alloc_.dealloc(e, 1);
alloc_->deallocate(e, sizeof(e));
}
}
@@ -314,7 +316,7 @@ Scheduler::queue_type::emplace(time_point when, Handler&& h) ->
typename by_when_set::iterator
{
using event_type = event_impl<std::decay_t<Handler>>;
auto const p = alloc_.alloc<event_type>(1);
auto const p = alloc_->allocate(sizeof(event_type));
auto& e = *new (p) event_type(when, std::forward<Handler>(h));
return by_when_.insert(e);
}
@@ -325,7 +327,7 @@ Scheduler::queue_type::erase(iterator iter) -> typename by_when_set::iterator
auto& e = *iter;
auto next = by_when_.erase(iter);
e.~event();
alloc_.dealloc(&e, 1);
alloc_->deallocate(&e, sizeof(e));
return next;
}
@@ -349,16 +351,10 @@ private:
};
//------------------------------------------------------------------------------
inline Scheduler::Scheduler() : queue_(alloc_)
inline Scheduler::Scheduler() : queue_(&alloc_)
{
}
inline qalloc const&
Scheduler::alloc() const
{
return alloc_;
}
inline auto
Scheduler::clock() const -> clock_type&
{

View File

@@ -17,10 +17,12 @@
*/
//==============================================================================
#include <ripple/basics/ByteUtilities.h>
#include <ripple/beast/unit_test.h>
#include <set>
#include <test/csf/Scheduler.h>
#include <set>
namespace ripple {
namespace test {