unique_ptr<IOBuf> IOBufQueue::split(size_t n, bool throwOnUnderflow) { auto guard = updateGuard(); unique_ptr<IOBuf> result; while (n != 0) { if (head_ == nullptr) { if (throwOnUnderflow) { throw std::underflow_error( "Attempt to remove more bytes than are present in IOBufQueue"); } else { break; } } else if (head_->length() <= n) { n -= head_->length(); chainLength_ -= head_->length(); unique_ptr<IOBuf> remainder = head_->pop(); appendToChain(result, std::move(head_), false); head_ = std::move(remainder); } else { unique_ptr<IOBuf> clone = head_->cloneOne(); clone->trimEnd(clone->length() - n); appendToChain(result, std::move(clone), false); head_->trimStart(n); chainLength_ -= n; break; } } if (UNLIKELY(result == nullptr)) { return IOBuf::create(0); } return result; }
pair<void*,uint64_t> IOBufQueue::preallocateSlow(uint64_t min, uint64_t newAllocationSize, uint64_t max) { // Allocate a new buffer of the requested max size. unique_ptr<IOBuf> newBuf(IOBuf::create(std::max(min, newAllocationSize))); appendToChain(head_, std::move(newBuf), false); IOBuf* last = head_->prev(); return make_pair(last->writableTail(), std::min(max, last->tailroom())); }
void IOBufQueue::append(unique_ptr<IOBuf>&& buf, bool pack) { if (!buf) { return; } if (options_.cacheChainLength) { chainLength_ += buf->computeChainDataLength(); } appendToChain(head_, std::move(buf), pack); }
pair<void*,uint64_t> IOBufQueue::preallocateSlow(uint64_t min, uint64_t newAllocationSize, uint64_t max) { // Avoid grabbing update guard, since we're manually setting the cache ptrs. flushCache(); // Allocate a new buffer of the requested max size. unique_ptr<IOBuf> newBuf(IOBuf::create(std::max(min, newAllocationSize))); tailStart_ = newBuf->writableTail(); cachePtr_->cachedRange = std::pair<uint8_t*, uint8_t*>( tailStart_, tailStart_ + newBuf->tailroom()); appendToChain(head_, std::move(newBuf), false); return make_pair(writableTail(), std::min<uint64_t>(max, tailroom())); }
void IOBufQueue::append(IOBufQueue& other, bool pack) { if (!other.head_) { return; } if (options_.cacheChainLength) { if (other.options_.cacheChainLength) { chainLength_ += other.chainLength_; } else { chainLength_ += other.head_->computeChainDataLength(); } } appendToChain(head_, std::move(other.head_), pack); other.chainLength_ = 0; }
unique_ptr<IOBuf> IOBufQueue::split(size_t n) { unique_ptr<IOBuf> result; while (n != 0) { if (head_ == nullptr) { throw std::underflow_error( "Attempt to remove more bytes than are present in IOBufQueue"); } else if (head_->length() <= n) { n -= head_->length(); chainLength_ -= head_->length(); unique_ptr<IOBuf> remainder = head_->pop(); appendToChain(result, std::move(head_), false); head_ = std::move(remainder); } else { unique_ptr<IOBuf> clone = head_->cloneOne(); clone->trimEnd(clone->length() - n); appendToChain(result, std::move(clone), false); head_->trimStart(n); chainLength_ -= n; break; } } return std::move(result); }
void IOBufQueue::append(IOBufQueue& other, bool pack) { if (!other.head_) { return; } // We're going to chain other, thus we need to grab both guards. auto otherGuard = other.updateGuard(); auto guard = updateGuard(); if (options_.cacheChainLength) { if (other.options_.cacheChainLength) { chainLength_ += other.chainLength_; } else { chainLength_ += other.head_->computeChainDataLength(); } } appendToChain(head_, std::move(other.head_), pack); other.chainLength_ = 0; }
void IOBufQueue::append(const void* buf, size_t len) { auto src = static_cast<const uint8_t*>(buf); while (len != 0) { if ((head_ == nullptr) || head_->prev()->isSharedOne() || (head_->prev()->tailroom() == 0)) { appendToChain(head_, IOBuf::create(std::max(MIN_ALLOC_SIZE, std::min(len, MAX_ALLOC_SIZE))), false); } IOBuf* last = head_->prev(); uint64_t copyLen = std::min(len, (size_t)last->tailroom()); memcpy(last->writableTail(), src, copyLen); src += copyLen; last->append(copyLen); chainLength_ += copyLen; len -= copyLen; } }