proxygen
IOBufQueueTest.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/IOBufQueue.h>
18 
19 #include <cstring>
20 #include <iostream>
21 #include <stdexcept>
22 
23 #include <folly/Range.h>
25 
26 using folly::IOBuf;
27 using folly::IOBufQueue;
28 using folly::StringPiece;
29 using std::pair;
30 using std::string;
31 using std::unique_ptr;
32 
33 // String Comma Length macro for string literals
34 #define SCL(x) (x), sizeof(x) - 1
35 
36 namespace {
37 
38 IOBufQueue::Options clOptions;
39 struct Initializer {
40  Initializer() {
41  clOptions.cacheChainLength = true;
42  }
43 };
44 Initializer initializer;
45 
46 unique_ptr<IOBuf> stringToIOBuf(const char* s, size_t len) {
47  unique_ptr<IOBuf> buf = IOBuf::create(len);
48  memcpy(buf->writableTail(), s, len);
49  buf->append(len);
50  return buf;
51 }
52 
53 void checkConsistency(const IOBufQueue& queue) {
54  if (queue.options().cacheChainLength) {
55  size_t len = queue.front() ? queue.front()->computeChainDataLength() : 0;
56  EXPECT_EQ(len, queue.chainLength());
57  }
58 }
59 
60 } // namespace
61 
62 TEST(IOBufQueue, Simple) {
63  IOBufQueue queue(clOptions);
64  EXPECT_EQ(nullptr, queue.front());
65  queue.append(SCL(""));
66  EXPECT_EQ(nullptr, queue.front());
67  queue.append(unique_ptr<IOBuf>());
68  EXPECT_EQ(nullptr, queue.front());
69  string emptyString;
70  queue.append(emptyString);
71  EXPECT_EQ(nullptr, queue.front());
72 }
73 
74 TEST(IOBufQueue, Append) {
75  IOBufQueue queue(clOptions);
76  queue.append(SCL("Hello"));
77  IOBufQueue queue2(clOptions);
78  queue2.append(SCL(", "));
79  queue2.append(SCL("World"));
80  checkConsistency(queue);
81  checkConsistency(queue2);
82  queue.append(queue2.move());
83  checkConsistency(queue);
84  checkConsistency(queue2);
85  const IOBuf* chain = queue.front();
86  EXPECT_NE((IOBuf*)nullptr, chain);
87  EXPECT_EQ(12, chain->computeChainDataLength());
88  EXPECT_EQ(nullptr, queue2.front());
89 }
90 
91 TEST(IOBufQueue, Append2) {
92  IOBufQueue queue(clOptions);
93  queue.append(SCL("Hello"));
94  IOBufQueue queue2(clOptions);
95  queue2.append(SCL(", "));
96  queue2.append(SCL("World"));
97  checkConsistency(queue);
98  checkConsistency(queue2);
99  queue.append(queue2);
100  checkConsistency(queue);
101  checkConsistency(queue2);
102  const IOBuf* chain = queue.front();
103  EXPECT_NE((IOBuf*)nullptr, chain);
104  EXPECT_EQ(12, chain->computeChainDataLength());
105  EXPECT_EQ(nullptr, queue2.front());
106 }
107 
108 TEST(IOBufQueue, AppendStringPiece) {
109  std::string s("Hello, World");
110  IOBufQueue queue(clOptions);
111  IOBufQueue queue2(clOptions);
112  queue.append(s.data(), s.length());
113  queue2.append(s);
114  checkConsistency(queue);
115  checkConsistency(queue2);
116  const IOBuf* chain = queue.front();
117  const IOBuf* chain2 = queue2.front();
118  EXPECT_EQ(s.length(), chain->computeChainDataLength());
119  EXPECT_EQ(s.length(), chain2->computeChainDataLength());
120  EXPECT_EQ(0, memcmp(chain->data(), chain2->data(), s.length()));
121 }
122 
123 TEST(IOBufQueue, Split) {
124  IOBufQueue queue(clOptions);
125  queue.append(stringToIOBuf(SCL("Hello")));
126  queue.append(stringToIOBuf(SCL(",")));
127  queue.append(stringToIOBuf(SCL(" ")));
128  queue.append(stringToIOBuf(SCL("")));
129  queue.append(stringToIOBuf(SCL("World")));
130  checkConsistency(queue);
131  EXPECT_EQ(12, queue.front()->computeChainDataLength());
132 
133  unique_ptr<IOBuf> prefix(queue.split(1));
134  checkConsistency(queue);
135  EXPECT_EQ(1, prefix->computeChainDataLength());
136  EXPECT_EQ(11, queue.front()->computeChainDataLength());
137  prefix = queue.split(2);
138  checkConsistency(queue);
139  EXPECT_EQ(2, prefix->computeChainDataLength());
140  EXPECT_EQ(9, queue.front()->computeChainDataLength());
141  prefix = queue.split(3);
142  checkConsistency(queue);
143  EXPECT_EQ(3, prefix->computeChainDataLength());
144  EXPECT_EQ(6, queue.front()->computeChainDataLength());
145  prefix = queue.split(1);
146  checkConsistency(queue);
147  EXPECT_EQ(1, prefix->computeChainDataLength());
148  EXPECT_EQ(5, queue.front()->computeChainDataLength());
149  prefix = queue.split(5);
150  checkConsistency(queue);
151  EXPECT_EQ(5, prefix->computeChainDataLength());
152  EXPECT_EQ((IOBuf*)nullptr, queue.front());
153 
154  queue.append(stringToIOBuf(SCL("Hello,")));
155  queue.append(stringToIOBuf(SCL(" World")));
156  checkConsistency(queue);
157  EXPECT_THROW({ prefix = queue.split(13); }, std::underflow_error);
158  checkConsistency(queue);
159 }
160 
161 TEST(IOBufQueue, SplitAtMost) {
162  IOBufQueue queue(clOptions);
163  queue.append(stringToIOBuf(SCL("Hello,")));
164  queue.append(stringToIOBuf(SCL(" World")));
165  auto buf = queue.splitAtMost(9999);
166  EXPECT_EQ(buf->computeChainDataLength(), 12);
167  EXPECT_TRUE(queue.empty());
168 }
169 
170 TEST(IOBufQueue, SplitZero) {
171  IOBufQueue queue(clOptions);
172  queue.append(stringToIOBuf(SCL("Hello world")));
173  auto buf = queue.split(0);
174  EXPECT_EQ(buf->computeChainDataLength(), 0);
175 }
176 
177 TEST(IOBufQueue, Preallocate) {
178  IOBufQueue queue(clOptions);
179  queue.append(string("Hello"));
180  pair<void*, std::size_t> writable = queue.preallocate(2, 64, 64);
181  checkConsistency(queue);
182  EXPECT_NE((void*)nullptr, writable.first);
183  EXPECT_LE(2, writable.second);
184  EXPECT_GE(64, writable.second);
185  memcpy(writable.first, SCL(", "));
186  queue.postallocate(2);
187  checkConsistency(queue);
188  EXPECT_EQ(7, queue.front()->computeChainDataLength());
189  queue.append(SCL("World"));
190  checkConsistency(queue);
191  EXPECT_EQ(12, queue.front()->computeChainDataLength());
192  // There are not 2048 bytes available, this will alloc a new buf
193  writable = queue.preallocate(2048, 4096);
194  checkConsistency(queue);
195  EXPECT_LE(2048, writable.second);
196  // IOBuf allocates more than newAllocationSize, and we didn't cap it
197  EXPECT_GE(writable.second, 4096);
198  queue.postallocate(writable.second);
199  // queue has no empty space, make sure we allocate at least min, even if
200  // newAllocationSize < min
201  writable = queue.preallocate(1024, 1, 1024);
202  checkConsistency(queue);
203  EXPECT_EQ(1024, writable.second);
204 }
205 
206 TEST(IOBufQueue, Wrap) {
207  IOBufQueue queue(clOptions);
208  const char* buf = "hello world goodbye";
209  size_t len = strlen(buf);
210  queue.wrapBuffer(buf, len, 6);
211  auto iob = queue.move();
212  EXPECT_EQ((len - 1) / 6 + 1, iob->countChainElements());
213  iob->unshare();
214  iob->coalesce();
215  EXPECT_EQ(
216  StringPiece(buf),
217  StringPiece(reinterpret_cast<const char*>(iob->data()), iob->length()));
218 }
219 
220 TEST(IOBufQueue, Trim) {
221  IOBufQueue queue(clOptions);
222  unique_ptr<IOBuf> a = IOBuf::create(4);
223  a->append(4);
224  queue.append(std::move(a));
225  checkConsistency(queue);
226  a = IOBuf::create(6);
227  a->append(6);
228  queue.append(std::move(a));
229  checkConsistency(queue);
230  a = IOBuf::create(8);
231  a->append(8);
232  queue.append(std::move(a));
233  checkConsistency(queue);
234  a = IOBuf::create(10);
235  a->append(10);
236  queue.append(std::move(a));
237  checkConsistency(queue);
238 
239  EXPECT_EQ(4, queue.front()->countChainElements());
240  EXPECT_EQ(28, queue.front()->computeChainDataLength());
241  EXPECT_EQ(4, queue.front()->length());
242 
243  queue.trimStart(1);
244  checkConsistency(queue);
245  EXPECT_EQ(4, queue.front()->countChainElements());
246  EXPECT_EQ(27, queue.front()->computeChainDataLength());
247  EXPECT_EQ(3, queue.front()->length());
248 
249  queue.trimStart(5);
250  checkConsistency(queue);
251  EXPECT_EQ(3, queue.front()->countChainElements());
252  EXPECT_EQ(22, queue.front()->computeChainDataLength());
253  EXPECT_EQ(4, queue.front()->length());
254 
255  queue.trimEnd(1);
256  checkConsistency(queue);
257  EXPECT_EQ(3, queue.front()->countChainElements());
258  EXPECT_EQ(21, queue.front()->computeChainDataLength());
259  EXPECT_EQ(9, queue.front()->prev()->length());
260 
261  queue.trimEnd(20);
262  checkConsistency(queue);
263  EXPECT_EQ(1, queue.front()->countChainElements());
264  EXPECT_EQ(1, queue.front()->computeChainDataLength());
265  EXPECT_EQ(1, queue.front()->prev()->length());
266 
267  queue.trimEnd(1);
268  checkConsistency(queue);
269  EXPECT_EQ(nullptr, queue.front());
270 
271  EXPECT_THROW(queue.trimStart(2), std::underflow_error);
272  checkConsistency(queue);
273 
274  EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
275  checkConsistency(queue);
276 }
277 
278 TEST(IOBufQueue, TrimStartAtMost) {
279  IOBufQueue queue(clOptions);
280  unique_ptr<IOBuf> a = IOBuf::create(4);
281  a->append(4);
282  queue.append(std::move(a));
283  checkConsistency(queue);
284  a = IOBuf::create(6);
285  a->append(6);
286  queue.append(std::move(a));
287  checkConsistency(queue);
288  a = IOBuf::create(8);
289  a->append(8);
290  queue.append(std::move(a));
291  checkConsistency(queue);
292  a = IOBuf::create(10);
293  a->append(10);
294  queue.append(std::move(a));
295  checkConsistency(queue);
296 
297  EXPECT_EQ(4, queue.front()->countChainElements());
298  EXPECT_EQ(28, queue.front()->computeChainDataLength());
299  EXPECT_EQ(4, queue.front()->length());
300 
301  queue.trimStartAtMost(1);
302  checkConsistency(queue);
303  EXPECT_EQ(4, queue.front()->countChainElements());
304  EXPECT_EQ(27, queue.front()->computeChainDataLength());
305  EXPECT_EQ(3, queue.front()->length());
306 
307  queue.trimStartAtMost(50);
308  checkConsistency(queue);
309  EXPECT_EQ(nullptr, queue.front());
310  EXPECT_EQ(0, queue.chainLength());
311 }
312 
313 TEST(IOBufQueue, TrimEndAtMost) {
314  IOBufQueue queue(clOptions);
315  unique_ptr<IOBuf> a = IOBuf::create(4);
316  a->append(4);
317  queue.append(std::move(a));
318  checkConsistency(queue);
319  a = IOBuf::create(6);
320  a->append(6);
321  queue.append(std::move(a));
322  checkConsistency(queue);
323  a = IOBuf::create(8);
324  a->append(8);
325  queue.append(std::move(a));
326  checkConsistency(queue);
327  a = IOBuf::create(10);
328  a->append(10);
329  queue.append(std::move(a));
330  checkConsistency(queue);
331 
332  EXPECT_EQ(4, queue.front()->countChainElements());
333  EXPECT_EQ(28, queue.front()->computeChainDataLength());
334  EXPECT_EQ(4, queue.front()->length());
335 
336  queue.trimEndAtMost(1);
337  checkConsistency(queue);
338  EXPECT_EQ(4, queue.front()->countChainElements());
339  EXPECT_EQ(27, queue.front()->computeChainDataLength());
340  EXPECT_EQ(4, queue.front()->length());
341 
342  queue.trimEndAtMost(50);
343  checkConsistency(queue);
344  EXPECT_EQ(nullptr, queue.front());
345  EXPECT_EQ(0, queue.chainLength());
346 }
347 
348 TEST(IOBufQueue, TrimPack) {
349  IOBufQueue queue(clOptions);
350  unique_ptr<IOBuf> a = IOBuf::create(64);
351  a->append(4);
352  queue.append(std::move(a), true);
353  checkConsistency(queue);
354  a = IOBuf::create(6);
355  a->append(6);
356  queue.append(std::move(a), true);
357  checkConsistency(queue);
358  a = IOBuf::create(8);
359  a->append(8);
360  queue.append(std::move(a), true);
361  checkConsistency(queue);
362  a = IOBuf::create(10);
363  a->append(10);
364  queue.append(std::move(a), true);
365  checkConsistency(queue);
366 
367  EXPECT_EQ(1, queue.front()->countChainElements());
368  EXPECT_EQ(28, queue.front()->computeChainDataLength());
369  EXPECT_EQ(28, queue.front()->length());
370 
371  queue.trimStart(1);
372  checkConsistency(queue);
373  EXPECT_EQ(1, queue.front()->countChainElements());
374  EXPECT_EQ(27, queue.front()->computeChainDataLength());
375  EXPECT_EQ(27, queue.front()->length());
376 
377  queue.trimStart(5);
378  checkConsistency(queue);
379  EXPECT_EQ(1, queue.front()->countChainElements());
380  EXPECT_EQ(22, queue.front()->computeChainDataLength());
381  EXPECT_EQ(22, queue.front()->length());
382 
383  queue.trimEnd(1);
384  checkConsistency(queue);
385  EXPECT_EQ(1, queue.front()->countChainElements());
386  EXPECT_EQ(21, queue.front()->computeChainDataLength());
387  EXPECT_EQ(21, queue.front()->prev()->length());
388 
389  queue.trimEnd(20);
390  checkConsistency(queue);
391  EXPECT_EQ(1, queue.front()->countChainElements());
392  EXPECT_EQ(1, queue.front()->computeChainDataLength());
393  EXPECT_EQ(1, queue.front()->prev()->length());
394 
395  queue.trimEnd(1);
396  checkConsistency(queue);
397  EXPECT_EQ(nullptr, queue.front());
398 
399  EXPECT_THROW(queue.trimStart(2), std::underflow_error);
400  checkConsistency(queue);
401 
402  EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
403  checkConsistency(queue);
404 }
405 
406 TEST(IOBufQueue, Prepend) {
407  folly::IOBufQueue queue;
408 
409  auto buf = folly::IOBuf::create(10);
410  buf->advance(5);
411  queue.append(std::move(buf));
412 
413  queue.append(SCL(" World"));
414  queue.prepend(SCL("Hello"));
415 
416  EXPECT_THROW(queue.prepend(SCL("x")), std::overflow_error);
417 
418  auto out = queue.move();
419  out->coalesce();
420  EXPECT_EQ(
421  "Hello World",
422  StringPiece(reinterpret_cast<const char*>(out->data()), out->length()));
423 }
424 
425 TEST(IOBufQueue, PopFirst) {
426  IOBufQueue queue(IOBufQueue::cacheChainLength());
427  const char* strings[] = {"Hello", ",", " ", "", "World"};
428 
429  const size_t numStrings = sizeof(strings) / sizeof(*strings);
430  size_t chainLength = 0;
431  for (size_t i = 0; i < numStrings; ++i) {
432  queue.append(stringToIOBuf(strings[i], strlen(strings[i])));
433  checkConsistency(queue);
434  chainLength += strlen(strings[i]);
435  }
436 
437  unique_ptr<IOBuf> first;
438  for (size_t i = 0; i < numStrings; ++i) {
439  checkConsistency(queue);
440  EXPECT_EQ(chainLength, queue.front()->computeChainDataLength());
441  EXPECT_EQ(chainLength, queue.chainLength());
442  first = queue.pop_front();
443  chainLength -= strlen(strings[i]);
444  EXPECT_EQ(strlen(strings[i]), first->computeChainDataLength());
445  }
446  checkConsistency(queue);
447  EXPECT_EQ(chainLength, queue.chainLength());
448 
449  EXPECT_EQ((IOBuf*)nullptr, queue.front());
450  first = queue.pop_front();
451  EXPECT_EQ((IOBuf*)nullptr, first.get());
452 
453  checkConsistency(queue);
454  EXPECT_EQ((IOBuf*)nullptr, queue.front());
455  EXPECT_EQ(0, queue.chainLength());
456 }
457 
458 TEST(IOBufQueue, AppendToString) {
459  IOBufQueue queue;
460  queue.append("hello ", 6);
461  queue.append("world", 5);
462  std::string s;
463  queue.appendToString(s);
464  EXPECT_EQ("hello world", s);
465 }
466 
467 TEST(IOBufQueue, Gather) {
468  IOBufQueue queue;
469 
470  queue.append(stringToIOBuf(SCL("hello ")));
471  queue.append(stringToIOBuf(SCL("world")));
472 
473  EXPECT_EQ(queue.front()->length(), 6);
474  queue.gather(11);
475  EXPECT_EQ(queue.front()->length(), 11);
476 
477  StringPiece s(
478  reinterpret_cast<const char*>(queue.front()->data()),
479  queue.front()->length());
480  EXPECT_EQ("hello world", s);
481 }
#define EXPECT_LE(val1, val2)
Definition: gtest.h:1928
std::unique_ptr< folly::IOBuf > split(size_t n)
Definition: IOBufQueue.h:420
#define SCL(x)
const folly::IOBuf * front() const
Definition: IOBufQueue.h:476
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
size_t chainLength() const
Definition: IOBufQueue.h:492
void prepend(const void *buf, std::size_t n)
Definition: IOBufQueue.cpp:132
std::unique_ptr< folly::IOBuf > splitAtMost(size_t n)
Definition: IOBufQueue.h:428
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
TEST(IOBufQueue, Simple)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
bool empty() const
Definition: IOBufQueue.h:503
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const uint8_t * data() const
Definition: IOBuf.h:499
std::unique_ptr< folly::IOBuf > move()
Definition: IOBufQueue.h:459
size_t countChainElements() const
Definition: IOBuf.cpp:493
void appendToString(std::string &out) const
Definition: IOBufQueue.cpp:340
bool prefix(Cursor &c, uint32_t expected)
#define EXPECT_GE(val1, val2)
Definition: gtest.h:1932
const Options & options() const
Definition: IOBufQueue.h:509
uint8_t * writableTail()
Definition: IOBuf.h:526
std::pair< void *, std::size_t > preallocate(std::size_t min, std::size_t newAllocationSize, std::size_t max=std::numeric_limits< std::size_t >::max())
Definition: IOBufQueue.h:356
size_t trimStartAtMost(size_t amount)
Definition: IOBufQueue.cpp:263
std::size_t length() const
Definition: IOBuf.h:533
void wrapBuffer(const void *buf, size_t len, std::size_t blockSize=(1U<< 31))
Definition: IOBufQueue.cpp:194
char a
size_t trimEndAtMost(size_t amount)
Definition: IOBufQueue.cpp:291
IOBuf * prev()
Definition: IOBuf.h:610
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
const char * string
Definition: Conv.cpp:212
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
static set< string > s
Definition: Traits.h:577
void trimStart(size_t amount)
Definition: IOBufQueue.cpp:255
Range< const char * > StringPiece
void trimEnd(size_t amount)
Definition: IOBufQueue.cpp:283
static vector< fbstring > strings
void postallocate(std::size_t n)
Definition: IOBufQueue.h:380
void gather(std::size_t maxLength)
Definition: IOBufQueue.cpp:361
void append(std::size_t amount)
Definition: IOBuf.h:689
std::unique_ptr< folly::IOBuf > pop_front()
Definition: IOBufQueue.cpp:316
constexpr detail::First first
Definition: Base-inl.h:2553