proxygen
IOBufTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013-present 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 #include <folly/io/IOBuf.h>
18 #include <folly/io/TypedIOBuf.h>
19 
20 #include <cstddef>
21 
22 #include <boost/random.hpp>
23 
24 #include <folly/Range.h>
25 #include <folly/memory/Malloc.h>
27 
28 using folly::ByteRange;
29 using folly::fbstring;
30 using folly::fbvector;
31 using folly::IOBuf;
32 using folly::ordering;
33 using folly::StringPiece;
34 using folly::TypedIOBuf;
35 using std::unique_ptr;
36 
37 void append(std::unique_ptr<IOBuf>& buf, StringPiece str) {
38  EXPECT_LE(str.size(), buf->tailroom());
39  memcpy(buf->writableData(), str.data(), str.size());
40  buf->append(str.size());
41 }
42 
43 void prepend(std::unique_ptr<IOBuf>& buf, StringPiece str) {
44  EXPECT_LE(str.size(), buf->headroom());
45  memcpy(buf->writableData() - str.size(), str.data(), str.size());
46  buf->prepend(str.size());
47 }
48 
49 TEST(IOBuf, Simple) {
50  unique_ptr<IOBuf> buf(IOBuf::create(100));
51  uint32_t cap = buf->capacity();
52  EXPECT_LE(100, cap);
53  EXPECT_EQ(0, buf->headroom());
54  EXPECT_EQ(0, buf->length());
55  EXPECT_EQ(cap, buf->tailroom());
56 
57  append(buf, "world");
58  buf->advance(10);
59  EXPECT_EQ(10, buf->headroom());
60  EXPECT_EQ(5, buf->length());
61  EXPECT_EQ(cap - 15, buf->tailroom());
62 
63  prepend(buf, "hello ");
64  EXPECT_EQ(4, buf->headroom());
65  EXPECT_EQ(11, buf->length());
66  EXPECT_EQ(cap - 15, buf->tailroom());
67 
68  const char* p = reinterpret_cast<const char*>(buf->data());
69  EXPECT_EQ("hello world", std::string(p, buf->length()));
70 
71  buf->clear();
72  EXPECT_EQ(0, buf->headroom());
73  EXPECT_EQ(0, buf->length());
74  EXPECT_EQ(cap, buf->tailroom());
75 }
76 
77 void testAllocSize(uint32_t requestedCapacity) {
78  unique_ptr<IOBuf> iobuf(IOBuf::create(requestedCapacity));
79  EXPECT_GE(iobuf->capacity(), requestedCapacity);
80 }
81 
82 TEST(IOBuf, AllocSizes) {
83  // Try with a small allocation size that should fit in the internal buffer
84  testAllocSize(28);
85 
86  // Try with a large allocation size that will require an external buffer.
87  testAllocSize(9000);
88 
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
92  // test code.)
93  testAllocSize(220);
94  testAllocSize(219);
95  testAllocSize(221);
96 }
97 
98 void deleteArrayBuffer(void* buf, void* arg) {
99  uint32_t* deleteCount = static_cast<uint32_t*>(arg);
100  ++(*deleteCount);
101  uint8_t* bufPtr = static_cast<uint8_t*>(buf);
102  delete[] bufPtr;
103 }
104 
105 TEST(IOBuf, TakeOwnership) {
106  uint32_t size1 = 99;
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());
113 
114  uint32_t deleteCount = 0;
115  uint32_t size2 = 4321;
116  uint8_t* buf2 = new uint8_t[size2];
117  unique_ptr<IOBuf> iobuf2(
118  IOBuf::takeOwnership(buf2, size2, deleteArrayBuffer, &deleteCount));
119  EXPECT_EQ(buf2, iobuf2->data());
120  EXPECT_EQ(size2, iobuf2->length());
121  EXPECT_EQ(buf2, iobuf2->buffer());
122  EXPECT_EQ(size2, iobuf2->capacity());
123  EXPECT_EQ(0, deleteCount);
124  iobuf2.reset();
125  EXPECT_EQ(1, deleteCount);
126 
127  deleteCount = 0;
128  uint32_t size3 = 3456;
129  uint8_t* buf3 = new uint8_t[size3];
130  uint32_t length3 = 48;
131  unique_ptr<IOBuf> iobuf3(IOBuf::takeOwnership(
132  buf3, size3, length3, deleteArrayBuffer, &deleteCount));
133  EXPECT_EQ(buf3, iobuf3->data());
134  EXPECT_EQ(length3, iobuf3->length());
135  EXPECT_EQ(buf3, iobuf3->buffer());
136  EXPECT_EQ(size3, iobuf3->capacity());
137  EXPECT_EQ(0, deleteCount);
138  iobuf3.reset();
139  EXPECT_EQ(1, deleteCount);
140 
141  deleteCount = 0;
142  {
143  uint32_t size4 = 1234;
144  uint8_t* buf4 = new uint8_t[size4];
145  uint32_t length4 = 48;
146  IOBuf iobuf4(
147  IOBuf::TAKE_OWNERSHIP,
148  buf4,
149  size4,
150  length4,
152  &deleteCount);
153  EXPECT_EQ(buf4, iobuf4.data());
154  EXPECT_EQ(length4, iobuf4.length());
155  EXPECT_EQ(buf4, iobuf4.buffer());
156  EXPECT_EQ(size4, iobuf4.capacity());
157 
158  IOBuf iobuf5 = std::move(iobuf4);
159  EXPECT_EQ(buf4, iobuf5.data());
160  EXPECT_EQ(length4, iobuf5.length());
161  EXPECT_EQ(buf4, iobuf5.buffer());
162  EXPECT_EQ(size4, iobuf5.capacity());
163  EXPECT_EQ(0, deleteCount);
164  }
165  EXPECT_EQ(1, deleteCount);
166 }
167 
168 TEST(IOBuf, WrapBuffer) {
169  const uint32_t size1 = 1234;
170  uint8_t buf1[size1];
171  unique_ptr<IOBuf> iobuf1(IOBuf::wrapBuffer(buf1, size1));
172  EXPECT_EQ(buf1, iobuf1->data());
173  EXPECT_EQ(size1, iobuf1->length());
174  EXPECT_EQ(buf1, iobuf1->buffer());
175  EXPECT_EQ(size1, iobuf1->capacity());
176 
177  uint32_t size2 = 0x1234;
178  unique_ptr<uint8_t[]> buf2(new uint8_t[size2]);
179  unique_ptr<IOBuf> iobuf2(IOBuf::wrapBuffer(buf2.get(), size2));
180  EXPECT_EQ(buf2.get(), iobuf2->data());
181  EXPECT_EQ(size2, iobuf2->length());
182  EXPECT_EQ(buf2.get(), iobuf2->buffer());
183  EXPECT_EQ(size2, iobuf2->capacity());
184 
185  uint32_t size3 = 4321;
186  unique_ptr<uint8_t[]> buf3(new uint8_t[size3]);
187  IOBuf iobuf3(IOBuf::WRAP_BUFFER, buf3.get(), size3);
188  EXPECT_EQ(buf3.get(), iobuf3.data());
189  EXPECT_EQ(size3, iobuf3.length());
190  EXPECT_EQ(buf3.get(), iobuf3.buffer());
191  EXPECT_EQ(size3, iobuf3.capacity());
192 
193  const uint32_t size4 = 2345;
194  unique_ptr<uint8_t[]> buf4(new uint8_t[size4]);
195  IOBuf iobuf4 = IOBuf::wrapBufferAsValue(buf4.get(), size4);
196  EXPECT_EQ(buf4.get(), iobuf4.data());
197  EXPECT_EQ(size4, iobuf4.length());
198  EXPECT_EQ(buf4.get(), iobuf4.buffer());
199  EXPECT_EQ(size4, iobuf4.capacity());
200 }
201 
202 TEST(IOBuf, CreateCombined) {
203  // Create a combined IOBuf, then destroy it.
204  // The data buffer and IOBuf both become unused as part of the destruction
205  {
206  auto buf = IOBuf::createCombined(256);
207  EXPECT_FALSE(buf->isShared());
208  }
209 
210  // Create a combined IOBuf, clone from it, and then destroy the original
211  // IOBuf. The data buffer cannot be deleted until the clone is also
212  // destroyed.
213  {
214  auto bufA = IOBuf::createCombined(256);
215  EXPECT_FALSE(bufA->isShared());
216  auto bufB = bufA->clone();
217  EXPECT_TRUE(bufA->isShared());
218  EXPECT_TRUE(bufB->isShared());
219  bufA.reset();
220  EXPECT_FALSE(bufB->isShared());
221  }
222 
223  // Create a combined IOBuf, then call reserve() to get a larger buffer.
224  // The IOBuf no longer points to the combined data buffer, but the
225  // overall memory segment cannot be deleted until the IOBuf is also
226  // destroyed.
227  {
228  auto buf = IOBuf::createCombined(256);
229  buf->reserve(0, buf->capacity() + 100);
230  }
231 
232  // Create a combined IOBuf, clone from it, then call unshare() on the original
233  // buffer. This creates a situation where bufB is pointing at the combined
234  // buffer associated with bufA, but bufA is now using a different buffer.
235  auto testSwap = [](bool resetAFirst) {
236  auto bufA = IOBuf::createCombined(256);
237  EXPECT_FALSE(bufA->isShared());
238  auto bufB = bufA->clone();
239  EXPECT_TRUE(bufA->isShared());
240  EXPECT_TRUE(bufB->isShared());
241  bufA->unshare();
242  EXPECT_FALSE(bufA->isShared());
243  EXPECT_FALSE(bufB->isShared());
244 
245  if (resetAFirst) {
246  bufA.reset();
247  bufB.reset();
248  } else {
249  bufB.reset();
250  bufA.reset();
251  }
252  };
253  testSwap(true);
254  testSwap(false);
255 }
256 
257 void fillBuf(uint8_t* buf, uint32_t length, boost::mt19937& gen) {
258  for (uint32_t n = 0; n < length; ++n) {
259  buf[n] = static_cast<uint8_t>(gen() & 0xff);
260  }
261 }
262 
263 void fillBuf(IOBuf* buf, boost::mt19937& gen) {
264  buf->unshare();
265  fillBuf(buf->writableData(), buf->length(), gen);
266 }
267 
268 void checkBuf(const uint8_t* buf, uint32_t length, boost::mt19937& gen) {
269  // Rather than using EXPECT_EQ() to check each character,
270  // count the number of differences and the first character that differs.
271  // This way on error we'll report just that information, rather than tons of
272  // failed checks for each byte in the buffer.
273  uint32_t numDifferences = 0;
274  uint32_t firstDiffIndex = 0;
275  uint8_t firstDiffExpected = 0;
276  for (uint32_t n = 0; n < length; ++n) {
277  uint8_t expected = static_cast<uint8_t>(gen() & 0xff);
278  if (buf[n] == expected) {
279  continue;
280  }
281 
282  if (numDifferences == 0) {
283  firstDiffIndex = n;
284  firstDiffExpected = expected;
285  }
286  ++numDifferences;
287  }
288 
289  EXPECT_EQ(0, numDifferences);
290  if (numDifferences > 0) {
291  // Cast to int so it will be printed numerically
292  // rather than as a char if the check fails
293  EXPECT_EQ(
294  static_cast<int>(buf[firstDiffIndex]),
295  static_cast<int>(firstDiffExpected));
296  }
297 }
298 
299 void checkBuf(IOBuf* buf, boost::mt19937& gen) {
300  checkBuf(buf->data(), buf->length(), gen);
301 }
302 
303 void checkBuf(ByteRange buf, boost::mt19937& gen) {
304  checkBuf(buf.data(), buf.size(), gen);
305 }
306 
307 void checkChain(IOBuf* buf, boost::mt19937& gen) {
308  IOBuf* current = buf;
309  do {
310  checkBuf(current->data(), current->length(), gen);
311  current = current->next();
312  } while (current != buf);
313 }
314 
315 TEST(IOBuf, Chaining) {
316  uint32_t fillSeed = 0x12345678;
317  boost::mt19937 gen(fillSeed);
318 
319  // An IOBuf with external storage
320  uint32_t headroom = 123;
321  unique_ptr<IOBuf> iob1(IOBuf::create(2048));
322  iob1->advance(headroom);
323  iob1->append(1500);
324  fillBuf(iob1.get(), gen);
325 
326  // An IOBuf with internal storage
327  unique_ptr<IOBuf> iob2(IOBuf::create(20));
328  iob2->append(20);
329  fillBuf(iob2.get(), gen);
330 
331  // An IOBuf around a buffer it doesn't own
332  uint8_t localbuf[1234];
333  fillBuf(localbuf, 1234, gen);
334  unique_ptr<IOBuf> iob3(IOBuf::wrapBuffer(localbuf, sizeof(localbuf)));
335 
336  // An IOBuf taking ownership of a user-supplied buffer
337  uint32_t heapBufSize = 900;
338  uint8_t* heapBuf = static_cast<uint8_t*>(malloc(heapBufSize));
339  fillBuf(heapBuf, heapBufSize, gen);
340  unique_ptr<IOBuf> iob4(IOBuf::takeOwnership(heapBuf, heapBufSize));
341 
342  // An IOBuf taking ownership of a user-supplied buffer with
343  // a custom free function
344  uint32_t arrayBufSize = 321;
345  uint8_t* arrayBuf = new uint8_t[arrayBufSize];
346  fillBuf(arrayBuf, arrayBufSize, gen);
347  uint32_t arrayBufFreeCount = 0;
348  unique_ptr<IOBuf> iob5(IOBuf::takeOwnership(
349  arrayBuf, arrayBufSize, deleteArrayBuffer, &arrayBufFreeCount));
350 
351  EXPECT_FALSE(iob1->isChained());
352  EXPECT_FALSE(iob2->isChained());
353  EXPECT_FALSE(iob3->isChained());
354  EXPECT_FALSE(iob4->isChained());
355  EXPECT_FALSE(iob5->isChained());
356 
357  EXPECT_FALSE(iob1->isSharedOne());
358  EXPECT_FALSE(iob2->isSharedOne());
359  EXPECT_TRUE(iob3->isSharedOne()); // since we own the buffer
360  EXPECT_FALSE(iob4->isSharedOne());
361  EXPECT_FALSE(iob5->isSharedOne());
362 
363  // Chain the buffers all together
364  // Since we are going to relinquish ownership of iob2-5 to the chain,
365  // store raw pointers to them so we can reference them later.
366  IOBuf* iob2ptr = iob2.get();
367  IOBuf* iob3ptr = iob3.get();
368  IOBuf* iob4ptr = iob4.get();
369  IOBuf* iob5ptr = iob5.get();
370 
371  iob1->prependChain(std::move(iob2));
372  iob1->prependChain(std::move(iob4));
373  iob2ptr->appendChain(std::move(iob3));
374  iob1->prependChain(std::move(iob5));
375 
376  EXPECT_EQ(iob2ptr, iob1->next());
377  EXPECT_EQ(iob3ptr, iob2ptr->next());
378  EXPECT_EQ(iob4ptr, iob3ptr->next());
379  EXPECT_EQ(iob5ptr, iob4ptr->next());
380  EXPECT_EQ(iob1.get(), iob5ptr->next());
381 
382  EXPECT_EQ(iob5ptr, iob1->prev());
383  EXPECT_EQ(iob1.get(), iob2ptr->prev());
384  EXPECT_EQ(iob2ptr, iob3ptr->prev());
385  EXPECT_EQ(iob3ptr, iob4ptr->prev());
386  EXPECT_EQ(iob4ptr, iob5ptr->prev());
387 
388  EXPECT_TRUE(iob1->isChained());
389  EXPECT_TRUE(iob2ptr->isChained());
390  EXPECT_TRUE(iob3ptr->isChained());
391  EXPECT_TRUE(iob4ptr->isChained());
392  EXPECT_TRUE(iob5ptr->isChained());
393 
394  std::size_t fullLength =
395  (iob1->length() + iob2ptr->length() + iob3ptr->length() +
396  iob4ptr->length() + iob5ptr->length());
397  EXPECT_EQ(5, iob1->countChainElements());
398  EXPECT_EQ(fullLength, iob1->computeChainDataLength());
399 
400  // Since iob3 is shared, the entire buffer should report itself as shared
401  EXPECT_TRUE(iob1->isShared());
402  // Unshare just iob3
403  iob3ptr->unshareOne();
404  EXPECT_FALSE(iob3ptr->isSharedOne());
405  // Now everything in the chain should be unshared.
406  // Check on all members of the chain just for good measure
407  EXPECT_FALSE(iob1->isShared());
408  EXPECT_FALSE(iob2ptr->isShared());
409  EXPECT_FALSE(iob3ptr->isShared());
410  EXPECT_FALSE(iob4ptr->isShared());
411  EXPECT_FALSE(iob5ptr->isShared());
412 
413  // Check iteration
414  gen.seed(fillSeed);
415  size_t count = 0;
416  for (auto buf : *iob1) {
417  checkBuf(buf, gen);
418  ++count;
419  }
420  EXPECT_EQ(5, count);
421 
422  // Clone one of the IOBufs in the chain
423  unique_ptr<IOBuf> iob4clone = iob4ptr->cloneOne();
424  gen.seed(fillSeed);
425  checkBuf(iob1.get(), gen);
426  checkBuf(iob2ptr, gen);
427  checkBuf(iob3ptr, gen);
428  checkBuf(iob4clone.get(), gen);
429  checkBuf(iob5ptr, gen);
430 
431  EXPECT_TRUE(iob1->isShared());
432  EXPECT_TRUE(iob2ptr->isShared());
433  EXPECT_TRUE(iob3ptr->isShared());
434  EXPECT_TRUE(iob4ptr->isShared());
435  EXPECT_TRUE(iob5ptr->isShared());
436 
437  EXPECT_FALSE(iob1->isSharedOne());
438  EXPECT_FALSE(iob2ptr->isSharedOne());
439  EXPECT_FALSE(iob3ptr->isSharedOne());
440  EXPECT_TRUE(iob4ptr->isSharedOne());
441  EXPECT_FALSE(iob5ptr->isSharedOne());
442 
443  // Unshare that clone
444  EXPECT_TRUE(iob4clone->isSharedOne());
445  iob4clone->unshare();
446  EXPECT_FALSE(iob4clone->isSharedOne());
447  EXPECT_FALSE(iob4ptr->isSharedOne());
448  EXPECT_FALSE(iob1->isShared());
449  iob4clone.reset();
450 
451  // Create a clone of a different IOBuf
452  EXPECT_FALSE(iob1->isShared());
453  EXPECT_FALSE(iob3ptr->isSharedOne());
454 
455  unique_ptr<IOBuf> iob3clone = iob3ptr->cloneOne();
456  gen.seed(fillSeed);
457  checkBuf(iob1.get(), gen);
458  checkBuf(iob2ptr, gen);
459  checkBuf(iob3clone.get(), gen);
460  checkBuf(iob4ptr, gen);
461  checkBuf(iob5ptr, gen);
462 
463  EXPECT_TRUE(iob1->isShared());
464  EXPECT_TRUE(iob3ptr->isSharedOne());
465  EXPECT_FALSE(iob1->isSharedOne());
466 
467  // Delete the clone and make sure the original is unshared
468  iob3clone.reset();
469  EXPECT_FALSE(iob1->isShared());
470  EXPECT_FALSE(iob3ptr->isSharedOne());
471 
472  // Clone the entire chain
473  unique_ptr<IOBuf> chainClone = iob1->clone();
474  // Verify that the data is correct.
475  EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
476  gen.seed(fillSeed);
477  checkChain(chainClone.get(), gen);
478 
479  // Check that the buffers report sharing correctly
480  EXPECT_TRUE(chainClone->isShared());
481  EXPECT_TRUE(iob1->isShared());
482 
483  EXPECT_TRUE(iob1->isSharedOne());
484  EXPECT_TRUE(iob2ptr->isSharedOne());
485  EXPECT_TRUE(iob3ptr->isSharedOne());
486  EXPECT_TRUE(iob4ptr->isSharedOne());
487  EXPECT_TRUE(iob5ptr->isSharedOne());
488 
489  // Unshare the cloned chain
490  chainClone->unshare();
491  EXPECT_FALSE(chainClone->isShared());
492  EXPECT_FALSE(iob1->isShared());
493 
494  // Make sure the unshared result still has the same data
495  EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
496  gen.seed(fillSeed);
497  checkChain(chainClone.get(), gen);
498 
499  // Destroy this chain
500  chainClone.reset();
501 
502  // Clone a new chain
503  EXPECT_FALSE(iob1->isShared());
504  chainClone = iob1->clone();
505  EXPECT_TRUE(iob1->isShared());
506  EXPECT_TRUE(chainClone->isShared());
507 
508  // Delete the original chain
509  iob1.reset();
510  EXPECT_FALSE(chainClone->isShared());
511 
512  // Coalesce the chain
513  //
514  // Coalescing this chain will create a new buffer and release the last
515  // refcount on the original buffers we created. Also make sure
516  // that arrayBufFreeCount increases to one to indicate that arrayBuf was
517  // freed.
518  EXPECT_EQ(5, chainClone->countChainElements());
519  EXPECT_EQ(0, arrayBufFreeCount);
520 
521  // Buffer lengths: 1500 20 1234 900 321
522  // Attempting to gather more data than available should fail
523  EXPECT_THROW(chainClone->gather(4000), std::overflow_error);
524  // Coalesce the first 3 buffers
525  chainClone->gather(1521);
526  EXPECT_EQ(3, chainClone->countChainElements());
527  EXPECT_EQ(0, arrayBufFreeCount);
528 
529  // Make sure the data is still the same after coalescing
530  EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
531  gen.seed(fillSeed);
532  checkChain(chainClone.get(), gen);
533 
534  // cloneCoalesced
535  {
536  auto chainCloneCoalesced = chainClone->cloneCoalesced();
537  EXPECT_EQ(1, chainCloneCoalesced->countChainElements());
538  EXPECT_EQ(fullLength, chainCloneCoalesced->computeChainDataLength());
539  gen.seed(fillSeed);
540  checkChain(chainCloneCoalesced.get(), gen);
541  }
542 
543  // Coalesce the entire chain
544  chainClone->coalesce();
545  EXPECT_EQ(1, chainClone->countChainElements());
546  EXPECT_EQ(1, arrayBufFreeCount);
547 
548  // Make sure the data is still the same after coalescing
549  EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
550  gen.seed(fillSeed);
551  checkChain(chainClone.get(), gen);
552 
553  // Make a new chain to test the unlink and pop operations
554  iob1 = IOBuf::create(1);
555  iob1->append(1);
556  IOBuf* iob1ptr = iob1.get();
557  iob2 = IOBuf::create(3);
558  iob2->append(3);
559  iob2ptr = iob2.get();
560  iob3 = IOBuf::create(5);
561  iob3->append(5);
562  iob3ptr = iob3.get();
563  iob4 = IOBuf::create(7);
564  iob4->append(7);
565  iob4ptr = iob4.get();
566  iob1->appendChain(std::move(iob2));
567  iob1->prev()->appendChain(std::move(iob3));
568  iob1->prev()->appendChain(std::move(iob4));
569  EXPECT_EQ(4, iob1->countChainElements());
570  EXPECT_EQ(16, iob1->computeChainDataLength());
571 
572  // Unlink from the middle of the chain
573  iob3 = iob3ptr->unlink();
574  EXPECT_TRUE(iob3.get() == iob3ptr);
575  EXPECT_EQ(3, iob1->countChainElements());
576  EXPECT_EQ(11, iob1->computeChainDataLength());
577 
578  // Unlink from the end of the chain
579  iob4 = iob1->prev()->unlink();
580  EXPECT_TRUE(iob4.get() == iob4ptr);
581  EXPECT_EQ(2, iob1->countChainElements());
582  EXPECT_TRUE(iob1->next() == iob2ptr);
583  EXPECT_EQ(4, iob1->computeChainDataLength());
584 
585  // Pop from the front of the chain
586  iob2 = iob1->pop();
587  EXPECT_TRUE(iob1.get() == iob1ptr);
588  EXPECT_EQ(1, iob1->countChainElements());
589  EXPECT_EQ(1, iob1->computeChainDataLength());
590  EXPECT_TRUE(iob2.get() == iob2ptr);
591  EXPECT_EQ(1, iob2->countChainElements());
592  EXPECT_EQ(3, iob2->computeChainDataLength());
593 }
594 
595 void testFreeFn(void* buffer, void* ptr) {
596  uint32_t* freeCount = static_cast<uint32_t*>(ptr);
597  ;
598  delete[] static_cast<uint8_t*>(buffer);
599  if (freeCount) {
600  ++(*freeCount);
601  }
602 }
603 
604 TEST(IOBuf, Reserve) {
605  uint32_t fillSeed = 0x23456789;
606  boost::mt19937 gen(fillSeed);
607 
608  // Reserve does nothing if empty and doesn't have to grow the buffer
609  {
610  gen.seed(fillSeed);
611  unique_ptr<IOBuf> iob(IOBuf::create(2000));
612  EXPECT_EQ(0, iob->headroom());
613  const void* p1 = iob->buffer();
614  iob->reserve(5, 15);
615  EXPECT_LE(5, iob->headroom());
616  EXPECT_EQ(p1, iob->buffer());
617  }
618 
619  // Reserve doesn't reallocate if we have enough total room
620  {
621  gen.seed(fillSeed);
622  unique_ptr<IOBuf> iob(IOBuf::create(2000));
623  iob->append(100);
624  fillBuf(iob.get(), gen);
625  EXPECT_EQ(0, iob->headroom());
626  EXPECT_EQ(100, iob->length());
627  const void* p1 = iob->buffer();
628  const uint8_t* d1 = iob->data();
629  iob->reserve(100, 1800);
630  EXPECT_LE(100, iob->headroom());
631  EXPECT_EQ(p1, iob->buffer());
632  EXPECT_EQ(d1 + 100, iob->data());
633  gen.seed(fillSeed);
634  checkBuf(iob.get(), gen);
635  }
636 
637  // Reserve reallocates if we don't have enough total room.
638  // NOTE that, with jemalloc, we know that this won't reallocate in place
639  // as the size is less than jemallocMinInPlaceExpanadable
640  {
641  gen.seed(fillSeed);
642  unique_ptr<IOBuf> iob(IOBuf::create(2000));
643  iob->append(100);
644  fillBuf(iob.get(), gen);
645  EXPECT_EQ(0, iob->headroom());
646  EXPECT_EQ(100, iob->length());
647  const void* p1 = iob->buffer();
648  iob->reserve(100, 2512); // allocation sizes are multiples of 256
649  EXPECT_LE(100, iob->headroom());
650  if (folly::usingJEMalloc()) {
651  EXPECT_NE(p1, iob->buffer());
652  }
653  gen.seed(fillSeed);
654  checkBuf(iob.get(), gen);
655  }
656 
657  // Test reserve from internal buffer, this used to segfault
658  {
659  unique_ptr<IOBuf> iob(IOBuf::create(0));
660  iob->reserve(0, 2000);
661  EXPECT_EQ(0, iob->headroom());
662  EXPECT_LE(2000, iob->tailroom());
663  }
664 
665  // Test reserving from a user-allocated buffer.
666  {
667  uint8_t* buf = static_cast<uint8_t*>(malloc(100));
668  auto iob = IOBuf::takeOwnership(buf, 100);
669  iob->reserve(0, 2000);
670  EXPECT_EQ(0, iob->headroom());
671  EXPECT_LE(2000, iob->tailroom());
672  }
673 
674  // Test reserving from a user-allocated with a custom free function.
675  {
676  uint32_t freeCount{0};
677  uint8_t* buf = new uint8_t[100];
678  auto iob = IOBuf::takeOwnership(buf, 100, testFreeFn, &freeCount);
679  iob->reserve(0, 2000);
680  EXPECT_EQ(0, iob->headroom());
681  EXPECT_LE(2000, iob->tailroom());
682  EXPECT_EQ(1, freeCount);
683  }
684 }
685 
687  std::string s("hello");
688  auto buf = IOBuf::copyBuffer(s.data(), s.size(), 1, 2);
689  EXPECT_EQ(1, buf->headroom());
690  EXPECT_EQ(
691  s,
692  std::string(reinterpret_cast<const char*>(buf->data()), buf->length()));
693  EXPECT_LE(2, buf->tailroom());
694 
695  buf = IOBuf::copyBuffer(s, 5, 7);
696  EXPECT_EQ(5, buf->headroom());
697  EXPECT_EQ(
698  s,
699  std::string(reinterpret_cast<const char*>(buf->data()), buf->length()));
700  EXPECT_LE(7, buf->tailroom());
701 
703  buf = IOBuf::copyBuffer(empty, 3, 6);
704  EXPECT_EQ(3, buf->headroom());
705  EXPECT_EQ(0, buf->length());
706  EXPECT_LE(6, buf->tailroom());
707 
708  // A stack-allocated version
709  IOBuf stackBuf(IOBuf::COPY_BUFFER, s, 1, 2);
710  EXPECT_EQ(1, stackBuf.headroom());
711  EXPECT_EQ(
712  s,
713  std::string(
714  reinterpret_cast<const char*>(stackBuf.data()), stackBuf.length()));
715  EXPECT_LE(2, stackBuf.tailroom());
716 }
717 
718 TEST(IOBuf, maybeCopyBuffer) {
719  std::string s("this is a test");
720  auto buf = IOBuf::maybeCopyBuffer(s, 1, 2);
721  EXPECT_EQ(1, buf->headroom());
722  EXPECT_EQ(
723  s,
724  std::string(reinterpret_cast<const char*>(buf->data()), buf->length()));
725  EXPECT_LE(2, buf->tailroom());
726 
728  buf = IOBuf::maybeCopyBuffer("", 5, 7);
729  EXPECT_EQ(nullptr, buf.get());
730 
731  buf = IOBuf::maybeCopyBuffer("");
732  EXPECT_EQ(nullptr, buf.get());
733 }
734 
735 TEST(IOBuf, copyEmptyBuffer) {
736  auto buf = IOBuf::copyBuffer(nullptr, 0);
737  EXPECT_EQ(buf->length(), 0);
738 }
739 
740 namespace {
741 
742 int customDeleterCount = 0;
743 int destructorCount = 0;
744 struct OwnershipTestClass {
745  explicit OwnershipTestClass(int v = 0) : val(v) {}
746  ~OwnershipTestClass() {
747  ++destructorCount;
748  }
749  int val;
750 };
751 
752 typedef std::function<void(OwnershipTestClass*)> CustomDeleter;
753 
754 void customDelete(OwnershipTestClass* p) {
755  ++customDeleterCount;
756  delete p;
757 }
758 
759 void customDeleteArray(OwnershipTestClass* p) {
760  ++customDeleterCount;
761  delete[] p;
762 }
763 
764 } // namespace
765 
766 TEST(IOBuf, takeOwnershipUniquePtr) {
767  destructorCount = 0;
768  { std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass()); }
769  EXPECT_EQ(1, destructorCount);
770 
771  destructorCount = 0;
772  { std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]); }
773  EXPECT_EQ(2, destructorCount);
774 
775  destructorCount = 0;
776  {
777  std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass());
778  std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
779  EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
780  EXPECT_EQ(0, destructorCount);
781  }
782  EXPECT_EQ(1, destructorCount);
783 
784  destructorCount = 0;
785  {
786  std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]);
787  std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
788  EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
789  EXPECT_EQ(0, destructorCount);
790  }
791  EXPECT_EQ(2, destructorCount);
792 
793  customDeleterCount = 0;
794  destructorCount = 0;
795  {
796  std::unique_ptr<OwnershipTestClass, CustomDeleter> p(
797  new OwnershipTestClass(), customDelete);
798  std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
799  EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
800  EXPECT_EQ(0, destructorCount);
801  }
802  EXPECT_EQ(1, destructorCount);
803  EXPECT_EQ(1, customDeleterCount);
804 
805  customDeleterCount = 0;
806  destructorCount = 0;
807  {
808  std::unique_ptr<OwnershipTestClass[], CustomDeleter> p(
809  new OwnershipTestClass[2], CustomDeleter(customDeleteArray));
810  std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
811  EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
812  EXPECT_EQ(0, destructorCount);
813  }
814  EXPECT_EQ(2, destructorCount);
815  EXPECT_EQ(1, customDeleterCount);
816 }
817 
818 TEST(IOBuf, Alignment) {
819  size_t alignment = alignof(std::max_align_t);
820 
821  std::vector<size_t> sizes{0, 1, 64, 256, 1024, 1 << 10};
822  for (size_t size : sizes) {
823  auto buf = IOBuf::create(size);
824  uintptr_t p = reinterpret_cast<uintptr_t>(buf->data());
825  EXPECT_EQ(0, p & (alignment - 1)) << "size=" << size;
826  }
827 }
828 
829 TEST(TypedIOBuf, Simple) {
830  auto buf = IOBuf::create(0);
831  TypedIOBuf<std::size_t> typed(buf.get());
832  const std::size_t n = 10000;
833  typed.reserve(0, n);
834  EXPECT_LE(n, typed.capacity());
835  for (std::size_t i = 0; i < n; i++) {
836  *typed.writableTail() = i;
837  typed.append(1);
838  }
839  EXPECT_EQ(n, typed.length());
840  for (std::size_t i = 0; i < n; i++) {
841  EXPECT_EQ(i, typed.data()[i]);
842  }
843 }
844 enum BufType {
849 };
850 
851 // chain element size, number of elements in chain, shared
853  : public ::testing::TestWithParam<std::tuple<int, int, bool, BufType>> {
854  protected:
855  void SetUp() override {
856  elementSize_ = std::get<0>(GetParam());
857  elementCount_ = std::get<1>(GetParam());
858  shared_ = std::get<2>(GetParam());
859  type_ = std::get<3>(GetParam());
860 
861  buf_ = makeBuf();
862  for (int i = 0; i < elementCount_ - 1; ++i) {
863  buf_->prependChain(makeBuf());
864  }
865  EXPECT_EQ(elementCount_, buf_->countChainElements());
866  EXPECT_EQ(elementCount_ * elementSize_, buf_->computeChainDataLength());
867  if (shared_) {
868  buf2_ = buf_->clone();
869  EXPECT_EQ(elementCount_, buf2_->countChainElements());
870  EXPECT_EQ(elementCount_ * elementSize_, buf2_->computeChainDataLength());
871  }
872  }
873 
874  std::unique_ptr<IOBuf> makeBuf() {
875  unique_ptr<IOBuf> buf;
876  switch (type_) {
877  case CREATE:
878  buf = IOBuf::create(elementSize_);
879  buf->append(elementSize_);
880  break;
881  case TAKE_OWNERSHIP_MALLOC: {
882  void* data = malloc(elementSize_);
883  if (!data) {
884  throw std::bad_alloc();
885  }
886  buf = IOBuf::takeOwnership(data, elementSize_);
887  break;
888  }
889  case TAKE_OWNERSHIP_CUSTOM: {
890  uint8_t* data = new uint8_t[elementSize_];
891  buf = IOBuf::takeOwnership(data, elementSize_, testFreeFn);
892  break;
893  }
894  case USER_OWNED: {
895  unique_ptr<uint8_t[]> data(new uint8_t[elementSize_]);
896  buf = IOBuf::wrapBuffer(data.get(), elementSize_);
897  ownedBuffers_.emplace_back(std::move(data));
898  break;
899  }
900  default:
901  throw std::invalid_argument("unexpected buffer type parameter");
902  }
903  memset(buf->writableData(), 'x', elementSize_);
904  return buf;
905  }
906 
907  void check(std::unique_ptr<IOBuf>& buf) {
908  fbstring str = buf->moveToFbString();
909  EXPECT_EQ(elementCount_ * elementSize_, str.size());
910  EXPECT_EQ(elementCount_ * elementSize_, strspn(str.c_str(), "x"));
911  EXPECT_EQ(0, buf->length());
912  EXPECT_EQ(1, buf->countChainElements());
914  EXPECT_FALSE(buf->isChained());
915  }
916 
919  bool shared_;
921  std::unique_ptr<IOBuf> buf_;
922  std::unique_ptr<IOBuf> buf2_;
923  std::vector<std::unique_ptr<uint8_t[]>> ownedBuffers_;
924 };
925 
927  check(buf_);
928  if (shared_) {
929  check(buf2_);
930  }
931 }
932 
934  MoveToFbString,
936  ::testing::Combine(
937  ::testing::Values(0, 1, 24, 256, 1 << 10, 1 << 20), // element size
938  ::testing::Values(1, 2, 10), // element count
939  ::testing::Bool(), // shared
940  ::testing::Values(
941  CREATE,
944  USER_OWNED)));
945 
946 TEST(IOBuf, getIov) {
947  uint32_t fillSeed = 0xdeadbeef;
948  boost::mt19937 gen(fillSeed);
949 
950  size_t len = 4096;
951  size_t count = 32;
952  auto buf = IOBuf::create(len + 1);
953  buf->append(rand() % len + 1);
954  fillBuf(buf.get(), gen);
955 
956  for (size_t i = 0; i < count - 1; i++) {
957  auto buf2 = IOBuf::create(len + 1);
958  buf2->append(rand() % len + 1);
959  fillBuf(buf2.get(), gen);
960  buf->prependChain(std::move(buf2));
961  }
962  EXPECT_EQ(count, buf->countChainElements());
963 
964  auto iov = buf->getIov();
965  EXPECT_EQ(count, iov.size());
966 
967  IOBuf const* p = buf.get();
968  for (size_t i = 0; i < count; i++, p = p->next()) {
969  EXPECT_EQ(p->data(), iov[i].iov_base);
970  EXPECT_EQ(p->length(), iov[i].iov_len);
971  }
972 
973  // an empty buf should be skipped in the iov.
974  buf->next()->clear();
975  iov = buf->getIov();
976  EXPECT_EQ(count - 1, iov.size());
977  EXPECT_EQ(buf->next()->next()->data(), iov[1].iov_base);
978 
979  // same for the first one being empty
980  buf->clear();
981  iov = buf->getIov();
982  EXPECT_EQ(count - 2, iov.size());
983  EXPECT_EQ(buf->next()->next()->data(), iov[0].iov_base);
984 
985  // and the last one
986  buf->prev()->clear();
987  iov = buf->getIov();
988  EXPECT_EQ(count - 3, iov.size());
989 
990  // test appending to an existing iovec array
991  iov.clear();
992  const char localBuf[] = "hello";
993  iov.push_back({(void*)localBuf, sizeof(localBuf)});
994  iov.push_back({(void*)localBuf, sizeof(localBuf)});
995  buf->appendToIov(&iov);
996  EXPECT_EQ(count - 1, iov.size());
997  EXPECT_EQ(localBuf, iov[0].iov_base);
998  EXPECT_EQ(localBuf, iov[1].iov_base);
999  // The first two IOBufs were cleared, so the next iov entry
1000  // should be the third IOBuf in the chain.
1001  EXPECT_EQ(buf->next()->next()->data(), iov[2].iov_base);
1002 }
1003 
1004 TEST(IOBuf, wrapIov) {
1005  // Test wrapping IOVs
1006  constexpr folly::StringPiece hello = "hello";
1007  constexpr folly::StringPiece world = "world!";
1009  iov.push_back({nullptr, 0});
1010  iov.push_back({(void*)hello.data(), hello.size()});
1011  iov.push_back({(void*)world.data(), world.size()});
1012  auto wrapped = IOBuf::wrapIov(iov.data(), iov.size());
1013  EXPECT_EQ(iov.size() - 1, wrapped->countChainElements());
1014  IOBuf const* w = wrapped.get();
1015  // skip the first iovec, which is empty/null, as it is ignored by
1016  // IOBuf::wrapIov
1017  for (size_t i = 0; i < wrapped->countChainElements(); ++i, w = w->next()) {
1018  EXPECT_EQ(w->data(), iov[i + 1].iov_base);
1019  EXPECT_EQ(w->length(), iov[i + 1].iov_len);
1020  }
1021 }
1022 
1023 TEST(IOBuf, takeOwnershipIov) {
1024  // Test taking IOVs ownership
1025  folly::fbvector<folly::StringPiece> words{"hello", "world!"};
1027  iov.push_back({nullptr, 0});
1028  for (size_t i = 0; i < words.size(); i++) {
1029  iov.push_back({(void*)strdup(words[i].data()), words[i].size() + 1});
1030  }
1031  auto buf = IOBuf::takeOwnershipIov(iov.data(), iov.size());
1032  EXPECT_EQ(iov.size() - 1, buf->countChainElements());
1033 
1034  IOBuf const* b = buf.get();
1035  // skip the first iovec, which is empty/null, as it is ignored by
1036  // IOBuf::takeIovOwnership
1037  for (size_t i = 0; i < buf->countChainElements(); ++i, b = b->next()) {
1038  EXPECT_EQ(words[i], static_cast<const char*>(iov[i + 1].iov_base));
1039  }
1040 }
1041 
1042 TEST(IOBuf, wrapZeroLenIov) {
1044  iov.push_back({nullptr, 0});
1045  iov.push_back({nullptr, 0});
1046  auto wrapped = IOBuf::wrapIov(iov.data(), iov.size());
1047  EXPECT_NE(nullptr, wrapped);
1048  EXPECT_EQ(wrapped->countChainElements(), 1);
1049  EXPECT_EQ(wrapped->length(), 0);
1050 
1051  wrapped = IOBuf::wrapIov(nullptr, 0);
1052  EXPECT_NE(nullptr, wrapped);
1053  EXPECT_EQ(wrapped->countChainElements(), 1);
1054  EXPECT_EQ(wrapped->length(), 0);
1055 }
1056 
1058  // Default allocate an IOBuf on the stack
1059  IOBuf outerBuf;
1060  char data[] = "foobar";
1061  uint32_t length = sizeof(data);
1062  uint32_t actualCapacity{0};
1063  const void* ptr{nullptr};
1064 
1065  {
1066  // Create a small IOBuf on the stack.
1067  // Note that IOBufs created on the stack always use an external buffer.
1068  IOBuf b1(IOBuf::CREATE, 10);
1069  actualCapacity = b1.capacity();
1070  EXPECT_GE(actualCapacity, 10);
1071  EXPECT_EQ(0, b1.length());
1072  EXPECT_FALSE(b1.isShared());
1073  ptr = b1.data();
1074  ASSERT_TRUE(ptr != nullptr);
1075  memcpy(b1.writableTail(), data, length);
1076  b1.append(length);
1077  EXPECT_EQ(length, b1.length());
1078 
1079  // Use the move constructor
1080  IOBuf b2(std::move(b1));
1081  EXPECT_EQ(ptr, b2.data());
1082  EXPECT_EQ(length, b2.length());
1083  EXPECT_EQ(actualCapacity, b2.capacity());
1084  EXPECT_FALSE(b2.isShared());
1085 
1086  // Use the move assignment operator
1087  outerBuf = std::move(b2);
1088  // Close scope, destroying b1 and b2
1089  // (which are both be invalid now anyway after moving out of them)
1090  }
1091 
1092  EXPECT_EQ(ptr, outerBuf.data());
1093  EXPECT_EQ(length, outerBuf.length());
1094  EXPECT_EQ(actualCapacity, outerBuf.capacity());
1095  EXPECT_FALSE(outerBuf.isShared());
1096 }
1097 
1098 namespace {
1099 std::unique_ptr<IOBuf> fromStr(StringPiece sp) {
1100  return IOBuf::copyBuffer(ByteRange(sp));
1101 }
1102 
1103 std::unique_ptr<IOBuf> seq(std::initializer_list<StringPiece> sps) {
1104  auto ret = IOBuf::create(0);
1105  for (auto sp : sps) {
1106  ret->prependChain(IOBuf::copyBuffer(ByteRange(sp)));
1107  }
1108  return ret;
1109 }
1110 } // namespace
1111 
1112 TEST(IOBuf, HashAndEqual) {
1114  folly::IOBufHash hash;
1115 
1116  EXPECT_TRUE(eq(nullptr, nullptr));
1117  EXPECT_EQ(0, hash(nullptr));
1118 
1119  auto empty = IOBuf::create(0);
1120 
1121  EXPECT_TRUE(eq(*empty, *empty));
1122  EXPECT_TRUE(eq(empty, empty));
1123  EXPECT_TRUE(eq(empty.get(), empty.get()));
1124 
1125  EXPECT_FALSE(eq(nullptr, empty));
1126  EXPECT_FALSE(eq(empty, nullptr));
1127  EXPECT_FALSE(eq(empty.get(), nullptr));
1128 
1129  EXPECT_EQ(hash(*empty), hash(empty));
1130  EXPECT_EQ(hash(*empty), hash(empty.get()));
1131  EXPECT_NE(0, hash(empty));
1132  EXPECT_NE(0, hash(empty.get()));
1133 
1134  auto a = fromStr("hello");
1135 
1136  EXPECT_TRUE(eq(*a, *a));
1137  EXPECT_TRUE(eq(a, a));
1138  EXPECT_TRUE(eq(a.get(), a.get()));
1139 
1140  EXPECT_FALSE(eq(nullptr, a));
1141  EXPECT_FALSE(eq(a, nullptr));
1142  EXPECT_FALSE(eq(a.get(), nullptr));
1143 
1144  EXPECT_EQ(hash(*a), hash(a));
1145  EXPECT_EQ(hash(*a), hash(a.get()));
1146  EXPECT_NE(0, hash(a));
1147  EXPECT_NE(0, hash(a.get()));
1148 
1149  auto b = fromStr("hello");
1150 
1151  EXPECT_TRUE(eq(*a, *b));
1152  EXPECT_TRUE(eq(a, b));
1153  EXPECT_TRUE(eq(a.get(), b.get()));
1154 
1155  EXPECT_EQ(hash(a), hash(b));
1156  EXPECT_EQ(hash(a.get()), hash(b.get()));
1157 
1158  auto c = fromStr("hellow");
1159 
1160  EXPECT_FALSE(eq(a, c));
1161  EXPECT_FALSE(eq(a.get(), c.get()));
1162  EXPECT_NE(hash(a), hash(c));
1163  EXPECT_NE(hash(a.get()), hash(c.get()));
1164 
1165  auto d = fromStr("world");
1166 
1167  EXPECT_FALSE(eq(a, d));
1168  EXPECT_FALSE(eq(a.get(), d.get()));
1169  EXPECT_NE(hash(a), hash(d));
1170  EXPECT_NE(hash(a.get()), hash(d.get()));
1171 
1172  auto e = fromStr("helloworld");
1173  auto f = fromStr("hello");
1174  f->prependChain(fromStr("wo"));
1175  f->prependChain(fromStr("rld"));
1176 
1177  EXPECT_TRUE(eq(e, f));
1178  EXPECT_TRUE(eq(e.get(), f.get()));
1179  EXPECT_EQ(hash(e), hash(f));
1180  EXPECT_EQ(hash(e.get()), hash(f.get()));
1181 }
1182 
1183 TEST(IOBuf, IOBufCompare) {
1185  auto n = std::unique_ptr<IOBuf>{};
1186  auto e = IOBuf::create(0);
1187  auto hello1 = seq({"hello"});
1188  auto hello2 = seq({"hel", "lo"});
1189  auto hello3 = seq({"he", "ll", "o"});
1190  auto hellow = seq({"hellow"});
1191  auto hellox = seq({"hellox"});
1192 
1193  EXPECT_EQ(ordering::eq, op(n, n));
1194  EXPECT_EQ(ordering::lt, op(n, e));
1195  EXPECT_EQ(ordering::gt, op(e, n));
1196  EXPECT_EQ(ordering::lt, op(e, hello1));
1197  EXPECT_EQ(ordering::gt, op(hello1, e));
1198  EXPECT_EQ(ordering::eq, op(hello1, hello1));
1199  EXPECT_EQ(ordering::eq, op(hello1, hello2));
1200  EXPECT_EQ(ordering::eq, op(hello1, hello3));
1201  EXPECT_EQ(ordering::lt, op(hello1, hellow));
1202  EXPECT_EQ(ordering::gt, op(hellow, hello1));
1203  EXPECT_EQ(ordering::lt, op(hellow, hellox));
1204  EXPECT_EQ(ordering::gt, op(hellox, hellow));
1205 }
1206 
1207 // reserveSlow() had a bug when reallocating the buffer in place. It would
1208 // preserve old headroom if it's not too much (heuristically) but wouldn't
1209 // adjust the requested amount of memory to account for that; the end result
1210 // would be that reserve() would return with less tailroom than requested.
1211 TEST(IOBuf, ReserveWithHeadroom) {
1212  // This is assuming jemalloc, where we know that 4096 and 8192 bytes are
1213  // valid (and consecutive) allocation sizes. We're hoping that our
1214  // 4096-byte buffer can be expanded in place to 8192 (in practice, this
1215  // usually happens).
1216  const char data[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
1217  constexpr size_t reservedSize = 24; // sizeof(SharedInfo)
1218  // chosen carefully so that the buffer is exactly 4096 bytes
1219  IOBuf buf(IOBuf::CREATE, 4096 - reservedSize);
1220  buf.advance(10);
1221  memcpy(buf.writableData(), data, sizeof(data));
1222  buf.append(sizeof(data));
1223  EXPECT_EQ(sizeof(data), buf.length());
1224 
1225  // Grow the buffer (hopefully in place); this would incorrectly reserve
1226  // the 10 bytes of headroom, giving us 10 bytes less than requested.
1227  size_t tailroom = 8192 - reservedSize - sizeof(data);
1228  buf.reserve(0, tailroom);
1229  EXPECT_LE(tailroom, buf.tailroom());
1230  EXPECT_EQ(sizeof(data), buf.length());
1231  EXPECT_EQ(0, memcmp(data, buf.data(), sizeof(data)));
1232 }
1233 
1234 TEST(IOBuf, CopyConstructorAndAssignmentOperator) {
1235  auto buf = IOBuf::create(4096);
1236  append(buf, "hello world");
1237  auto buf2 = IOBuf::create(4096);
1238  append(buf2, " goodbye");
1239  buf->prependChain(std::move(buf2));
1240  EXPECT_FALSE(buf->isShared());
1241 
1242  {
1243  auto copy = *buf;
1244  EXPECT_TRUE(buf->isShared());
1245  EXPECT_TRUE(copy.isShared());
1246  EXPECT_EQ((void*)buf->data(), (void*)copy.data());
1247  EXPECT_NE(buf->next(), copy.next()); // actually different buffers
1248 
1249  auto copy2 = *buf;
1250  copy2.coalesce();
1251  EXPECT_TRUE(buf->isShared());
1252  EXPECT_TRUE(copy.isShared());
1253  EXPECT_FALSE(copy2.isShared());
1254 
1255  auto p = reinterpret_cast<const char*>(copy2.data());
1256  EXPECT_EQ("hello world goodbye", std::string(p, copy2.length()));
1257  }
1258 
1259  EXPECT_FALSE(buf->isShared());
1260 
1261  {
1262  folly::IOBuf newBuf(folly::IOBuf::CREATE, 4096);
1263  EXPECT_FALSE(newBuf.isShared());
1264 
1265  auto newBufCopy = newBuf;
1266  EXPECT_TRUE(newBuf.isShared());
1267  EXPECT_TRUE(newBufCopy.isShared());
1268 
1269  newBufCopy = *buf;
1270  EXPECT_TRUE(buf->isShared());
1271  EXPECT_FALSE(newBuf.isShared());
1272  EXPECT_TRUE(newBufCopy.isShared());
1273  }
1274 
1275  EXPECT_FALSE(buf->isShared());
1276 }
1277 
1278 TEST(IOBuf, CloneAsValue) {
1279  auto buf = IOBuf::create(4096);
1280  append(buf, "hello world");
1281  {
1282  auto buf2 = IOBuf::create(4096);
1283  append(buf2, " goodbye");
1284  buf->prependChain(std::move(buf2));
1285  EXPECT_FALSE(buf->isShared());
1286  }
1287 
1288  {
1289  auto copy = buf->cloneOneAsValue();
1290  EXPECT_TRUE(buf->isShared());
1291  EXPECT_TRUE(copy.isShared());
1292  EXPECT_EQ((void*)buf->data(), (void*)copy.data());
1293  EXPECT_TRUE(buf->isChained());
1294  EXPECT_FALSE(copy.isChained());
1295 
1296  auto copy2 = buf->cloneAsValue();
1297  EXPECT_TRUE(buf->isShared());
1298  EXPECT_TRUE(copy.isShared());
1299  EXPECT_TRUE(copy2.isShared());
1300  EXPECT_TRUE(buf->isChained());
1301  EXPECT_TRUE(copy2.isChained());
1302 
1303  copy.unshareOne();
1304  EXPECT_TRUE(buf->isShared());
1305  EXPECT_FALSE(copy.isShared());
1306  EXPECT_NE((void*)buf->data(), (void*)copy.data());
1307  EXPECT_TRUE(copy2.isShared());
1308 
1309  auto p = reinterpret_cast<const char*>(copy.data());
1310  EXPECT_EQ("hello world", std::string(p, copy.length()));
1311 
1312  copy2.coalesce();
1313  EXPECT_FALSE(buf->isShared());
1314  EXPECT_FALSE(copy.isShared());
1315  EXPECT_FALSE(copy2.isShared());
1316  EXPECT_FALSE(copy2.isChained());
1317 
1318  auto p2 = reinterpret_cast<const char*>(copy2.data());
1319  EXPECT_EQ("hello world goodbye", std::string(p2, copy2.length()));
1320  }
1321 
1322  EXPECT_FALSE(buf->isShared());
1323 }
1324 
1325 namespace {
1326 // Use with string literals only
1327 std::unique_ptr<IOBuf> wrap(const char* str) {
1328  return IOBuf::wrapBuffer(str, strlen(str));
1329 }
1330 
1331 std::unique_ptr<IOBuf> copy(const char* str) {
1332  // At least 1KiB of tailroom, to ensure an external buffer
1333  return IOBuf::copyBuffer(str, strlen(str), 0, 1024);
1334 }
1335 
1336 std::string toString(const folly::IOBuf& buf) {
1337  std::string result;
1338  result.reserve(buf.computeChainDataLength());
1339  for (auto& b : buf) {
1340  result.append(reinterpret_cast<const char*>(b.data()), b.size());
1341  }
1342  return result;
1343 }
1344 
1345 char* writableStr(folly::IOBuf& buf) {
1346  return reinterpret_cast<char*>(buf.writableData());
1347 }
1348 
1349 } // namespace
1350 
1351 TEST(IOBuf, ExternallyShared) {
1352  struct Item {
1353  Item(const char* src, size_t len) : size(len) {
1354  CHECK_LE(len, sizeof(buffer));
1355  memcpy(buffer, src, len);
1356  }
1357  uint32_t refcount{0};
1358  uint8_t size;
1359  char buffer[256];
1360  };
1361 
1362  auto hello = "hello";
1363  struct Item it(hello, strlen(hello));
1364 
1365  {
1366  auto freeFn = [](void* /* unused */, void* userData) {
1367  auto it2 = static_cast<struct Item*>(userData);
1368  it2->refcount--;
1369  };
1370  it.refcount++;
1371  auto buf1 = IOBuf::takeOwnership(it.buffer, it.size, freeFn, &it);
1372  EXPECT_TRUE(buf1->isManagedOne());
1373  EXPECT_FALSE(buf1->isSharedOne());
1374 
1375  buf1->markExternallyShared();
1376  EXPECT_TRUE(buf1->isSharedOne());
1377 
1378  {
1379  auto buf2 = buf1->clone();
1380  EXPECT_TRUE(buf2->isManagedOne());
1381  EXPECT_TRUE(buf2->isSharedOne());
1382  EXPECT_EQ(buf1->data(), buf2->data());
1383  EXPECT_EQ(it.refcount, 1);
1384  }
1385  EXPECT_EQ(it.refcount, 1);
1386  }
1387  EXPECT_EQ(it.refcount, 0);
1388 }
1389 
1390 TEST(IOBuf, Managed) {
1391  auto hello = "hello";
1392  auto buf1UP = wrap(hello);
1393  auto buf1 = buf1UP.get();
1394  EXPECT_FALSE(buf1->isManagedOne());
1395  auto buf2UP = copy("world");
1396  auto buf2 = buf2UP.get();
1397  EXPECT_TRUE(buf2->isManagedOne());
1398  auto buf3UP = wrap(hello);
1399  auto buf3 = buf3UP.get();
1400  auto buf4UP = buf2->clone();
1401  auto buf4 = buf4UP.get();
1402 
1403  // buf1 and buf3 share the same memory (but are unmanaged)
1404  EXPECT_FALSE(buf1->isManagedOne());
1405  EXPECT_FALSE(buf3->isManagedOne());
1406  EXPECT_TRUE(buf1->isSharedOne());
1407  EXPECT_TRUE(buf3->isSharedOne());
1408  EXPECT_EQ(buf1->data(), buf3->data());
1409 
1410  // buf2 and buf4 share the same memory (but are managed)
1411  EXPECT_TRUE(buf2->isManagedOne());
1412  EXPECT_TRUE(buf4->isManagedOne());
1413  EXPECT_TRUE(buf2->isSharedOne());
1414  EXPECT_TRUE(buf4->isSharedOne());
1415  EXPECT_EQ(buf2->data(), buf4->data());
1416 
1417  buf1->prependChain(std::move(buf2UP));
1418  buf1->prependChain(std::move(buf3UP));
1419  buf1->prependChain(std::move(buf4UP));
1420 
1421  EXPECT_EQ("helloworldhelloworld", toString(*buf1));
1422  EXPECT_FALSE(buf1->isManaged());
1423 
1424  buf1->makeManaged();
1425  EXPECT_TRUE(buf1->isManaged());
1426 
1427  // buf1 and buf3 are now unshared (because they were unmanaged)
1428  EXPECT_TRUE(buf1->isManagedOne());
1429  EXPECT_TRUE(buf3->isManagedOne());
1430  EXPECT_FALSE(buf1->isSharedOne());
1431  EXPECT_FALSE(buf3->isSharedOne());
1432  EXPECT_NE(buf1->data(), buf3->data());
1433 
1434  // buf2 and buf4 are still shared
1435  EXPECT_TRUE(buf2->isManagedOne());
1436  EXPECT_TRUE(buf4->isManagedOne());
1437  EXPECT_TRUE(buf2->isSharedOne());
1438  EXPECT_TRUE(buf4->isSharedOne());
1439  EXPECT_EQ(buf2->data(), buf4->data());
1440 
1441  // And verify that the truth is what we expect: modify a byte in buf1 and
1442  // buf2, see that the change from buf1 is *not* reflected in buf3, but the
1443  // change from buf2 is reflected in buf4.
1444  writableStr(*buf1)[0] = 'j';
1445  writableStr(*buf2)[0] = 'x';
1446  EXPECT_EQ("jelloxorldhelloxorld", toString(*buf1));
1447 }
1448 
1449 TEST(IOBuf, CoalesceEmptyBuffers) {
1450  auto b1 = IOBuf::takeOwnership(nullptr, 0);
1451  auto b2 = fromStr("hello");
1452  auto b3 = IOBuf::takeOwnership(nullptr, 0);
1453 
1454  b2->appendChain(std::move(b3));
1455  b1->appendChain(std::move(b2));
1456 
1457  auto br = b1->coalesce();
1458 
1459  EXPECT_TRUE(ByteRange(StringPiece("hello")) == br);
1460 }
1461 
1462 TEST(IOBuf, CloneCoalescedChain) {
1463  auto b = IOBuf::createChain(1000, 100);
1464  b->advance(10);
1465  const uint32_t fillSeed = 0x12345678;
1466  boost::mt19937 gen(fillSeed);
1467  {
1468  auto c = b.get();
1469  std::size_t length = c->tailroom();
1470  do {
1471  length = std::min(length, c->tailroom());
1472  c->append(length--);
1473  fillBuf(c, gen);
1474  c = c->next();
1475  } while (c != b.get());
1476  }
1477  auto c = b->cloneCoalescedAsValue();
1478  EXPECT_FALSE(c.isChained()); // Not chained
1479  EXPECT_FALSE(c.isSharedOne()); // Not shared
1480  EXPECT_EQ(b->headroom(), c.headroom()); // Preserves headroom
1481  EXPECT_LE(b->prev()->tailroom(), c.tailroom()); // Preserves minimum tailroom
1482  EXPECT_EQ(b->computeChainDataLength(), c.length()); // Same length
1483  gen.seed(fillSeed);
1484  checkBuf(&c, gen); // Same contents
1485 }
1486 
1487 TEST(IOBuf, CloneCoalescedSingle) {
1488  auto b = IOBuf::create(1000);
1489  b->advance(10);
1490  b->append(900);
1491  const uint32_t fillSeed = 0x12345678;
1492  boost::mt19937 gen(fillSeed);
1493  fillBuf(b.get(), gen);
1494 
1495  auto c = b->cloneCoalesced();
1496  EXPECT_FALSE(c->isChained()); // Not chained
1497  EXPECT_TRUE(c->isSharedOne()); // Shared
1498  EXPECT_EQ(b->buffer(), c->buffer());
1499  EXPECT_EQ(b->capacity(), c->capacity());
1500  EXPECT_EQ(b->data(), c->data());
1501  EXPECT_EQ(b->length(), c->length());
1502 }
#define EXPECT_LE(val1, val2)
Definition: gtest.h:1928
void * ptr
std::vector< uint8_t > buffer(kBufferSize+16)
folly::StringPiece toString(StateEnum state)
Definition: State.cpp:16
auto f
void unshare()
Definition: IOBuf.h:997
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
TEST_P(MoveToFbStringTest, Simple)
Definition: IOBufTest.cpp:926
char b
void testFreeFn(void *buffer, void *ptr)
Definition: IOBufTest.cpp:595
bool usingJEMalloc() noexcept
Definition: Malloc.h:147
void checkChain(IOBuf *buf, boost::mt19937 &gen)
Definition: IOBufTest.cpp:307
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
fbstring moveToFbString()
Definition: IOBuf.cpp:968
void appendChain(std::unique_ptr< IOBuf > &&iobuf)
Definition: IOBuf.h:827
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
bool isSharedOne() const
Definition: IOBuf.h:952
void append(std::unique_ptr< IOBuf > &buf, StringPiece str)
Definition: IOBufTest.cpp:37
void advance(std::size_t amount)
Definition: IOBuf.h:632
double val
Definition: String.cpp:273
const uint8_t * data() const
Definition: IOBuf.h:499
Gen seq(Value first, Value last)
Definition: Base.h:484
void reserve(std::size_t minHeadroom, std::size_t minTailroom)
Definition: IOBuf.h:741
bool isChained() const
Definition: IOBuf.h:760
size_t countChainElements() const
Definition: IOBuf.cpp:493
#define EXPECT_GE(val1, val2)
Definition: gtest.h:1932
T * data() noexcept
Definition: FBVector.h:1135
std::size_t capacity() const
Definition: IOBuf.h:593
std::unique_ptr< IOBuf > buf2_
Definition: IOBufTest.cpp:922
void unshareOne()
Definition: IOBuf.h:1015
std::size_t tailroom() const
Definition: IOBuf.h:551
std::vector< std::unique_ptr< uint8_t[]> > ownedBuffers_
Definition: IOBufTest.cpp:923
uint8_t * writableTail()
Definition: IOBuf.h:526
uint32_t capacity() const
Definition: TypedIOBuf.h:96
void push_back(const T &value)
Definition: FBVector.h:1156
std::unique_ptr< folly::IOBuf > makeBuf(uint32_t size)
Definition: ZlibTests.cpp:26
int current
constexpr std::decay< T >::type copy(T &&value) noexcept(noexcept(typename std::decay< T >::type(std::forward< T >(value))))
Definition: Utility.h:72
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
void prepend(std::unique_ptr< IOBuf > &buf, StringPiece str)
Definition: IOBufTest.cpp:43
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
TEST(IOBuf, Simple)
Definition: IOBufTest.cpp:49
LogLevel min
Definition: LogLevel.cpp:30
const int sizes[]
void prepend(std::size_t amount)
Definition: IOBuf.h:673
ordering
Definition: Ordering.h:21
Type type_
Definition: JSONSchema.cpp:208
uint8_t * writableData()
Definition: IOBuf.h:509
std::size_t headroom() const
Definition: IOBuf.h:542
std::size_t length() const
Definition: IOBuf.h:533
void deleteArrayBuffer(void *buf, void *arg)
Definition: IOBufTest.cpp:98
INSTANTIATE_TEST_CASE_P(MoveToFbString, MoveToFbStringTest,::testing::Combine(::testing::Values(0, 1, 24, 256, 1<< 10, 1<< 20),::testing::Values(1, 2, 10),::testing::Bool(),::testing::Values(CREATE, TAKE_OWNERSHIP_MALLOC, TAKE_OWNERSHIP_CUSTOM, USER_OWNED)))
char a
std::unique_ptr< IOBuf > cloneOne() const
Definition: IOBuf.cpp:531
std::unique_ptr< IOBuf > unlink()
Definition: IOBuf.h:847
void check(std::unique_ptr< IOBuf > &buf)
Definition: IOBufTest.cpp:907
IOBuf * next()
Definition: IOBuf.h:600
void fillBuf(uint8_t *buf, uint32_t length, boost::mt19937 &gen)
Definition: IOBufTest.cpp:257
bool isShared() const
Definition: IOBuf.h:902
void prependChain(std::unique_ptr< IOBuf > &&iobuf)
Definition: IOBuf.cpp:509
void SetUp() override
Definition: IOBufTest.cpp:855
IOBuf * prev()
Definition: IOBuf.h:610
int * count
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
std::unique_ptr< IOBuf > copyBuffer(const folly::IOBuf &buf)
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
void clear()
Definition: IOBuf.h:728
const char * string
Definition: Conv.cpp:212
std::unique_ptr< IOBuf > makeBuf()
Definition: IOBufTest.cpp:874
Range< const unsigned char * > ByteRange
Definition: Range.h:1163
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
static set< string > s
bool_constant< B > Bool
Definition: TypeList.h:81
void checkBuf(const uint8_t *buf, uint32_t length, boost::mt19937 &gen)
Definition: IOBufTest.cpp:268
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
BufType
Definition: IOBufTest.cpp:844
basic_fbstring< char > fbstring
Definition: FBString.h:2904
Range< const char * > StringPiece
size_type size() const noexcept
Definition: FBVector.h:964
const uint8_t * buffer() const
Definition: IOBuf.h:562
char c
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43
void reserve(uint32_t minHeadroom, uint32_t minTailroom)
Definition: TypedIOBuf.h:120
bool check(const dynamic &schema, const dynamic &value, bool check=true)
std::unique_ptr< IOBuf > buf_
Definition: IOBufTest.cpp:921
void append(std::size_t amount)
Definition: IOBuf.h:689
void testAllocSize(uint32_t requestedCapacity)
Definition: IOBufTest.cpp:77