17 #ifndef __STDC_LIMIT_MACROS 18 #define __STDC_LIMIT_MACROS 37 using std::unique_ptr;
59 kDefaultCombinedBufSize = 1024
63 void takeOwnershipError(
76 freeFn(buf, userData);
113 static_assert(
sizeof(
HeapStorage) <= 64,
"IOBuf may not grow over 56 bytes!");
123 refcount.store(1, std::memory_order_relaxed);
130 refcount.store(1, std::memory_order_relaxed);
133 void* IOBuf::operator
new(
size_t size) {
137 new (&storage->prefix)
HeapPrefix(kIOBufInUse);
138 return &(storage->buf);
141 void* IOBuf::operator
new(
size_t ,
void*
ptr) {
145 void IOBuf::operator
delete(
void*
ptr) {
147 auto* storage =
reinterpret_cast<HeapStorage*
>(storageAddr);
151 void IOBuf::operator
delete(
void* ,
void* ) {
158 CHECK_EQ(storage->
prefix.
magic, static_cast<uint16_t>(kHeapMagic));
164 DCHECK_EQ((
flags & freeFlags), freeFlags);
170 storage->
prefix.HeapPrefix::~HeapPrefix();
177 auto ret = storage->
prefix.
flags.compare_exchange_weak(
178 flags, newFlags, std::memory_order_acq_rel);
212 std::size_t minTailroom)
216 assert(buf !=
nullptr);
226 std::size_t minTailroom)
239 if (capacity <= kDefaultCombinedBufSize) {
252 new (&storage->hs.prefix)
HeapPrefix(kIOBufInUse | kDataInUse);
256 uint8_t* storageEnd =
reinterpret_cast<uint8_t*
>(storage) + mallocSize;
257 size_t actualCapacity = size_t(storageEnd - bufAddr);
258 unique_ptr<IOBuf> ret(
new (&storage->hs.buf)
IOBuf(
273 size_t totalCapacity,
274 std::size_t maxBufCapacity) {
275 unique_ptr<IOBuf> out =
277 size_t allocatedCapacity = out->capacity();
279 while (allocatedCapacity < totalCapacity) {
280 unique_ptr<IOBuf> newBuf =
create(
281 std::min(totalCapacity - allocatedCapacity,
size_t(maxBufCapacity)));
282 allocatedCapacity += newBuf->capacity();
308 takeOwnershipError(freeOnError, buf, freeFn, userData);
330 return std::make_unique<IOBuf>(
333 takeOwnershipError(freeOnError, buf, freeFn, userData);
345 static_cast<uint8_t*>(const_cast<void*>(buf)),
347 static_cast<uint8_t*>(const_cast<void*>(buf)),
351 :
IOBuf(
op, br.data(), br.size()) {}
370 other.data_ =
nullptr;
371 other.buf_ =
nullptr;
374 other.flagsAndSharedInfo_ = 0;
378 if (other.next_ != &other) {
381 other.
next_ = &other;
385 other.
prev_ = &other;
389 DCHECK_EQ(other.prev_, &other);
390 DCHECK_EQ(other.next_, &other);
399 uintptr_t flagsAndSharedInfo,
419 while (
next_ !=
this) {
429 if (
this == &other) {
434 while (
next_ !=
this) {
450 other.data_ =
nullptr;
451 other.buf_ =
nullptr;
454 other.flagsAndSharedInfo_ = 0;
458 if (other.next_ != &other) {
461 other.
next_ = &other;
465 other.
prev_ = &other;
469 DCHECK_EQ(other.prev_, &other);
470 DCHECK_EQ(other.next_, &other);
476 if (
this != &other) {
477 *
this =
IOBuf(other);
485 if (current->
length() != 0) {
488 current = current->
next_;
489 }
while (current !=
this);
494 size_t numElements = 1;
502 std::size_t fullLength =
length_;
504 fullLength +=
current->length_;
511 IOBuf* other = iobuf.release();
523 otherTail->
next_ =
this;
540 std::size_t newHeadroom,
541 std::size_t newTailroom)
const {
542 return std::make_unique<IOBuf>(
550 tmp.prependChain(
current->cloneOne());
559 info->refcount.fetch_add(1, std::memory_order_acq_rel);
571 const std::size_t newHeadroom =
headroom();
577 std::size_t newHeadroom,
578 std::size_t newTailroom)
const {
584 const std::size_t newCapacity = newLength + newHeadroom + newTailroom;
586 newBuf.advance(newHeadroom);
591 DCHECK_NOTNULL(
current->data());
592 DCHECK_LE(
current->length(), newBuf.tailroom());
593 memcpy(newBuf.writableTail(),
current->data(),
current->length());
594 newBuf.append(
current->length());
599 DCHECK_EQ(newLength, newBuf.length());
600 DCHECK_EQ(newHeadroom, newBuf.headroom());
601 DCHECK_LE(newTailroom, newBuf.tailroom());
610 std::size_t actualCapacity;
618 assert(
data_ !=
nullptr);
628 data_ = buf + headlen;
644 current = current->
next_;
645 if (current ==
this) {
660 current = current->
next_;
661 }
while (current !=
this);
670 current = current->
next_;
671 if (current ==
this) {
683 std::size_t newLength = 0;
688 }
while (end !=
this);
702 std::size_t newLength = 0;
707 if (newLength >= maxLength) {
711 throw std::overflow_error(
712 "attempted to coalesce more data than " 726 size_t newTailroom) {
727 std::size_t newCapacity = newLength + newHeadroom + newTailroom;
734 std::size_t actualCapacity;
738 uint8_t* newData = newBuf + newHeadroom;
741 size_t remaining = newLength;
744 assert(current->
length_ <= remaining);
745 assert(current->
data_ !=
nullptr);
750 current = current->
next_;
751 }
while (current != end);
752 assert(remaining == 0);
809 size_t newCapacity = (size_t)
length_ + minHeadroom + minTailroom;
810 DCHECK_LT(newCapacity, UINT32_MAX);
838 size_t newAllocatedCapacity = 0;
840 std::size_t newHeadroom = 0;
841 std::size_t oldHeadroom =
headroom();
847 oldHeadroom >= minHeadroom) {
848 size_t headSlack = oldHeadroom - minHeadroom;
856 if (headSlack * 4 <= newCapacity) {
860 if (
xallocx(p, newAllocatedCapacity, 0, 0) == newAllocatedCapacity) {
861 newBuffer =
static_cast<uint8_t*
>(p);
862 newHeadroom = oldHeadroom;
869 if (copySlack * 2 <=
length_) {
870 void* p = realloc(
buf_, newAllocatedCapacity);
872 throw std::bad_alloc();
874 newBuffer =
static_cast<uint8_t*
>(p);
875 newHeadroom = oldHeadroom;
882 if (newBuffer ==
nullptr) {
886 assert(
data_ !=
nullptr);
892 newHeadroom = minHeadroom;
905 data_ = newBuffer + newHeadroom;
928 std::size_t minCapacity,
931 std::size_t* capacityReturn) {
943 size_t minSize =
static_cast<size_t>(minCapacity) +
sizeof(
SharedInfo);
946 minSize = (minSize + 7) & ~7;
958 std::size_t* capacityReturn) {
964 *capacityReturn = std::size_t(infoStart - buf);
1017 IOBuf const* p =
this;
1024 }
while (p !=
this);
1028 unique_ptr<IOBuf> result =
nullptr;
1029 for (
size_t i = 0;
i <
count; ++
i) {
1030 size_t len = vec[
i].iov_len;
1031 void*
data = vec[
i].iov_base;
1053 unique_ptr<IOBuf> result =
nullptr;
1054 for (
size_t i = 0;
i <
count; ++
i) {
1055 size_t len = vec[
i].iov_len;
1056 void*
data = vec[
i].iov_base;
1058 auto buf =
takeOwnership(data, len, freeFn, userData, freeOnError);
1073 IOBuf const* p =
this;
1100 cursor.
skip(
b.size());
1104 hasher.
Final(&h1, &h2);
1105 return static_cast<std::size_t
>(h1);
1114 if (ba.empty() || bb.empty()) {
1115 return to_ordering(
int(bb.empty()) -
int(ba.empty()));
1117 const size_t n =
std::min(ba.size(), bb.size());
void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom)
constexpr ordering to_ordering(T c)
static std::unique_ptr< IOBuf > createCombined(std::size_t capacity)
void markExternallyShared()
static void allocExtBuffer(std::size_t minCapacity, uint8_t **bufReturn, SharedInfo **infoReturn, std::size_t *capacityReturn)
void * checkedMalloc(size_t size)
IOBuf cloneOneAsValue() const
static std::unique_ptr< IOBuf > create(std::size_t capacity)
void(* FreeFunction)(void *buf, void *userData)
static std::unique_ptr< IOBuf > wrapBuffer(const void *buf, std::size_t capacity)
bool usingJEMalloc() noexcept
fbstring moveToFbString()
constexpr detail::Map< Move > move
void reserve(size_type n)
void advance(std::size_t amount)
const uint8_t * data() const
std::unique_ptr< IOBuf > cloneCoalesced() const
folly::fbvector< struct iovec > getIov() const
—— Concurrent Priority Queue Implementation ——
std::unique_ptr< IOBuf > clone() const
size_t countChainElements() const
void Init(uint64_t seed1, uint64_t seed2)
void makeManagedChained()
requires E e noexcept(noexcept(s.error(std::move(e))))
std::unique_ptr< IOBuf > separateChain(IOBuf *head, IOBuf *tail)
std::size_t capacity() const
static const size_t jemallocMinInPlaceExpandable
std::size_t tailroom() const
static std::unique_ptr< IOBuf > createSeparate(std::size_t capacity)
ordering impl(IOBuf const &a, IOBuf const &b) const noexcept
uint8_t * writableBuffer()
void coalesceAndReallocate(size_t newHeadroom, size_t newLength, IOBuf *end, size_t newTailroom)
size_t operator()(const IOBuf &buf) const noexcept
static void releaseStorage(HeapStorage *storage, uint16_t freeFlags)
void push_back(const T &value)
size_t(* xallocx)(void *, size_t, size_t, int)
size_t fillIov(struct iovec *iov, size_t len) const
constexpr auto size(C const &c) -> decltype(c.size())
void setSharedInfo(SharedInfo *info)
std::size_t headroom() const
IOBuf cloneAsValue() const
std::size_t length() const
static std::unique_ptr< IOBuf > takeOwnershipIov(const iovec *vec, size_t count, FreeFunction freeFn=nullptr, void *userData=nullptr, bool freeOnError=true)
IOBuf & operator=(IOBuf &&other) noexcept
std::unique_ptr< IOBuf > cloneCoalescedWithHeadroomTailroom(std::size_t newHeadroom, std::size_t newTailroom) const
static uintptr_t packFlagsAndSharedInfo(uintptr_t flags, SharedInfo *info)
std::unique_ptr< IOBuf > cloneOne() const
std::unique_ptr< IOBuf > unlink()
static IOBuf wrapBufferAsValue(const void *buf, std::size_t capacity) noexcept
void prependChain(std::unique_ptr< IOBuf > &&iobuf)
void Final(uint64_t *hash1, uint64_t *hash2) const
static std::unique_ptr< IOBuf > createChain(size_t totalCapacity, std::size_t maxBufCapacity)
void markExternallySharedOne()
std::size_t computeChainDataLength() const
static std::unique_ptr< IOBuf > takeOwnership(void *buf, std::size_t capacity, FreeFunction freeFn=nullptr, void *userData=nullptr, bool freeOnError=true)
static void freeInternalBuf(void *buf, void *userData)
SharedInfo * sharedInfo() const
static size_t goodExtBufferSize(std::size_t minCapacity)
void Update(const void *message, size_t length)
uintptr_t flagsAndSharedInfo_
IOBuf cloneCoalescedAsValue() const
void appendToIov(folly::fbvector< struct iovec > *iov) const
std::atomic< uint32_t > refcount
void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo *info)
std::atomic< uint16_t > flags
void setFlags(uintptr_t flags) const
IOBuf cloneCoalescedAsValueWithHeadroomTailroom(std::size_t newHeadroom, std::size_t newTailroom) const
static void initExtBuffer(uint8_t *buf, size_t mallocSize, SharedInfo **infoReturn, std::size_t *capacityReturn)
void append(std::size_t amount)
static std::unique_ptr< IOBuf > wrapIov(const iovec *vec, size_t count)
size_t goodMallocSize(size_t minSize) noexcept