bug fix when rallocm fails
[folly.git] / folly / io / IOBuf.cpp
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define __STDC_LIMIT_MACROS
18
19 #include "folly/io/IOBuf.h"
20
21 #include "folly/Conv.h"
22 #include "folly/Likely.h"
23 #include "folly/Malloc.h"
24 #include "folly/Memory.h"
25 #include "folly/ScopeGuard.h"
26
27 #include <stdexcept>
28 #include <assert.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31
32 using std::unique_ptr;
33
34 namespace {
35
36 enum : uint16_t {
37   kHeapMagic = 0xa5a5,
38   // This memory segment contains an IOBuf that is still in use
39   kIOBufInUse = 0x01,
40   // This memory segment contains buffer data that is still in use
41   kDataInUse = 0x02,
42 };
43
44 enum : uint32_t {
45   // When create() is called for buffers less than kDefaultCombinedBufSize,
46   // we allocate a single combined memory segment for the IOBuf and the data
47   // together.  See the comments for createCombined()/createSeparate() for more
48   // details.
49   //
50   // (The size of 1k is largely just a guess here.  We could could probably do
51   // benchmarks of real applications to see if adjusting this number makes a
52   // difference.  Callers that know their exact use case can also explicitly
53   // call createCombined() or createSeparate().)
54   kDefaultCombinedBufSize = 1024
55 };
56
57 // Helper function for IOBuf::takeOwnership()
58 void takeOwnershipError(bool freeOnError, void* buf,
59                         folly::IOBuf::FreeFunction freeFn,
60                         void* userData) {
61   if (!freeOnError) {
62     return;
63   }
64   if (!freeFn) {
65     free(buf);
66     return;
67   }
68   try {
69     freeFn(buf, userData);
70   } catch (...) {
71     // The user's free function is not allowed to throw.
72     // (We are already in the middle of throwing an exception, so
73     // we cannot let this exception go unhandled.)
74     abort();
75   }
76 }
77
78 } // unnamed namespace
79
80 namespace folly {
81
82 struct IOBuf::HeapPrefix {
83   HeapPrefix(uint16_t flg)
84     : magic(kHeapMagic),
85       flags(flg) {}
86   ~HeapPrefix() {
87     // Reset magic to 0 on destruction.  This is solely for debugging purposes
88     // to help catch bugs where someone tries to use HeapStorage after it has
89     // been deleted.
90     magic = 0;
91   }
92
93   uint16_t magic;
94   std::atomic<uint16_t> flags;
95 };
96
97 struct IOBuf::HeapStorage {
98   HeapPrefix prefix;
99   // The IOBuf is last in the HeapStorage object.
100   // This way operator new will work even if allocating a subclass of IOBuf
101   // that requires more space.
102   folly::IOBuf buf;
103 };
104
105 struct IOBuf::HeapFullStorage {
106   HeapStorage hs;
107   SharedInfo shared;
108   MaxAlign align;
109 };
110
111 IOBuf::SharedInfo::SharedInfo()
112   : freeFn(NULL),
113     userData(NULL) {
114   // Use relaxed memory ordering here.  Since we are creating a new SharedInfo,
115   // no other threads should be referring to it yet.
116   refcount.store(1, std::memory_order_relaxed);
117 }
118
119 IOBuf::SharedInfo::SharedInfo(FreeFunction fn, void* arg)
120   : freeFn(fn),
121     userData(arg) {
122   // Use relaxed memory ordering here.  Since we are creating a new SharedInfo,
123   // no other threads should be referring to it yet.
124   refcount.store(1, std::memory_order_relaxed);
125 }
126
127 void* IOBuf::operator new(size_t size) {
128   size_t fullSize = offsetof(HeapStorage, buf) + size;
129   auto* storage = static_cast<HeapStorage*>(malloc(fullSize));
130   // operator new is not allowed to return NULL
131   if (UNLIKELY(storage == nullptr)) {
132     throw std::bad_alloc();
133   }
134
135   new (&storage->prefix) HeapPrefix(kIOBufInUse);
136   return &(storage->buf);
137 }
138
139 void* IOBuf::operator new(size_t size, void* ptr) {
140   return ptr;
141 }
142
143 void IOBuf::operator delete(void* ptr) {
144   auto* storageAddr = static_cast<uint8_t*>(ptr) - offsetof(HeapStorage, buf);
145   auto* storage = reinterpret_cast<HeapStorage*>(storageAddr);
146   releaseStorage(storage, kIOBufInUse);
147 }
148
149 void IOBuf::releaseStorage(HeapStorage* storage, uint16_t freeFlags) {
150   CHECK_EQ(storage->prefix.magic, static_cast<uint16_t>(kHeapMagic));
151
152   // Use relaxed memory order here.  If we are unlucky and happen to get
153   // out-of-date data the compare_exchange_weak() call below will catch
154   // it and load new data with memory_order_acq_rel.
155   auto flags = storage->prefix.flags.load(std::memory_order_acquire);
156   DCHECK_EQ((flags & freeFlags), freeFlags);
157
158   while (true) {
159     uint16_t newFlags = (flags & ~freeFlags);
160     if (newFlags == 0) {
161       // The storage space is now unused.  Free it.
162       storage->prefix.HeapPrefix::~HeapPrefix();
163       free(storage);
164       return;
165     }
166
167     // This storage segment still contains portions that are in use.
168     // Just clear the flags specified in freeFlags for now.
169     auto ret = storage->prefix.flags.compare_exchange_weak(
170         flags, newFlags, std::memory_order_acq_rel);
171     if (ret) {
172       // We successfully updated the flags.
173       return;
174     }
175
176     // We failed to update the flags.  Some other thread probably updated them
177     // and cleared some of the other bits.  Continue around the loop to see if
178     // we are the last user now, or if we need to try updating the flags again.
179   }
180 }
181
182 void IOBuf::freeInternalBuf(void* buf, void* userData) {
183   auto* storage = static_cast<HeapStorage*>(userData);
184   releaseStorage(storage, kDataInUse);
185 }
186
187 IOBuf::IOBuf(CreateOp, uint32_t capacity)
188   : next_(this),
189     prev_(this),
190     data_(nullptr),
191     length_(0),
192     flags_(0),
193     type_(kExtAllocated) {
194   allocExtBuffer(capacity, &buf_, &sharedInfo_, &capacity_);
195   data_ = buf_;
196 }
197
198 IOBuf::IOBuf(CopyBufferOp op, const void* buf, uint32_t size,
199              uint32_t headroom, uint32_t minTailroom)
200   : IOBuf(CREATE, headroom + size + minTailroom) {
201   advance(headroom);
202   memcpy(writableData(), buf, size);
203   append(size);
204 }
205
206 IOBuf::IOBuf(CopyBufferOp op, ByteRange br,
207              uint32_t headroom, uint32_t minTailroom)
208   : IOBuf(op, br.data(), br.size(), headroom, minTailroom) {
209 }
210
211 unique_ptr<IOBuf> IOBuf::create(uint32_t capacity) {
212   // For smaller-sized buffers, allocate the IOBuf, SharedInfo, and the buffer
213   // all with a single allocation.
214   //
215   // We don't do this for larger buffers since it can be wasteful if the user
216   // needs to reallocate the buffer but keeps using the same IOBuf object.
217   // In this case we can't free the data space until the IOBuf is also
218   // destroyed.  Callers can explicitly call createCombined() or
219   // createSeparate() if they know their use case better, and know if they are
220   // likely to reallocate the buffer later.
221   if (capacity <= kDefaultCombinedBufSize) {
222     return createCombined(capacity);
223   }
224   return createSeparate(capacity);
225 }
226
227 unique_ptr<IOBuf> IOBuf::createCombined(uint32_t capacity) {
228   // To save a memory allocation, allocate space for the IOBuf object, the
229   // SharedInfo struct, and the data itself all with a single call to malloc().
230   size_t requiredStorage = offsetof(HeapFullStorage, align) + capacity;
231   size_t mallocSize = goodMallocSize(requiredStorage);
232   auto* storage = static_cast<HeapFullStorage*>(malloc(mallocSize));
233
234   new (&storage->hs.prefix) HeapPrefix(kIOBufInUse | kDataInUse);
235   new (&storage->shared) SharedInfo(freeInternalBuf, storage);
236
237   uint8_t* bufAddr = reinterpret_cast<uint8_t*>(&storage->align);
238   uint8_t* storageEnd = reinterpret_cast<uint8_t*>(storage) + mallocSize;
239   size_t actualCapacity = storageEnd - bufAddr;
240   unique_ptr<IOBuf> ret(new (&storage->hs.buf) IOBuf(
241         kCombinedAlloc, 0, bufAddr, actualCapacity,
242         bufAddr, 0, &storage->shared));
243   return ret;
244 }
245
246 unique_ptr<IOBuf> IOBuf::createSeparate(uint32_t capacity) {
247   return make_unique<IOBuf>(CREATE, capacity);
248 }
249
250 unique_ptr<IOBuf> IOBuf::createChain(
251     size_t totalCapacity, uint32_t maxBufCapacity) {
252   unique_ptr<IOBuf> out = create(
253       std::min(totalCapacity, size_t(maxBufCapacity)));
254   size_t allocatedCapacity = out->capacity();
255
256   while (allocatedCapacity < totalCapacity) {
257     unique_ptr<IOBuf> newBuf = create(
258         std::min(totalCapacity - allocatedCapacity, size_t(maxBufCapacity)));
259     allocatedCapacity += newBuf->capacity();
260     out->prependChain(std::move(newBuf));
261   }
262
263   return out;
264 }
265
266 IOBuf::IOBuf(TakeOwnershipOp, void* buf, uint32_t capacity, uint32_t length,
267              FreeFunction freeFn, void* userData,
268              bool freeOnError)
269   : next_(this),
270     prev_(this),
271     data_(static_cast<uint8_t*>(buf)),
272     buf_(static_cast<uint8_t*>(buf)),
273     length_(length),
274     capacity_(capacity),
275     flags_(kFlagFreeSharedInfo),
276     type_(kExtUserSupplied) {
277   try {
278     sharedInfo_ = new SharedInfo(freeFn, userData);
279   } catch (...) {
280     takeOwnershipError(freeOnError, buf, freeFn, userData);
281     throw;
282   }
283 }
284
285 unique_ptr<IOBuf> IOBuf::takeOwnership(void* buf, uint32_t capacity,
286                                        uint32_t length,
287                                        FreeFunction freeFn,
288                                        void* userData,
289                                        bool freeOnError) {
290   try {
291     // TODO: We could allocate the IOBuf object and SharedInfo all in a single
292     // memory allocation.  We could use the existing HeapStorage class, and
293     // define a new kSharedInfoInUse flag.  We could change our code to call
294     // releaseStorage(kFlagFreeSharedInfo) when this kFlagFreeSharedInfo,
295     // rather than directly calling delete.
296     //
297     // Note that we always pass freeOnError as false to the constructor.
298     // If the constructor throws we'll handle it below.  (We have to handle
299     // allocation failures from make_unique too.)
300     return make_unique<IOBuf>(TAKE_OWNERSHIP, buf, capacity, length,
301                               freeFn, userData, false);
302   } catch (...) {
303     takeOwnershipError(freeOnError, buf, freeFn, userData);
304     throw;
305   }
306 }
307
308 IOBuf::IOBuf(WrapBufferOp, const void* buf, uint32_t capacity)
309   : IOBuf(kExtUserOwned, kFlagUserOwned,
310           // We cast away the const-ness of the buffer here.
311           // This is okay since IOBuf users must use unshare() to create a copy
312           // of this buffer before writing to the buffer.
313           static_cast<uint8_t*>(const_cast<void*>(buf)), capacity,
314           static_cast<uint8_t*>(const_cast<void*>(buf)), capacity,
315           nullptr) {
316 }
317
318 IOBuf::IOBuf(WrapBufferOp op, ByteRange br)
319   : IOBuf(op, br.data(), folly::to<uint32_t>(br.size())) {
320 }
321
322 unique_ptr<IOBuf> IOBuf::wrapBuffer(const void* buf, uint32_t capacity) {
323   return make_unique<IOBuf>(WRAP_BUFFER, buf, capacity);
324 }
325
326 IOBuf::IOBuf() noexcept {
327 }
328
329 IOBuf::IOBuf(IOBuf&& other) noexcept {
330   *this = std::move(other);
331 }
332
333 IOBuf::IOBuf(ExtBufTypeEnum type,
334              uint32_t flags,
335              uint8_t* buf,
336              uint32_t capacity,
337              uint8_t* data,
338              uint32_t length,
339              SharedInfo* sharedInfo)
340   : next_(this),
341     prev_(this),
342     data_(data),
343     buf_(buf),
344     length_(length),
345     capacity_(capacity),
346     flags_(flags),
347     type_(type),
348     sharedInfo_(sharedInfo) {
349   assert(data >= buf);
350   assert(data + length <= buf + capacity);
351   assert(static_cast<bool>(flags & kFlagUserOwned) ==
352          (sharedInfo == NULL));
353 }
354
355 IOBuf::~IOBuf() {
356   // Destroying an IOBuf destroys the entire chain.
357   // Users of IOBuf should only explicitly delete the head of any chain.
358   // The other elements in the chain will be automatically destroyed.
359   while (next_ != this) {
360     // Since unlink() returns unique_ptr() and we don't store it,
361     // it will automatically delete the unlinked element.
362     (void)next_->unlink();
363   }
364
365   decrementRefcount();
366 }
367
368 IOBuf& IOBuf::operator=(IOBuf&& other) noexcept {
369   // If we are part of a chain, delete the rest of the chain.
370   while (next_ != this) {
371     // Since unlink() returns unique_ptr() and we don't store it,
372     // it will automatically delete the unlinked element.
373     (void)next_->unlink();
374   }
375
376   // Decrement our refcount on the current buffer
377   decrementRefcount();
378
379   // Take ownership of the other buffer's data
380   data_ = other.data_;
381   buf_ = other.buf_;
382   length_ = other.length_;
383   capacity_ = other.capacity_;
384   flags_ = other.flags_;
385   type_ = other.type_;
386   sharedInfo_ = other.sharedInfo_;
387   // Reset other so it is a clean state to be destroyed.
388   other.data_ = nullptr;
389   other.buf_ = nullptr;
390   other.length_ = 0;
391   other.capacity_ = 0;
392   other.flags_ = kFlagUserOwned;
393   other.type_ = kExtUserOwned;
394   other.sharedInfo_ = nullptr;
395
396   // If other was part of the chain, assume ownership of the rest of its chain.
397   // (It's only valid to perform move assignment on the head of a chain.)
398   if (other.next_ != &other) {
399     next_ = other.next_;
400     next_->prev_ = this;
401     other.next_ = &other;
402
403     prev_ = other.prev_;
404     prev_->next_ = this;
405     other.prev_ = &other;
406   }
407
408   // Sanity check to make sure that other is in a valid state to be destroyed.
409   DCHECK_EQ(other.prev_, &other);
410   DCHECK_EQ(other.next_, &other);
411   DCHECK(other.flags_ & kFlagUserOwned);
412
413   return *this;
414 }
415
416 bool IOBuf::empty() const {
417   const IOBuf* current = this;
418   do {
419     if (current->length() != 0) {
420       return false;
421     }
422     current = current->next_;
423   } while (current != this);
424   return true;
425 }
426
427 uint32_t IOBuf::countChainElements() const {
428   uint32_t numElements = 1;
429   for (IOBuf* current = next_; current != this; current = current->next_) {
430     ++numElements;
431   }
432   return numElements;
433 }
434
435 uint64_t IOBuf::computeChainDataLength() const {
436   uint64_t fullLength = length_;
437   for (IOBuf* current = next_; current != this; current = current->next_) {
438     fullLength += current->length_;
439   }
440   return fullLength;
441 }
442
443 void IOBuf::prependChain(unique_ptr<IOBuf>&& iobuf) {
444   // Take ownership of the specified IOBuf
445   IOBuf* other = iobuf.release();
446
447   // Remember the pointer to the tail of the other chain
448   IOBuf* otherTail = other->prev_;
449
450   // Hook up prev_->next_ to point at the start of the other chain,
451   // and other->prev_ to point at prev_
452   prev_->next_ = other;
453   other->prev_ = prev_;
454
455   // Hook up otherTail->next_ to point at us,
456   // and prev_ to point back at otherTail,
457   otherTail->next_ = this;
458   prev_ = otherTail;
459 }
460
461 unique_ptr<IOBuf> IOBuf::clone() const {
462   unique_ptr<IOBuf> newHead(cloneOne());
463
464   for (IOBuf* current = next_; current != this; current = current->next_) {
465     newHead->prependChain(current->cloneOne());
466   }
467
468   return newHead;
469 }
470
471 unique_ptr<IOBuf> IOBuf::cloneOne() const {
472   if (sharedInfo_) {
473     flags_ |= kFlagMaybeShared;
474   }
475   unique_ptr<IOBuf> iobuf(new IOBuf(static_cast<ExtBufTypeEnum>(type_),
476                                     flags_, buf_, capacity_,
477                                     data_, length_,
478                                     sharedInfo_));
479   if (sharedInfo_) {
480     sharedInfo_->refcount.fetch_add(1, std::memory_order_acq_rel);
481   }
482   return iobuf;
483 }
484
485 void IOBuf::unshareOneSlow() {
486   // Allocate a new buffer for the data
487   uint8_t* buf;
488   SharedInfo* sharedInfo;
489   uint32_t actualCapacity;
490   allocExtBuffer(capacity_, &buf, &sharedInfo, &actualCapacity);
491
492   // Copy the data
493   // Maintain the same amount of headroom.  Since we maintained the same
494   // minimum capacity we also maintain at least the same amount of tailroom.
495   uint32_t headlen = headroom();
496   memcpy(buf + headlen, data_, length_);
497
498   // Release our reference on the old buffer
499   decrementRefcount();
500   // Make sure kFlagUserOwned, kFlagMaybeShared, and kFlagFreeSharedInfo
501   // are all cleared.
502   flags_ = 0;
503
504   // Update the buffer pointers to point to the new buffer
505   data_ = buf + headlen;
506   buf_ = buf;
507   sharedInfo_ = sharedInfo;
508 }
509
510 void IOBuf::unshareChained() {
511   // unshareChained() should only be called if we are part of a chain of
512   // multiple IOBufs.  The caller should have already verified this.
513   assert(isChained());
514
515   IOBuf* current = this;
516   while (true) {
517     if (current->isSharedOne()) {
518       // we have to unshare
519       break;
520     }
521
522     current = current->next_;
523     if (current == this) {
524       // None of the IOBufs in the chain are shared,
525       // so return without doing anything
526       return;
527     }
528   }
529
530   // We have to unshare.  Let coalesceSlow() do the work.
531   coalesceSlow();
532 }
533
534 void IOBuf::coalesceSlow() {
535   // coalesceSlow() should only be called if we are part of a chain of multiple
536   // IOBufs.  The caller should have already verified this.
537   DCHECK(isChained());
538
539   // Compute the length of the entire chain
540   uint64_t newLength = 0;
541   IOBuf* end = this;
542   do {
543     newLength += end->length_;
544     end = end->next_;
545   } while (end != this);
546
547   coalesceAndReallocate(newLength, end);
548   // We should be only element left in the chain now
549   DCHECK(!isChained());
550 }
551
552 void IOBuf::coalesceSlow(size_t maxLength) {
553   // coalesceSlow() should only be called if we are part of a chain of multiple
554   // IOBufs.  The caller should have already verified this.
555   DCHECK(isChained());
556   DCHECK_LT(length_, maxLength);
557
558   // Compute the length of the entire chain
559   uint64_t newLength = 0;
560   IOBuf* end = this;
561   while (true) {
562     newLength += end->length_;
563     end = end->next_;
564     if (newLength >= maxLength) {
565       break;
566     }
567     if (end == this) {
568       throw std::overflow_error("attempted to coalesce more data than "
569                                 "available");
570     }
571   }
572
573   coalesceAndReallocate(newLength, end);
574   // We should have the requested length now
575   DCHECK_GE(length_, maxLength);
576 }
577
578 void IOBuf::coalesceAndReallocate(size_t newHeadroom,
579                                   size_t newLength,
580                                   IOBuf* end,
581                                   size_t newTailroom) {
582   uint64_t newCapacity = newLength + newHeadroom + newTailroom;
583   if (newCapacity > UINT32_MAX) {
584     throw std::overflow_error("IOBuf chain too large to coalesce");
585   }
586
587   // Allocate space for the coalesced buffer.
588   // We always convert to an external buffer, even if we happened to be an
589   // internal buffer before.
590   uint8_t* newBuf;
591   SharedInfo* newInfo;
592   uint32_t actualCapacity;
593   allocExtBuffer(newCapacity, &newBuf, &newInfo, &actualCapacity);
594
595   // Copy the data into the new buffer
596   uint8_t* newData = newBuf + newHeadroom;
597   uint8_t* p = newData;
598   IOBuf* current = this;
599   size_t remaining = newLength;
600   do {
601     assert(current->length_ <= remaining);
602     remaining -= current->length_;
603     memcpy(p, current->data_, current->length_);
604     p += current->length_;
605     current = current->next_;
606   } while (current != end);
607   assert(remaining == 0);
608
609   // Point at the new buffer
610   decrementRefcount();
611
612   // Make sure kFlagUserOwned, kFlagMaybeShared, and kFlagFreeSharedInfo
613   // are all cleared.
614   flags_ = 0;
615
616   capacity_ = actualCapacity;
617   type_ = kExtAllocated;
618   buf_ = newBuf;
619   sharedInfo_ = newInfo;
620   data_ = newData;
621   length_ = newLength;
622
623   // Separate from the rest of our chain.
624   // Since we don't store the unique_ptr returned by separateChain(),
625   // this will immediately delete the returned subchain.
626   if (isChained()) {
627     (void)separateChain(next_, current->prev_);
628   }
629 }
630
631 void IOBuf::decrementRefcount() {
632   // Externally owned buffers don't have a SharedInfo object and aren't managed
633   // by the reference count
634   if (flags_ & kFlagUserOwned) {
635     assert(sharedInfo_ == nullptr);
636     return;
637   }
638
639   // Decrement the refcount
640   uint32_t newcnt = sharedInfo_->refcount.fetch_sub(
641       1, std::memory_order_acq_rel);
642   // Note that fetch_sub() returns the value before we decremented.
643   // If it is 1, we were the only remaining user; if it is greater there are
644   // still other users.
645   if (newcnt > 1) {
646     return;
647   }
648
649   // We were the last user.  Free the buffer
650   freeExtBuffer();
651
652   // Free the SharedInfo if it was allocated separately.
653   //
654   // This is only used by takeOwnership().
655   //
656   // To avoid this special case handling in decrementRefcount(), we could have
657   // takeOwnership() set a custom freeFn() that calls the user's free function
658   // then frees the SharedInfo object.  (This would require that
659   // takeOwnership() store the user's free function with its allocated
660   // SharedInfo object.)  However, handling this specially with a flag seems
661   // like it shouldn't be problematic.
662   if (flags_ & kFlagFreeSharedInfo) {
663     delete sharedInfo_;
664   }
665 }
666
667 void IOBuf::reserveSlow(uint32_t minHeadroom, uint32_t minTailroom) {
668   size_t newCapacity = (size_t)length_ + minHeadroom + minTailroom;
669   DCHECK_LT(newCapacity, UINT32_MAX);
670
671   // reserveSlow() is dangerous if anyone else is sharing the buffer, as we may
672   // reallocate and free the original buffer.  It should only ever be called if
673   // we are the only user of the buffer.
674   DCHECK(!isSharedOne());
675
676   // We'll need to reallocate the buffer.
677   // There are a few options.
678   // - If we have enough total room, move the data around in the buffer
679   //   and adjust the data_ pointer.
680   // - If we're using an internal buffer, we'll switch to an external
681   //   buffer with enough headroom and tailroom.
682   // - If we have enough headroom (headroom() >= minHeadroom) but not too much
683   //   (so we don't waste memory), we can try one of two things, depending on
684   //   whether we use jemalloc or not:
685   //   - If using jemalloc, we can try to expand in place, avoiding a memcpy()
686   //   - If not using jemalloc and we don't have too much to copy,
687   //     we'll use realloc() (note that realloc might have to copy
688   //     headroom + data + tailroom, see smartRealloc in folly/Malloc.h)
689   // - Otherwise, bite the bullet and reallocate.
690   if (headroom() + tailroom() >= minHeadroom + minTailroom) {
691     uint8_t* newData = writableBuffer() + minHeadroom;
692     memmove(newData, data_, length_);
693     data_ = newData;
694     return;
695   }
696
697   size_t newAllocatedCapacity = goodExtBufferSize(newCapacity);
698   uint8_t* newBuffer = nullptr;
699   uint32_t newHeadroom = 0;
700   uint32_t oldHeadroom = headroom();
701
702   // If we have a buffer allocated with malloc and we just need more tailroom,
703   // try to use realloc()/rallocm() to grow the buffer in place.
704   if ((flags_ & kFlagUserOwned) == 0 && (sharedInfo_->freeFn == nullptr) &&
705       length_ != 0 && oldHeadroom >= minHeadroom) {
706     if (usingJEMalloc()) {
707       size_t headSlack = oldHeadroom - minHeadroom;
708       // We assume that tailroom is more useful and more important than
709       // headroom (not least because realloc / rallocm allow us to grow the
710       // buffer at the tail, but not at the head)  So, if we have more headroom
711       // than we need, we consider that "wasted".  We arbitrarily define "too
712       // much" headroom to be 25% of the capacity.
713       if (headSlack * 4 <= newCapacity) {
714         size_t allocatedCapacity = capacity() + sizeof(SharedInfo);
715         void* p = buf_;
716         if (allocatedCapacity >= jemallocMinInPlaceExpandable) {
717           // rallocm can write to its 2nd arg even if it returns
718           // ALLOCM_ERR_NOT_MOVED. So, we pass a temporary to its 2nd arg and
719           // update newAllocatedCapacity only on success.
720           size_t allocatedSize;
721           int r = rallocm(&p, &allocatedSize, newAllocatedCapacity,
722                           0, ALLOCM_NO_MOVE);
723           if (r == ALLOCM_SUCCESS) {
724             newBuffer = static_cast<uint8_t*>(p);
725             newHeadroom = oldHeadroom;
726             newAllocatedCapacity = allocatedSize;
727           } else if (r == ALLOCM_ERR_OOM) {
728             // shouldn't happen as we don't actually allocate new memory
729             // (due to ALLOCM_NO_MOVE)
730             throw std::bad_alloc();
731           }
732           // if ALLOCM_ERR_NOT_MOVED, do nothing, fall back to
733           // malloc/memcpy/free
734         }
735       }
736     } else {  // Not using jemalloc
737       size_t copySlack = capacity() - length_;
738       if (copySlack * 2 <= length_) {
739         void* p = realloc(buf_, newAllocatedCapacity);
740         if (UNLIKELY(p == nullptr)) {
741           throw std::bad_alloc();
742         }
743         newBuffer = static_cast<uint8_t*>(p);
744         newHeadroom = oldHeadroom;
745       }
746     }
747   }
748
749   // None of the previous reallocation strategies worked (or we're using
750   // an internal buffer).  malloc/copy/free.
751   if (newBuffer == nullptr) {
752     void* p = malloc(newAllocatedCapacity);
753     if (UNLIKELY(p == nullptr)) {
754       throw std::bad_alloc();
755     }
756     newBuffer = static_cast<uint8_t*>(p);
757     memcpy(newBuffer + minHeadroom, data_, length_);
758     if ((flags_ & kFlagUserOwned) == 0) {
759       freeExtBuffer();
760     }
761     newHeadroom = minHeadroom;
762   }
763
764   SharedInfo* info;
765   uint32_t cap;
766   initExtBuffer(newBuffer, newAllocatedCapacity, &info, &cap);
767
768   if (flags_ & kFlagFreeSharedInfo) {
769     delete sharedInfo_;
770   }
771
772   flags_ = 0;
773   capacity_ = cap;
774   type_ = kExtAllocated;
775   buf_ = newBuffer;
776   sharedInfo_ = info;
777   data_ = newBuffer + newHeadroom;
778   // length_ is unchanged
779 }
780
781 void IOBuf::freeExtBuffer() {
782   DCHECK((flags_ & kFlagUserOwned) == 0);
783
784   if (sharedInfo_->freeFn) {
785     try {
786       sharedInfo_->freeFn(buf_, sharedInfo_->userData);
787     } catch (...) {
788       // The user's free function should never throw.  Otherwise we might
789       // throw from the IOBuf destructor.  Other code paths like coalesce()
790       // also assume that decrementRefcount() cannot throw.
791       abort();
792     }
793   } else {
794     free(buf_);
795   }
796 }
797
798 void IOBuf::allocExtBuffer(uint32_t minCapacity,
799                            uint8_t** bufReturn,
800                            SharedInfo** infoReturn,
801                            uint32_t* capacityReturn) {
802   size_t mallocSize = goodExtBufferSize(minCapacity);
803   uint8_t* buf = static_cast<uint8_t*>(malloc(mallocSize));
804   if (UNLIKELY(buf == NULL)) {
805     throw std::bad_alloc();
806   }
807   initExtBuffer(buf, mallocSize, infoReturn, capacityReturn);
808   *bufReturn = buf;
809 }
810
811 size_t IOBuf::goodExtBufferSize(uint32_t minCapacity) {
812   // Determine how much space we should allocate.  We'll store the SharedInfo
813   // for the external buffer just after the buffer itself.  (We store it just
814   // after the buffer rather than just before so that the code can still just
815   // use free(buf_) to free the buffer.)
816   size_t minSize = static_cast<size_t>(minCapacity) + sizeof(SharedInfo);
817   // Add room for padding so that the SharedInfo will be aligned on an 8-byte
818   // boundary.
819   minSize = (minSize + 7) & ~7;
820
821   // Use goodMallocSize() to bump up the capacity to a decent size to request
822   // from malloc, so we can use all of the space that malloc will probably give
823   // us anyway.
824   return goodMallocSize(minSize);
825 }
826
827 void IOBuf::initExtBuffer(uint8_t* buf, size_t mallocSize,
828                           SharedInfo** infoReturn,
829                           uint32_t* capacityReturn) {
830   // Find the SharedInfo storage at the end of the buffer
831   // and construct the SharedInfo.
832   uint8_t* infoStart = (buf + mallocSize) - sizeof(SharedInfo);
833   SharedInfo* sharedInfo = new(infoStart) SharedInfo;
834
835   size_t actualCapacity = infoStart - buf;
836   // On the unlikely possibility that the actual capacity is larger than can
837   // fit in a uint32_t after adding room for the refcount and calling
838   // goodMallocSize(), truncate downwards if necessary.
839   if (actualCapacity >= UINT32_MAX) {
840     *capacityReturn = UINT32_MAX;
841   } else {
842     *capacityReturn = actualCapacity;
843   }
844
845   *infoReturn = sharedInfo;
846 }
847
848 fbstring IOBuf::moveToFbString() {
849   // malloc-allocated buffers are just fine, everything else needs
850   // to be turned into one.
851   if ((flags_ & kFlagUserOwned) ||  // user owned, not ours to give up
852       sharedInfo_->freeFn != nullptr || // not malloc()-ed
853       headroom() != 0 ||     // malloc()-ed block doesn't start at beginning
854       tailroom() == 0 ||     // no room for NUL terminator
855       isShared() ||          // shared
856       isChained()) {         // chained
857     // We might as well get rid of all head and tailroom if we're going
858     // to reallocate; we need 1 byte for NUL terminator.
859     coalesceAndReallocate(0, computeChainDataLength(), this, 1);
860   }
861
862   // Ensure NUL terminated
863   *writableTail() = 0;
864   fbstring str(reinterpret_cast<char*>(writableData()),
865                length(),  capacity(),
866                AcquireMallocatedString());
867
868   if (flags_ & kFlagFreeSharedInfo) {
869     delete sharedInfo_;
870   }
871
872   // Reset to a state where we can be deleted cleanly
873   flags_ = kFlagUserOwned;
874   sharedInfo_ = nullptr;
875   buf_ = nullptr;
876   clear();
877   return str;
878 }
879
880 IOBuf::Iterator IOBuf::cbegin() const {
881   return Iterator(this, this);
882 }
883
884 IOBuf::Iterator IOBuf::cend() const {
885   return Iterator(nullptr, nullptr);
886 }
887
888 folly::fbvector<struct iovec> IOBuf::getIov() const {
889   folly::fbvector<struct iovec> iov;
890   iov.reserve(countChainElements());
891   IOBuf const* p = this;
892   do {
893     // some code can get confused by empty iovs, so skip them
894     if (p->length() > 0) {
895       iov.push_back({(void*)p->data(), p->length()});
896     }
897     p = p->next();
898   } while (p != this);
899   return iov;
900 }
901
902 } // folly