mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
This change replaces all include guards in the `src/` and `include/` directories by `#pragma once`.
109 lines
3.3 KiB
C++
109 lines
3.3 KiB
C++
#pragma once
|
|
|
|
#include <xrpl/beast/utility/instrumentation.h>
|
|
#include <xrpl/nodestore/NodeObject.h>
|
|
|
|
#include <boost/align/align_up.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cstdint>
|
|
|
|
namespace xrpl {
|
|
namespace NodeStore {
|
|
|
|
/** Convert a NodeObject from in-memory to database format.
|
|
|
|
The (suboptimal) database format consists of:
|
|
|
|
- 8 prefix bytes which will typically be 0, but don't assume that's the
|
|
case; earlier versions of the code would use these bytes to store the
|
|
ledger index either once or twice.
|
|
- A single byte denoting the type of the object.
|
|
- The payload.
|
|
|
|
@note This class is typically instantiated on the stack, so the size of
|
|
the object does not matter as much as it normally would since the
|
|
allocation is, effectively, free.
|
|
|
|
We leverage that fact to preallocate enough memory to handle most
|
|
payloads as part of this object, eliminating the need for dynamic
|
|
allocation. As of this writing ~94% of objects require fewer than
|
|
1024 payload bytes.
|
|
*/
|
|
|
|
class EncodedBlob
|
|
{
|
|
/** The 32-byte key of the serialized object. */
|
|
std::array<std::uint8_t, 32> key_;
|
|
|
|
/** A pre-allocated buffer for the serialized object.
|
|
|
|
The buffer is large enough for the 9 byte prefix and at least
|
|
1024 more bytes. The precise size is calculated automatically
|
|
at compile time so as to avoid wasting space on padding bytes.
|
|
*/
|
|
std::array<std::uint8_t, boost::alignment::align_up(9 + 1024, alignof(std::uint32_t))> payload_;
|
|
|
|
/** The size of the serialized data. */
|
|
std::uint32_t size_;
|
|
|
|
/** A pointer to the serialized data.
|
|
|
|
This may point to the pre-allocated buffer (if it is sufficiently
|
|
large) or to a dynamically allocated buffer.
|
|
*/
|
|
std::uint8_t* const ptr_;
|
|
|
|
public:
|
|
explicit EncodedBlob(std::shared_ptr<NodeObject> const& obj)
|
|
: size_([&obj]() {
|
|
XRPL_ASSERT(obj, "xrpl::NodeStore::EncodedBlob::EncodedBlob : non-null input");
|
|
|
|
if (!obj)
|
|
throw std::runtime_error("EncodedBlob: unseated std::shared_ptr used.");
|
|
|
|
return obj->getData().size() + 9;
|
|
}())
|
|
, ptr_((size_ <= payload_.size()) ? payload_.data() : new std::uint8_t[size_])
|
|
{
|
|
std::fill_n(ptr_, 8, std::uint8_t{0});
|
|
ptr_[8] = static_cast<std::uint8_t>(obj->getType());
|
|
std::copy_n(obj->getData().data(), obj->getData().size(), ptr_ + 9);
|
|
std::copy_n(obj->getHash().data(), obj->getHash().size(), key_.data());
|
|
}
|
|
|
|
~EncodedBlob()
|
|
{
|
|
XRPL_ASSERT(
|
|
((ptr_ == payload_.data()) && (size_ <= payload_.size())) ||
|
|
((ptr_ != payload_.data()) && (size_ > payload_.size())),
|
|
"xrpl::NodeStore::EncodedBlob::~EncodedBlob : valid payload "
|
|
"pointer");
|
|
|
|
if (ptr_ != payload_.data())
|
|
delete[] ptr_;
|
|
}
|
|
|
|
[[nodiscard]] void const*
|
|
getKey() const noexcept
|
|
{
|
|
return static_cast<void const*>(key_.data());
|
|
}
|
|
|
|
[[nodiscard]] std::size_t
|
|
getSize() const noexcept
|
|
{
|
|
return size_;
|
|
}
|
|
|
|
[[nodiscard]] void const*
|
|
getData() const noexcept
|
|
{
|
|
return static_cast<void const*>(ptr_);
|
|
}
|
|
};
|
|
|
|
} // namespace NodeStore
|
|
} // namespace xrpl
|