2 * Copyright 2017 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/IOBufQueue.h>
23 #include <folly/Range.h>
24 #include <folly/portability/GTest.h>
27 using folly::IOBufQueue;
28 using folly::StringPiece;
31 using std::unique_ptr;
33 // String Comma Length macro for string literals
34 #define SCL(x) (x), sizeof(x) - 1
38 IOBufQueue::Options clOptions;
41 clOptions.cacheChainLength = true;
44 Initializer initializer;
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);
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());
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());
70 queue.append(emptyString);
71 EXPECT_EQ(nullptr, queue.front());
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());
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);
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());
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());
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()));
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());
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());
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);
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());
170 TEST(IOBufQueue, Preallocate) {
171 IOBufQueue queue(clOptions);
172 queue.append(string("Hello"));
173 pair<void*,uint32_t> writable = queue.preallocate(2, 64, 64);
174 checkConsistency(queue);
175 EXPECT_NE((void*)nullptr, writable.first);
176 EXPECT_LE(2, writable.second);
177 EXPECT_GE(64, writable.second);
178 memcpy(writable.first, SCL(", "));
179 queue.postallocate(2);
180 checkConsistency(queue);
181 EXPECT_EQ(7, queue.front()->computeChainDataLength());
182 queue.append(SCL("World"));
183 checkConsistency(queue);
184 EXPECT_EQ(12, queue.front()->computeChainDataLength());
185 // There are not 2048 bytes available, this will alloc a new buf
186 writable = queue.preallocate(2048, 4096);
187 checkConsistency(queue);
188 EXPECT_LE(2048, writable.second);
189 // IOBuf allocates more than newAllocationSize, and we didn't cap it
190 EXPECT_GE(writable.second, 4096);
191 queue.postallocate(writable.second);
192 // queue has no empty space, make sure we allocate at least min, even if
193 // newAllocationSize < min
194 writable = queue.preallocate(1024, 1, 1024);
195 checkConsistency(queue);
196 EXPECT_EQ(1024, writable.second);
199 TEST(IOBufQueue, Wrap) {
200 IOBufQueue queue(clOptions);
201 const char* buf = "hello world goodbye";
202 size_t len = strlen(buf);
203 queue.wrapBuffer(buf, len, 6);
204 auto iob = queue.move();
205 EXPECT_EQ((len - 1) / 6 + 1, iob->countChainElements());
208 EXPECT_EQ(StringPiece(buf),
209 StringPiece(reinterpret_cast<const char*>(iob->data()),
213 TEST(IOBufQueue, Trim) {
214 IOBufQueue queue(clOptions);
215 unique_ptr<IOBuf> a = IOBuf::create(4);
217 queue.append(std::move(a));
218 checkConsistency(queue);
219 a = IOBuf::create(6);
221 queue.append(std::move(a));
222 checkConsistency(queue);
223 a = IOBuf::create(8);
225 queue.append(std::move(a));
226 checkConsistency(queue);
227 a = IOBuf::create(10);
229 queue.append(std::move(a));
230 checkConsistency(queue);
232 EXPECT_EQ(4, queue.front()->countChainElements());
233 EXPECT_EQ(28, queue.front()->computeChainDataLength());
234 EXPECT_EQ(4, queue.front()->length());
237 checkConsistency(queue);
238 EXPECT_EQ(4, queue.front()->countChainElements());
239 EXPECT_EQ(27, queue.front()->computeChainDataLength());
240 EXPECT_EQ(3, queue.front()->length());
243 checkConsistency(queue);
244 EXPECT_EQ(3, queue.front()->countChainElements());
245 EXPECT_EQ(22, queue.front()->computeChainDataLength());
246 EXPECT_EQ(4, queue.front()->length());
249 checkConsistency(queue);
250 EXPECT_EQ(3, queue.front()->countChainElements());
251 EXPECT_EQ(21, queue.front()->computeChainDataLength());
252 EXPECT_EQ(9, queue.front()->prev()->length());
255 checkConsistency(queue);
256 EXPECT_EQ(1, queue.front()->countChainElements());
257 EXPECT_EQ(1, queue.front()->computeChainDataLength());
258 EXPECT_EQ(1, queue.front()->prev()->length());
261 checkConsistency(queue);
262 EXPECT_EQ(nullptr, queue.front());
264 EXPECT_THROW(queue.trimStart(2), std::underflow_error);
265 checkConsistency(queue);
267 EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
268 checkConsistency(queue);
271 TEST(IOBufQueue, TrimStartAtMost) {
272 IOBufQueue queue(clOptions);
273 unique_ptr<IOBuf> a = IOBuf::create(4);
275 queue.append(std::move(a));
276 checkConsistency(queue);
277 a = IOBuf::create(6);
279 queue.append(std::move(a));
280 checkConsistency(queue);
281 a = IOBuf::create(8);
283 queue.append(std::move(a));
284 checkConsistency(queue);
285 a = IOBuf::create(10);
287 queue.append(std::move(a));
288 checkConsistency(queue);
290 EXPECT_EQ(4, queue.front()->countChainElements());
291 EXPECT_EQ(28, queue.front()->computeChainDataLength());
292 EXPECT_EQ(4, queue.front()->length());
294 queue.trimStartAtMost(1);
295 checkConsistency(queue);
296 EXPECT_EQ(4, queue.front()->countChainElements());
297 EXPECT_EQ(27, queue.front()->computeChainDataLength());
298 EXPECT_EQ(3, queue.front()->length());
300 queue.trimStartAtMost(50);
301 checkConsistency(queue);
302 EXPECT_EQ(nullptr, queue.front());
303 EXPECT_EQ(0, queue.chainLength());
306 TEST(IOBufQueue, TrimEndAtMost) {
307 IOBufQueue queue(clOptions);
308 unique_ptr<IOBuf> a = IOBuf::create(4);
310 queue.append(std::move(a));
311 checkConsistency(queue);
312 a = IOBuf::create(6);
314 queue.append(std::move(a));
315 checkConsistency(queue);
316 a = IOBuf::create(8);
318 queue.append(std::move(a));
319 checkConsistency(queue);
320 a = IOBuf::create(10);
322 queue.append(std::move(a));
323 checkConsistency(queue);
325 EXPECT_EQ(4, queue.front()->countChainElements());
326 EXPECT_EQ(28, queue.front()->computeChainDataLength());
327 EXPECT_EQ(4, queue.front()->length());
329 queue.trimEndAtMost(1);
330 checkConsistency(queue);
331 EXPECT_EQ(4, queue.front()->countChainElements());
332 EXPECT_EQ(27, queue.front()->computeChainDataLength());
333 EXPECT_EQ(4, queue.front()->length());
335 queue.trimEndAtMost(50);
336 checkConsistency(queue);
337 EXPECT_EQ(nullptr, queue.front());
338 EXPECT_EQ(0, queue.chainLength());
341 TEST(IOBufQueue, TrimPack) {
342 IOBufQueue queue(clOptions);
343 unique_ptr<IOBuf> a = IOBuf::create(64);
345 queue.append(std::move(a), true);
346 checkConsistency(queue);
347 a = IOBuf::create(6);
349 queue.append(std::move(a), true);
350 checkConsistency(queue);
351 a = IOBuf::create(8);
353 queue.append(std::move(a), true);
354 checkConsistency(queue);
355 a = IOBuf::create(10);
357 queue.append(std::move(a), true);
358 checkConsistency(queue);
360 EXPECT_EQ(1, queue.front()->countChainElements());
361 EXPECT_EQ(28, queue.front()->computeChainDataLength());
362 EXPECT_EQ(28, queue.front()->length());
365 checkConsistency(queue);
366 EXPECT_EQ(1, queue.front()->countChainElements());
367 EXPECT_EQ(27, queue.front()->computeChainDataLength());
368 EXPECT_EQ(27, queue.front()->length());
371 checkConsistency(queue);
372 EXPECT_EQ(1, queue.front()->countChainElements());
373 EXPECT_EQ(22, queue.front()->computeChainDataLength());
374 EXPECT_EQ(22, queue.front()->length());
377 checkConsistency(queue);
378 EXPECT_EQ(1, queue.front()->countChainElements());
379 EXPECT_EQ(21, queue.front()->computeChainDataLength());
380 EXPECT_EQ(21, queue.front()->prev()->length());
383 checkConsistency(queue);
384 EXPECT_EQ(1, queue.front()->countChainElements());
385 EXPECT_EQ(1, queue.front()->computeChainDataLength());
386 EXPECT_EQ(1, queue.front()->prev()->length());
389 checkConsistency(queue);
390 EXPECT_EQ(nullptr, queue.front());
392 EXPECT_THROW(queue.trimStart(2), std::underflow_error);
393 checkConsistency(queue);
395 EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
396 checkConsistency(queue);
399 TEST(IOBufQueue, Prepend) {
400 folly::IOBufQueue queue;
402 auto buf = folly::IOBuf::create(10);
404 queue.append(std::move(buf));
406 queue.append(SCL(" World"));
407 queue.prepend(SCL("Hello"));
409 EXPECT_THROW(queue.prepend(SCL("x")), std::overflow_error);
411 auto out = queue.move();
413 EXPECT_EQ("Hello World",
414 StringPiece(reinterpret_cast<const char*>(out->data()),
418 TEST(IOBufQueue, PopFirst) {
419 IOBufQueue queue(IOBufQueue::cacheChainLength());
420 const char * strings[] = {
428 const size_t numStrings=sizeof(strings)/sizeof(*strings);
429 size_t chainLength = 0;
430 for(size_t i = 0; i < numStrings; ++i) {
431 queue.append(stringToIOBuf(strings[i], strlen(strings[i])));
432 checkConsistency(queue);
433 chainLength += strlen(strings[i]);
436 unique_ptr<IOBuf> first;
437 for(size_t i = 0; i < numStrings; ++i) {
438 checkConsistency(queue);
439 EXPECT_EQ(chainLength, queue.front()->computeChainDataLength());
440 EXPECT_EQ(chainLength, queue.chainLength());
441 first = queue.pop_front();
442 chainLength-=strlen(strings[i]);
443 EXPECT_EQ(strlen(strings[i]), first->computeChainDataLength());
445 checkConsistency(queue);
446 EXPECT_EQ(chainLength, queue.chainLength());
448 EXPECT_EQ((IOBuf*)nullptr, queue.front());
449 first = queue.pop_front();
450 EXPECT_EQ((IOBuf*)nullptr, first.get());
452 checkConsistency(queue);
453 EXPECT_EQ((IOBuf*)nullptr, queue.front());
454 EXPECT_EQ(0, queue.chainLength());
457 TEST(IOBufQueue, AppendToString) {
459 queue.append("hello ", 6);
460 queue.append("world", 5);
462 queue.appendToString(s);
463 EXPECT_EQ("hello world", s);
466 TEST(IOBufQueue, Gather) {
469 queue.append(stringToIOBuf(SCL("hello ")));
470 queue.append(stringToIOBuf(SCL("world")));
472 EXPECT_EQ(queue.front()->length(), 6);
474 EXPECT_EQ(queue.front()->length(), 11);
477 reinterpret_cast<const char*>(queue.front()->data()),
478 queue.front()->length());
479 EXPECT_EQ("hello world", s);