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.
45 SHAMapItem(uint256 const& tag, Slice data) : tag_(tag), size_(static_cast<std::uint32_t>(data.size()))
46 {
47 std::memcpy(reinterpret_cast<std::uint8_t*>(this) + sizeof(*this), data.data(), data.size());
48 }
49
50public:
51 SHAMapItem() = delete;
52
53 SHAMapItem(SHAMapItem const& other) = delete;
54
56 operator=(SHAMapItem const& other) = delete;
57
58 SHAMapItem(SHAMapItem&& other) = delete;
59
61 operator=(SHAMapItem&&) = delete;
62
63 uint256 const&
64 key() const
65 {
66 return tag_;
67 }
68
70 size() const
71 {
72 return size_;
73 }
74
75 void const*
76 data() const
77 {
78 return reinterpret_cast<std::uint8_t const*>(this) + sizeof(*this);
79 }
80
81 Slice
82 slice() const
83 {
84 return {data(), size()};
85 }
86};
87
88namespace detail {
89
90// clang-format off
91// The slab cutoffs and the number of megabytes per allocation are customized
92// based on the number of objects of each size we expect to need at any point
93// in time and with an eye to minimize the number of slack bytes in a block.
95 { 128, megabytes(std::size_t(60)) },
96 { 192, megabytes(std::size_t(46)) },
97 { 272, megabytes(std::size_t(60)) },
98 { 384, megabytes(std::size_t(56)) },
99 { 564, megabytes(std::size_t(40)) },
100 { 772, megabytes(std::size_t(46)) },
101 { 1052, megabytes(std::size_t(60)) },
102});
103// clang-format on
104
105} // namespace detail
106
107inline void
109{
110 // This can only happen if someone releases the last reference to the
111 // item while we were trying to increment the refcount.
112 if (x->refcount_++ == 0)
113 LogicError("SHAMapItem: the reference count is 0!");
114}
115
116inline void
118{
119 if (--x->refcount_ == 0)
120 {
121 auto p = reinterpret_cast<std::uint8_t const*>(x);
122
123 // The SHAMapItem constructor isn't trivial (because the destructor
124 // for CountedObject isn't) so we can't avoid calling it here, but
125 // plan for a future where we might not need to.
128
129 // If the slabber doesn't claim this pointer, it was allocated
130 // manually, so we free it manually.
131 if (!detail::slabber.deallocate(const_cast<std::uint8_t*>(p)))
132 delete[] p;
133 }
134}
135
136inline boost::intrusive_ptr<SHAMapItem>
138{
139 XRPL_ASSERT(data.size() <= megabytes<std::size_t>(16), "xrpl::make_shamapitem : maximum input size");
140
141 std::uint8_t* raw = detail::slabber.allocate(data.size());
142
143 // If we can't grab memory from the slab allocators, we fall back to
144 // the standard library and try to grab a precisely-sized memory block:
145 if (raw == nullptr)
146 raw = new std::uint8_t[sizeof(SHAMapItem) + data.size()];
147
148 // We do not increment the reference count here on purpose: the
149 // constructor of SHAMapItem explicitly sets it to 1. We use the fact
150 // that the refcount can never be zero before incrementing as an
151 // invariant.
152 return {new (raw) SHAMapItem{tag, data}, false};
153}
154
155static_assert(alignof(SHAMapItem) != 40);
156static_assert(alignof(SHAMapItem) == 8 || alignof(SHAMapItem) == 4);
157
158inline boost::intrusive_ptr<SHAMapItem>
160{
161 return make_shamapitem(other.key(), other.slice());
162}
163
164} // 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:108
SHAMapItem(SHAMapItem const &other)=delete
std::size_t size() const
Definition SHAMapItem.h:70
friend void intrusive_ptr_release(SHAMapItem const *x)
Definition SHAMapItem.h:117
Slice slice() const
Definition SHAMapItem.h:82
friend boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:137
void const * data() const
Definition SHAMapItem.h:76
uint256 const & key() const
Definition SHAMapItem.h:64
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:137
void intrusive_ptr_release(SHAMapItem const *x)
Definition SHAMapItem.h:117
void intrusive_ptr_add_ref(SHAMapItem const *x)
Definition SHAMapItem.h:108
constexpr auto megabytes(T value) noexcept