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