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 find_dependency (Boost 1.70
COMPONENTS COMPONENTS
chrono chrono
container
context context
coroutine coroutine
date_time date_time

View File

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

View File

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

View File

@@ -44,6 +44,7 @@ if [[ ${BOOST_BUILD_ALL:-false} == "true" ]]; then
BLDARGS+=(--without-python) BLDARGS+=(--without-python)
else else
BLDARGS+=(--with-chrono) BLDARGS+=(--with-chrono)
BLDARGS+=(--with-container)
BLDARGS+=(--with-context) BLDARGS+=(--with-context)
BLDARGS+=(--with-coroutine) BLDARGS+=(--with-coroutine)
BLDARGS+=(--with-date_time) 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 #define RIPPLE_LEDGER_OPENVIEW_H_INCLUDED
#include <ripple/basics/XRPAmount.h> #include <ripple/basics/XRPAmount.h>
#include <ripple/basics/qalloc.h>
#include <ripple/ledger/RawView.h> #include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h> #include <ripple/ledger/ReadView.h>
#include <ripple/ledger/detail/RawStateTable.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 <functional>
#include <utility> #include <utility>
@@ -52,25 +55,43 @@ extern open_ledger_t const open_ledger;
class OpenView final : public ReadView, public TxsRawView class OpenView final : public ReadView, public TxsRawView
{ {
private: 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; 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 // 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< using txs_map = std::map<
key_type, key_type,
std::pair< txData,
std::shared_ptr<Serializer const>,
std::shared_ptr<Serializer const>>,
std::less<key_type>, std::less<key_type>,
qalloc_type< boost::container::pmr::polymorphic_allocator<
std::pair< std::pair<key_type const, txData>>>;
key_type const,
std::pair<
std::shared_ptr<Serializer const>,
std::shared_ptr<Serializer const>>>,
false>>;
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_; txs_map txs_;
Rules rules_;
LedgerInfo info_; LedgerInfo info_;
ReadView const* base_; ReadView const* base_;
detail::RawStateTable items_; detail::RawStateTable items_;
@@ -98,7 +119,7 @@ public:
Since the SLEs are immutable, calls on the Since the SLEs are immutable, calls on the
RawView interface cannot break invariants. RawView interface cannot break invariants.
*/ */
OpenView(OpenView const&) = default; OpenView(OpenView const&);
/** Construct an open ledger view. /** Construct an open ledger view.

View File

@@ -20,9 +20,12 @@
#ifndef RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED #ifndef RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED
#define RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED #define RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED
#include <ripple/basics/qalloc.h>
#include <ripple/ledger/RawView.h> #include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h> #include <ripple/ledger/ReadView.h>
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
#include <boost/container/pmr/polymorphic_allocator.hpp>
#include <map> #include <map>
#include <utility> #include <utility>
@@ -34,9 +37,24 @@ class RawStateTable
{ {
public: public:
using key_type = ReadView::key_type; 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(RawStateTable&&) = default;
RawStateTable& RawStateTable&
@@ -89,15 +107,32 @@ private:
class sles_iter_impl; 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< using items_t = std::map<
key_type, key_type,
std::pair<Action, std::shared_ptr<SLE>>, sleAction,
std::less<key_type>, std::less<key_type>,
qalloc_type< boost::container::pmr::polymorphic_allocator<
std::pair<key_type const, std::pair<Action, std::shared_ptr<SLE>>>, std::pair<const key_type, sleAction>>>;
false>>; // 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_; items_t items_;
XRPAmount dropsDestroyed_{0}; XRPAmount dropsDestroyed_{0};
}; };

View File

@@ -60,12 +60,12 @@ public:
{ {
value_type result; value_type result;
{ {
SerialIter sit(iter_->second.first->slice()); SerialIter sit(iter_->second.txn->slice());
result.first = std::make_shared<STTx const>(sit); result.first = std::make_shared<STTx const>(sit);
} }
if (metadata_) if (metadata_)
{ {
SerialIter sit(iter_->second.second->slice()); SerialIter sit(iter_->second.meta->slice());
result.second = std::make_shared<STObject const>(sit, sfMetadata); result.second = std::make_shared<STObject const>(sit, sfMetadata);
} }
return result; 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( OpenView::OpenView(
open_ledger_t, open_ledger_t,
ReadView const* base, ReadView const* base,
Rules const& rules, Rules const& rules,
std::shared_ptr<void const> hold) 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_.validated = false;
info_.accepted = false; info_.accepted = false;
@@ -89,7 +108,10 @@ OpenView::OpenView(
} }
OpenView::OpenView(ReadView const* base, std::shared_ptr<void const> hold) 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()) , info_(base->info())
, base_(base) , base_(base)
, hold_(std::move(hold)) , hold_(std::move(hold))
@@ -108,7 +130,7 @@ OpenView::apply(TxsRawView& to) const
{ {
items_.apply(to); items_.apply(to);
for (auto const& item : txs_) 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()) if (iter == txs_.end())
return base_->txRead(key); return base_->txRead(key);
auto const& item = iter->second; 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; decltype(tx_type::second) sto;
if (item.second) if (item.meta)
sto = std::make_shared<STObject const>( sto = std::make_shared<STObject const>(
SerialIter{item.second->slice()}, sfMetadata); SerialIter{item.meta->slice()}, sfMetadata);
else else
sto = nullptr; sto = nullptr;
return {std::move(stx), std::move(sto)}; 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& txn,
std::shared_ptr<Serializer const> const& metaData) 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) if (!result.second)
LogicError("rawTxInsert: duplicate TX id" + to_string(key)); LogicError("rawTxInsert: duplicate TX id" + to_string(key));
} }

View File

@@ -47,7 +47,7 @@ public:
sle0_ = *iter0_; sle0_ = *iter0_;
if (iter1_ != end1) if (iter1_ != end1)
{ {
sle1_ = iter1_->second.second; sle1_ = iter1_->second.sle;
skip(); skip();
} }
} }
@@ -129,13 +129,13 @@ private:
if (iter1_ == end1_) if (iter1_ == end1_)
sle1_ = nullptr; sle1_ = nullptr;
else else
sle1_ = iter1_->second.second; sle1_ = iter1_->second.sle;
} }
void void
skip() skip()
{ {
while (iter1_ != end1_ && iter1_->second.first == Action::erase && while (iter1_ != end1_ && iter1_->second.action == Action::erase &&
sle0_->key() == sle1_->key()) sle0_->key() == sle1_->key())
{ {
inc1(); inc1();
@@ -157,16 +157,16 @@ RawStateTable::apply(RawView& to) const
for (auto const& elem : items_) for (auto const& elem : items_)
{ {
auto const& item = elem.second; auto const& item = elem.second;
switch (item.first) switch (item.action)
{ {
case Action::erase: case Action::erase:
to.rawErase(item.second); to.rawErase(item.sle);
break; break;
case Action::insert: case Action::insert:
to.rawInsert(item.second); to.rawInsert(item.sle);
break; break;
case Action::replace: case Action::replace:
to.rawReplace(item.second); to.rawReplace(item.sle);
break; break;
} }
} }
@@ -180,9 +180,9 @@ RawStateTable::exists(ReadView const& base, Keylet const& k) const
if (iter == items_.end()) if (iter == items_.end())
return base.exists(k); return base.exists(k);
auto const& item = iter->second; auto const& item = iter->second;
if (item.first == Action::erase) if (item.action == Action::erase)
return false; return false;
if (!k.check(*item.second)) if (!k.check(*item.sle))
return false; return false;
return true; return true;
} }
@@ -207,11 +207,11 @@ RawStateTable::succ(
if (!next) if (!next)
break; break;
iter = items_.find(*next); 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 // Find non-deleted successor in our list
for (iter = items_.upper_bound(key); iter != items_.end(); ++iter) 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 // Found both, return the lower key
if (!next || next > iter->first) if (!next || next > iter->first)
@@ -237,7 +237,7 @@ RawStateTable::erase(std::shared_ptr<SLE> const& sle)
if (result.second) if (result.second)
return; return;
auto& item = result.first->second; auto& item = result.first->second;
switch (item.first) switch (item.action)
{ {
case Action::erase: case Action::erase:
LogicError("RawStateTable::erase: already erased"); LogicError("RawStateTable::erase: already erased");
@@ -246,8 +246,8 @@ RawStateTable::erase(std::shared_ptr<SLE> const& sle)
items_.erase(result.first); items_.erase(result.first);
break; break;
case Action::replace: case Action::replace:
item.first = Action::erase; item.action = Action::erase;
item.second = sle; item.sle = sle;
break; break;
} }
} }
@@ -262,11 +262,11 @@ RawStateTable::insert(std::shared_ptr<SLE> const& sle)
if (result.second) if (result.second)
return; return;
auto& item = result.first->second; auto& item = result.first->second;
switch (item.first) switch (item.action)
{ {
case Action::erase: case Action::erase:
item.first = Action::replace; item.action = Action::replace;
item.second = sle; item.sle = sle;
break; break;
case Action::insert: case Action::insert:
LogicError("RawStateTable::insert: already inserted"); LogicError("RawStateTable::insert: already inserted");
@@ -287,14 +287,14 @@ RawStateTable::replace(std::shared_ptr<SLE> const& sle)
if (result.second) if (result.second)
return; return;
auto& item = result.first->second; auto& item = result.first->second;
switch (item.first) switch (item.action)
{ {
case Action::erase: case Action::erase:
LogicError("RawStateTable::replace: was erased"); LogicError("RawStateTable::replace: was erased");
break; break;
case Action::insert: case Action::insert:
case Action::replace: case Action::replace:
item.second = sle; item.sle = sle;
break; break;
} }
} }
@@ -306,10 +306,10 @@ RawStateTable::read(ReadView const& base, Keylet const& k) const
if (iter == items_.end()) if (iter == items_.end())
return base.read(k); return base.read(k);
auto const& item = iter->second; auto const& item = iter->second;
if (item.first == Action::erase) if (item.action == Action::erase)
return nullptr; return nullptr;
// Convert to SLE const // Convert to SLE const
std::shared_ptr<SLE const> sle = item.second; std::shared_ptr<SLE const> sle = item.sle;
if (!k.check(*sle)) if (!k.check(*sle))
return nullptr; return nullptr;
return sle; 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 #ifndef RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED
#define 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 <ripple/beast/clock/manual_clock.h>
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
#include <boost/intrusive/set.hpp> #include <boost/intrusive/set.hpp>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@@ -109,8 +112,8 @@ private:
using by_when_set = typename boost::intrusive::make_multiset< using by_when_set = typename boost::intrusive::make_multiset<
event, event,
boost::intrusive::constant_time_size<false>>::type; boost::intrusive::constant_time_size<false>>::type;
// alloc_ is owned by the scheduler
qalloc alloc_; boost::container::pmr::monotonic_buffer_resource* alloc_;
by_when_set by_when_; by_when_set by_when_;
public: public:
@@ -120,7 +123,8 @@ private:
queue_type& queue_type&
operator=(queue_type const&) = delete; operator=(queue_type const&) = delete;
explicit queue_type(qalloc const& alloc); explicit queue_type(
boost::container::pmr::monotonic_buffer_resource* alloc);
~queue_type(); ~queue_type();
@@ -141,7 +145,7 @@ private:
erase(iterator iter); erase(iterator iter);
}; };
qalloc alloc_; boost::container::pmr::monotonic_buffer_resource alloc_{kilobytes(256)};
queue_type queue_; queue_type queue_;
// Aged containers that rely on this clock take a non-const reference =( // Aged containers that rely on this clock take a non-const reference =(
@@ -154,10 +158,6 @@ public:
Scheduler(); Scheduler();
/** Return the allocator. */
qalloc const&
alloc() const;
/** Return the clock. (aged_containers want a non-const ref =( */ /** Return the clock. (aged_containers want a non-const ref =( */
clock_type& clock_type&
clock() const; 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; auto e = &*iter;
++iter; ++iter;
e->~event(); 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 typename by_when_set::iterator
{ {
using event_type = event_impl<std::decay_t<Handler>>; 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)); auto& e = *new (p) event_type(when, std::forward<Handler>(h));
return by_when_.insert(e); return by_when_.insert(e);
} }
@@ -325,7 +327,7 @@ Scheduler::queue_type::erase(iterator iter) -> typename by_when_set::iterator
auto& e = *iter; auto& e = *iter;
auto next = by_when_.erase(iter); auto next = by_when_.erase(iter);
e.~event(); e.~event();
alloc_.dealloc(&e, 1); alloc_->deallocate(&e, sizeof(e));
return next; 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 inline auto
Scheduler::clock() const -> clock_type& Scheduler::clock() const -> clock_type&
{ {

View File

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