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;
47 stringToIOBuf(const char* s, uint32_t len) {
48 unique_ptr<IOBuf> buf = IOBuf::create(len);
49 memcpy(buf->writableTail(), s, len);
54 void checkConsistency(const IOBufQueue& queue) {
55 if (queue.options().cacheChainLength) {
56 size_t len = queue.front() ? queue.front()->computeChainDataLength() : 0;
57 EXPECT_EQ(len, queue.chainLength());
63 TEST(IOBufQueue, Simple) {
64 IOBufQueue queue(clOptions);
65 EXPECT_EQ(nullptr, queue.front());
66 queue.append(SCL(""));
67 EXPECT_EQ(nullptr, queue.front());
68 queue.append(unique_ptr<IOBuf>());
69 EXPECT_EQ(nullptr, queue.front());
71 queue.append(emptyString);
72 EXPECT_EQ(nullptr, queue.front());
75 TEST(IOBufQueue, Append) {
76 IOBufQueue queue(clOptions);
77 queue.append(SCL("Hello"));
78 IOBufQueue queue2(clOptions);
79 queue2.append(SCL(", "));
80 queue2.append(SCL("World"));
81 checkConsistency(queue);
82 checkConsistency(queue2);
83 queue.append(queue2.move());
84 checkConsistency(queue);
85 checkConsistency(queue2);
86 const IOBuf* chain = queue.front();
87 EXPECT_NE((IOBuf*)nullptr, chain);
88 EXPECT_EQ(12, chain->computeChainDataLength());
89 EXPECT_EQ(nullptr, queue2.front());
92 TEST(IOBufQueue, Append2) {
93 IOBufQueue queue(clOptions);
94 queue.append(SCL("Hello"));
95 IOBufQueue queue2(clOptions);
96 queue2.append(SCL(", "));
97 queue2.append(SCL("World"));
98 checkConsistency(queue);
99 checkConsistency(queue2);
100 queue.append(queue2);
101 checkConsistency(queue);
102 checkConsistency(queue2);
103 const IOBuf* chain = queue.front();
104 EXPECT_NE((IOBuf*)nullptr, chain);
105 EXPECT_EQ(12, chain->computeChainDataLength());
106 EXPECT_EQ(nullptr, queue2.front());
109 TEST(IOBufQueue, AppendStringPiece) {
110 std::string s("Hello, World");
111 IOBufQueue queue(clOptions);
112 IOBufQueue queue2(clOptions);
113 queue.append(s.data(), s.length());
115 checkConsistency(queue);
116 checkConsistency(queue2);
117 const IOBuf* chain = queue.front();
118 const IOBuf* chain2 = queue2.front();
119 EXPECT_EQ(s.length(), chain->computeChainDataLength());
120 EXPECT_EQ(s.length(), chain2->computeChainDataLength());
121 EXPECT_EQ(0, memcmp(chain->data(), chain2->data(), s.length()));
124 TEST(IOBufQueue, Split) {
125 IOBufQueue queue(clOptions);
126 queue.append(stringToIOBuf(SCL("Hello")));
127 queue.append(stringToIOBuf(SCL(",")));
128 queue.append(stringToIOBuf(SCL(" ")));
129 queue.append(stringToIOBuf(SCL("")));
130 queue.append(stringToIOBuf(SCL("World")));
131 checkConsistency(queue);
132 EXPECT_EQ(12, queue.front()->computeChainDataLength());
134 unique_ptr<IOBuf> prefix(queue.split(1));
135 checkConsistency(queue);
136 EXPECT_EQ(1, prefix->computeChainDataLength());
137 EXPECT_EQ(11, queue.front()->computeChainDataLength());
138 prefix = queue.split(2);
139 checkConsistency(queue);
140 EXPECT_EQ(2, prefix->computeChainDataLength());
141 EXPECT_EQ(9, queue.front()->computeChainDataLength());
142 prefix = queue.split(3);
143 checkConsistency(queue);
144 EXPECT_EQ(3, prefix->computeChainDataLength());
145 EXPECT_EQ(6, queue.front()->computeChainDataLength());
146 prefix = queue.split(1);
147 checkConsistency(queue);
148 EXPECT_EQ(1, prefix->computeChainDataLength());
149 EXPECT_EQ(5, queue.front()->computeChainDataLength());
150 prefix = queue.split(5);
151 checkConsistency(queue);
152 EXPECT_EQ(5, prefix->computeChainDataLength());
153 EXPECT_EQ((IOBuf*)nullptr, queue.front());
155 queue.append(stringToIOBuf(SCL("Hello,")));
156 queue.append(stringToIOBuf(SCL(" World")));
157 checkConsistency(queue);
158 EXPECT_THROW({prefix = queue.split(13);}, std::underflow_error);
159 checkConsistency(queue);
162 TEST(IOBufQueue, SplitAtMost) {
163 IOBufQueue queue(clOptions);
164 queue.append(stringToIOBuf(SCL("Hello,")));
165 queue.append(stringToIOBuf(SCL(" World")));
166 auto buf = queue.splitAtMost(9999);
167 EXPECT_EQ(buf->computeChainDataLength(), 12);
168 EXPECT_TRUE(queue.empty());
171 TEST(IOBufQueue, Preallocate) {
172 IOBufQueue queue(clOptions);
173 queue.append(string("Hello"));
174 pair<void*,uint32_t> writable = queue.preallocate(2, 64, 64);
175 checkConsistency(queue);
176 EXPECT_NE((void*)nullptr, writable.first);
177 EXPECT_LE(2, writable.second);
178 EXPECT_GE(64, writable.second);
179 memcpy(writable.first, SCL(", "));
180 queue.postallocate(2);
181 checkConsistency(queue);
182 EXPECT_EQ(7, queue.front()->computeChainDataLength());
183 queue.append(SCL("World"));
184 checkConsistency(queue);
185 EXPECT_EQ(12, queue.front()->computeChainDataLength());
186 // There are not 2048 bytes available, this will alloc a new buf
187 writable = queue.preallocate(2048, 4096);
188 checkConsistency(queue);
189 EXPECT_LE(2048, writable.second);
190 // IOBuf allocates more than newAllocationSize, and we didn't cap it
191 EXPECT_GE(writable.second, 4096);
192 queue.postallocate(writable.second);
193 // queue has no empty space, make sure we allocate at least min, even if
194 // newAllocationSize < min
195 writable = queue.preallocate(1024, 1, 1024);
196 checkConsistency(queue);
197 EXPECT_EQ(1024, writable.second);
200 TEST(IOBufQueue, Wrap) {
201 IOBufQueue queue(clOptions);
202 const char* buf = "hello world goodbye";
203 size_t len = strlen(buf);
204 queue.wrapBuffer(buf, len, 6);
205 auto iob = queue.move();
206 EXPECT_EQ((len - 1) / 6 + 1, iob->countChainElements());
209 EXPECT_EQ(StringPiece(buf),
210 StringPiece(reinterpret_cast<const char*>(iob->data()),
214 TEST(IOBufQueue, Trim) {
215 IOBufQueue queue(clOptions);
216 unique_ptr<IOBuf> a = IOBuf::create(4);
218 queue.append(std::move(a));
219 checkConsistency(queue);
220 a = IOBuf::create(6);
222 queue.append(std::move(a));
223 checkConsistency(queue);
224 a = IOBuf::create(8);
226 queue.append(std::move(a));
227 checkConsistency(queue);
228 a = IOBuf::create(10);
230 queue.append(std::move(a));
231 checkConsistency(queue);
233 EXPECT_EQ(4, queue.front()->countChainElements());
234 EXPECT_EQ(28, queue.front()->computeChainDataLength());
235 EXPECT_EQ(4, queue.front()->length());
238 checkConsistency(queue);
239 EXPECT_EQ(4, queue.front()->countChainElements());
240 EXPECT_EQ(27, queue.front()->computeChainDataLength());
241 EXPECT_EQ(3, queue.front()->length());
244 checkConsistency(queue);
245 EXPECT_EQ(3, queue.front()->countChainElements());
246 EXPECT_EQ(22, queue.front()->computeChainDataLength());
247 EXPECT_EQ(4, queue.front()->length());
250 checkConsistency(queue);
251 EXPECT_EQ(3, queue.front()->countChainElements());
252 EXPECT_EQ(21, queue.front()->computeChainDataLength());
253 EXPECT_EQ(9, queue.front()->prev()->length());
256 checkConsistency(queue);
257 EXPECT_EQ(1, queue.front()->countChainElements());
258 EXPECT_EQ(1, queue.front()->computeChainDataLength());
259 EXPECT_EQ(1, queue.front()->prev()->length());
262 checkConsistency(queue);
263 EXPECT_EQ(nullptr, queue.front());
265 EXPECT_THROW(queue.trimStart(2), std::underflow_error);
266 checkConsistency(queue);
268 EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
269 checkConsistency(queue);
272 TEST(IOBufQueue, TrimPack) {
273 IOBufQueue queue(clOptions);
274 unique_ptr<IOBuf> a = IOBuf::create(64);
276 queue.append(std::move(a), true);
277 checkConsistency(queue);
278 a = IOBuf::create(6);
280 queue.append(std::move(a), true);
281 checkConsistency(queue);
282 a = IOBuf::create(8);
284 queue.append(std::move(a), true);
285 checkConsistency(queue);
286 a = IOBuf::create(10);
288 queue.append(std::move(a), true);
289 checkConsistency(queue);
291 EXPECT_EQ(1, queue.front()->countChainElements());
292 EXPECT_EQ(28, queue.front()->computeChainDataLength());
293 EXPECT_EQ(28, queue.front()->length());
296 checkConsistency(queue);
297 EXPECT_EQ(1, queue.front()->countChainElements());
298 EXPECT_EQ(27, queue.front()->computeChainDataLength());
299 EXPECT_EQ(27, queue.front()->length());
302 checkConsistency(queue);
303 EXPECT_EQ(1, queue.front()->countChainElements());
304 EXPECT_EQ(22, queue.front()->computeChainDataLength());
305 EXPECT_EQ(22, queue.front()->length());
308 checkConsistency(queue);
309 EXPECT_EQ(1, queue.front()->countChainElements());
310 EXPECT_EQ(21, queue.front()->computeChainDataLength());
311 EXPECT_EQ(21, queue.front()->prev()->length());
314 checkConsistency(queue);
315 EXPECT_EQ(1, queue.front()->countChainElements());
316 EXPECT_EQ(1, queue.front()->computeChainDataLength());
317 EXPECT_EQ(1, queue.front()->prev()->length());
320 checkConsistency(queue);
321 EXPECT_EQ(nullptr, queue.front());
323 EXPECT_THROW(queue.trimStart(2), std::underflow_error);
324 checkConsistency(queue);
326 EXPECT_THROW(queue.trimEnd(30), std::underflow_error);
327 checkConsistency(queue);
330 TEST(IOBufQueue, Prepend) {
331 folly::IOBufQueue queue;
333 auto buf = folly::IOBuf::create(10);
335 queue.append(std::move(buf));
337 queue.append(SCL(" World"));
338 queue.prepend(SCL("Hello"));
340 EXPECT_THROW(queue.prepend(SCL("x")), std::overflow_error);
342 auto out = queue.move();
344 EXPECT_EQ("Hello World",
345 StringPiece(reinterpret_cast<const char*>(out->data()),
349 TEST(IOBufQueue, PopFirst) {
350 IOBufQueue queue(IOBufQueue::cacheChainLength());
351 const char * strings[] = {
359 const size_t numStrings=sizeof(strings)/sizeof(*strings);
360 size_t chainLength = 0;
361 for(size_t i = 0; i < numStrings; ++i) {
362 queue.append(stringToIOBuf(strings[i], strlen(strings[i])));
363 checkConsistency(queue);
364 chainLength += strlen(strings[i]);
367 unique_ptr<IOBuf> first;
368 for(size_t i = 0; i < numStrings; ++i) {
369 checkConsistency(queue);
370 EXPECT_EQ(chainLength, queue.front()->computeChainDataLength());
371 EXPECT_EQ(chainLength, queue.chainLength());
372 first = queue.pop_front();
373 chainLength-=strlen(strings[i]);
374 EXPECT_EQ(strlen(strings[i]), first->computeChainDataLength());
376 checkConsistency(queue);
377 EXPECT_EQ(chainLength, queue.chainLength());
379 EXPECT_EQ((IOBuf*)nullptr, queue.front());
380 first = queue.pop_front();
381 EXPECT_EQ((IOBuf*)nullptr, first.get());
383 checkConsistency(queue);
384 EXPECT_EQ((IOBuf*)nullptr, queue.front());
385 EXPECT_EQ(0, queue.chainLength());
388 TEST(IOBufQueue, AppendToString) {
390 queue.append("hello ", 6);
391 queue.append("world", 5);
393 queue.appendToString(s);
394 EXPECT_EQ("hello world", s);
397 TEST(IOBufQueue, Gather) {
400 queue.append(stringToIOBuf(SCL("hello ")));
401 queue.append(stringToIOBuf(SCL("world")));
403 EXPECT_EQ(queue.front()->length(), 6);
405 EXPECT_EQ(queue.front()->length(), 11);
408 reinterpret_cast<const char*>(queue.front()->data()),
409 queue.front()->length());
410 EXPECT_EQ("hello world", s);