void IOBuf::unshareOneSlow() { // Allocate a new buffer for the data uint8_t* buf; SharedInfo* sharedInfo; uint64_t actualCapacity; allocExtBuffer(capacity_, &buf, &sharedInfo, &actualCapacity); // Copy the data // Maintain the same amount of headroom. Since we maintained the same // minimum capacity we also maintain at least the same amount of tailroom. uint64_t headlen = headroom(); if (length_ > 0) { assert(data_ != nullptr); memcpy(buf + headlen, data_, length_); } // Release our reference on the old buffer decrementRefcount(); // Make sure kFlagMaybeShared and kFlagFreeSharedInfo are all cleared. setFlagsAndSharedInfo(0, sharedInfo); // Update the buffer pointers to point to the new buffer data_ = buf + headlen; buf_ = buf; }
IOBuf::IOBuf(CreateOp, uint32_t capacity) : next_(this), prev_(this), data_(nullptr), length_(0), flags_(0), type_(kExtAllocated) { allocExtBuffer(capacity, &buf_, &sharedInfo_, &capacity_); data_ = buf_; }
IOBuf::IOBuf(CreateOp, uint64_t capacity) : next_(this), prev_(this), data_(nullptr), length_(0), flagsAndSharedInfo_(0) { SharedInfo* info; allocExtBuffer(capacity, &buf_, &info, &capacity_); setSharedInfo(info); data_ = buf_; }
void IOBuf::coalesceAndReallocate(size_t newHeadroom, size_t newLength, IOBuf* end, size_t newTailroom) { uint64_t newCapacity = newLength + newHeadroom + newTailroom; if (newCapacity > UINT32_MAX) { throw std::overflow_error("IOBuf chain too large to coalesce"); } // Allocate space for the coalesced buffer. // We always convert to an external buffer, even if we happened to be an // internal buffer before. uint8_t* newBuf; SharedInfo* newInfo; uint32_t actualCapacity; allocExtBuffer(newCapacity, &newBuf, &newInfo, &actualCapacity); // Copy the data into the new buffer uint8_t* newData = newBuf + newHeadroom; uint8_t* p = newData; IOBuf* current = this; size_t remaining = newLength; do { assert(current->length_ <= remaining); remaining -= current->length_; memcpy(p, current->data_, current->length_); p += current->length_; current = current->next_; } while (current != end); assert(remaining == 0); // Point at the new buffer decrementRefcount(); // Make sure kFlagUserOwned, kFlagMaybeShared, and kFlagFreeSharedInfo // are all cleared. flags_ = 0; capacity_ = actualCapacity; type_ = kExtAllocated; buf_ = newBuf; sharedInfo_ = newInfo; data_ = newData; length_ = newLength; // Separate from the rest of our chain. // Since we don't store the unique_ptr returned by separateChain(), // this will immediately delete the returned subchain. if (isChained()) { (void)separateChain(next_, current->prev_); } }
void IOBuf::coalesceAndReallocate(size_t newHeadroom, size_t newLength, IOBuf* end, size_t newTailroom) { uint64_t newCapacity = newLength + newHeadroom + newTailroom; // Allocate space for the coalesced buffer. // We always convert to an external buffer, even if we happened to be an // internal buffer before. uint8_t* newBuf; SharedInfo* newInfo; uint64_t actualCapacity; allocExtBuffer(newCapacity, &newBuf, &newInfo, &actualCapacity); // Copy the data into the new buffer uint8_t* newData = newBuf + newHeadroom; uint8_t* p = newData; IOBuf* current = this; size_t remaining = newLength; do { if (current->length_ > 0) { assert(current->length_ <= remaining); assert(current->data_ != nullptr); remaining -= current->length_; memcpy(p, current->data_, current->length_); p += current->length_; } current = current->next_; } while (current != end); assert(remaining == 0); // Point at the new buffer decrementRefcount(); // Make sure kFlagMaybeShared and kFlagFreeSharedInfo are all cleared. setFlagsAndSharedInfo(0, newInfo); capacity_ = actualCapacity; buf_ = newBuf; data_ = newData; length_ = newLength; // Separate from the rest of our chain. // Since we don't store the unique_ptr returned by separateChain(), // this will immediately delete the returned subchain. if (isChained()) { (void)separateChain(next_, current->prev_); } }
void IOBuf::unshareOneSlow() { // Allocate a new buffer for the data uint8_t* buf; SharedInfo* sharedInfo; uint32_t actualCapacity; allocExtBuffer(capacity_, &buf, &sharedInfo, &actualCapacity); // Copy the data // Maintain the same amount of headroom. Since we maintained the same // minimum capacity we also maintain at least the same amount of tailroom. uint32_t headlen = headroom(); memcpy(buf + headlen, data_, length_); // Release our reference on the old buffer decrementRefcount(); // Make sure kFlagUserOwned, kFlagMaybeShared, and kFlagFreeSharedInfo // are all cleared. flags_ = 0; // Update the buffer pointers to point to the new buffer data_ = buf + headlen; buf_ = buf; sharedInfo_ = sharedInfo; }