rippled
Loading...
Searching...
No Matches
SHAMapItem.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#ifndef RIPPLE_SHAMAP_SHAMAPITEM_H_INCLUDED
21#define RIPPLE_SHAMAP_SHAMAPITEM_H_INCLUDED
22
23#include <xrpl/basics/ByteUtilities.h>
24#include <xrpl/basics/CountedObject.h>
25#include <xrpl/basics/SlabAllocator.h>
26#include <xrpl/basics/Slice.h>
27#include <xrpl/basics/base_uint.h>
28#include <xrpl/beast/utility/instrumentation.h>
29
30#include <boost/smart_ptr/intrusive_ptr.hpp>
31
32namespace ripple {
33
34// an item stored in a SHAMap
35class SHAMapItem : public CountedObject<SHAMapItem>
36{
37 // These are used to support boost::intrusive_ptr reference counting
38 // These functions are used internally by boost::intrusive_ptr to handle
39 // lifetime management.
40 friend void
42
43 friend void
45
46 // This is the interface for creating new instances of this class.
47 friend boost::intrusive_ptr<SHAMapItem>
48 make_shamapitem(uint256 const& tag, Slice data);
49
50private:
52
53 // We use std::uint32_t to minimize the size; there's no SHAMapItem whose
54 // size exceeds 4GB and there won't ever be (famous last words?), so this
55 // is safe.
57
58 // This is the reference count used to support boost::intrusive_ptr
60
61 // Because of the unusual way in which SHAMapItem objects are constructed
62 // the only way to properly create one is to first allocate enough memory
63 // so we limit this constructor to codepaths that do this right and limit
64 // arbitrary construction.
66 : tag_(tag), size_(static_cast<std::uint32_t>(data.size()))
67 {
69 reinterpret_cast<std::uint8_t*>(this) + sizeof(*this),
70 data.data(),
71 data.size());
72 }
73
74public:
75 SHAMapItem() = delete;
76
77 SHAMapItem(SHAMapItem const& other) = delete;
78
80 operator=(SHAMapItem const& other) = delete;
81
82 SHAMapItem(SHAMapItem&& other) = delete;
83
85 operator=(SHAMapItem&&) = delete;
86
87 uint256 const&
88 key() const
89 {
90 return tag_;
91 }
92
94 size() const
95 {
96 return size_;
97 }
98
99 void const*
100 data() const
101 {
102 return reinterpret_cast<std::uint8_t const*>(this) + sizeof(*this);
103 }
104
105 Slice
106 slice() const
107 {
108 return {data(), size()};
109 }
110};
111
112namespace detail {
113
114// clang-format off
115// The slab cutoffs and the number of megabytes per allocation are customized
116// based on the number of objects of each size we expect to need at any point
117// in time and with an eye to minimize the number of slack bytes in a block.
119 { 128, megabytes(std::size_t(60)) },
120 { 192, megabytes(std::size_t(46)) },
121 { 272, megabytes(std::size_t(60)) },
122 { 384, megabytes(std::size_t(56)) },
123 { 564, megabytes(std::size_t(40)) },
124 { 772, megabytes(std::size_t(46)) },
125 { 1052, megabytes(std::size_t(60)) },
126});
127// clang-format on
128
129} // namespace detail
130
131inline void
133{
134 // This can only happen if someone releases the last reference to the
135 // item while we were trying to increment the refcount.
136 if (x->refcount_++ == 0)
137 LogicError("SHAMapItem: the reference count is 0!");
138}
139
140inline void
142{
143 if (--x->refcount_ == 0)
144 {
145 auto p = reinterpret_cast<std::uint8_t const*>(x);
146
147 // The SHAMapItem constuctor isn't trivial (because the destructor
148 // for CountedObject isn't) so we can't avoid calling it here, but
149 // plan for a future where we might not need to.
152
153 // If the slabber doens't claim this pointer, it was allocated
154 // manually, so we free it manually.
155 if (!detail::slabber.deallocate(const_cast<std::uint8_t*>(p)))
156 delete[] p;
157 }
158}
159
160inline boost::intrusive_ptr<SHAMapItem>
162{
163 XRPL_ASSERT(
164 data.size() <= megabytes<std::size_t>(16),
165 "ripple::make_shamapitem : maximum input size");
166
167 std::uint8_t* raw = detail::slabber.allocate(data.size());
168
169 // If we can't grab memory from the slab allocators, we fall back to
170 // the standard library and try to grab a precisely-sized memory block:
171 if (raw == nullptr)
172 raw = new std::uint8_t[sizeof(SHAMapItem) + data.size()];
173
174 // We do not increment the reference count here on purpose: the
175 // constructor of SHAMapItem explicitly sets it to 1. We use the fact
176 // that the refcount can never be zero before incrementing as an
177 // invariant.
178 return {new (raw) SHAMapItem{tag, data}, false};
179}
180
181static_assert(alignof(SHAMapItem) != 40);
182static_assert(alignof(SHAMapItem) == 8 || alignof(SHAMapItem) == 4);
183
184inline boost::intrusive_ptr<SHAMapItem>
186{
187 return make_shamapitem(other.key(), other.slice());
188}
189
190} // namespace ripple
191
192#endif
Tracks the number of instances of an object.
SHAMapItem(SHAMapItem &&other)=delete
void const * data() const
Definition SHAMapItem.h:100
Slice slice() const
Definition SHAMapItem.h:106
friend void intrusive_ptr_add_ref(SHAMapItem const *x)
Definition SHAMapItem.h:132
uint256 const & key() const
Definition SHAMapItem.h:88
std::uint32_t const size_
Definition SHAMapItem.h:56
uint256 const tag_
Definition SHAMapItem.h:51
SHAMapItem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:65
friend void intrusive_ptr_release(SHAMapItem const *x)
Definition SHAMapItem.h:141
SHAMapItem & operator=(SHAMapItem const &other)=delete
friend boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:161
std::atomic< std::uint32_t > refcount_
Definition SHAMapItem.h:59
std::size_t size() const
Definition SHAMapItem.h:94
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:46
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:25
constexpr auto megabytes(T value) noexcept
void intrusive_ptr_release(SHAMapItem const *x)
Definition SHAMapItem.h:141
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:161
void intrusive_ptr_add_ref(SHAMapItem const *x)
Definition SHAMapItem.h:132
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
STL namespace.