2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/io/IOBuf.h>
18 #include <folly/io/TypedIOBuf.h>
22 #include <boost/random.hpp>
23 #include <gtest/gtest.h>
25 #include <folly/Malloc.h>
26 #include <folly/Range.h>
28 using folly::fbstring;
29 using folly::fbvector;
31 using folly::TypedIOBuf;
32 using folly::StringPiece;
33 using folly::ByteRange;
34 using std::unique_ptr;
36 void append(std::unique_ptr<IOBuf>& buf, StringPiece str) {
37 EXPECT_LE(str.size(), buf->tailroom());
38 memcpy(buf->writableData(), str.data(), str.size());
39 buf->append(str.size());
42 void prepend(std::unique_ptr<IOBuf>& buf, StringPiece str) {
43 EXPECT_LE(str.size(), buf->headroom());
44 memcpy(buf->writableData() - str.size(), str.data(), str.size());
45 buf->prepend(str.size());
49 unique_ptr<IOBuf> buf(IOBuf::create(100));
50 uint32_t cap = buf->capacity();
52 EXPECT_EQ(0, buf->headroom());
53 EXPECT_EQ(0, buf->length());
54 EXPECT_EQ(cap, buf->tailroom());
58 EXPECT_EQ(10, buf->headroom());
59 EXPECT_EQ(5, buf->length());
60 EXPECT_EQ(cap - 15, buf->tailroom());
62 prepend(buf, "hello ");
63 EXPECT_EQ(4, buf->headroom());
64 EXPECT_EQ(11, buf->length());
65 EXPECT_EQ(cap - 15, buf->tailroom());
67 const char* p = reinterpret_cast<const char*>(buf->data());
68 EXPECT_EQ("hello world", std::string(p, buf->length()));
71 EXPECT_EQ(0, buf->headroom());
72 EXPECT_EQ(0, buf->length());
73 EXPECT_EQ(cap, buf->tailroom());
77 void testAllocSize(uint32_t requestedCapacity) {
78 unique_ptr<IOBuf> iobuf(IOBuf::create(requestedCapacity));
79 EXPECT_GE(iobuf->capacity(), requestedCapacity);
82 TEST(IOBuf, AllocSizes) {
83 // Try with a small allocation size that should fit in the internal buffer
86 // Try with a large allocation size that will require an external buffer.
89 // 220 bytes is currently the cutoff
90 // (It would be nice to use the IOBuf::kMaxInternalDataSize constant,
91 // but it's private and it doesn't seem worth making it public just for this
98 void deleteArrayBuffer(void *buf, void* arg) {
99 uint32_t* deleteCount = static_cast<uint32_t*>(arg);
101 uint8_t* bufPtr = static_cast<uint8_t*>(buf);
105 TEST(IOBuf, TakeOwnership) {
107 uint8_t *buf1 = static_cast<uint8_t*>(malloc(size1));
108 unique_ptr<IOBuf> iobuf1(IOBuf::takeOwnership(buf1, size1));
109 EXPECT_EQ(buf1, iobuf1->data());
110 EXPECT_EQ(size1, iobuf1->length());
111 EXPECT_EQ(buf1, iobuf1->buffer());
112 EXPECT_EQ(size1, iobuf1->capacity());
114 uint32_t deleteCount = 0;
115 uint32_t size2 = 4321;
116 uint8_t *buf2 = new uint8_t[size2];
117 unique_ptr<IOBuf> iobuf2(IOBuf::takeOwnership(buf2, size2,
120 EXPECT_EQ(buf2, iobuf2->data());
121 EXPECT_EQ(size2, iobuf2->length());
122 EXPECT_EQ(buf2, iobuf2->buffer());
123 EXPECT_EQ(size2, iobuf2->capacity());
124 EXPECT_EQ(0, deleteCount);
126 EXPECT_EQ(1, deleteCount);
129 uint32_t size3 = 3456;
130 uint8_t *buf3 = new uint8_t[size3];
131 uint32_t length3 = 48;
132 unique_ptr<IOBuf> iobuf3(IOBuf::takeOwnership(buf3, size3, length3,
135 EXPECT_EQ(buf3, iobuf3->data());
136 EXPECT_EQ(length3, iobuf3->length());
137 EXPECT_EQ(buf3, iobuf3->buffer());
138 EXPECT_EQ(size3, iobuf3->capacity());
139 EXPECT_EQ(0, deleteCount);
141 EXPECT_EQ(1, deleteCount);
145 uint32_t size4 = 1234;
146 uint8_t *buf4 = new uint8_t[size4];
147 uint32_t length4 = 48;
148 IOBuf iobuf4(IOBuf::TAKE_OWNERSHIP, buf4, size4, length4,
149 deleteArrayBuffer, &deleteCount);
150 EXPECT_EQ(buf4, iobuf4.data());
151 EXPECT_EQ(length4, iobuf4.length());
152 EXPECT_EQ(buf4, iobuf4.buffer());
153 EXPECT_EQ(size4, iobuf4.capacity());
155 IOBuf iobuf5 = std::move(iobuf4);
156 EXPECT_EQ(buf4, iobuf5.data());
157 EXPECT_EQ(length4, iobuf5.length());
158 EXPECT_EQ(buf4, iobuf5.buffer());
159 EXPECT_EQ(size4, iobuf5.capacity());
160 EXPECT_EQ(0, deleteCount);
162 EXPECT_EQ(1, deleteCount);
165 TEST(IOBuf, WrapBuffer) {
166 const uint32_t size1 = 1234;
168 unique_ptr<IOBuf> iobuf1(IOBuf::wrapBuffer(buf1, size1));
169 EXPECT_EQ(buf1, iobuf1->data());
170 EXPECT_EQ(size1, iobuf1->length());
171 EXPECT_EQ(buf1, iobuf1->buffer());
172 EXPECT_EQ(size1, iobuf1->capacity());
174 uint32_t size2 = 0x1234;
175 unique_ptr<uint8_t[]> buf2(new uint8_t[size2]);
176 unique_ptr<IOBuf> iobuf2(IOBuf::wrapBuffer(buf2.get(), size2));
177 EXPECT_EQ(buf2.get(), iobuf2->data());
178 EXPECT_EQ(size2, iobuf2->length());
179 EXPECT_EQ(buf2.get(), iobuf2->buffer());
180 EXPECT_EQ(size2, iobuf2->capacity());
182 uint32_t size3 = 4321;
183 unique_ptr<uint8_t[]> buf3(new uint8_t[size3]);
184 IOBuf iobuf3(IOBuf::WRAP_BUFFER, buf3.get(), size3);
185 EXPECT_EQ(buf3.get(), iobuf3.data());
186 EXPECT_EQ(size3, iobuf3.length());
187 EXPECT_EQ(buf3.get(), iobuf3.buffer());
188 EXPECT_EQ(size3, iobuf3.capacity());
191 TEST(IOBuf, CreateCombined) {
192 // Create a combined IOBuf, then destroy it.
193 // The data buffer and IOBuf both become unused as part of the destruction
195 auto buf = IOBuf::createCombined(256);
196 EXPECT_FALSE(buf->isShared());
199 // Create a combined IOBuf, clone from it, and then destroy the original
200 // IOBuf. The data buffer cannot be deleted until the clone is also
203 auto bufA = IOBuf::createCombined(256);
204 EXPECT_FALSE(bufA->isShared());
205 auto bufB = bufA->clone();
206 EXPECT_TRUE(bufA->isShared());
207 EXPECT_TRUE(bufB->isShared());
209 EXPECT_FALSE(bufB->isShared());
212 // Create a combined IOBuf, then call reserve() to get a larger buffer.
213 // The IOBuf no longer points to the combined data buffer, but the
214 // overall memory segment cannot be deleted until the IOBuf is also
217 auto buf = IOBuf::createCombined(256);
218 buf->reserve(0, buf->capacity() + 100);
221 // Create a combined IOBuf, clone from it, then call unshare() on the original
222 // buffer. This creates a situation where bufB is pointing at the combined
223 // buffer associated with bufA, but bufA is now using a different buffer.
224 auto testSwap = [](bool resetAFirst) {
225 auto bufA = IOBuf::createCombined(256);
226 EXPECT_FALSE(bufA->isShared());
227 auto bufB = bufA->clone();
228 EXPECT_TRUE(bufA->isShared());
229 EXPECT_TRUE(bufB->isShared());
231 EXPECT_FALSE(bufA->isShared());
232 EXPECT_FALSE(bufB->isShared());
246 void fillBuf(uint8_t* buf, uint32_t length, boost::mt19937& gen) {
247 for (uint32_t n = 0; n < length; ++n) {
248 buf[n] = static_cast<uint8_t>(gen() & 0xff);
252 void fillBuf(IOBuf* buf, boost::mt19937& gen) {
254 fillBuf(buf->writableData(), buf->length(), gen);
257 void checkBuf(const uint8_t* buf, uint32_t length, boost::mt19937& gen) {
258 // Rather than using EXPECT_EQ() to check each character,
259 // count the number of differences and the first character that differs.
260 // This way on error we'll report just that information, rather than tons of
261 // failed checks for each byte in the buffer.
262 uint32_t numDifferences = 0;
263 uint32_t firstDiffIndex = 0;
264 uint8_t firstDiffExpected = 0;
265 for (uint32_t n = 0; n < length; ++n) {
266 uint8_t expected = static_cast<uint8_t>(gen() & 0xff);
267 if (buf[n] == expected) {
271 if (numDifferences == 0) {
273 firstDiffExpected = expected;
278 EXPECT_EQ(0, numDifferences);
279 if (numDifferences > 0) {
280 // Cast to int so it will be printed numerically
281 // rather than as a char if the check fails
282 EXPECT_EQ(static_cast<int>(buf[firstDiffIndex]),
283 static_cast<int>(firstDiffExpected));
287 void checkBuf(IOBuf* buf, boost::mt19937& gen) {
288 checkBuf(buf->data(), buf->length(), gen);
291 void checkBuf(ByteRange buf, boost::mt19937& gen) {
292 checkBuf(buf.data(), buf.size(), gen);
295 void checkChain(IOBuf* buf, boost::mt19937& gen) {
296 IOBuf *current = buf;
298 checkBuf(current->data(), current->length(), gen);
299 current = current->next();
300 } while (current != buf);
303 TEST(IOBuf, Chaining) {
304 uint32_t fillSeed = 0x12345678;
305 boost::mt19937 gen(fillSeed);
307 // An IOBuf with external storage
308 uint32_t headroom = 123;
309 unique_ptr<IOBuf> iob1(IOBuf::create(2048));
310 iob1->advance(headroom);
312 fillBuf(iob1.get(), gen);
314 // An IOBuf with internal storage
315 unique_ptr<IOBuf> iob2(IOBuf::create(20));
317 fillBuf(iob2.get(), gen);
319 // An IOBuf around a buffer it doesn't own
320 uint8_t localbuf[1234];
321 fillBuf(localbuf, 1234, gen);
322 unique_ptr<IOBuf> iob3(IOBuf::wrapBuffer(localbuf, sizeof(localbuf)));
324 // An IOBuf taking ownership of a user-supplied buffer
325 uint32_t heapBufSize = 900;
326 uint8_t* heapBuf = static_cast<uint8_t*>(malloc(heapBufSize));
327 fillBuf(heapBuf, heapBufSize, gen);
328 unique_ptr<IOBuf> iob4(IOBuf::takeOwnership(heapBuf, heapBufSize));
330 // An IOBuf taking ownership of a user-supplied buffer with
331 // a custom free function
332 uint32_t arrayBufSize = 321;
333 uint8_t* arrayBuf = new uint8_t[arrayBufSize];
334 fillBuf(arrayBuf, arrayBufSize, gen);
335 uint32_t arrayBufFreeCount = 0;
336 unique_ptr<IOBuf> iob5(IOBuf::takeOwnership(arrayBuf, arrayBufSize,
338 &arrayBufFreeCount));
340 EXPECT_FALSE(iob1->isChained());
341 EXPECT_FALSE(iob2->isChained());
342 EXPECT_FALSE(iob3->isChained());
343 EXPECT_FALSE(iob4->isChained());
344 EXPECT_FALSE(iob5->isChained());
346 EXPECT_FALSE(iob1->isSharedOne());
347 EXPECT_FALSE(iob2->isSharedOne());
348 EXPECT_TRUE(iob3->isSharedOne()); // since we own the buffer
349 EXPECT_FALSE(iob4->isSharedOne());
350 EXPECT_FALSE(iob5->isSharedOne());
352 // Chain the buffers all together
353 // Since we are going to relinquish ownership of iob2-5 to the chain,
354 // store raw pointers to them so we can reference them later.
355 IOBuf* iob2ptr = iob2.get();
356 IOBuf* iob3ptr = iob3.get();
357 IOBuf* iob4ptr = iob4.get();
358 IOBuf* iob5ptr = iob5.get();
360 iob1->prependChain(std::move(iob2));
361 iob1->prependChain(std::move(iob4));
362 iob2ptr->appendChain(std::move(iob3));
363 iob1->prependChain(std::move(iob5));
365 EXPECT_EQ(iob2ptr, iob1->next());
366 EXPECT_EQ(iob3ptr, iob2ptr->next());
367 EXPECT_EQ(iob4ptr, iob3ptr->next());
368 EXPECT_EQ(iob5ptr, iob4ptr->next());
369 EXPECT_EQ(iob1.get(), iob5ptr->next());
371 EXPECT_EQ(iob5ptr, iob1->prev());
372 EXPECT_EQ(iob1.get(), iob2ptr->prev());
373 EXPECT_EQ(iob2ptr, iob3ptr->prev());
374 EXPECT_EQ(iob3ptr, iob4ptr->prev());
375 EXPECT_EQ(iob4ptr, iob5ptr->prev());
377 EXPECT_TRUE(iob1->isChained());
378 EXPECT_TRUE(iob2ptr->isChained());
379 EXPECT_TRUE(iob3ptr->isChained());
380 EXPECT_TRUE(iob4ptr->isChained());
381 EXPECT_TRUE(iob5ptr->isChained());
383 uint64_t fullLength = (iob1->length() + iob2ptr->length() +
384 iob3ptr->length() + iob4ptr->length() +
386 EXPECT_EQ(5, iob1->countChainElements());
387 EXPECT_EQ(fullLength, iob1->computeChainDataLength());
389 // Since iob3 is shared, the entire buffer should report itself as shared
390 EXPECT_TRUE(iob1->isShared());
392 iob3ptr->unshareOne();
393 EXPECT_FALSE(iob3ptr->isSharedOne());
394 // Now everything in the chain should be unshared.
395 // Check on all members of the chain just for good measure
396 EXPECT_FALSE(iob1->isShared());
397 EXPECT_FALSE(iob2ptr->isShared());
398 EXPECT_FALSE(iob3ptr->isShared());
399 EXPECT_FALSE(iob4ptr->isShared());
400 EXPECT_FALSE(iob5ptr->isShared());
405 for (auto buf : *iob1) {
411 // Clone one of the IOBufs in the chain
412 unique_ptr<IOBuf> iob4clone = iob4ptr->cloneOne();
414 checkBuf(iob1.get(), gen);
415 checkBuf(iob2ptr, gen);
416 checkBuf(iob3ptr, gen);
417 checkBuf(iob4clone.get(), gen);
418 checkBuf(iob5ptr, gen);
420 EXPECT_TRUE(iob1->isShared());
421 EXPECT_TRUE(iob2ptr->isShared());
422 EXPECT_TRUE(iob3ptr->isShared());
423 EXPECT_TRUE(iob4ptr->isShared());
424 EXPECT_TRUE(iob5ptr->isShared());
426 EXPECT_FALSE(iob1->isSharedOne());
427 EXPECT_FALSE(iob2ptr->isSharedOne());
428 EXPECT_FALSE(iob3ptr->isSharedOne());
429 EXPECT_TRUE(iob4ptr->isSharedOne());
430 EXPECT_FALSE(iob5ptr->isSharedOne());
432 // Unshare that clone
433 EXPECT_TRUE(iob4clone->isSharedOne());
434 iob4clone->unshare();
435 EXPECT_FALSE(iob4clone->isSharedOne());
436 EXPECT_FALSE(iob4ptr->isSharedOne());
437 EXPECT_FALSE(iob1->isShared());
441 // Create a clone of a different IOBuf
442 EXPECT_FALSE(iob1->isShared());
443 EXPECT_FALSE(iob3ptr->isSharedOne());
445 unique_ptr<IOBuf> iob3clone = iob3ptr->cloneOne();
447 checkBuf(iob1.get(), gen);
448 checkBuf(iob2ptr, gen);
449 checkBuf(iob3clone.get(), gen);
450 checkBuf(iob4ptr, gen);
451 checkBuf(iob5ptr, gen);
453 EXPECT_TRUE(iob1->isShared());
454 EXPECT_TRUE(iob3ptr->isSharedOne());
455 EXPECT_FALSE(iob1->isSharedOne());
457 // Delete the clone and make sure the original is unshared
459 EXPECT_FALSE(iob1->isShared());
460 EXPECT_FALSE(iob3ptr->isSharedOne());
463 // Clone the entire chain
464 unique_ptr<IOBuf> chainClone = iob1->clone();
465 // Verify that the data is correct.
466 EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
468 checkChain(chainClone.get(), gen);
470 // Check that the buffers report sharing correctly
471 EXPECT_TRUE(chainClone->isShared());
472 EXPECT_TRUE(iob1->isShared());
474 EXPECT_TRUE(iob1->isSharedOne());
475 EXPECT_TRUE(iob2ptr->isSharedOne());
476 EXPECT_TRUE(iob3ptr->isSharedOne());
477 EXPECT_TRUE(iob4ptr->isSharedOne());
478 EXPECT_TRUE(iob5ptr->isSharedOne());
480 // Unshare the cloned chain
481 chainClone->unshare();
482 EXPECT_FALSE(chainClone->isShared());
483 EXPECT_FALSE(iob1->isShared());
485 // Make sure the unshared result still has the same data
486 EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
488 checkChain(chainClone.get(), gen);
490 // Destroy this chain
495 EXPECT_FALSE(iob1->isShared());
496 chainClone = iob1->clone();
497 EXPECT_TRUE(iob1->isShared());
498 EXPECT_TRUE(chainClone->isShared());
500 // Delete the original chain
502 EXPECT_FALSE(chainClone->isShared());
504 // Coalesce the chain
506 // Coalescing this chain will create a new buffer and release the last
507 // refcount on the original buffers we created. Also make sure
508 // that arrayBufFreeCount increases to one to indicate that arrayBuf was
510 EXPECT_EQ(5, chainClone->countChainElements());
511 EXPECT_EQ(0, arrayBufFreeCount);
513 // Buffer lengths: 1500 20 1234 900 321
514 // Attempting to gather more data than available should fail
515 EXPECT_THROW(chainClone->gather(4000), std::overflow_error);
516 // Coalesce the first 3 buffers
517 chainClone->gather(1521);
518 EXPECT_EQ(3, chainClone->countChainElements());
519 EXPECT_EQ(0, arrayBufFreeCount);
521 // Make sure the data is still the same after coalescing
522 EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
524 checkChain(chainClone.get(), gen);
526 // Coalesce the entire chain
527 chainClone->coalesce();
528 EXPECT_EQ(1, chainClone->countChainElements());
529 EXPECT_EQ(1, arrayBufFreeCount);
531 // Make sure the data is still the same after coalescing
532 EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
534 checkChain(chainClone.get(), gen);
536 // Make a new chain to test the unlink and pop operations
537 iob1 = IOBuf::create(1);
539 IOBuf *iob1ptr = iob1.get();
540 iob2 = IOBuf::create(3);
542 iob2ptr = iob2.get();
543 iob3 = IOBuf::create(5);
545 iob3ptr = iob3.get();
546 iob4 = IOBuf::create(7);
548 iob4ptr = iob4.get();
549 iob1->appendChain(std::move(iob2));
550 iob1->prev()->appendChain(std::move(iob3));
551 iob1->prev()->appendChain(std::move(iob4));
552 EXPECT_EQ(4, iob1->countChainElements());
553 EXPECT_EQ(16, iob1->computeChainDataLength());
555 // Unlink from the middle of the chain
556 iob3 = iob3ptr->unlink();
557 EXPECT_TRUE(iob3.get() == iob3ptr);
558 EXPECT_EQ(3, iob1->countChainElements());
559 EXPECT_EQ(11, iob1->computeChainDataLength());
561 // Unlink from the end of the chain
562 iob4 = iob1->prev()->unlink();
563 EXPECT_TRUE(iob4.get() == iob4ptr);
564 EXPECT_EQ(2, iob1->countChainElements());
565 EXPECT_TRUE(iob1->next() == iob2ptr);
566 EXPECT_EQ(4, iob1->computeChainDataLength());
568 // Pop from the front of the chain
570 EXPECT_TRUE(iob1.get() == iob1ptr);
571 EXPECT_EQ(1, iob1->countChainElements());
572 EXPECT_EQ(1, iob1->computeChainDataLength());
573 EXPECT_TRUE(iob2.get() == iob2ptr);
574 EXPECT_EQ(1, iob2->countChainElements());
575 EXPECT_EQ(3, iob2->computeChainDataLength());
578 void testFreeFn(void* buffer, void* ptr) {
579 uint32_t* freeCount = static_cast<uint32_t*>(ptr);;
580 delete[] static_cast<uint8_t*>(buffer);
586 TEST(IOBuf, Reserve) {
587 uint32_t fillSeed = 0x23456789;
588 boost::mt19937 gen(fillSeed);
590 // Reserve does nothing if empty and doesn't have to grow the buffer
593 unique_ptr<IOBuf> iob(IOBuf::create(2000));
594 EXPECT_EQ(0, iob->headroom());
595 const void* p1 = iob->buffer();
597 EXPECT_LE(5, iob->headroom());
598 EXPECT_EQ(p1, iob->buffer());
601 // Reserve doesn't reallocate if we have enough total room
604 unique_ptr<IOBuf> iob(IOBuf::create(2000));
606 fillBuf(iob.get(), gen);
607 EXPECT_EQ(0, iob->headroom());
608 EXPECT_EQ(100, iob->length());
609 const void* p1 = iob->buffer();
610 const uint8_t* d1 = iob->data();
611 iob->reserve(100, 1800);
612 EXPECT_LE(100, iob->headroom());
613 EXPECT_EQ(p1, iob->buffer());
614 EXPECT_EQ(d1 + 100, iob->data());
616 checkBuf(iob.get(), gen);
619 // Reserve reallocates if we don't have enough total room.
620 // NOTE that, with jemalloc, we know that this won't reallocate in place
621 // as the size is less than jemallocMinInPlaceExpanadable
624 unique_ptr<IOBuf> iob(IOBuf::create(2000));
626 fillBuf(iob.get(), gen);
627 EXPECT_EQ(0, iob->headroom());
628 EXPECT_EQ(100, iob->length());
629 const void* p1 = iob->buffer();
630 iob->reserve(100, 2512); // allocation sizes are multiples of 256
631 EXPECT_LE(100, iob->headroom());
632 if (folly::usingJEMalloc()) {
633 EXPECT_NE(p1, iob->buffer());
636 checkBuf(iob.get(), gen);
639 // Test reserve from internal buffer, this used to segfault
641 unique_ptr<IOBuf> iob(IOBuf::create(0));
642 iob->reserve(0, 2000);
643 EXPECT_EQ(0, iob->headroom());
644 EXPECT_LE(2000, iob->tailroom());
647 // Test reserving from a user-allocated buffer.
649 uint8_t* buf = static_cast<uint8_t*>(malloc(100));
650 auto iob = IOBuf::takeOwnership(buf, 100);
651 iob->reserve(0, 2000);
652 EXPECT_EQ(0, iob->headroom());
653 EXPECT_LE(2000, iob->tailroom());
656 // Test reserving from a user-allocated with a custom free function.
658 uint32_t freeCount{0};
659 uint8_t* buf = new uint8_t[100];
660 auto iob = IOBuf::takeOwnership(buf, 100, testFreeFn, &freeCount);
661 iob->reserve(0, 2000);
662 EXPECT_EQ(0, iob->headroom());
663 EXPECT_LE(2000, iob->tailroom());
664 EXPECT_EQ(1, freeCount);
668 TEST(IOBuf, copyBuffer) {
669 std::string s("hello");
670 auto buf = IOBuf::copyBuffer(s.data(), s.size(), 1, 2);
671 EXPECT_EQ(1, buf->headroom());
672 EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
674 EXPECT_LE(2, buf->tailroom());
676 buf = IOBuf::copyBuffer(s, 5, 7);
677 EXPECT_EQ(5, buf->headroom());
678 EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
680 EXPECT_LE(7, buf->tailroom());
683 buf = IOBuf::copyBuffer(empty, 3, 6);
684 EXPECT_EQ(3, buf->headroom());
685 EXPECT_EQ(0, buf->length());
686 EXPECT_LE(6, buf->tailroom());
688 // A stack-allocated version
689 IOBuf stackBuf(IOBuf::COPY_BUFFER, s, 1, 2);
690 EXPECT_EQ(1, stackBuf.headroom());
691 EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(stackBuf.data()),
693 EXPECT_LE(2, stackBuf.tailroom());
696 TEST(IOBuf, maybeCopyBuffer) {
697 std::string s("this is a test");
698 auto buf = IOBuf::maybeCopyBuffer(s, 1, 2);
699 EXPECT_EQ(1, buf->headroom());
700 EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
702 EXPECT_LE(2, buf->tailroom());
705 buf = IOBuf::maybeCopyBuffer("", 5, 7);
706 EXPECT_EQ(nullptr, buf.get());
708 buf = IOBuf::maybeCopyBuffer("");
709 EXPECT_EQ(nullptr, buf.get());
714 int customDeleterCount = 0;
715 int destructorCount = 0;
716 struct OwnershipTestClass {
717 explicit OwnershipTestClass(int v = 0) : val(v) { }
718 ~OwnershipTestClass() {
724 typedef std::function<void(OwnershipTestClass*)> CustomDeleter;
726 void customDelete(OwnershipTestClass* p) {
727 ++customDeleterCount;
731 void customDeleteArray(OwnershipTestClass* p) {
732 ++customDeleterCount;
738 TEST(IOBuf, takeOwnershipUniquePtr) {
741 std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass());
743 EXPECT_EQ(1, destructorCount);
747 std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]);
749 EXPECT_EQ(2, destructorCount);
753 std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass());
754 std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
755 EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
756 EXPECT_EQ(0, destructorCount);
758 EXPECT_EQ(1, destructorCount);
762 std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]);
763 std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
764 EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
765 EXPECT_EQ(0, destructorCount);
767 EXPECT_EQ(2, destructorCount);
769 customDeleterCount = 0;
772 std::unique_ptr<OwnershipTestClass, CustomDeleter>
773 p(new OwnershipTestClass(), customDelete);
774 std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
775 EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
776 EXPECT_EQ(0, destructorCount);
778 EXPECT_EQ(1, destructorCount);
779 EXPECT_EQ(1, customDeleterCount);
781 customDeleterCount = 0;
784 std::unique_ptr<OwnershipTestClass[], CustomDeleter>
785 p(new OwnershipTestClass[2], CustomDeleter(customDeleteArray));
786 std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
787 EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
788 EXPECT_EQ(0, destructorCount);
790 EXPECT_EQ(2, destructorCount);
791 EXPECT_EQ(1, customDeleterCount);
794 TEST(IOBuf, Alignment) {
795 size_t alignment = alignof(std::max_align_t);
797 std::vector<size_t> sizes {0, 1, 64, 256, 1024, 1 << 10};
798 for (size_t size : sizes) {
799 auto buf = IOBuf::create(size);
800 uintptr_t p = reinterpret_cast<uintptr_t>(buf->data());
801 EXPECT_EQ(0, p & (alignment - 1)) << "size=" << size;
805 TEST(TypedIOBuf, Simple) {
806 auto buf = IOBuf::create(0);
807 TypedIOBuf<uint64_t> typed(buf.get());
808 const uint64_t n = 10000;
810 EXPECT_LE(n, typed.capacity());
811 for (uint64_t i = 0; i < n; i++) {
812 *typed.writableTail() = i;
815 EXPECT_EQ(n, typed.length());
816 for (uint64_t i = 0; i < n; i++) {
817 EXPECT_EQ(i, typed.data()[i]);
822 TAKE_OWNERSHIP_MALLOC,
823 TAKE_OWNERSHIP_CUSTOM,
827 // chain element size, number of elements in chain, shared
828 class MoveToFbStringTest
829 : public ::testing::TestWithParam<std::tr1::tuple<int, int, bool, BufType>> {
831 void SetUp() override {
832 elementSize_ = std::tr1::get<0>(GetParam());
833 elementCount_ = std::tr1::get<1>(GetParam());
834 shared_ = std::tr1::get<2>(GetParam());
835 type_ = std::tr1::get<3>(GetParam());
838 for (int i = 0; i < elementCount_ - 1; ++i) {
839 buf_->prependChain(makeBuf());
841 EXPECT_EQ(elementCount_, buf_->countChainElements());
842 EXPECT_EQ(elementCount_ * elementSize_, buf_->computeChainDataLength());
844 buf2_ = buf_->clone();
845 EXPECT_EQ(elementCount_, buf2_->countChainElements());
846 EXPECT_EQ(elementCount_ * elementSize_, buf2_->computeChainDataLength());
850 std::unique_ptr<IOBuf> makeBuf() {
851 unique_ptr<IOBuf> buf;
854 buf = IOBuf::create(elementSize_);
855 buf->append(elementSize_);
857 case TAKE_OWNERSHIP_MALLOC: {
858 void* data = malloc(elementSize_);
860 throw std::bad_alloc();
862 buf = IOBuf::takeOwnership(data, elementSize_);
865 case TAKE_OWNERSHIP_CUSTOM: {
866 uint8_t* data = new uint8_t[elementSize_];
867 buf = IOBuf::takeOwnership(data, elementSize_, testFreeFn);
871 unique_ptr<uint8_t[]> data(new uint8_t[elementSize_]);
872 buf = IOBuf::wrapBuffer(data.get(), elementSize_);
873 ownedBuffers_.emplace_back(std::move(data));
877 throw std::invalid_argument("unexpected buffer type parameter");
880 memset(buf->writableData(), 'x', elementSize_);
884 void check(std::unique_ptr<IOBuf>& buf) {
885 fbstring str = buf->moveToFbString();
886 EXPECT_EQ(elementCount_ * elementSize_, str.size());
887 EXPECT_EQ(elementCount_ * elementSize_, strspn(str.c_str(), "x"));
888 EXPECT_EQ(0, buf->length());
889 EXPECT_EQ(1, buf->countChainElements());
890 EXPECT_EQ(0, buf->computeChainDataLength());
891 EXPECT_FALSE(buf->isChained());
898 std::unique_ptr<IOBuf> buf_;
899 std::unique_ptr<IOBuf> buf2_;
900 std::vector<std::unique_ptr<uint8_t[]>> ownedBuffers_;
903 TEST_P(MoveToFbStringTest, Simple) {
910 INSTANTIATE_TEST_CASE_P(
914 ::testing::Values(0, 1, 24, 256, 1 << 10, 1 << 20), // element size
915 ::testing::Values(1, 2, 10), // element count
916 ::testing::Bool(), // shared
917 ::testing::Values(CREATE, TAKE_OWNERSHIP_MALLOC,
918 TAKE_OWNERSHIP_CUSTOM, USER_OWNED)));
920 TEST(IOBuf, getIov) {
921 uint32_t fillSeed = 0xdeadbeef;
922 boost::mt19937 gen(fillSeed);
926 auto buf = IOBuf::create(len + 1);
927 buf->append(rand() % len + 1);
928 fillBuf(buf.get(), gen);
930 for (size_t i = 0; i < count - 1; i++) {
931 auto buf2 = IOBuf::create(len + 1);
932 buf2->append(rand() % len + 1);
933 fillBuf(buf2.get(), gen);
934 buf->prependChain(std::move(buf2));
936 EXPECT_EQ(count, buf->countChainElements());
938 auto iov = buf->getIov();
939 EXPECT_EQ(count, iov.size());
941 IOBuf const* p = buf.get();
942 for (size_t i = 0; i < count; i++, p = p->next()) {
943 EXPECT_EQ(p->data(), iov[i].iov_base);
944 EXPECT_EQ(p->length(), iov[i].iov_len);
947 // an empty buf should be skipped in the iov.
948 buf->next()->clear();
950 EXPECT_EQ(count - 1, iov.size());
951 EXPECT_EQ(buf->next()->next()->data(), iov[1].iov_base);
953 // same for the first one being empty
956 EXPECT_EQ(count - 2, iov.size());
957 EXPECT_EQ(buf->next()->next()->data(), iov[0].iov_base);
960 buf->prev()->clear();
962 EXPECT_EQ(count - 3, iov.size());
964 // test appending to an existing iovec array
966 const char localBuf[] = "hello";
967 iov.push_back({(void*)localBuf, sizeof(localBuf)});
968 iov.push_back({(void*)localBuf, sizeof(localBuf)});
969 buf->appendToIov(&iov);
970 EXPECT_EQ(count - 1, iov.size());
971 EXPECT_EQ(localBuf, iov[0].iov_base);
972 EXPECT_EQ(localBuf, iov[1].iov_base);
973 // The first two IOBufs were cleared, so the next iov entry
974 // should be the third IOBuf in the chain.
975 EXPECT_EQ(buf->next()->next()->data(), iov[2].iov_base);
979 // Default allocate an IOBuf on the stack
981 char data[] = "foobar";
982 uint32_t length = sizeof(data);
983 uint32_t actualCapacity{0};
984 const void* ptr{nullptr};
987 // Create a small IOBuf on the stack.
988 // Note that IOBufs created on the stack always use an external buffer.
989 IOBuf b1(IOBuf::CREATE, 10);
990 actualCapacity = b1.capacity();
991 EXPECT_GE(actualCapacity, 10);
992 EXPECT_EQ(0, b1.length());
993 EXPECT_FALSE(b1.isShared());
995 ASSERT_TRUE(ptr != nullptr);
996 memcpy(b1.writableTail(), data, length);
998 EXPECT_EQ(length, b1.length());
1000 // Use the move constructor
1001 IOBuf b2(std::move(b1));
1002 EXPECT_EQ(ptr, b2.data());
1003 EXPECT_EQ(length, b2.length());
1004 EXPECT_EQ(actualCapacity, b2.capacity());
1005 EXPECT_FALSE(b2.isShared());
1007 // Use the move assignment operator
1008 outerBuf = std::move(b2);
1009 // Close scope, destroying b1 and b2
1010 // (which are both be invalid now anyway after moving out of them)
1013 EXPECT_EQ(ptr, outerBuf.data());
1014 EXPECT_EQ(length, outerBuf.length());
1015 EXPECT_EQ(actualCapacity, outerBuf.capacity());
1016 EXPECT_FALSE(outerBuf.isShared());
1020 std::unique_ptr<IOBuf> fromStr(StringPiece sp) {
1021 return IOBuf::copyBuffer(ByteRange(sp));
1025 TEST(IOBuf, HashAndEqual) {
1026 folly::IOBufEqual eq;
1027 folly::IOBufHash hash;
1029 EXPECT_TRUE(eq(nullptr, nullptr));
1030 EXPECT_EQ(0, hash(nullptr));
1032 auto empty = IOBuf::create(0);
1034 EXPECT_TRUE(eq(*empty, *empty));
1035 EXPECT_TRUE(eq(empty, empty));
1037 EXPECT_FALSE(eq(nullptr, empty));
1038 EXPECT_FALSE(eq(empty, nullptr));
1040 EXPECT_EQ(hash(*empty), hash(empty));
1041 EXPECT_NE(0, hash(empty));
1043 auto a = fromStr("hello");
1045 EXPECT_TRUE(eq(*a, *a));
1046 EXPECT_TRUE(eq(a, a));
1048 EXPECT_FALSE(eq(nullptr, a));
1049 EXPECT_FALSE(eq(a, nullptr));
1051 EXPECT_EQ(hash(*a), hash(a));
1052 EXPECT_NE(0, hash(a));
1054 auto b = fromStr("hello");
1056 EXPECT_TRUE(eq(*a, *b));
1057 EXPECT_TRUE(eq(a, b));
1059 EXPECT_EQ(hash(a), hash(b));
1061 auto c = fromStr("hellow");
1063 EXPECT_FALSE(eq(a, c));
1064 EXPECT_NE(hash(a), hash(c));
1066 auto d = fromStr("world");
1068 EXPECT_FALSE(eq(a, d));
1069 EXPECT_NE(hash(a), hash(d));
1071 auto e = fromStr("helloworld");
1072 auto f = fromStr("hello");
1073 f->prependChain(fromStr("wo"));
1074 f->prependChain(fromStr("rld"));
1076 EXPECT_TRUE(eq(e, f));
1077 EXPECT_EQ(hash(e), hash(f));
1080 // reserveSlow() had a bug when reallocating the buffer in place. It would
1081 // preserve old headroom if it's not too much (heuristically) but wouldn't
1082 // adjust the requested amount of memory to account for that; the end result
1083 // would be that reserve() would return with less tailroom than requested.
1084 TEST(IOBuf, ReserveWithHeadroom) {
1085 // This is assuming jemalloc, where we know that 4096 and 8192 bytes are
1086 // valid (and consecutive) allocation sizes. We're hoping that our
1087 // 4096-byte buffer can be expanded in place to 8192 (in practice, this
1088 // usually happens).
1089 const char data[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
1090 constexpr size_t reservedSize = 24; // sizeof(SharedInfo)
1091 // chosen carefully so that the buffer is exactly 4096 bytes
1092 IOBuf buf(IOBuf::CREATE, 4096 - reservedSize);
1094 memcpy(buf.writableData(), data, sizeof(data));
1095 buf.append(sizeof(data));
1096 EXPECT_EQ(sizeof(data), buf.length());
1098 // Grow the buffer (hopefully in place); this would incorrectly reserve
1099 // the 10 bytes of headroom, giving us 10 bytes less than requested.
1100 size_t tailroom = 8192 - reservedSize - sizeof(data);
1101 buf.reserve(0, tailroom);
1102 EXPECT_LE(tailroom, buf.tailroom());
1103 EXPECT_EQ(sizeof(data), buf.length());
1104 EXPECT_EQ(0, memcmp(data, buf.data(), sizeof(data)));
1107 TEST(IOBuf, CopyConstructorAndAssignmentOperator) {
1108 auto buf = IOBuf::create(4096);
1109 append(buf, "hello world");
1110 auto buf2 = IOBuf::create(4096);
1111 append(buf2, " goodbye");
1112 buf->prependChain(std::move(buf2));
1113 EXPECT_FALSE(buf->isShared());
1117 EXPECT_TRUE(buf->isShared());
1118 EXPECT_TRUE(copy.isShared());
1119 EXPECT_EQ((void*)buf->data(), (void*)copy.data());
1120 EXPECT_NE(buf->next(), copy.next()); // actually different buffers
1124 EXPECT_TRUE(buf->isShared());
1125 EXPECT_TRUE(copy.isShared());
1126 EXPECT_FALSE(copy2.isShared());
1128 auto p = reinterpret_cast<const char*>(copy2.data());
1129 EXPECT_EQ("hello world goodbye", std::string(p, copy2.length()));
1132 EXPECT_FALSE(buf->isShared());
1135 folly::IOBuf newBuf(folly::IOBuf::CREATE, 4096);
1136 EXPECT_FALSE(newBuf.isShared());
1138 auto newBufCopy = newBuf;
1139 EXPECT_TRUE(newBuf.isShared());
1140 EXPECT_TRUE(newBufCopy.isShared());
1143 EXPECT_TRUE(buf->isShared());
1144 EXPECT_FALSE(newBuf.isShared());
1145 EXPECT_TRUE(newBufCopy.isShared());
1148 EXPECT_FALSE(buf->isShared());
1151 TEST(IOBuf, CloneAsValue) {
1152 auto buf = IOBuf::create(4096);
1153 append(buf, "hello world");
1155 auto buf2 = IOBuf::create(4096);
1156 append(buf2, " goodbye");
1157 buf->prependChain(std::move(buf2));
1158 EXPECT_FALSE(buf->isShared());
1162 auto copy = buf->cloneOneAsValue();
1163 EXPECT_TRUE(buf->isShared());
1164 EXPECT_TRUE(copy.isShared());
1165 EXPECT_EQ((void*)buf->data(), (void*)copy.data());
1166 EXPECT_TRUE(buf->isChained());
1167 EXPECT_FALSE(copy.isChained());
1169 auto copy2 = buf->cloneAsValue();
1170 EXPECT_TRUE(buf->isShared());
1171 EXPECT_TRUE(copy.isShared());
1172 EXPECT_TRUE(copy2.isShared());
1173 EXPECT_TRUE(buf->isChained());
1174 EXPECT_TRUE(copy2.isChained());
1177 EXPECT_TRUE(buf->isShared());
1178 EXPECT_FALSE(copy.isShared());
1179 EXPECT_NE((void*)buf->data(), (void*)copy.data());
1180 EXPECT_TRUE(copy2.isShared());
1182 auto p = reinterpret_cast<const char*>(copy.data());
1183 EXPECT_EQ("hello world", std::string(p, copy.length()));
1186 EXPECT_FALSE(buf->isShared());
1187 EXPECT_FALSE(copy.isShared());
1188 EXPECT_FALSE(copy2.isShared());
1189 EXPECT_FALSE(copy2.isChained());
1191 auto p2 = reinterpret_cast<const char*>(copy2.data());
1192 EXPECT_EQ("hello world goodbye", std::string(p2, copy2.length()));
1195 EXPECT_FALSE(buf->isShared());
1199 // Use with string literals only
1200 std::unique_ptr<IOBuf> wrap(const char* str) {
1201 return IOBuf::wrapBuffer(str, strlen(str));
1204 std::unique_ptr<IOBuf> copy(const char* str) {
1205 // At least 1KiB of tailroom, to ensure an external buffer
1206 return IOBuf::copyBuffer(str, strlen(str), 0, 1024);
1209 std::string toString(const folly::IOBuf& buf) {
1211 result.reserve(buf.computeChainDataLength());
1212 for (auto& b : buf) {
1213 result.append(reinterpret_cast<const char*>(b.data()), b.size());
1218 char* writableStr(folly::IOBuf& buf) {
1219 return reinterpret_cast<char*>(buf.writableData());
1224 TEST(IOBuf, Managed) {
1225 auto hello = "hello";
1226 auto buf1UP = wrap(hello);
1227 auto buf1 = buf1UP.get();
1228 EXPECT_FALSE(buf1->isManagedOne());
1229 auto buf2UP = copy("world");
1230 auto buf2 = buf2UP.get();
1231 EXPECT_TRUE(buf2->isManagedOne());
1232 auto buf3UP = wrap(hello);
1233 auto buf3 = buf3UP.get();
1234 auto buf4UP = buf2->clone();
1235 auto buf4 = buf4UP.get();
1237 // buf1 and buf3 share the same memory (but are unmanaged)
1238 EXPECT_FALSE(buf1->isManagedOne());
1239 EXPECT_FALSE(buf3->isManagedOne());
1240 EXPECT_TRUE(buf1->isSharedOne());
1241 EXPECT_TRUE(buf3->isSharedOne());
1242 EXPECT_EQ(buf1->data(), buf3->data());
1244 // buf2 and buf4 share the same memory (but are managed)
1245 EXPECT_TRUE(buf2->isManagedOne());
1246 EXPECT_TRUE(buf4->isManagedOne());
1247 EXPECT_TRUE(buf2->isSharedOne());
1248 EXPECT_TRUE(buf4->isSharedOne());
1249 EXPECT_EQ(buf2->data(), buf4->data());
1251 buf1->prependChain(std::move(buf2UP));
1252 buf1->prependChain(std::move(buf3UP));
1253 buf1->prependChain(std::move(buf4UP));
1255 EXPECT_EQ("helloworldhelloworld", toString(*buf1));
1256 EXPECT_FALSE(buf1->isManaged());
1258 buf1->makeManaged();
1259 EXPECT_TRUE(buf1->isManaged());
1261 // buf1 and buf3 are now unshared (because they were unmanaged)
1262 EXPECT_TRUE(buf1->isManagedOne());
1263 EXPECT_TRUE(buf3->isManagedOne());
1264 EXPECT_FALSE(buf1->isSharedOne());
1265 EXPECT_FALSE(buf3->isSharedOne());
1266 EXPECT_NE(buf1->data(), buf3->data());
1268 // buf2 and buf4 are still shared
1269 EXPECT_TRUE(buf2->isManagedOne());
1270 EXPECT_TRUE(buf4->isManagedOne());
1271 EXPECT_TRUE(buf2->isSharedOne());
1272 EXPECT_TRUE(buf4->isSharedOne());
1273 EXPECT_EQ(buf2->data(), buf4->data());
1275 // And verify that the truth is what we expect: modify a byte in buf1 and
1276 // buf2, see that the change from buf1 is *not* reflected in buf3, but the
1277 // change from buf2 is reflected in buf4.
1278 writableStr(*buf1)[0] = 'j';
1279 writableStr(*buf2)[0] = 'x';
1280 EXPECT_EQ("jelloxorldhelloxorld", toString(*buf1));