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