rippled
Loading...
Searching...
No Matches
SHAMapItem.h
1#pragma once
2
3#include <xrpl/basics/ByteUtilities.h>
4#include <xrpl/basics/CountedObject.h>
5#include <xrpl/basics/SlabAllocator.h>
6#include <xrpl/basics/Slice.h>
7#include <xrpl/basics/base_uint.h>
8#include <xrpl/beast/utility/instrumentation.h>
9
10#include <boost/smart_ptr/intrusive_ptr.hpp>
11
12namespace xrpl {
13
14// an item stored in a SHAMap
15class SHAMapItem : public CountedObject<SHAMapItem>
16{
17 // These are used to support boost::intrusive_ptr reference counting
18 // These functions are used internally by boost::intrusive_ptr to handle
19 // lifetime management.
20 friend void
22
23 friend void
25
26 // This is the interface for creating new instances of this class.
27 friend boost::intrusive_ptr<SHAMapItem>
28 make_shamapitem(uint256 const& tag, Slice data);
29
30private:
32
33 // We use std::uint32_t to minimize the size; there's no SHAMapItem whose
34 // size exceeds 4GB and there won't ever be (famous last words?), so this
35 // is safe.
37
38 // This is the reference count used to support boost::intrusive_ptr
40
41 // Because of the unusual way in which SHAMapItem objects are constructed
42 // the only way to properly create one is to first allocate enough memory
43 // so we limit this constructor to codepaths that do this right and limit
44 // arbitrary construction.
46 : tag_(tag), size_(static_cast<std::uint32_t>(data.size()))
47 {
49 reinterpret_cast<std::uint8_t*>(this) + sizeof(*this), data.data(), data.size());
50 }
51
52public:
53 SHAMapItem() = delete;
54
55 SHAMapItem(SHAMapItem const& other) = delete;
56
58 operator=(SHAMapItem const& other) = delete;
59
60 SHAMapItem(SHAMapItem&& other) = delete;
61
63 operator=(SHAMapItem&&) = delete;
64
65 uint256 const&
66 key() const
67 {
68 return tag_;
69 }
70
72 size() const
73 {
74 return size_;
75 }
76
77 void const*
78 data() const
79 {
80 return reinterpret_cast<std::uint8_t const*>(this) + sizeof(*this);
81 }
82
83 Slice
84 slice() const
85 {
86 return {data(), size()};
87 }
88};
89
90namespace detail {
91
92// clang-format off
93// The slab cutoffs and the number of megabytes per allocation are customized
94// based on the number of objects of each size we expect to need at any point
95// in time and with an eye to minimize the number of slack bytes in a block.
97 { 128, megabytes(std::size_t(60)) },
98 { 192, megabytes(std::size_t(46)) },
99 { 272, megabytes(std::size_t(60)) },
100 { 384, megabytes(std::size_t(56)) },
101 { 564, megabytes(std::size_t(40)) },
102 { 772, megabytes(std::size_t(46)) },
103 { 1052, megabytes(std::size_t(60)) },
104});
105// clang-format on
106
107} // namespace detail
108
109inline void
111{
112 // This can only happen if someone releases the last reference to the
113 // item while we were trying to increment the refcount.
114 if (x->refcount_++ == 0)
115 LogicError("SHAMapItem: the reference count is 0!");
116}
117
118inline void
120{
121 if (--x->refcount_ == 0)
122 {
123 auto p = reinterpret_cast<std::uint8_t const*>(x);
124
125 // The SHAMapItem constructor isn't trivial (because the destructor
126 // for CountedObject isn't) so we can't avoid calling it here, but
127 // plan for a future where we might not need to.
130
131 // If the slabber doesn't claim this pointer, it was allocated
132 // manually, so we free it manually.
133 if (!detail::slabber.deallocate(const_cast<std::uint8_t*>(p)))
134 delete[] p;
135 }
136}
137
138inline boost::intrusive_ptr<SHAMapItem>
140{
141 XRPL_ASSERT(
142 data.size() <= megabytes<std::size_t>(16), "xrpl::make_shamapitem : maximum input size");
143
144 // NOLINTNEXTLINE(misc-const-correctness)
145 std::uint8_t* raw = detail::slabber.allocate(data.size());
146
147 // If we can't grab memory from the slab allocators, we fall back to
148 // the standard library and try to grab a precisely-sized memory block:
149 if (raw == nullptr)
150 raw = new std::uint8_t[sizeof(SHAMapItem) + data.size()];
151
152 // We do not increment the reference count here on purpose: the
153 // constructor of SHAMapItem explicitly sets it to 1. We use the fact
154 // that the refcount can never be zero before incrementing as an
155 // invariant.
156 return {new (raw) SHAMapItem{tag, data}, false};
157}
158
159static_assert(alignof(SHAMapItem) != 40);
160static_assert(alignof(SHAMapItem) == 8 || alignof(SHAMapItem) == 4);
161
162inline boost::intrusive_ptr<SHAMapItem>
164{
165 return make_shamapitem(other.key(), other.slice());
166}
167
168} // namespace xrpl
Tracks the number of instances of an object.
SHAMapItem & operator=(SHAMapItem const &other)=delete
uint256 const tag_
Definition SHAMapItem.h:31
SHAMapItem(SHAMapItem &&other)=delete
SHAMapItem()=delete
std::uint32_t const size_
Definition SHAMapItem.h:36
SHAMapItem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:45
friend void intrusive_ptr_add_ref(SHAMapItem const *x)
Definition SHAMapItem.h:110
SHAMapItem(SHAMapItem const &other)=delete
std::size_t size() const
Definition SHAMapItem.h:72
friend void intrusive_ptr_release(SHAMapItem const *x)
Definition SHAMapItem.h:119
Slice slice() const
Definition SHAMapItem.h:84
friend boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:139
void const * data() const
Definition SHAMapItem.h:78
uint256 const & key() const
Definition SHAMapItem.h:66
std::atomic< std::uint32_t > refcount_
Definition SHAMapItem.h:39
SHAMapItem & operator=(SHAMapItem &&)=delete
A collection of slab allocators of various sizes for a given type.
An immutable linear range of bytes.
Definition Slice.h:26
T destroy_at(T... args)
T is_same_v
T memcpy(T... args)
STL namespace.
SlabAllocatorSet< SHAMapItem > slabber({ { 128, megabytes(std::size_t(60)) }, { 192, megabytes(std::size_t(46)) }, { 272, megabytes(std::size_t(60)) }, { 384, megabytes(std::size_t(56)) }, { 564, megabytes(std::size_t(40)) }, { 772, megabytes(std::size_t(46)) }, { 1052, megabytes(std::size_t(60)) }, })
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:139
void intrusive_ptr_release(SHAMapItem const *x)
Definition SHAMapItem.h:119
void intrusive_ptr_add_ref(SHAMapItem const *x)
Definition SHAMapItem.h:110
constexpr auto megabytes(T value) noexcept