]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/bufferlist.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / bufferlist.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
7 *
8 * Author: Loic Dachary <loic@dachary.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library Public License for more details.
19 *
20 */
21
22 #include <limits.h>
23 #include <errno.h>
24 #include <sys/uio.h>
25
26 #include "include/buffer.h"
27 #include "include/buffer_raw.h"
28 #include "include/compat.h"
29 #include "include/utime.h"
30 #include "include/coredumpctl.h"
31 #include "include/encoding.h"
32 #include "common/buffer_instrumentation.h"
33 #include "common/environment.h"
34 #include "common/Clock.h"
35 #include "common/safe_io.h"
36
37 #include "gtest/gtest.h"
38 #include "stdlib.h"
39 #include "fcntl.h"
40 #include "sys/stat.h"
41 #include "include/crc32c.h"
42 #include "common/sctp_crc32.h"
43
44 #define MAX_TEST 1000000
45 #define FILENAME "bufferlist"
46
47 using namespace std;
48
49 static char cmd[128];
50
51 using ceph::buffer_instrumentation::instrumented_bptr;
52
53 TEST(Buffer, constructors) {
54 unsigned len = 17;
55 //
56 // buffer::create
57 //
58 {
59 bufferptr ptr(buffer::create(len));
60 EXPECT_EQ(len, ptr.length());
61 }
62 //
63 // buffer::claim_char
64 //
65 {
66 char* str = new char[len];
67 ::memset(str, 'X', len);
68 bufferptr ptr(buffer::claim_char(len, str));
69 EXPECT_EQ(len, ptr.length());
70 EXPECT_EQ(str, ptr.c_str());
71 EXPECT_EQ(0, ::memcmp(str, ptr.c_str(), len));
72 delete [] str;
73 }
74 //
75 // buffer::create_static
76 //
77 {
78 char* str = new char[len];
79 bufferptr ptr(buffer::create_static(len, str));
80 EXPECT_EQ(len, ptr.length());
81 EXPECT_EQ(str, ptr.c_str());
82 delete [] str;
83 }
84 //
85 // buffer::create_malloc
86 //
87 {
88 bufferptr ptr(buffer::create_malloc(len));
89 EXPECT_EQ(len, ptr.length());
90 // this doesn't throw on my x86_64 wheezy box --sage
91 //EXPECT_THROW(buffer::create_malloc((unsigned)ULLONG_MAX), buffer::bad_alloc);
92 }
93 //
94 // buffer::claim_malloc
95 //
96 {
97 char* str = (char*)malloc(len);
98 ::memset(str, 'X', len);
99 bufferptr ptr(buffer::claim_malloc(len, str));
100 EXPECT_EQ(len, ptr.length());
101 EXPECT_EQ(str, ptr.c_str());
102 EXPECT_EQ(0, ::memcmp(str, ptr.c_str(), len));
103 }
104 //
105 // buffer::copy
106 //
107 {
108 const std::string expected(len, 'X');
109 bufferptr ptr(buffer::copy(expected.c_str(), expected.size()));
110 EXPECT_NE(expected.c_str(), ptr.c_str());
111 EXPECT_EQ(0, ::memcmp(expected.c_str(), ptr.c_str(), len));
112 }
113 //
114 // buffer::create_page_aligned
115 //
116 {
117 bufferptr ptr(buffer::create_page_aligned(len));
118 ::memset(ptr.c_str(), 'X', len);
119 // doesn't throw on my x86_64 wheezy box --sage
120 //EXPECT_THROW(buffer::create_page_aligned((unsigned)ULLONG_MAX), buffer::bad_alloc);
121 #ifndef DARWIN
122 ASSERT_TRUE(ptr.is_page_aligned());
123 #endif // DARWIN
124 }
125 }
126
127 void bench_buffer_alloc(int size, int num)
128 {
129 utime_t start = ceph_clock_now();
130 for (int i=0; i<num; ++i) {
131 bufferptr p = buffer::create(size);
132 p.zero();
133 }
134 utime_t end = ceph_clock_now();
135 cout << num << " alloc of size " << size
136 << " in " << (end - start) << std::endl;
137 }
138
139 TEST(Buffer, BenchAlloc) {
140 bench_buffer_alloc(16384, 1000000);
141 bench_buffer_alloc(4096, 1000000);
142 bench_buffer_alloc(1024, 1000000);
143 bench_buffer_alloc(256, 1000000);
144 bench_buffer_alloc(32, 1000000);
145 bench_buffer_alloc(4, 1000000);
146 }
147
148 TEST(BufferRaw, ostream) {
149 bufferptr ptr(1);
150 std::ostringstream stream;
151 stream << *static_cast<instrumented_bptr&>(ptr).get_raw();
152 EXPECT_GT(stream.str().size(), stream.str().find("buffer::raw("));
153 EXPECT_GT(stream.str().size(), stream.str().find("len 1 nref 1)"));
154 }
155
156 //
157 // +-----------+ +-----+
158 // | | | |
159 // | offset +----------------+ |
160 // | | | |
161 // | length +---- | |
162 // | | \------- | |
163 // +-----------+ \---+ |
164 // | ptr | +-----+
165 // +-----------+ | raw |
166 // +-----+
167 //
168 TEST(BufferPtr, constructors) {
169 unsigned len = 17;
170 //
171 // ptr::ptr()
172 //
173 {
174 buffer::ptr ptr;
175 EXPECT_FALSE(ptr.have_raw());
176 EXPECT_EQ((unsigned)0, ptr.offset());
177 EXPECT_EQ((unsigned)0, ptr.length());
178 }
179 //
180 // ptr::ptr(raw *r)
181 //
182 {
183 bufferptr ptr(buffer::create(len));
184 EXPECT_TRUE(ptr.have_raw());
185 EXPECT_EQ((unsigned)0, ptr.offset());
186 EXPECT_EQ(len, ptr.length());
187 EXPECT_EQ(ptr.raw_length(), ptr.length());
188 EXPECT_EQ(1, ptr.raw_nref());
189 }
190 //
191 // ptr::ptr(unsigned l)
192 //
193 {
194 bufferptr ptr(len);
195 EXPECT_TRUE(ptr.have_raw());
196 EXPECT_EQ((unsigned)0, ptr.offset());
197 EXPECT_EQ(len, ptr.length());
198 EXPECT_EQ(1, ptr.raw_nref());
199 }
200 //
201 // ptr(const char *d, unsigned l)
202 //
203 {
204 const std::string str(len, 'X');
205 bufferptr ptr(str.c_str(), len);
206 EXPECT_TRUE(ptr.have_raw());
207 EXPECT_EQ((unsigned)0, ptr.offset());
208 EXPECT_EQ(len, ptr.length());
209 EXPECT_EQ(1, ptr.raw_nref());
210 EXPECT_EQ(0, ::memcmp(str.c_str(), ptr.c_str(), len));
211 }
212 //
213 // ptr(const ptr& p)
214 //
215 {
216 const std::string str(len, 'X');
217 bufferptr original(str.c_str(), len);
218 bufferptr ptr(original);
219 EXPECT_TRUE(ptr.have_raw());
220 EXPECT_EQ(static_cast<instrumented_bptr&>(original).get_raw(),
221 static_cast<instrumented_bptr&>(ptr).get_raw());
222 EXPECT_EQ(2, ptr.raw_nref());
223 EXPECT_EQ(0, ::memcmp(original.c_str(), ptr.c_str(), len));
224 }
225 //
226 // ptr(const ptr& p, unsigned o, unsigned l)
227 //
228 {
229 const std::string str(len, 'X');
230 bufferptr original(str.c_str(), len);
231 bufferptr ptr(original, 0, 0);
232 EXPECT_TRUE(ptr.have_raw());
233 EXPECT_EQ(static_cast<instrumented_bptr&>(original).get_raw(),
234 static_cast<instrumented_bptr&>(ptr).get_raw());
235 EXPECT_EQ(2, ptr.raw_nref());
236 EXPECT_EQ(0, ::memcmp(original.c_str(), ptr.c_str(), len));
237 PrCtl unset_dumpable;
238 EXPECT_DEATH(bufferptr(original, 0, original.length() + 1), "");
239 EXPECT_DEATH(bufferptr(bufferptr(), 0, 0), "");
240 }
241 //
242 // ptr(ptr&& p)
243 //
244 {
245 const std::string str(len, 'X');
246 bufferptr original(str.c_str(), len);
247 bufferptr ptr(std::move(original));
248 EXPECT_TRUE(ptr.have_raw());
249 EXPECT_FALSE(original.have_raw());
250 EXPECT_EQ(0, ::memcmp(str.c_str(), ptr.c_str(), len));
251 EXPECT_EQ(1, ptr.raw_nref());
252 }
253 }
254
255 TEST(BufferPtr, operator_assign) {
256 //
257 // ptr& operator= (const ptr& p)
258 //
259 bufferptr ptr(10);
260 ptr.copy_in(0, 3, "ABC");
261 char dest[1];
262 {
263 bufferptr copy = ptr;
264 copy.copy_out(1, 1, dest);
265 ASSERT_EQ('B', dest[0]);
266 }
267
268 //
269 // ptr& operator= (ptr&& p)
270 //
271 bufferptr move = std::move(ptr);
272 {
273 move.copy_out(1, 1, dest);
274 ASSERT_EQ('B', dest[0]);
275 }
276 EXPECT_FALSE(ptr.have_raw());
277 }
278
279 TEST(BufferPtr, assignment) {
280 unsigned len = 17;
281 //
282 // override a bufferptr set with the same raw
283 //
284 {
285 bufferptr original(len);
286 bufferptr same_raw(original);
287 unsigned offset = 5;
288 unsigned length = len - offset;
289 original.set_offset(offset);
290 original.set_length(length);
291 same_raw = original;
292 ASSERT_EQ(2, original.raw_nref());
293 ASSERT_EQ(static_cast<instrumented_bptr&>(same_raw).get_raw(),
294 static_cast<instrumented_bptr&>(original).get_raw());
295 ASSERT_EQ(same_raw.offset(), original.offset());
296 ASSERT_EQ(same_raw.length(), original.length());
297 }
298
299 //
300 // self assignment is a noop
301 //
302 {
303 bufferptr original(len);
304 #pragma clang diagnostic push
305 #pragma clang diagnostic ignored "-Wself-assign-overloaded"
306 original = original;
307 #pragma clang diagnostic pop
308 ASSERT_EQ(1, original.raw_nref());
309 ASSERT_EQ((unsigned)0, original.offset());
310 ASSERT_EQ(len, original.length());
311 }
312
313 //
314 // a copy points to the same raw
315 //
316 {
317 bufferptr original(len);
318 unsigned offset = 5;
319 unsigned length = len - offset;
320 original.set_offset(offset);
321 original.set_length(length);
322 bufferptr ptr;
323 ptr = original;
324 ASSERT_EQ(2, original.raw_nref());
325 ASSERT_EQ(static_cast<instrumented_bptr&>(ptr).get_raw(),
326 static_cast<instrumented_bptr&>(original).get_raw());
327 ASSERT_EQ(original.offset(), ptr.offset());
328 ASSERT_EQ(original.length(), ptr.length());
329 }
330 }
331
332 TEST(BufferPtr, swap) {
333 unsigned len = 17;
334
335 bufferptr ptr1(len);
336 ::memset(ptr1.c_str(), 'X', len);
337 unsigned ptr1_offset = 4;
338 ptr1.set_offset(ptr1_offset);
339 unsigned ptr1_length = 3;
340 ptr1.set_length(ptr1_length);
341
342 bufferptr ptr2(len);
343 ::memset(ptr2.c_str(), 'Y', len);
344 unsigned ptr2_offset = 5;
345 ptr2.set_offset(ptr2_offset);
346 unsigned ptr2_length = 7;
347 ptr2.set_length(ptr2_length);
348
349 ptr1.swap(ptr2);
350
351 EXPECT_EQ(ptr2_length, ptr1.length());
352 EXPECT_EQ(ptr2_offset, ptr1.offset());
353 EXPECT_EQ('Y', ptr1[0]);
354
355 EXPECT_EQ(ptr1_length, ptr2.length());
356 EXPECT_EQ(ptr1_offset, ptr2.offset());
357 EXPECT_EQ('X', ptr2[0]);
358 }
359
360 TEST(BufferPtr, release) {
361 unsigned len = 17;
362
363 bufferptr ptr1(len);
364 {
365 bufferptr ptr2(ptr1);
366 EXPECT_EQ(2, ptr1.raw_nref());
367 }
368 EXPECT_EQ(1, ptr1.raw_nref());
369 }
370
371 TEST(BufferPtr, have_raw) {
372 {
373 bufferptr ptr;
374 EXPECT_FALSE(ptr.have_raw());
375 }
376 {
377 bufferptr ptr(1);
378 EXPECT_TRUE(ptr.have_raw());
379 }
380 }
381
382 TEST(BufferPtr, is_n_page_sized) {
383 {
384 bufferptr ptr(CEPH_PAGE_SIZE);
385 EXPECT_TRUE(ptr.is_n_page_sized());
386 }
387 {
388 bufferptr ptr(1);
389 EXPECT_FALSE(ptr.is_n_page_sized());
390 }
391 }
392
393 TEST(BufferPtr, is_partial) {
394 bufferptr a;
395 EXPECT_FALSE(a.is_partial());
396 bufferptr b(10);
397 EXPECT_FALSE(b.is_partial());
398 bufferptr c(b, 1, 9);
399 EXPECT_TRUE(c.is_partial());
400 bufferptr d(b, 0, 9);
401 EXPECT_TRUE(d.is_partial());
402 }
403
404 TEST(BufferPtr, accessors) {
405 unsigned len = 17;
406 bufferptr ptr(len);
407 ptr.c_str()[0] = 'X';
408 ptr[1] = 'Y';
409 const bufferptr const_ptr(ptr);
410
411 EXPECT_NE((void*)nullptr, (void*)static_cast<instrumented_bptr&>(ptr).get_raw());
412 EXPECT_EQ('X', ptr.c_str()[0]);
413 {
414 bufferptr ptr;
415 PrCtl unset_dumpable;
416 EXPECT_DEATH(ptr.c_str(), "");
417 EXPECT_DEATH(ptr[0], "");
418 }
419 EXPECT_EQ('X', const_ptr.c_str()[0]);
420 {
421 const bufferptr const_ptr;
422 PrCtl unset_dumpable;
423 EXPECT_DEATH(const_ptr.c_str(), "");
424 EXPECT_DEATH(const_ptr[0], "");
425 }
426 EXPECT_EQ(len, const_ptr.length());
427 EXPECT_EQ((unsigned)0, const_ptr.offset());
428 EXPECT_EQ((unsigned)0, const_ptr.start());
429 EXPECT_EQ(len, const_ptr.end());
430 EXPECT_EQ(len, const_ptr.end());
431 {
432 bufferptr ptr(len);
433 unsigned unused = 1;
434 ptr.set_length(ptr.length() - unused);
435 EXPECT_EQ(unused, ptr.unused_tail_length());
436 }
437 {
438 bufferptr ptr;
439 EXPECT_EQ((unsigned)0, ptr.unused_tail_length());
440 }
441 {
442 PrCtl unset_dumpable;
443 EXPECT_DEATH(ptr[len], "");
444 EXPECT_DEATH(const_ptr[len], "");
445 }
446 {
447 const bufferptr const_ptr;
448 PrCtl unset_dumpable;
449 EXPECT_DEATH(const_ptr.raw_c_str(), "");
450 EXPECT_DEATH(const_ptr.raw_length(), "");
451 EXPECT_DEATH(const_ptr.raw_nref(), "");
452 }
453 EXPECT_NE((const char *)NULL, const_ptr.raw_c_str());
454 EXPECT_EQ(len, const_ptr.raw_length());
455 EXPECT_EQ(2, const_ptr.raw_nref());
456 {
457 bufferptr ptr(len);
458 unsigned wasted = 1;
459 ptr.set_length(ptr.length() - wasted * 2);
460 ptr.set_offset(wasted);
461 EXPECT_EQ(wasted * 2, ptr.wasted());
462 }
463 }
464
465 TEST(BufferPtr, cmp) {
466 bufferptr empty;
467 bufferptr a("A", 1);
468 bufferptr ab("AB", 2);
469 bufferptr af("AF", 2);
470 bufferptr acc("ACC", 3);
471 EXPECT_GE(-1, empty.cmp(a));
472 EXPECT_LE(1, a.cmp(empty));
473 EXPECT_GE(-1, a.cmp(ab));
474 EXPECT_LE(1, ab.cmp(a));
475 EXPECT_EQ(0, ab.cmp(ab));
476 EXPECT_GE(-1, ab.cmp(af));
477 EXPECT_LE(1, af.cmp(ab));
478 EXPECT_GE(-1, acc.cmp(af));
479 EXPECT_LE(1, af.cmp(acc));
480 }
481
482 TEST(BufferPtr, is_zero) {
483 char str[2] = { '\0', 'X' };
484 {
485 const bufferptr ptr(buffer::create_static(2, str));
486 EXPECT_FALSE(ptr.is_zero());
487 }
488 {
489 const bufferptr ptr(buffer::create_static(1, str));
490 EXPECT_TRUE(ptr.is_zero());
491 }
492 }
493
494 TEST(BufferPtr, copy_out) {
495 {
496 const bufferptr ptr;
497 PrCtl unset_dumpable;
498 EXPECT_DEATH(ptr.copy_out((unsigned)0, (unsigned)0, NULL), "");
499 }
500 {
501 char in[] = "ABC";
502 const bufferptr ptr(buffer::create_static(strlen(in), in));
503 EXPECT_THROW(ptr.copy_out((unsigned)0, strlen(in) + 1, NULL), buffer::end_of_buffer);
504 EXPECT_THROW(ptr.copy_out(strlen(in) + 1, (unsigned)0, NULL), buffer::end_of_buffer);
505 char out[1] = { 'X' };
506 ptr.copy_out((unsigned)1, (unsigned)1, out);
507 EXPECT_EQ('B', out[0]);
508 }
509 }
510
511 TEST(BufferPtr, copy_out_bench) {
512 for (int s=1; s<=8; s*=2) {
513 utime_t start = ceph_clock_now();
514 int buflen = 1048576;
515 int count = 1000;
516 uint64_t v;
517 for (int i=0; i<count; ++i) {
518 bufferptr bp(buflen);
519 for (int64_t j=0; j<buflen; j += s) {
520 bp.copy_out(j, s, (char *)&v);
521 }
522 }
523 utime_t end = ceph_clock_now();
524 cout << count << " fills of buffer len " << buflen
525 << " with " << s << " byte copy_out in "
526 << (end - start) << std::endl;
527 }
528 }
529
530 TEST(BufferPtr, copy_in) {
531 {
532 bufferptr ptr;
533 PrCtl unset_dumpable;
534 EXPECT_DEATH(ptr.copy_in((unsigned)0, (unsigned)0, NULL), "");
535 }
536 {
537 char in[] = "ABCD";
538 bufferptr ptr(2);
539 {
540 PrCtl unset_dumpable;
541 EXPECT_DEATH(ptr.copy_in((unsigned)0, strlen(in) + 1, NULL), "");
542 EXPECT_DEATH(ptr.copy_in(strlen(in) + 1, (unsigned)0, NULL), "");
543 }
544 ptr.copy_in((unsigned)0, (unsigned)2, in);
545 EXPECT_EQ(in[0], ptr[0]);
546 EXPECT_EQ(in[1], ptr[1]);
547 }
548 }
549
550 TEST(BufferPtr, copy_in_bench) {
551 for (int s=1; s<=8; s*=2) {
552 utime_t start = ceph_clock_now();
553 int buflen = 1048576;
554 int count = 1000;
555 for (int i=0; i<count; ++i) {
556 bufferptr bp(buflen);
557 for (int64_t j=0; j<buflen; j += s) {
558 bp.copy_in(j, s, (char *)&j, false);
559 }
560 }
561 utime_t end = ceph_clock_now();
562 cout << count << " fills of buffer len " << buflen
563 << " with " << s << " byte copy_in in "
564 << (end - start) << std::endl;
565 }
566 }
567
568 TEST(BufferPtr, append) {
569 {
570 bufferptr ptr;
571 PrCtl unset_dumpable;
572 EXPECT_DEATH(ptr.append('A'), "");
573 EXPECT_DEATH(ptr.append("B", (unsigned)1), "");
574 }
575 {
576 bufferptr ptr(2);
577 {
578 PrCtl unset_dumpable;
579 EXPECT_DEATH(ptr.append('A'), "");
580 EXPECT_DEATH(ptr.append("B", (unsigned)1), "");
581 }
582 ptr.set_length(0);
583 ptr.append('A');
584 EXPECT_EQ((unsigned)1, ptr.length());
585 EXPECT_EQ('A', ptr[0]);
586 ptr.append("B", (unsigned)1);
587 EXPECT_EQ((unsigned)2, ptr.length());
588 EXPECT_EQ('B', ptr[1]);
589 }
590 }
591
592 TEST(BufferPtr, append_bench) {
593 char src[1048576];
594 memset(src, 0, sizeof(src));
595 for (int s=4; s<=16384; s*=4) {
596 utime_t start = ceph_clock_now();
597 int buflen = 1048576;
598 int count = 4000;
599 for (int i=0; i<count; ++i) {
600 bufferptr bp(buflen);
601 bp.set_length(0);
602 for (int64_t j=0; j<buflen; j += s) {
603 bp.append(src + j, s);
604 }
605 }
606 utime_t end = ceph_clock_now();
607 cout << count << " fills of buffer len " << buflen
608 << " with " << s << " byte appends in "
609 << (end - start) << std::endl;
610 }
611 }
612
613 TEST(BufferPtr, zero) {
614 char str[] = "XXXX";
615 bufferptr ptr(buffer::create_static(strlen(str), str));
616 {
617 PrCtl unset_dumpable;
618 EXPECT_DEATH(ptr.zero(ptr.length() + 1, 0), "");
619 }
620 ptr.zero(1, 1);
621 EXPECT_EQ('X', ptr[0]);
622 EXPECT_EQ('\0', ptr[1]);
623 EXPECT_EQ('X', ptr[2]);
624 ptr.zero();
625 EXPECT_EQ('\0', ptr[0]);
626 }
627
628 TEST(BufferPtr, ostream) {
629 {
630 bufferptr ptr;
631 std::ostringstream stream;
632 stream << ptr;
633 EXPECT_GT(stream.str().size(), stream.str().find("buffer:ptr(0~0 no raw"));
634 }
635 {
636 char str[] = "XXXX";
637 bufferptr ptr(buffer::create_static(strlen(str), str));
638 std::ostringstream stream;
639 stream << ptr;
640 EXPECT_GT(stream.str().size(), stream.str().find("len 4 nref 1)"));
641 }
642 }
643
644 //
645 // +---------+
646 // | +-----+ |
647 // list ptr | | | |
648 // +----------+ +-----+ | | | |
649 // | append_ >-------> >--------------------> | |
650 // | buffer | +-----+ | | | |
651 // +----------+ ptr | | | |
652 // | _len | list +-----+ | | | |
653 // +----------+ +------+ ,--->+ >-----> | |
654 // | _buffers >----> >----- +-----+ | +-----+ |
655 // +----------+ +----^-+ \ ptr | raw |
656 // | last_p | / `-->+-----+ | +-----+ |
657 // +--------+-+ / + >-----> | |
658 // | ,- ,--->+-----+ | | | |
659 // | / ,--- | | | |
660 // | / ,--- | | | |
661 // +-v--+-^--+--^+-------+ | | | |
662 // | bl | ls | p | p_off >--------------->| | |
663 // +----+----+-----+-----+ | +-----+ |
664 // | | off >------------->| raw |
665 // +---------------+-----+ | |
666 // iterator +---------+
667 //
668 TEST(BufferListIterator, constructors) {
669 //
670 // iterator()
671 //
672 {
673 buffer::list::iterator i;
674 EXPECT_EQ((unsigned)0, i.get_off());
675 }
676
677 //
678 // iterator(list *l, unsigned o=0)
679 //
680 {
681 bufferlist bl;
682 bl.append("ABC", 3);
683
684 {
685 bufferlist::iterator i(&bl);
686 EXPECT_EQ((unsigned)0, i.get_off());
687 EXPECT_EQ('A', *i);
688 }
689 {
690 bufferlist::iterator i(&bl, 1);
691 EXPECT_EQ('B', *i);
692 EXPECT_EQ((unsigned)2, i.get_remaining());
693 }
694 }
695
696 //
697 // iterator(list *l, unsigned o, std::list<ptr>::iterator ip, unsigned po)
698 // not tested because of http://tracker.ceph.com/issues/4101
699
700 //
701 // iterator(const iterator& other)
702 //
703 {
704 bufferlist bl;
705 bl.append("ABC", 3);
706 bufferlist::iterator i(&bl, 1);
707 bufferlist::iterator j(i);
708 EXPECT_EQ(*i, *j);
709 ++j;
710 EXPECT_NE(*i, *j);
711 EXPECT_EQ('B', *i);
712 EXPECT_EQ('C', *j);
713 bl.c_str()[1] = 'X';
714 }
715
716 //
717 // const_iterator(const iterator& other)
718 //
719 {
720 bufferlist bl;
721 bl.append("ABC", 3);
722 bufferlist::iterator i(&bl);
723 bufferlist::const_iterator ci(i);
724 EXPECT_EQ(0u, ci.get_off());
725 EXPECT_EQ('A', *ci);
726 }
727 }
728
729 TEST(BufferListIterator, empty_create_append_copy) {
730 bufferlist bl, bl2, bl3, out;
731 bl2.append("bar");
732 bl.swap(bl2);
733 bl2.append("xxx");
734 bl.append(bl2);
735 bl.rebuild();
736 bl.begin().copy(6, out);
737 ASSERT_TRUE(out.contents_equal(bl));
738 }
739
740 TEST(BufferListIterator, operator_assign) {
741 bufferlist bl;
742 bl.append("ABC", 3);
743 bufferlist::iterator i(&bl, 1);
744
745 #pragma clang diagnostic push
746 #pragma clang diagnostic ignored "-Wself-assign-overloaded"
747 i = i;
748 #pragma clang diagnostic pop
749 EXPECT_EQ('B', *i);
750 bufferlist::iterator j;
751 j = i;
752 EXPECT_EQ('B', *j);
753 }
754
755 TEST(BufferListIterator, get_off) {
756 bufferlist bl;
757 bl.append("ABC", 3);
758 bufferlist::iterator i(&bl, 1);
759 EXPECT_EQ((unsigned)1, i.get_off());
760 }
761
762 TEST(BufferListIterator, get_remaining) {
763 bufferlist bl;
764 bl.append("ABC", 3);
765 bufferlist::iterator i(&bl, 1);
766 EXPECT_EQ((unsigned)2, i.get_remaining());
767 }
768
769 TEST(BufferListIterator, end) {
770 bufferlist bl;
771 {
772 bufferlist::iterator i(&bl);
773 EXPECT_TRUE(i.end());
774 }
775 bl.append("ABC", 3);
776 {
777 bufferlist::iterator i(&bl);
778 EXPECT_FALSE(i.end());
779 }
780 }
781
782 static void bench_bufferlistiter_deref(const size_t step,
783 const size_t bufsize,
784 const size_t bufnum) {
785 const std::string buf(bufsize, 'a');
786 ceph::bufferlist bl;
787
788 for (size_t i = 0; i < bufnum; i++) {
789 bl.append(ceph::bufferptr(buf.c_str(), buf.size()));
790 }
791
792 utime_t start = ceph_clock_now();
793 bufferlist::iterator iter = bl.begin();
794 while (iter != bl.end()) {
795 iter += step;
796 }
797 utime_t end = ceph_clock_now();
798 cout << bufsize * bufnum << " derefs over bl with " << bufnum
799 << " buffers, each " << bufsize << " bytes long"
800 << " in " << (end - start) << std::endl;
801 }
802
803 TEST(BufferListIterator, BenchDeref) {
804 bench_bufferlistiter_deref(1, 1, 4096000);
805 bench_bufferlistiter_deref(1, 10, 409600);
806 bench_bufferlistiter_deref(1, 100, 40960);
807 bench_bufferlistiter_deref(1, 1000, 4096);
808
809 bench_bufferlistiter_deref(4, 1, 1024000);
810 bench_bufferlistiter_deref(4, 10, 102400);
811 bench_bufferlistiter_deref(4, 100, 10240);
812 bench_bufferlistiter_deref(4, 1000, 1024);
813 }
814
815 TEST(BufferListIterator, advance) {
816 bufferlist bl;
817 const std::string one("ABC");
818 bl.append(bufferptr(one.c_str(), one.size()));
819 const std::string two("DEF");
820 bl.append(bufferptr(two.c_str(), two.size()));
821
822 {
823 bufferlist::iterator i(&bl);
824 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
825 }
826 {
827 bufferlist::iterator i(&bl);
828 EXPECT_EQ('A', *i);
829 i += 1u;
830 EXPECT_EQ('B', *i);
831 i += 3u;
832 EXPECT_EQ('E', *i);
833 }
834 }
835
836 TEST(BufferListIterator, iterate_with_empties) {
837 ceph::bufferlist bl;
838 EXPECT_EQ(bl.get_num_buffers(), 0u);
839
840 bl.push_back(ceph::buffer::create(0));
841 EXPECT_EQ(bl.length(), 0u);
842 EXPECT_EQ(bl.get_num_buffers(), 1u);
843
844 encode(int64_t(42), bl);
845 EXPECT_EQ(bl.get_num_buffers(), 2u);
846
847 bl.push_back(ceph::buffer::create(0));
848 EXPECT_EQ(bl.get_num_buffers(), 3u);
849
850 // append bufferlist with single, 0-sized ptr inside
851 {
852 ceph::bufferlist bl_with_empty_ptr;
853 bl_with_empty_ptr.push_back(ceph::buffer::create(0));
854 EXPECT_EQ(bl_with_empty_ptr.length(), 0u);
855 EXPECT_EQ(bl_with_empty_ptr.get_num_buffers(), 1u);
856
857 bl.append(bl_with_empty_ptr);
858 }
859
860 encode(int64_t(24), bl);
861 EXPECT_EQ(bl.get_num_buffers(), 5u);
862
863 auto i = bl.cbegin();
864 int64_t val;
865 decode(val, i);
866 EXPECT_EQ(val, 42l);
867
868 decode(val, i);
869 EXPECT_EQ(val, 24l);
870
871 val = 0;
872 i.seek(sizeof(val));
873 decode(val, i);
874 EXPECT_EQ(val, 24l);
875 EXPECT_TRUE(i == bl.end());
876
877 i.seek(0);
878 decode(val, i);
879 EXPECT_EQ(val, 42);
880 EXPECT_FALSE(i == bl.end());
881 }
882
883 TEST(BufferListIterator, get_ptr_and_advance)
884 {
885 bufferptr a("one", 3);
886 bufferptr b("two", 3);
887 bufferptr c("three", 5);
888 bufferlist bl;
889 bl.append(a);
890 bl.append(b);
891 bl.append(c);
892 const char *ptr;
893 bufferlist::iterator p = bl.begin();
894 ASSERT_EQ(3u, p.get_ptr_and_advance(11u, &ptr));
895 ASSERT_EQ(bl.length() - 3u, p.get_remaining());
896 ASSERT_EQ(0, memcmp(ptr, "one", 3));
897 ASSERT_EQ(2u, p.get_ptr_and_advance(2u, &ptr));
898 ASSERT_EQ(0, memcmp(ptr, "tw", 2));
899 ASSERT_EQ(1u, p.get_ptr_and_advance(4u, &ptr));
900 ASSERT_EQ(0, memcmp(ptr, "o", 1));
901 ASSERT_EQ(5u, p.get_ptr_and_advance(5u, &ptr));
902 ASSERT_EQ(0, memcmp(ptr, "three", 5));
903 ASSERT_EQ(0u, p.get_remaining());
904 }
905
906 TEST(BufferListIterator, iterator_crc32c) {
907 bufferlist bl1;
908 bufferlist bl2;
909 bufferlist bl3;
910
911 string s1(100, 'a');
912 string s2(50, 'b');
913 string s3(7, 'c');
914 string s;
915 bl1.append(s1);
916 bl1.append(s2);
917 bl1.append(s3);
918 s = s1 + s2 + s3;
919 bl2.append(s);
920
921 bufferlist::iterator it = bl2.begin();
922 ASSERT_EQ(bl1.crc32c(0), it.crc32c(it.get_remaining(), 0));
923 ASSERT_EQ(0u, it.get_remaining());
924
925 it = bl1.begin();
926 ASSERT_EQ(bl2.crc32c(0), it.crc32c(it.get_remaining(), 0));
927
928 bl3.append(s.substr(98, 55));
929 it = bl1.begin();
930 it += 98u;
931 ASSERT_EQ(bl3.crc32c(0), it.crc32c(55, 0));
932 ASSERT_EQ(4u, it.get_remaining());
933
934 bl3.clear();
935 bl3.append(s.substr(98 + 55));
936 it = bl1.begin();
937 it += 98u + 55u;
938 ASSERT_EQ(bl3.crc32c(0), it.crc32c(10, 0));
939 ASSERT_EQ(0u, it.get_remaining());
940 }
941
942 TEST(BufferListIterator, seek) {
943 bufferlist bl;
944 bl.append("ABC", 3);
945 bufferlist::iterator i(&bl, 1);
946 EXPECT_EQ('B', *i);
947 i.seek(2);
948 EXPECT_EQ('C', *i);
949 }
950
951 TEST(BufferListIterator, operator_star) {
952 bufferlist bl;
953 {
954 bufferlist::iterator i(&bl);
955 EXPECT_THROW(*i, buffer::end_of_buffer);
956 }
957 bl.append("ABC", 3);
958 {
959 bufferlist::iterator i(&bl);
960 EXPECT_EQ('A', *i);
961 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
962 EXPECT_THROW(*i, buffer::end_of_buffer);
963 }
964 }
965
966 TEST(BufferListIterator, operator_equal) {
967 bufferlist bl;
968 bl.append("ABC", 3);
969 {
970 bufferlist::iterator i(&bl);
971 bufferlist::iterator j(&bl);
972 EXPECT_EQ(i, j);
973 }
974 {
975 bufferlist::const_iterator ci = bl.begin();
976 bufferlist::iterator i = bl.begin();
977 EXPECT_EQ(i, ci);
978 EXPECT_EQ(ci, i);
979 }
980 }
981
982 TEST(BufferListIterator, operator_nequal) {
983 bufferlist bl;
984 bl.append("ABC", 3);
985 {
986 bufferlist::iterator i(&bl);
987 bufferlist::iterator j(&bl);
988 EXPECT_NE(++i, j);
989 }
990 {
991 bufferlist::const_iterator ci = bl.begin();
992 bufferlist::const_iterator cj = bl.begin();
993 ++ci;
994 EXPECT_NE(ci, cj);
995 bufferlist::iterator i = bl.begin();
996 EXPECT_NE(i, ci);
997 EXPECT_NE(ci, i);
998 }
999 {
1000 // tests begin(), end(), operator++() also
1001 string s("ABC");
1002 int i = 0;
1003 for (auto c : bl) {
1004 EXPECT_EQ(s[i++], c);
1005 }
1006 }
1007 }
1008
1009 TEST(BufferListIterator, operator_plus_plus) {
1010 bufferlist bl;
1011 {
1012 bufferlist::iterator i(&bl);
1013 EXPECT_THROW(++i, buffer::end_of_buffer);
1014 }
1015 bl.append("ABC", 3);
1016 {
1017 bufferlist::iterator i(&bl);
1018 ++i;
1019 EXPECT_EQ('B', *i);
1020 }
1021 }
1022
1023 TEST(BufferListIterator, get_current_ptr) {
1024 bufferlist bl;
1025 {
1026 bufferlist::iterator i(&bl);
1027 EXPECT_THROW(++i, buffer::end_of_buffer);
1028 }
1029 bl.append("ABC", 3);
1030 {
1031 bufferlist::iterator i(&bl, 1);
1032 const buffer::ptr ptr = i.get_current_ptr();
1033 EXPECT_EQ('B', ptr[0]);
1034 EXPECT_EQ((unsigned)1, ptr.offset());
1035 EXPECT_EQ((unsigned)2, ptr.length());
1036 }
1037 }
1038
1039 TEST(BufferListIterator, copy) {
1040 bufferlist bl;
1041 const char *expected = "ABC";
1042 bl.append(expected, 3);
1043 //
1044 // void copy(unsigned len, char *dest);
1045 //
1046 {
1047 char* copy = (char*)malloc(3);
1048 ::memset(copy, 'X', 3);
1049 bufferlist::iterator i(&bl);
1050 //
1051 // demonstrates that it seeks back to offset if p == ls->end()
1052 //
1053 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1054 i.copy(2, copy);
1055 EXPECT_EQ(0, ::memcmp(copy, expected, 2));
1056 EXPECT_EQ('X', copy[2]);
1057 i.seek(0);
1058 i.copy(3, copy);
1059 EXPECT_EQ(0, ::memcmp(copy, expected, 3));
1060 free(copy);
1061 }
1062 //
1063 // void copy(unsigned len, char *dest) via begin(size_t offset)
1064 //
1065 {
1066 bufferlist bl;
1067 EXPECT_THROW(bl.begin((unsigned)100).copy((unsigned)100, (char*)0), buffer::end_of_buffer);
1068 const char *expected = "ABC";
1069 bl.append(expected);
1070 char *dest = new char[2];
1071 bl.begin(1).copy(2, dest);
1072 EXPECT_EQ(0, ::memcmp(expected + 1, dest, 2));
1073 delete [] dest;
1074 }
1075 //
1076 // void buffer::list::iterator::copy_deep(unsigned len, ptr &dest)
1077 //
1078 {
1079 bufferptr ptr;
1080 bufferlist::iterator i(&bl);
1081 i.copy_deep(2, ptr);
1082 EXPECT_EQ((unsigned)2, ptr.length());
1083 EXPECT_EQ('A', ptr[0]);
1084 EXPECT_EQ('B', ptr[1]);
1085 }
1086 //
1087 // void buffer::list::iterator::copy_shallow(unsigned len, ptr &dest)
1088 //
1089 {
1090 bufferptr ptr;
1091 bufferlist::iterator i(&bl);
1092 i.copy_shallow(2, ptr);
1093 EXPECT_EQ((unsigned)2, ptr.length());
1094 EXPECT_EQ('A', ptr[0]);
1095 EXPECT_EQ('B', ptr[1]);
1096 }
1097 //
1098 // void buffer::list::iterator::copy(unsigned len, list &dest)
1099 //
1100 {
1101 bufferlist copy;
1102 bufferlist::iterator i(&bl);
1103 //
1104 // demonstrates that it seeks back to offset if p == ls->end()
1105 //
1106 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1107 i.copy(2, copy);
1108 EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2));
1109 i.seek(0);
1110 i.copy(3, copy);
1111 EXPECT_EQ('A', copy[0]);
1112 EXPECT_EQ('B', copy[1]);
1113 EXPECT_EQ('A', copy[2]);
1114 EXPECT_EQ('B', copy[3]);
1115 EXPECT_EQ('C', copy[4]);
1116 EXPECT_EQ((unsigned)(2 + 3), copy.length());
1117 }
1118 //
1119 // void buffer::list::iterator::copy(unsigned len, list &dest) via begin(size_t offset)
1120 //
1121 {
1122 bufferlist bl;
1123 bufferlist dest;
1124 EXPECT_THROW(bl.begin((unsigned)100).copy((unsigned)100, dest), buffer::end_of_buffer);
1125 const char *expected = "ABC";
1126 bl.append(expected);
1127 bl.begin(1).copy(2, dest);
1128 EXPECT_EQ(0, ::memcmp(expected + 1, dest.c_str(), 2));
1129 }
1130 //
1131 // void buffer::list::iterator::copy_all(list &dest)
1132 //
1133 {
1134 bufferlist copy;
1135 bufferlist::iterator i(&bl);
1136 //
1137 // demonstrates that it seeks back to offset if p == ls->end()
1138 //
1139 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1140 i.copy_all(copy);
1141 EXPECT_EQ('A', copy[0]);
1142 EXPECT_EQ('B', copy[1]);
1143 EXPECT_EQ('C', copy[2]);
1144 EXPECT_EQ((unsigned)3, copy.length());
1145 }
1146 //
1147 // void copy(unsigned len, std::string &dest)
1148 //
1149 {
1150 std::string copy;
1151 bufferlist::iterator i(&bl);
1152 //
1153 // demonstrates that it seeks back to offset if p == ls->end()
1154 //
1155 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1156 i.copy(2, copy);
1157 EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2));
1158 i.seek(0);
1159 i.copy(3, copy);
1160 EXPECT_EQ('A', copy[0]);
1161 EXPECT_EQ('B', copy[1]);
1162 EXPECT_EQ('A', copy[2]);
1163 EXPECT_EQ('B', copy[3]);
1164 EXPECT_EQ('C', copy[4]);
1165 EXPECT_EQ((unsigned)(2 + 3), copy.length());
1166 }
1167 //
1168 // void copy(unsigned len, std::string &dest) via begin(size_t offset)
1169 //
1170 {
1171 bufferlist bl;
1172 std::string dest;
1173 EXPECT_THROW(bl.begin((unsigned)100).copy((unsigned)100, dest), buffer::end_of_buffer);
1174 const char *expected = "ABC";
1175 bl.append(expected);
1176 bl.begin(1).copy(2, dest);
1177 EXPECT_EQ(0, ::memcmp(expected + 1, dest.c_str(), 2));
1178 }
1179 }
1180
1181 TEST(BufferListIterator, copy_in) {
1182 bufferlist bl;
1183 const char *existing = "XXX";
1184 bl.append(existing, 3);
1185 //
1186 // void buffer::list::iterator::copy_in(unsigned len, const char *src)
1187 //
1188 {
1189 bufferlist::iterator i(&bl);
1190 //
1191 // demonstrates that it seeks back to offset if p == ls->end()
1192 //
1193 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1194 const char *expected = "ABC";
1195 i.copy_in(3, expected);
1196 EXPECT_EQ(0, ::memcmp(bl.c_str(), expected, 3));
1197 EXPECT_EQ('A', bl[0]);
1198 EXPECT_EQ('B', bl[1]);
1199 EXPECT_EQ('C', bl[2]);
1200 EXPECT_EQ((unsigned)3, bl.length());
1201 }
1202 //
1203 // void copy_in(unsigned len, const char *src) via begin(size_t offset)
1204 //
1205 {
1206 bufferlist bl;
1207 bl.append("XXX");
1208 EXPECT_THROW(bl.begin((unsigned)100).copy_in((unsigned)100, (char*)0), buffer::end_of_buffer);
1209 bl.begin(1).copy_in(2, "AB");
1210 EXPECT_EQ(0, ::memcmp("XAB", bl.c_str(), 3));
1211 }
1212 //
1213 // void buffer::list::iterator::copy_in(unsigned len, const list& otherl)
1214 //
1215 {
1216 bufferlist::iterator i(&bl);
1217 //
1218 // demonstrates that it seeks back to offset if p == ls->end()
1219 //
1220 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1221 bufferlist expected;
1222 expected.append("ABC", 3);
1223 i.copy_in(3, expected);
1224 EXPECT_EQ(0, ::memcmp(bl.c_str(), expected.c_str(), 3));
1225 EXPECT_EQ('A', bl[0]);
1226 EXPECT_EQ('B', bl[1]);
1227 EXPECT_EQ('C', bl[2]);
1228 EXPECT_EQ((unsigned)3, bl.length());
1229 }
1230 //
1231 // void copy_in(unsigned len, const list& src) via begin(size_t offset)
1232 //
1233 {
1234 bufferlist bl;
1235 bl.append("XXX");
1236 bufferlist src;
1237 src.append("ABC");
1238 EXPECT_THROW(bl.begin((unsigned)100).copy_in((unsigned)100, src), buffer::end_of_buffer);
1239 bl.begin(1).copy_in(2, src);
1240 EXPECT_EQ(0, ::memcmp("XAB", bl.c_str(), 3));
1241 }
1242 }
1243
1244 // iterator& buffer::list::const_iterator::operator++()
1245 TEST(BufferListConstIterator, operator_plus_plus) {
1246 bufferlist bl;
1247 {
1248 bufferlist::const_iterator i(&bl);
1249 EXPECT_THROW(++i, buffer::end_of_buffer);
1250 }
1251 bl.append("ABC", 3);
1252 {
1253 const bufferlist const_bl(bl);
1254 bufferlist::const_iterator i(const_bl.begin());
1255 ++i;
1256 EXPECT_EQ('B', *i);
1257 }
1258
1259 }
1260
1261 TEST(BufferList, constructors) {
1262 //
1263 // list()
1264 //
1265 {
1266 bufferlist bl;
1267 ASSERT_EQ((unsigned)0, bl.length());
1268 }
1269 //
1270 // list(unsigned prealloc)
1271 //
1272 {
1273 bufferlist bl(1);
1274 ASSERT_EQ((unsigned)0, bl.length());
1275 bl.append('A');
1276 ASSERT_EQ('A', bl[0]);
1277 }
1278 //
1279 // list(const list& other)
1280 //
1281 {
1282 bufferlist bl(1);
1283 bl.append('A');
1284 ASSERT_EQ('A', bl[0]);
1285 bufferlist copy(bl);
1286 ASSERT_EQ('A', copy[0]);
1287 }
1288 //
1289 // list(list&& other)
1290 //
1291 {
1292 bufferlist bl(1);
1293 bl.append('A');
1294 bufferlist copy = std::move(bl);
1295 ASSERT_EQ(0U, bl.length());
1296 ASSERT_EQ(1U, copy.length());
1297 ASSERT_EQ('A', copy[0]);
1298 }
1299 }
1300
1301 TEST(BufferList, append_after_move) {
1302 bufferlist bl(6);
1303 bl.append("ABC", 3);
1304 EXPECT_EQ(1, bl.get_num_buffers());
1305
1306 bufferlist moved_to_bl(std::move(bl));
1307 moved_to_bl.append("123", 3);
1308 // it's expected that the list(list&&) ctor will preserve the _carriage
1309 EXPECT_EQ(1, moved_to_bl.get_num_buffers());
1310 EXPECT_EQ(0, ::memcmp("ABC123", moved_to_bl.c_str(), 6));
1311 }
1312
1313 void bench_bufferlist_alloc(int size, int num, int per)
1314 {
1315 utime_t start = ceph_clock_now();
1316 for (int i=0; i<num; ++i) {
1317 bufferlist bl;
1318 for (int j=0; j<per; ++j)
1319 bl.push_back(buffer::ptr_node::create(buffer::create(size)));
1320 }
1321 utime_t end = ceph_clock_now();
1322 cout << num << " alloc of size " << size
1323 << " in " << (end - start) << std::endl;
1324 }
1325
1326 TEST(BufferList, BenchAlloc) {
1327 bench_bufferlist_alloc(32768, 100000, 16);
1328 bench_bufferlist_alloc(25000, 100000, 16);
1329 bench_bufferlist_alloc(16384, 100000, 16);
1330 bench_bufferlist_alloc(10000, 100000, 16);
1331 bench_bufferlist_alloc(8192, 100000, 16);
1332 bench_bufferlist_alloc(6000, 100000, 16);
1333 bench_bufferlist_alloc(4096, 100000, 16);
1334 bench_bufferlist_alloc(1024, 100000, 16);
1335 bench_bufferlist_alloc(256, 100000, 16);
1336 bench_bufferlist_alloc(32, 100000, 16);
1337 bench_bufferlist_alloc(4, 100000, 16);
1338 }
1339
1340 /*
1341 * append_bench tests now have multiple variants:
1342 *
1343 * Version 1 tests allocate a single bufferlist during loop iteration.
1344 * Ultimately very little memory is utilized since the bufferlist immediately
1345 * drops out of scope. This was the original variant of these tests but showed
1346 * unexpected performance characteristics that appears to be tied to tcmalloc
1347 * and/or kernel behavior depending on the bufferlist size and step size.
1348 *
1349 * Version 2 tests allocate a configurable number of bufferlists that are
1350 * replaced round-robin during loop iteration. Version 2 tests are designed
1351 * to better mimic performance when multiple bufferlists are in memory at the
1352 * same time. During testing this showed more consistent and seemingly
1353 * accurate behavior across bufferlist and step sizes.
1354 */
1355
1356 TEST(BufferList, append_bench_with_size_hint) {
1357 std::array<char, 1048576> src = { 0, };
1358
1359 for (size_t step = 4; step <= 16384; step *= 4) {
1360 const utime_t start = ceph_clock_now();
1361
1362 constexpr size_t rounds = 4000;
1363 for (size_t r = 0; r < rounds; ++r) {
1364 ceph::bufferlist bl(std::size(src));
1365 for (auto iter = std::begin(src);
1366 iter != std::end(src);
1367 iter = std::next(iter, step)) {
1368 bl.append(&*iter, step);
1369 }
1370 }
1371 cout << rounds << " fills of buffer len " << src.size()
1372 << " with " << step << " byte appends in "
1373 << (ceph_clock_now() - start) << std::endl;
1374 }
1375 }
1376
1377 TEST(BufferList, append_bench_with_size_hint2) {
1378 std::array<char, 1048576> src = { 0, };
1379 constexpr size_t rounds = 4000;
1380 constexpr int conc_bl = 400;
1381 std::vector<ceph::bufferlist*> bls(conc_bl);
1382
1383 for (int i = 0; i < conc_bl; i++) {
1384 bls[i] = new ceph::bufferlist;
1385 }
1386 for (size_t step = 4; step <= 16384; step *= 4) {
1387 const utime_t start = ceph_clock_now();
1388 for (size_t r = 0; r < rounds; ++r) {
1389 delete bls[r % conc_bl];
1390 bls[r % conc_bl] = new ceph::bufferlist(std::size(src));
1391 for (auto iter = std::begin(src);
1392 iter != std::end(src);
1393 iter = std::next(iter, step)) {
1394 bls[r % conc_bl]->append(&*iter, step);
1395 }
1396 }
1397 cout << rounds << " fills of buffer len " << src.size()
1398 << " with " << step << " byte appends in "
1399 << (ceph_clock_now() - start) << std::endl;
1400 }
1401 for (int i = 0; i < conc_bl; i++) {
1402 delete bls[i];
1403 }
1404 }
1405
1406 TEST(BufferList, append_bench) {
1407 std::array<char, 1048576> src = { 0, };
1408 for (size_t step = 4; step <= 16384; step *= 4) {
1409 const utime_t start = ceph_clock_now();
1410 constexpr size_t rounds = 4000;
1411 for (size_t r = 0; r < rounds; ++r) {
1412 ceph::bufferlist bl;
1413 for (auto iter = std::begin(src);
1414 iter != std::end(src);
1415 iter = std::next(iter, step)) {
1416 bl.append(&*iter, step);
1417 }
1418 }
1419 cout << rounds << " fills of buffer len " << src.size()
1420 << " with " << step << " byte appends in "
1421 << (ceph_clock_now() - start) << std::endl;
1422 }
1423 }
1424
1425 TEST(BufferList, append_bench2) {
1426 std::array<char, 1048576> src = { 0, };
1427 constexpr size_t rounds = 4000;
1428 constexpr int conc_bl = 400;
1429 std::vector<ceph::bufferlist*> bls(conc_bl);
1430
1431 for (int i = 0; i < conc_bl; i++) {
1432 bls[i] = new ceph::bufferlist;
1433 }
1434 for (size_t step = 4; step <= 16384; step *= 4) {
1435 const utime_t start = ceph_clock_now();
1436 for (size_t r = 0; r < rounds; ++r) {
1437 delete bls[r % conc_bl];
1438 bls[r % conc_bl] = new ceph::bufferlist;
1439 for (auto iter = std::begin(src);
1440 iter != std::end(src);
1441 iter = std::next(iter, step)) {
1442 bls[r % conc_bl]->append(&*iter, step);
1443 }
1444 }
1445 cout << rounds << " fills of buffer len " << src.size()
1446 << " with " << step << " byte appends in "
1447 << (ceph_clock_now() - start) << std::endl;
1448 }
1449 for (int i = 0; i < conc_bl; i++) {
1450 delete bls[i];
1451 }
1452 }
1453
1454 TEST(BufferList, append_hole_bench) {
1455 constexpr size_t targeted_bl_size = 1048576;
1456
1457 for (size_t step = 512; step <= 65536; step *= 2) {
1458 const utime_t start = ceph_clock_now();
1459 constexpr size_t rounds = 80000;
1460 for (size_t r = 0; r < rounds; ++r) {
1461 ceph::bufferlist bl;
1462 while (bl.length() < targeted_bl_size) {
1463 bl.append_hole(step);
1464 }
1465 }
1466 cout << rounds << " fills of buffer len " << targeted_bl_size
1467 << " with " << step << " byte long append_hole in "
1468 << (ceph_clock_now() - start) << std::endl;
1469 }
1470 }
1471
1472 TEST(BufferList, append_hole_bench2) {
1473 constexpr size_t targeted_bl_size = 1048576;
1474 constexpr size_t rounds = 80000;
1475 constexpr int conc_bl = 400;
1476 std::vector<ceph::bufferlist*> bls(conc_bl);
1477
1478 for (int i = 0; i < conc_bl; i++) {
1479 bls[i] = new ceph::bufferlist;
1480 }
1481 for (size_t step = 512; step <= 65536; step *= 2) {
1482 const utime_t start = ceph_clock_now();
1483 for (size_t r = 0; r < rounds; ++r) {
1484 delete bls[r % conc_bl];
1485 bls[r % conc_bl] = new ceph::bufferlist;
1486 while (bls[r % conc_bl]->length() < targeted_bl_size) {
1487 bls[r % conc_bl]->append_hole(step);
1488 }
1489 }
1490 cout << rounds << " fills of buffer len " << targeted_bl_size
1491 << " with " << step << " byte long append_hole in "
1492 << (ceph_clock_now() - start) << std::endl;
1493 }
1494 for (int i = 0; i < conc_bl; i++) {
1495 delete bls[i];
1496 }
1497 }
1498
1499 TEST(BufferList, operator_assign_rvalue) {
1500 bufferlist from;
1501 {
1502 bufferptr ptr(2);
1503 from.append(ptr);
1504 }
1505 bufferlist to;
1506 {
1507 bufferptr ptr(4);
1508 to.append(ptr);
1509 }
1510 EXPECT_EQ((unsigned)4, to.length());
1511 EXPECT_EQ((unsigned)1, to.get_num_buffers());
1512 to = std::move(from);
1513 EXPECT_EQ((unsigned)2, to.length());
1514 EXPECT_EQ((unsigned)1, to.get_num_buffers());
1515 EXPECT_EQ((unsigned)0, from.get_num_buffers());
1516 EXPECT_EQ((unsigned)0, from.length());
1517 }
1518
1519 TEST(BufferList, operator_equal) {
1520 //
1521 // list& operator= (const list& other)
1522 //
1523 bufferlist bl;
1524 bl.append("ABC", 3);
1525 {
1526 std::string dest;
1527 bl.begin(1).copy(1, dest);
1528 ASSERT_EQ('B', dest[0]);
1529 }
1530 {
1531 bufferlist copy = bl;
1532 std::string dest;
1533 copy.begin(1).copy(1, dest);
1534 ASSERT_EQ('B', dest[0]);
1535 }
1536
1537 //
1538 // list& operator= (list&& other)
1539 //
1540 bufferlist move;
1541 move = std::move(bl);
1542 {
1543 std::string dest;
1544 move.begin(1).copy(1, dest);
1545 ASSERT_EQ('B', dest[0]);
1546 }
1547 EXPECT_TRUE(move.length());
1548 EXPECT_TRUE(!bl.length());
1549 }
1550
1551 TEST(BufferList, buffers) {
1552 bufferlist bl;
1553 ASSERT_EQ((unsigned)0, bl.get_num_buffers());
1554 bl.append('A');
1555 ASSERT_EQ((unsigned)1, bl.get_num_buffers());
1556 }
1557
1558 TEST(BufferList, to_str) {
1559 {
1560 bufferlist bl;
1561 bl.append("foo");
1562 ASSERT_EQ(bl.to_str(), string("foo"));
1563 }
1564 {
1565 bufferptr a("foobarbaz", 9);
1566 bufferptr b("123456789", 9);
1567 bufferptr c("ABCDEFGHI", 9);
1568 bufferlist bl;
1569 bl.append(a);
1570 bl.append(b);
1571 bl.append(c);
1572 ASSERT_EQ(bl.to_str(), string("foobarbaz123456789ABCDEFGHI"));
1573 }
1574 }
1575
1576 TEST(BufferList, swap) {
1577 bufferlist b1;
1578 b1.append('A');
1579
1580 bufferlist b2;
1581 b2.append('B');
1582
1583 b1.swap(b2);
1584
1585 std::string s1;
1586 b1.begin().copy(1, s1);
1587 ASSERT_EQ('B', s1[0]);
1588
1589 std::string s2;
1590 b2.begin().copy(1, s2);
1591 ASSERT_EQ('A', s2[0]);
1592 }
1593
1594 TEST(BufferList, length) {
1595 bufferlist bl;
1596 ASSERT_EQ((unsigned)0, bl.length());
1597 bl.append('A');
1598 ASSERT_EQ((unsigned)1, bl.length());
1599 }
1600
1601 TEST(BufferList, contents_equal) {
1602 //
1603 // A BB
1604 // AB B
1605 //
1606 bufferlist bl1;
1607 bl1.append("A");
1608 bl1.append("BB");
1609 bufferlist bl2;
1610 ASSERT_FALSE(bl1.contents_equal(bl2)); // different length
1611 bl2.append("AB");
1612 bl2.append("B");
1613 ASSERT_TRUE(bl1.contents_equal(bl2)); // same length same content
1614 //
1615 // ABC
1616 //
1617 bufferlist bl3;
1618 bl3.append("ABC");
1619 ASSERT_FALSE(bl1.contents_equal(bl3)); // same length different content
1620 }
1621
1622 TEST(BufferList, is_aligned) {
1623 const int SIMD_ALIGN = 32;
1624 {
1625 bufferlist bl;
1626 EXPECT_TRUE(bl.is_aligned(SIMD_ALIGN));
1627 }
1628 {
1629 bufferlist bl;
1630 bufferptr ptr(buffer::create_aligned(2, SIMD_ALIGN));
1631 ptr.set_offset(1);
1632 ptr.set_length(1);
1633 bl.append(ptr);
1634 EXPECT_FALSE(bl.is_aligned(SIMD_ALIGN));
1635 bl.rebuild_aligned(SIMD_ALIGN);
1636 EXPECT_TRUE(bl.is_aligned(SIMD_ALIGN));
1637 }
1638 {
1639 bufferlist bl;
1640 bufferptr ptr(buffer::create_aligned(SIMD_ALIGN + 1, SIMD_ALIGN));
1641 ptr.set_offset(1);
1642 ptr.set_length(SIMD_ALIGN);
1643 bl.append(ptr);
1644 EXPECT_FALSE(bl.is_aligned(SIMD_ALIGN));
1645 bl.rebuild_aligned(SIMD_ALIGN);
1646 EXPECT_TRUE(bl.is_aligned(SIMD_ALIGN));
1647 }
1648 }
1649
1650 TEST(BufferList, is_n_align_sized) {
1651 const int SIMD_ALIGN = 32;
1652 {
1653 bufferlist bl;
1654 EXPECT_TRUE(bl.is_n_align_sized(SIMD_ALIGN));
1655 }
1656 {
1657 bufferlist bl;
1658 bl.append_zero(1);
1659 EXPECT_FALSE(bl.is_n_align_sized(SIMD_ALIGN));
1660 }
1661 {
1662 bufferlist bl;
1663 bl.append_zero(SIMD_ALIGN);
1664 EXPECT_TRUE(bl.is_n_align_sized(SIMD_ALIGN));
1665 }
1666 }
1667
1668 TEST(BufferList, is_page_aligned) {
1669 {
1670 bufferlist bl;
1671 EXPECT_TRUE(bl.is_page_aligned());
1672 }
1673 {
1674 bufferlist bl;
1675 bufferptr ptr(buffer::create_page_aligned(2));
1676 ptr.set_offset(1);
1677 ptr.set_length(1);
1678 bl.append(ptr);
1679 EXPECT_FALSE(bl.is_page_aligned());
1680 bl.rebuild_page_aligned();
1681 EXPECT_TRUE(bl.is_page_aligned());
1682 }
1683 {
1684 bufferlist bl;
1685 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1));
1686 ptr.set_offset(1);
1687 ptr.set_length(CEPH_PAGE_SIZE);
1688 bl.append(ptr);
1689 EXPECT_FALSE(bl.is_page_aligned());
1690 bl.rebuild_page_aligned();
1691 EXPECT_TRUE(bl.is_page_aligned());
1692 }
1693 }
1694
1695 TEST(BufferList, is_n_page_sized) {
1696 {
1697 bufferlist bl;
1698 EXPECT_TRUE(bl.is_n_page_sized());
1699 }
1700 {
1701 bufferlist bl;
1702 bl.append_zero(1);
1703 EXPECT_FALSE(bl.is_n_page_sized());
1704 }
1705 {
1706 bufferlist bl;
1707 bl.append_zero(CEPH_PAGE_SIZE);
1708 EXPECT_TRUE(bl.is_n_page_sized());
1709 }
1710 }
1711
1712 TEST(BufferList, page_aligned_appender) {
1713 bufferlist bl;
1714 {
1715 auto a = bl.get_page_aligned_appender(5);
1716 a.append("asdf", 4);
1717 cout << bl << std::endl;
1718 ASSERT_EQ(1u, bl.get_num_buffers());
1719 ASSERT_TRUE(bl.contents_equal("asdf", 4));
1720 a.append("asdf", 4);
1721 for (unsigned n = 0; n < 3 * CEPH_PAGE_SIZE; ++n) {
1722 a.append("x", 1);
1723 }
1724 cout << bl << std::endl;
1725 ASSERT_EQ(1u, bl.get_num_buffers());
1726 // verify the beginning
1727 {
1728 bufferlist t;
1729 t.substr_of(bl, 0, 10);
1730 ASSERT_TRUE(t.contents_equal("asdfasdfxx", 10));
1731 }
1732 for (unsigned n = 0; n < 3 * CEPH_PAGE_SIZE; ++n) {
1733 a.append("y", 1);
1734 }
1735 cout << bl << std::endl;
1736 ASSERT_EQ(2u, bl.get_num_buffers());
1737
1738 a.append_zero(42);
1739 // ensure append_zero didn't introduce a fragmentation
1740 ASSERT_EQ(2u, bl.get_num_buffers());
1741 // verify the end is actually zeroed
1742 {
1743 bufferlist t;
1744 t.substr_of(bl, bl.length() - 42, 42);
1745 ASSERT_TRUE(t.is_zero());
1746 }
1747
1748 // let's check whether appending a bufferlist directly to `bl`
1749 // doesn't fragment further C string appends via appender.
1750 {
1751 const auto& initial_back = bl.back();
1752 {
1753 bufferlist src;
1754 src.append("abc", 3);
1755 bl.claim_append(src);
1756 // surely the extra `ptr_node` taken from `src` must get
1757 // reflected in the `bl` instance
1758 ASSERT_EQ(3u, bl.get_num_buffers());
1759 }
1760
1761 // moreover, the next C string-taking `append()` had to
1762 // create anoter `ptr_node` instance but...
1763 a.append("xyz", 3);
1764 ASSERT_EQ(4u, bl.get_num_buffers());
1765
1766 // ... it should point to the same `buffer::raw` instance
1767 // (to the same same block of memory).
1768 ASSERT_EQ(bl.back().raw_c_str(), initial_back.raw_c_str());
1769 }
1770
1771 // check whether it'll take the first byte only and whether
1772 // the auto-flushing works.
1773 for (unsigned n = 0; n < 10 * CEPH_PAGE_SIZE - 3; ++n) {
1774 a.append("zasdf", 1);
1775 }
1776 }
1777
1778 {
1779 cout << bl << std::endl;
1780 ASSERT_EQ(6u, bl.get_num_buffers());
1781 }
1782
1783 // Verify that `page_aligned_appender` does respect the carrying
1784 // `_carriage` over multiple allocations. Although `append_zero()`
1785 // is used here, this affects other members of the append family.
1786 // This part would be crucial for e.g. `encode()`.
1787 {
1788 bl.append_zero(42);
1789 cout << bl << std::endl;
1790 ASSERT_EQ(6u, bl.get_num_buffers());
1791 }
1792 }
1793
1794 TEST(BufferList, rebuild_aligned_size_and_memory) {
1795 const unsigned SIMD_ALIGN = 32;
1796 const unsigned BUFFER_SIZE = 67;
1797
1798 bufferlist bl;
1799 // These two must be concatenated into one memory + size aligned
1800 // bufferptr
1801 {
1802 bufferptr ptr(buffer::create_aligned(2, SIMD_ALIGN));
1803 ptr.set_offset(1);
1804 ptr.set_length(1);
1805 bl.append(ptr);
1806 }
1807 {
1808 bufferptr ptr(buffer::create_aligned(BUFFER_SIZE - 1, SIMD_ALIGN));
1809 bl.append(ptr);
1810 }
1811 // This one must be left alone
1812 {
1813 bufferptr ptr(buffer::create_aligned(BUFFER_SIZE, SIMD_ALIGN));
1814 bl.append(ptr);
1815 }
1816 // These two must be concatenated into one memory + size aligned
1817 // bufferptr
1818 {
1819 bufferptr ptr(buffer::create_aligned(2, SIMD_ALIGN));
1820 ptr.set_offset(1);
1821 ptr.set_length(1);
1822 bl.append(ptr);
1823 }
1824 {
1825 bufferptr ptr(buffer::create_aligned(BUFFER_SIZE - 1, SIMD_ALIGN));
1826 bl.append(ptr);
1827 }
1828 EXPECT_FALSE(bl.is_aligned(SIMD_ALIGN));
1829 EXPECT_FALSE(bl.is_n_align_sized(BUFFER_SIZE));
1830 EXPECT_EQ(BUFFER_SIZE * 3, bl.length());
1831 EXPECT_FALSE(bl.front().is_aligned(SIMD_ALIGN));
1832 EXPECT_FALSE(bl.front().is_n_align_sized(BUFFER_SIZE));
1833 EXPECT_EQ(5U, bl.get_num_buffers());
1834 bl.rebuild_aligned_size_and_memory(BUFFER_SIZE, SIMD_ALIGN);
1835 EXPECT_TRUE(bl.is_aligned(SIMD_ALIGN));
1836 EXPECT_TRUE(bl.is_n_align_sized(BUFFER_SIZE));
1837 EXPECT_EQ(3U, bl.get_num_buffers());
1838
1839 {
1840 /* bug replicator, to test rebuild_aligned_size_and_memory() in the
1841 * scenario where the first bptr is both size and memory aligned and
1842 * the second is 0-length */
1843 bl.clear();
1844 bl.append(bufferptr{buffer::create_aligned(4096, 4096)});
1845 bufferptr ptr(buffer::create_aligned(42, 4096));
1846 /* bl.back().length() must be 0. offset set to 42 guarantees
1847 * the entire list is unaligned. */
1848 bl.append(ptr, 42, 0);
1849 EXPECT_EQ(bl.get_num_buffers(), 2);
1850 EXPECT_EQ(bl.back().length(), 0);
1851 EXPECT_FALSE(bl.is_aligned(4096));
1852 /* rebuild_aligned() calls rebuild_aligned_size_and_memory().
1853 * we assume the rebuild always happens. */
1854 EXPECT_TRUE(bl.rebuild_aligned(4096));
1855 EXPECT_EQ(bl.get_num_buffers(), 1);
1856 }
1857 }
1858
1859 TEST(BufferList, is_zero) {
1860 {
1861 bufferlist bl;
1862 EXPECT_TRUE(bl.is_zero());
1863 }
1864 {
1865 bufferlist bl;
1866 bl.append('A');
1867 EXPECT_FALSE(bl.is_zero());
1868 }
1869 {
1870 bufferlist bl;
1871 bl.append_zero(1);
1872 EXPECT_TRUE(bl.is_zero());
1873 }
1874
1875 for (size_t i = 1; i <= 256; ++i) {
1876 bufferlist bl;
1877 bl.append_zero(i);
1878 EXPECT_TRUE(bl.is_zero());
1879 bl.append('A');
1880 // ensure buffer is a single, contiguous before testing
1881 bl.rebuild();
1882 EXPECT_FALSE(bl.is_zero());
1883 }
1884
1885 }
1886
1887 TEST(BufferList, clear) {
1888 bufferlist bl;
1889 unsigned len = 17;
1890 bl.append_zero(len);
1891 bl.clear();
1892 EXPECT_EQ((unsigned)0, bl.length());
1893 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
1894 }
1895
1896 TEST(BufferList, push_back) {
1897 //
1898 // void push_back(ptr& bp)
1899 //
1900 {
1901 bufferlist bl;
1902 bufferptr ptr;
1903 bl.push_back(ptr);
1904 EXPECT_EQ((unsigned)0, bl.length());
1905 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
1906 }
1907 unsigned len = 17;
1908 {
1909 bufferlist bl;
1910 bl.append('A');
1911 bufferptr ptr(len);
1912 ptr.c_str()[0] = 'B';
1913 bl.push_back(ptr);
1914 EXPECT_EQ((unsigned)(1 + len), bl.length());
1915 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
1916 EXPECT_EQ('B', bl.back()[0]);
1917 const bufferptr& back_bp = bl.back();
1918 EXPECT_EQ(static_cast<instrumented_bptr&>(ptr).get_raw(),
1919 static_cast<const instrumented_bptr&>(back_bp).get_raw());
1920 }
1921 //
1922 // void push_back(ptr&& bp)
1923 //
1924 {
1925 bufferlist bl;
1926 bufferptr ptr;
1927 bl.push_back(std::move(ptr));
1928 EXPECT_EQ((unsigned)0, bl.length());
1929 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
1930 }
1931 {
1932 bufferlist bl;
1933 bl.append('A');
1934 bufferptr ptr(len);
1935 ptr.c_str()[0] = 'B';
1936 bl.push_back(std::move(ptr));
1937 EXPECT_EQ((unsigned)(1 + len), bl.length());
1938 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
1939 EXPECT_EQ('B', bl.buffers().back()[0]);
1940 EXPECT_FALSE(static_cast<instrumented_bptr&>(ptr).get_raw());
1941 }
1942 }
1943
1944 TEST(BufferList, is_contiguous) {
1945 bufferlist bl;
1946 EXPECT_TRUE(bl.is_contiguous());
1947 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
1948 bl.append('A');
1949 EXPECT_TRUE(bl.is_contiguous());
1950 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
1951 bufferptr ptr(1);
1952 bl.push_back(ptr);
1953 EXPECT_FALSE(bl.is_contiguous());
1954 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
1955 }
1956
1957 TEST(BufferList, rebuild) {
1958 {
1959 bufferlist bl;
1960 bufferptr ptr(buffer::create_page_aligned(2));
1961 ptr[0] = 'X';
1962 ptr[1] = 'Y';
1963 ptr.set_offset(1);
1964 ptr.set_length(1);
1965 bl.append(ptr);
1966 EXPECT_FALSE(bl.is_page_aligned());
1967 bl.rebuild();
1968 EXPECT_EQ(1U, bl.length());
1969 EXPECT_EQ('Y', *bl.begin());
1970 }
1971 {
1972 bufferlist bl;
1973 const std::string str(CEPH_PAGE_SIZE, 'X');
1974 bl.append(str.c_str(), str.size());
1975 bl.append(str.c_str(), str.size());
1976 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
1977 //EXPECT_TRUE(bl.is_aligned(CEPH_BUFFER_APPEND_SIZE));
1978 bl.rebuild();
1979 EXPECT_TRUE(bl.is_page_aligned());
1980 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
1981 }
1982 {
1983 bufferlist bl;
1984 char t1[] = "X";
1985 bufferlist a2;
1986 a2.append(t1, 1);
1987 bl.rebuild();
1988 bl.append(a2);
1989 EXPECT_EQ((unsigned)1, bl.length());
1990 bufferlist::iterator p = bl.begin();
1991 char dst[1];
1992 p.copy(1, dst);
1993 EXPECT_EQ(0, memcmp(dst, "X", 1));
1994 }
1995 }
1996
1997 TEST(BufferList, rebuild_page_aligned) {
1998 {
1999 bufferlist bl;
2000 {
2001 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1));
2002 ptr.set_offset(1);
2003 ptr.set_length(CEPH_PAGE_SIZE);
2004 bl.append(ptr);
2005 }
2006 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2007 EXPECT_FALSE(bl.is_page_aligned());
2008 bl.rebuild_page_aligned();
2009 EXPECT_TRUE(bl.is_page_aligned());
2010 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2011 }
2012 {
2013 bufferlist bl;
2014 bufferptr ptr(buffer::create_page_aligned(1));
2015 char *p = ptr.c_str();
2016 bl.append(ptr);
2017 bl.rebuild_page_aligned();
2018 EXPECT_EQ(p, bl.front().c_str());
2019 }
2020 {
2021 bufferlist bl;
2022 {
2023 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE));
2024 EXPECT_TRUE(ptr.is_page_aligned());
2025 EXPECT_TRUE(ptr.is_n_page_sized());
2026 bl.append(ptr);
2027 }
2028 {
2029 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1));
2030 EXPECT_TRUE(ptr.is_page_aligned());
2031 EXPECT_FALSE(ptr.is_n_page_sized());
2032 bl.append(ptr);
2033 }
2034 {
2035 bufferptr ptr(buffer::create_page_aligned(2));
2036 ptr.set_offset(1);
2037 ptr.set_length(1);
2038 EXPECT_FALSE(ptr.is_page_aligned());
2039 EXPECT_FALSE(ptr.is_n_page_sized());
2040 bl.append(ptr);
2041 }
2042 {
2043 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE - 2));
2044 EXPECT_TRUE(ptr.is_page_aligned());
2045 EXPECT_FALSE(ptr.is_n_page_sized());
2046 bl.append(ptr);
2047 }
2048 {
2049 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE));
2050 EXPECT_TRUE(ptr.is_page_aligned());
2051 EXPECT_TRUE(ptr.is_n_page_sized());
2052 bl.append(ptr);
2053 }
2054 {
2055 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1));
2056 ptr.set_offset(1);
2057 ptr.set_length(CEPH_PAGE_SIZE);
2058 EXPECT_FALSE(ptr.is_page_aligned());
2059 EXPECT_TRUE(ptr.is_n_page_sized());
2060 bl.append(ptr);
2061 }
2062 EXPECT_EQ((unsigned)6, bl.get_num_buffers());
2063 EXPECT_TRUE((bl.length() & ~CEPH_PAGE_MASK) == 0);
2064 EXPECT_FALSE(bl.is_page_aligned());
2065 bl.rebuild_page_aligned();
2066 EXPECT_TRUE(bl.is_page_aligned());
2067 EXPECT_EQ((unsigned)4, bl.get_num_buffers());
2068 }
2069 }
2070
2071 TEST(BufferList, claim_append) {
2072 bufferlist from;
2073 {
2074 bufferptr ptr(2);
2075 from.append(ptr);
2076 }
2077 bufferlist to;
2078 {
2079 bufferptr ptr(4);
2080 to.append(ptr);
2081 }
2082 EXPECT_EQ((unsigned)4, to.length());
2083 EXPECT_EQ((unsigned)1, to.get_num_buffers());
2084 to.claim_append(from);
2085 EXPECT_EQ((unsigned)(4 + 2), to.length());
2086 EXPECT_EQ((unsigned)4, to.front().length());
2087 EXPECT_EQ((unsigned)2, to.back().length());
2088 EXPECT_EQ((unsigned)2, to.get_num_buffers());
2089 EXPECT_EQ((unsigned)0, from.get_num_buffers());
2090 EXPECT_EQ((unsigned)0, from.length());
2091 }
2092
2093 TEST(BufferList, begin) {
2094 bufferlist bl;
2095 bl.append("ABC");
2096 bufferlist::iterator i = bl.begin();
2097 EXPECT_EQ('A', *i);
2098 }
2099
2100 TEST(BufferList, end) {
2101 bufferlist bl;
2102 bl.append("AB");
2103 bufferlist::iterator i = bl.end();
2104 bl.append("C");
2105 EXPECT_EQ('C', bl[i.get_off()]);
2106 }
2107
2108 TEST(BufferList, append) {
2109 //
2110 // void append(char c);
2111 //
2112 {
2113 bufferlist bl;
2114 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2115 bl.append('A');
2116 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2117 //EXPECT_TRUE(bl.is_aligned(CEPH_BUFFER_APPEND_SIZE));
2118 }
2119 //
2120 // void append(const char *data, unsigned len);
2121 //
2122 {
2123 bufferlist bl(CEPH_PAGE_SIZE);
2124 std::string str(CEPH_PAGE_SIZE * 2, 'X');
2125 bl.append(str.c_str(), str.size());
2126 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
2127 EXPECT_EQ(CEPH_PAGE_SIZE, bl.front().length());
2128 EXPECT_EQ(CEPH_PAGE_SIZE, bl.back().length());
2129 }
2130 //
2131 // void append(const std::string& s);
2132 //
2133 {
2134 bufferlist bl(CEPH_PAGE_SIZE);
2135 std::string str(CEPH_PAGE_SIZE * 2, 'X');
2136 bl.append(str);
2137 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
2138 EXPECT_EQ(CEPH_PAGE_SIZE, bl.front().length());
2139 EXPECT_EQ(CEPH_PAGE_SIZE, bl.back().length());
2140 }
2141 //
2142 // void append(const ptr& bp);
2143 //
2144 {
2145 bufferlist bl;
2146 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2147 EXPECT_EQ((unsigned)0, bl.length());
2148 {
2149 bufferptr ptr;
2150 bl.append(ptr);
2151 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2152 EXPECT_EQ((unsigned)0, bl.length());
2153 }
2154 {
2155 bufferptr ptr(3);
2156 bl.append(ptr);
2157 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2158 EXPECT_EQ((unsigned)3, bl.length());
2159 }
2160 }
2161 //
2162 // void append(const ptr& bp, unsigned off, unsigned len);
2163 //
2164 {
2165 bufferlist bl;
2166 bl.append('A');
2167 bufferptr back(bl.back());
2168 bufferptr in(back);
2169 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2170 EXPECT_EQ((unsigned)1, bl.length());
2171 {
2172 PrCtl unset_dumpable;
2173 EXPECT_DEATH(bl.append(in, (unsigned)100, (unsigned)100), "");
2174 }
2175 EXPECT_LT((unsigned)0, in.unused_tail_length());
2176 in.append('B');
2177 bl.append(in, back.end(), 1);
2178 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2179 EXPECT_EQ((unsigned)2, bl.length());
2180 EXPECT_EQ('B', bl[1]);
2181 }
2182 {
2183 bufferlist bl;
2184 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2185 EXPECT_EQ((unsigned)0, bl.length());
2186 bufferptr ptr(2);
2187 ptr.set_length(0);
2188 ptr.append("AB", 2);
2189 bl.append(ptr, 1, 1);
2190 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2191 EXPECT_EQ((unsigned)1, bl.length());
2192 }
2193 //
2194 // void append(const list& bl);
2195 //
2196 {
2197 bufferlist bl;
2198 bl.append('A');
2199 bufferlist other;
2200 other.append('B');
2201 bl.append(other);
2202 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
2203 EXPECT_EQ('B', bl[1]);
2204 }
2205 //
2206 // void append(std::istream& in);
2207 //
2208 {
2209 bufferlist bl;
2210 std::string expected("ABC\nDEF\n");
2211 std::istringstream is("ABC\n\nDEF");
2212 bl.append(is);
2213 EXPECT_EQ(0, ::memcmp(expected.c_str(), bl.c_str(), expected.size()));
2214 EXPECT_EQ(expected.size(), bl.length());
2215 }
2216 //
2217 // void append(ptr&& bp);
2218 //
2219 {
2220 bufferlist bl;
2221 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2222 EXPECT_EQ((unsigned)0, bl.length());
2223 {
2224 bufferptr ptr;
2225 bl.append(std::move(ptr));
2226 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2227 EXPECT_EQ((unsigned)0, bl.length());
2228 }
2229 {
2230 bufferptr ptr(3);
2231 bl.append(std::move(ptr));
2232 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2233 EXPECT_EQ((unsigned)3, bl.length());
2234 EXPECT_FALSE(static_cast<instrumented_bptr&>(ptr).get_raw());
2235 }
2236 }
2237 }
2238
2239 TEST(BufferList, append_hole) {
2240 {
2241 bufferlist bl;
2242 auto filler = bl.append_hole(1);
2243 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2244 EXPECT_EQ((unsigned)1, bl.length());
2245
2246 bl.append("BC", 2);
2247 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2248 EXPECT_EQ((unsigned)3, bl.length());
2249
2250 const char a = 'A';
2251 filler.copy_in((unsigned)1, &a);
2252 EXPECT_EQ((unsigned)3, bl.length());
2253
2254 EXPECT_EQ(0, ::memcmp("ABC", bl.c_str(), 3));
2255 }
2256
2257 {
2258 bufferlist bl;
2259 bl.append('A');
2260 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2261 EXPECT_EQ((unsigned)1, bl.length());
2262
2263 auto filler = bl.append_hole(1);
2264 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2265 EXPECT_EQ((unsigned)2, bl.length());
2266
2267 bl.append('C');
2268 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2269 EXPECT_EQ((unsigned)3, bl.length());
2270
2271 const char b = 'B';
2272 filler.copy_in((unsigned)1, &b);
2273 EXPECT_EQ((unsigned)3, bl.length());
2274
2275 EXPECT_EQ(0, ::memcmp("ABC", bl.c_str(), 3));
2276 }
2277 }
2278
2279 TEST(BufferList, append_zero) {
2280 bufferlist bl;
2281 bl.append('A');
2282 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2283 EXPECT_EQ((unsigned)1, bl.length());
2284 bl.append_zero(1);
2285 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2286 EXPECT_EQ((unsigned)2, bl.length());
2287 EXPECT_EQ('\0', bl[1]);
2288 }
2289
2290 TEST(BufferList, operator_brackets) {
2291 bufferlist bl;
2292 EXPECT_THROW(bl[1], buffer::end_of_buffer);
2293 bl.append('A');
2294 bufferlist other;
2295 other.append('B');
2296 bl.append(other);
2297 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
2298 EXPECT_EQ('B', bl[1]);
2299 }
2300
2301 TEST(BufferList, c_str) {
2302 bufferlist bl;
2303 EXPECT_EQ((const char*)NULL, bl.c_str());
2304 bl.append('A');
2305 bufferlist other;
2306 other.append('B');
2307 bl.append(other);
2308 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
2309 EXPECT_EQ(0, ::memcmp("AB", bl.c_str(), 2));
2310 }
2311
2312 TEST(BufferList, c_str_carriage) {
2313 // verify the c_str() optimization for carriage handling
2314 buffer::ptr bp("A", 1);
2315 bufferlist bl;
2316 bl.append(bp);
2317 bl.append('B');
2318 EXPECT_EQ(2U, bl.get_num_buffers());
2319 EXPECT_EQ(2U, bl.length());
2320
2321 // this should leave an empty bptr for carriage at the end of the bl
2322 bl.splice(1, 1);
2323 EXPECT_EQ(2U, bl.get_num_buffers());
2324 EXPECT_EQ(1U, bl.length());
2325
2326 std::ignore = bl.c_str();
2327 // if we have an empty bptr at the end, we don't need to rebuild
2328 EXPECT_EQ(2U, bl.get_num_buffers());
2329 }
2330
2331 TEST(BufferList, substr_of) {
2332 bufferlist bl;
2333 EXPECT_THROW(bl.substr_of(bl, 1, 1), buffer::end_of_buffer);
2334 const char *s[] = {
2335 "ABC",
2336 "DEF",
2337 "GHI",
2338 "JKL"
2339 };
2340 for (unsigned i = 0; i < 4; i++) {
2341 bufferptr ptr(s[i], strlen(s[i]));
2342 bl.push_back(ptr);
2343 }
2344 EXPECT_EQ((unsigned)4, bl.get_num_buffers());
2345
2346 bufferlist other;
2347 other.append("TO BE CLEARED");
2348 other.substr_of(bl, 4, 4);
2349 EXPECT_EQ((unsigned)2, other.get_num_buffers());
2350 EXPECT_EQ((unsigned)4, other.length());
2351 EXPECT_EQ(0, ::memcmp("EFGH", other.c_str(), 4));
2352 }
2353
2354 TEST(BufferList, splice) {
2355 bufferlist bl;
2356 EXPECT_THROW(bl.splice(1, 1), buffer::end_of_buffer);
2357 const char *s[] = {
2358 "ABC",
2359 "DEF",
2360 "GHI",
2361 "JKL"
2362 };
2363 for (unsigned i = 0; i < 4; i++) {
2364 bufferptr ptr(s[i], strlen(s[i]));
2365 bl.push_back(ptr);
2366 }
2367 EXPECT_EQ((unsigned)4, bl.get_num_buffers());
2368 bl.splice(0, 0);
2369
2370 bufferlist other;
2371 other.append('X');
2372 bl.splice(4, 4, &other);
2373 EXPECT_EQ((unsigned)3, other.get_num_buffers());
2374 EXPECT_EQ((unsigned)5, other.length());
2375 EXPECT_EQ(0, ::memcmp("XEFGH", other.c_str(), other.length()));
2376 EXPECT_EQ((unsigned)8, bl.length());
2377 {
2378 bufferlist tmp(bl);
2379 EXPECT_EQ(0, ::memcmp("ABCDIJKL", tmp.c_str(), tmp.length()));
2380 }
2381
2382 bl.splice(4, 4);
2383 EXPECT_EQ((unsigned)4, bl.length());
2384 EXPECT_EQ(0, ::memcmp("ABCD", bl.c_str(), bl.length()));
2385
2386 {
2387 bl.clear();
2388 bufferptr ptr1("0123456789", 10);
2389 bl.push_back(ptr1);
2390 bufferptr ptr2("abcdefghij", 10);
2391 bl.append(ptr2, 5, 5);
2392 other.clear();
2393 bl.splice(10, 4, &other);
2394 EXPECT_EQ((unsigned)11, bl.length());
2395 EXPECT_EQ(0, ::memcmp("fghi", other.c_str(), other.length()));
2396 }
2397 }
2398
2399 TEST(BufferList, write) {
2400 std::ostringstream stream;
2401 bufferlist bl;
2402 bl.append("ABC");
2403 bl.write(1, 2, stream);
2404 EXPECT_EQ("BC", stream.str());
2405 }
2406
2407 TEST(BufferList, encode_base64) {
2408 bufferlist bl;
2409 bl.append("ABCD");
2410 bufferlist other;
2411 bl.encode_base64(other);
2412 const char *expected = "QUJDRA==";
2413 EXPECT_EQ(0, ::memcmp(expected, other.c_str(), strlen(expected)));
2414 }
2415
2416 TEST(BufferList, decode_base64) {
2417 bufferlist bl;
2418 bl.append("QUJDRA==");
2419 bufferlist other;
2420 other.decode_base64(bl);
2421 const char *expected = "ABCD";
2422 EXPECT_EQ(0, ::memcmp(expected, other.c_str(), strlen(expected)));
2423 bufferlist malformed;
2424 malformed.append("QUJDRA");
2425 EXPECT_THROW(other.decode_base64(malformed), buffer::malformed_input);
2426 }
2427
2428 TEST(BufferList, hexdump) {
2429 bufferlist bl;
2430 std::ostringstream stream;
2431 bl.append("013245678901234\0006789012345678901234", 32);
2432 bl.hexdump(stream);
2433 EXPECT_EQ("00000000 30 31 33 32 34 35 36 37 38 39 30 31 32 33 34 00 |013245678901234.|\n"
2434 "00000010 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 |6789012345678901|\n"
2435 "00000020\n",
2436 stream.str());
2437 }
2438
2439 TEST(BufferList, read_file) {
2440 std::string error;
2441 bufferlist bl;
2442 ::unlink(FILENAME);
2443 EXPECT_EQ(-ENOENT, bl.read_file("UNLIKELY", &error));
2444 snprintf(cmd, sizeof(cmd), "echo ABC> %s", FILENAME);
2445 EXPECT_EQ(0, ::system(cmd));
2446 #ifndef _WIN32
2447 snprintf(cmd, sizeof(cmd), "chmod 0 %s", FILENAME);
2448 EXPECT_EQ(0, ::system(cmd));
2449 if (getuid() != 0) {
2450 EXPECT_EQ(-EACCES, bl.read_file(FILENAME, &error));
2451 }
2452 snprintf(cmd, sizeof(cmd), "chmod +r %s", FILENAME);
2453 EXPECT_EQ(0, ::system(cmd));
2454 #endif /* _WIN32 */
2455 EXPECT_EQ(0, bl.read_file(FILENAME, &error));
2456 ::unlink(FILENAME);
2457 EXPECT_EQ((unsigned)4, bl.length());
2458 std::string actual(bl.c_str(), bl.length());
2459 EXPECT_EQ("ABC\n", actual);
2460 }
2461
2462 TEST(BufferList, read_fd) {
2463 unsigned len = 4;
2464 ::unlink(FILENAME);
2465 snprintf(cmd, sizeof(cmd), "echo ABC > %s", FILENAME);
2466 EXPECT_EQ(0, ::system(cmd));
2467 int fd = -1;
2468 bufferlist bl;
2469 EXPECT_EQ(-EBADF, bl.read_fd(fd, len));
2470 fd = ::open(FILENAME, O_RDONLY);
2471 ASSERT_NE(-1, fd);
2472 EXPECT_EQ(len, (unsigned)bl.read_fd(fd, len));
2473 //EXPECT_EQ(CEPH_BUFFER_APPEND_SIZE - len, bl.front().unused_tail_length());
2474 EXPECT_EQ(len, bl.length());
2475 ::close(fd);
2476 ::unlink(FILENAME);
2477 }
2478
2479 TEST(BufferList, write_file) {
2480 ::unlink(FILENAME);
2481 int mode = 0600;
2482 bufferlist bl;
2483 EXPECT_EQ(-ENOENT, bl.write_file("un/like/ly", mode));
2484 bl.append("ABC");
2485 EXPECT_EQ(0, bl.write_file(FILENAME, mode));
2486 struct stat st;
2487 memset(&st, 0, sizeof(st));
2488 ASSERT_EQ(0, ::stat(FILENAME, &st));
2489 #ifndef _WIN32
2490 EXPECT_EQ((unsigned)(mode | S_IFREG), st.st_mode);
2491 #endif
2492 ::unlink(FILENAME);
2493 }
2494
2495 TEST(BufferList, write_fd) {
2496 ::unlink(FILENAME);
2497 int fd = ::open(FILENAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
2498 ASSERT_NE(-1, fd);
2499 bufferlist bl;
2500 for (unsigned i = 0; i < IOV_MAX * 2; i++) {
2501 bufferptr ptr("A", 1);
2502 bl.push_back(ptr);
2503 }
2504 EXPECT_EQ(0, bl.write_fd(fd));
2505 ::close(fd);
2506 struct stat st;
2507 memset(&st, 0, sizeof(st));
2508 ASSERT_EQ(0, ::stat(FILENAME, &st));
2509 EXPECT_EQ(IOV_MAX * 2, st.st_size);
2510 ::unlink(FILENAME);
2511 }
2512
2513 TEST(BufferList, write_fd_offset) {
2514 ::unlink(FILENAME);
2515 int fd = ::open(FILENAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
2516 ASSERT_NE(-1, fd);
2517 bufferlist bl;
2518 for (unsigned i = 0; i < IOV_MAX * 2; i++) {
2519 bufferptr ptr("A", 1);
2520 bl.push_back(ptr);
2521 }
2522 uint64_t offset = 200;
2523 EXPECT_EQ(0, bl.write_fd(fd, offset));
2524 ::close(fd);
2525 struct stat st;
2526 memset(&st, 0, sizeof(st));
2527 ASSERT_EQ(0, ::stat(FILENAME, &st));
2528 EXPECT_EQ(IOV_MAX * 2 + offset, (unsigned)st.st_size);
2529 ::unlink(FILENAME);
2530 }
2531
2532 TEST(BufferList, crc32c) {
2533 bufferlist bl;
2534 __u32 crc = 0;
2535 bl.append("A");
2536 crc = bl.crc32c(crc);
2537 EXPECT_EQ((unsigned)0xB3109EBF, crc);
2538 crc = bl.crc32c(crc);
2539 EXPECT_EQ((unsigned)0x5FA5C0CC, crc);
2540 }
2541
2542 TEST(BufferList, crc32c_append) {
2543 bufferlist bl1;
2544 bufferlist bl2;
2545
2546 for (int j = 0; j < 200; ++j) {
2547 bufferlist bl;
2548 for (int i = 0; i < 200; ++i) {
2549 char x = rand();
2550 bl.append(x);
2551 bl1.append(x);
2552 }
2553 bl.crc32c(rand()); // mess with the cached bufferptr crc values
2554 bl2.append(bl);
2555 }
2556 ASSERT_EQ(bl1.crc32c(0), bl2.crc32c(0));
2557 }
2558
2559 TEST(BufferList, crc32c_zeros) {
2560 char buffer[4*1024];
2561 for (size_t i=0; i < sizeof(buffer); i++)
2562 {
2563 buffer[i] = i;
2564 }
2565
2566 bufferlist bla;
2567 bufferlist blb;
2568
2569 for (size_t j=0; j < 1000; j++)
2570 {
2571 bufferptr a(buffer, sizeof(buffer));
2572
2573 bla.push_back(a);
2574 uint32_t crca = bla.crc32c(111);
2575
2576 blb.push_back(a);
2577 uint32_t crcb = ceph_crc32c(111, (unsigned char*)blb.c_str(), blb.length());
2578
2579 EXPECT_EQ(crca, crcb);
2580 }
2581 }
2582
2583 TEST(BufferList, crc32c_append_perf) {
2584 int len = 256 * 1024 * 1024;
2585 bufferptr a(len);
2586 bufferptr b(len);
2587 bufferptr c(len);
2588 bufferptr d(len);
2589 std::cout << "populating large buffers (a, b=c=d)" << std::endl;
2590 char *pa = a.c_str();
2591 char *pb = b.c_str();
2592 char *pc = c.c_str();
2593 char *pd = c.c_str();
2594 for (int i=0; i<len; i++) {
2595 pa[i] = (i & 0xff) ^ 73;
2596 pb[i] = (i & 0xff) ^ 123;
2597 pc[i] = (i & 0xff) ^ 123;
2598 pd[i] = (i & 0xff) ^ 123;
2599 }
2600
2601 // track usage of cached crcs
2602 buffer::track_cached_crc(true);
2603
2604 [[maybe_unused]] int base_cached = buffer::get_cached_crc();
2605 [[maybe_unused]] int base_cached_adjusted = buffer::get_cached_crc_adjusted();
2606
2607 bufferlist bla;
2608 bla.push_back(a);
2609 bufferlist blb;
2610 blb.push_back(b);
2611 {
2612 utime_t start = ceph_clock_now();
2613 uint32_t r = bla.crc32c(0);
2614 utime_t end = ceph_clock_now();
2615 float rate = (float)len / (float)(1024*1024) / (float)(end - start);
2616 std::cout << "a.crc32c(0) = " << r << " at " << rate << " MB/sec" << std::endl;
2617 ASSERT_EQ(r, 1138817026u);
2618 }
2619 ceph_assert(buffer::get_cached_crc() == 0 + base_cached);
2620 {
2621 utime_t start = ceph_clock_now();
2622 uint32_t r = bla.crc32c(0);
2623 utime_t end = ceph_clock_now();
2624 float rate = (float)len / (float)(1024*1024) / (float)(end - start);
2625 std::cout << "a.crc32c(0) (again) = " << r << " at " << rate << " MB/sec" << std::endl;
2626 ASSERT_EQ(r, 1138817026u);
2627 }
2628 ceph_assert(buffer::get_cached_crc() == 1 + base_cached);
2629
2630 {
2631 utime_t start = ceph_clock_now();
2632 uint32_t r = bla.crc32c(5);
2633 utime_t end = ceph_clock_now();
2634 float rate = (float)len / (float)(1024*1024) / (float)(end - start);
2635 std::cout << "a.crc32c(5) = " << r << " at " << rate << " MB/sec" << std::endl;
2636 ASSERT_EQ(r, 3239494520u);
2637 }
2638 ceph_assert(buffer::get_cached_crc() == 1 + base_cached);
2639 ceph_assert(buffer::get_cached_crc_adjusted() == 1 + base_cached_adjusted);
2640 {
2641 utime_t start = ceph_clock_now();
2642 uint32_t r = bla.crc32c(5);
2643 utime_t end = ceph_clock_now();
2644 float rate = (float)len / (float)(1024*1024) / (float)(end - start);
2645 std::cout << "a.crc32c(5) (again) = " << r << " at " << rate << " MB/sec" << std::endl;
2646 ASSERT_EQ(r, 3239494520u);
2647 }
2648 ceph_assert(buffer::get_cached_crc() == 1 + base_cached);
2649 ceph_assert(buffer::get_cached_crc_adjusted() == 2 + base_cached_adjusted);
2650 {
2651 utime_t start = ceph_clock_now();
2652 uint32_t r = blb.crc32c(0);
2653 utime_t end = ceph_clock_now();
2654 float rate = (float)len / (float)(1024*1024) / (float)(end - start);
2655 std::cout << "b.crc32c(0) = " << r << " at " << rate << " MB/sec" << std::endl;
2656 ASSERT_EQ(r, 2481791210u);
2657 }
2658 ceph_assert(buffer::get_cached_crc() == 1 + base_cached);
2659 {
2660 utime_t start = ceph_clock_now();
2661 uint32_t r = blb.crc32c(0);
2662 utime_t end = ceph_clock_now();
2663 float rate = (float)len / (float)(1024*1024) / (float)(end - start);
2664 std::cout << "b.crc32c(0) (again)= " << r << " at " << rate << " MB/sec" << std::endl;
2665 ASSERT_EQ(r, 2481791210u);
2666 }
2667 ceph_assert(buffer::get_cached_crc() == 2 + base_cached);
2668
2669 bufferlist ab;
2670 ab.push_back(a);
2671 ab.push_back(b);
2672 {
2673 utime_t start = ceph_clock_now();
2674 uint32_t r = ab.crc32c(0);
2675 utime_t end = ceph_clock_now();
2676 float rate = (float)ab.length() / (float)(1024*1024) / (float)(end - start);
2677 std::cout << "ab.crc32c(0) = " << r << " at " << rate << " MB/sec" << std::endl;
2678 ASSERT_EQ(r, 2988268779u);
2679 }
2680 ceph_assert(buffer::get_cached_crc() == 3 + base_cached);
2681 ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted);
2682 bufferlist ac;
2683 ac.push_back(a);
2684 ac.push_back(c);
2685 {
2686 utime_t start = ceph_clock_now();
2687 uint32_t r = ac.crc32c(0);
2688 utime_t end = ceph_clock_now();
2689 float rate = (float)ac.length() / (float)(1024*1024) / (float)(end - start);
2690 std::cout << "ac.crc32c(0) = " << r << " at " << rate << " MB/sec" << std::endl;
2691 ASSERT_EQ(r, 2988268779u);
2692 }
2693 ceph_assert(buffer::get_cached_crc() == 4 + base_cached);
2694 ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted);
2695
2696 bufferlist ba;
2697 ba.push_back(b);
2698 ba.push_back(a);
2699 {
2700 utime_t start = ceph_clock_now();
2701 uint32_t r = ba.crc32c(0);
2702 utime_t end = ceph_clock_now();
2703 float rate = (float)ba.length() / (float)(1024*1024) / (float)(end - start);
2704 std::cout << "ba.crc32c(0) = " << r << " at " << rate << " MB/sec" << std::endl;
2705 ASSERT_EQ(r, 169240695u);
2706 }
2707 ceph_assert(buffer::get_cached_crc() == 5 + base_cached);
2708 ceph_assert(buffer::get_cached_crc_adjusted() == 4 + base_cached_adjusted);
2709 {
2710 utime_t start = ceph_clock_now();
2711 uint32_t r = ba.crc32c(5);
2712 utime_t end = ceph_clock_now();
2713 float rate = (float)ba.length() / (float)(1024*1024) / (float)(end - start);
2714 std::cout << "ba.crc32c(5) = " << r << " at " << rate << " MB/sec" << std::endl;
2715 ASSERT_EQ(r, 1265464778u);
2716 }
2717 ceph_assert(buffer::get_cached_crc() == 5 + base_cached);
2718 ceph_assert(buffer::get_cached_crc_adjusted() == 6 + base_cached_adjusted);
2719
2720 cout << "crc cache hits (same start) = " << buffer::get_cached_crc() << std::endl;
2721 cout << "crc cache hits (adjusted) = " << buffer::get_cached_crc_adjusted() << std::endl;
2722 }
2723
2724 TEST(BufferList, compare) {
2725 bufferlist a;
2726 a.append("A");
2727 bufferlist ab; // AB in segments
2728 ab.append(bufferptr("A", 1));
2729 ab.append(bufferptr("B", 1));
2730 bufferlist ac;
2731 ac.append("AC");
2732 //
2733 // bool operator>(bufferlist& l, bufferlist& r)
2734 //
2735 ASSERT_FALSE(a > ab);
2736 ASSERT_TRUE(ab > a);
2737 ASSERT_TRUE(ac > ab);
2738 ASSERT_FALSE(ab > ac);
2739 ASSERT_FALSE(ab > ab);
2740 //
2741 // bool operator>=(bufferlist& l, bufferlist& r)
2742 //
2743 ASSERT_FALSE(a >= ab);
2744 ASSERT_TRUE(ab >= a);
2745 ASSERT_TRUE(ac >= ab);
2746 ASSERT_FALSE(ab >= ac);
2747 ASSERT_TRUE(ab >= ab);
2748 //
2749 // bool operator<(bufferlist& l, bufferlist& r)
2750 //
2751 ASSERT_TRUE(a < ab);
2752 ASSERT_FALSE(ab < a);
2753 ASSERT_FALSE(ac < ab);
2754 ASSERT_TRUE(ab < ac);
2755 ASSERT_FALSE(ab < ab);
2756 //
2757 // bool operator<=(bufferlist& l, bufferlist& r)
2758 //
2759 ASSERT_TRUE(a <= ab);
2760 ASSERT_FALSE(ab <= a);
2761 ASSERT_FALSE(ac <= ab);
2762 ASSERT_TRUE(ab <= ac);
2763 ASSERT_TRUE(ab <= ab);
2764 //
2765 // bool operator==(bufferlist &l, bufferlist &r)
2766 //
2767 ASSERT_FALSE(a == ab);
2768 ASSERT_FALSE(ac == ab);
2769 ASSERT_TRUE(ab == ab);
2770 }
2771
2772 TEST(BufferList, ostream) {
2773 std::ostringstream stream;
2774 bufferlist bl;
2775 const char *s[] = {
2776 "ABC",
2777 "DEF"
2778 };
2779 for (unsigned i = 0; i < 2; i++) {
2780 bufferptr ptr(s[i], strlen(s[i]));
2781 bl.push_back(ptr);
2782 }
2783 stream << bl;
2784 std::cerr << stream.str() << std::endl;
2785 EXPECT_GT(stream.str().size(), stream.str().find("list(len=6,"));
2786 EXPECT_GT(stream.str().size(), stream.str().find("len 3 nref 1),\n"));
2787 EXPECT_GT(stream.str().size(), stream.str().find("len 3 nref 1)\n"));
2788 }
2789
2790 TEST(BufferList, zero) {
2791 //
2792 // void zero()
2793 //
2794 {
2795 bufferlist bl;
2796 bl.append('A');
2797 EXPECT_EQ('A', bl[0]);
2798 bl.zero();
2799 EXPECT_EQ('\0', bl[0]);
2800 }
2801 //
2802 // void zero(unsigned o, unsigned l)
2803 //
2804 const char *s[] = {
2805 "ABC",
2806 "DEF",
2807 "GHI",
2808 "KLM"
2809 };
2810 {
2811 bufferlist bl;
2812 bufferptr ptr(s[0], strlen(s[0]));
2813 bl.push_back(ptr);
2814 bl.zero((unsigned)0, (unsigned)1);
2815 EXPECT_EQ(0, ::memcmp("\0BC", bl.c_str(), 3));
2816 }
2817 {
2818 bufferlist bl;
2819 for (unsigned i = 0; i < 4; i++) {
2820 bufferptr ptr(s[i], strlen(s[i]));
2821 bl.push_back(ptr);
2822 }
2823 {
2824 PrCtl unset_dumpable;
2825 EXPECT_DEATH(bl.zero((unsigned)0, (unsigned)2000), "");
2826 }
2827 bl.zero((unsigned)2, (unsigned)5);
2828 EXPECT_EQ(0, ::memcmp("AB\0\0\0\0\0HIKLM", bl.c_str(), 9));
2829 }
2830 {
2831 bufferlist bl;
2832 for (unsigned i = 0; i < 4; i++) {
2833 bufferptr ptr(s[i], strlen(s[i]));
2834 bl.push_back(ptr);
2835 }
2836 bl.zero((unsigned)3, (unsigned)3);
2837 EXPECT_EQ(0, ::memcmp("ABC\0\0\0GHIKLM", bl.c_str(), 9));
2838 }
2839 {
2840 bufferlist bl;
2841 bufferptr ptr1(4);
2842 bufferptr ptr2(4);
2843 memset(ptr1.c_str(), 'a', 4);
2844 memset(ptr2.c_str(), 'b', 4);
2845 bl.append(ptr1);
2846 bl.append(ptr2);
2847 bl.zero((unsigned)2, (unsigned)4);
2848 EXPECT_EQ(0, ::memcmp("aa\0\0\0\0bb", bl.c_str(), 8));
2849 }
2850 }
2851
2852 TEST(BufferList, EmptyAppend) {
2853 bufferlist bl;
2854 bufferptr ptr;
2855 bl.push_back(ptr);
2856 ASSERT_EQ(bl.begin().end(), 1);
2857 }
2858
2859 TEST(BufferList, InternalCarriage) {
2860 ceph::bufferlist bl;
2861 EXPECT_EQ(bl.get_num_buffers(), 0u);
2862
2863 encode(int64_t(42), bl);
2864 EXPECT_EQ(bl.get_num_buffers(), 1u);
2865
2866 {
2867 ceph::bufferlist bl_with_foo;
2868 bl_with_foo.append("foo", 3);
2869 EXPECT_EQ(bl_with_foo.length(), 3u);
2870 EXPECT_EQ(bl_with_foo.get_num_buffers(), 1u);
2871
2872 bl.append(bl_with_foo);
2873 EXPECT_EQ(bl.get_num_buffers(), 2u);
2874 }
2875
2876 encode(int64_t(24), bl);
2877 EXPECT_EQ(bl.get_num_buffers(), 3u);
2878 }
2879
2880 TEST(BufferList, ContiguousAppender) {
2881 ceph::bufferlist bl;
2882 EXPECT_EQ(bl.get_num_buffers(), 0u);
2883
2884 // we expect a flush in ~contiguous_appender
2885 {
2886 auto ap = bl.get_contiguous_appender(100);
2887
2888 denc(int64_t(42), ap);
2889 EXPECT_EQ(bl.get_num_buffers(), 1u);
2890
2891 // append bufferlist with single ptr inside. This should
2892 // commit changes to bl::_len and the underlying bp::len.
2893 {
2894 ceph::bufferlist bl_with_foo;
2895 bl_with_foo.append("foo", 3);
2896 EXPECT_EQ(bl_with_foo.length(), 3u);
2897 EXPECT_EQ(bl_with_foo.get_num_buffers(), 1u);
2898
2899 ap.append(bl_with_foo);
2900 // 3 as the ap::append(const bl&) splits the bp with free
2901 // space.
2902 EXPECT_EQ(bl.get_num_buffers(), 3u);
2903 }
2904
2905 denc(int64_t(24), ap);
2906 EXPECT_EQ(bl.get_num_buffers(), 3u);
2907 EXPECT_EQ(bl.length(), sizeof(int64_t) + 3u);
2908 }
2909 EXPECT_EQ(bl.length(), 2u * sizeof(int64_t) + 3u);
2910 }
2911
2912 TEST(BufferList, TestPtrAppend) {
2913 bufferlist bl;
2914 char correct[MAX_TEST];
2915 int curpos = 0;
2916 int length = random() % 5 > 0 ? random() % 1000 : 0;
2917 while (curpos + length < MAX_TEST) {
2918 if (!length) {
2919 bufferptr ptr;
2920 bl.push_back(ptr);
2921 } else {
2922 char *current = correct + curpos;
2923 for (int i = 0; i < length; ++i) {
2924 char next = random() % 255;
2925 correct[curpos++] = next;
2926 }
2927 bufferptr ptr(current, length);
2928 bl.append(ptr);
2929 }
2930 length = random() % 5 > 0 ? random() % 1000 : 0;
2931 }
2932 ASSERT_EQ(memcmp(bl.c_str(), correct, curpos), 0);
2933 }
2934
2935 TEST(BufferList, TestDirectAppend) {
2936 bufferlist bl;
2937 char correct[MAX_TEST];
2938 int curpos = 0;
2939 int length = random() % 5 > 0 ? random() % 1000 : 0;
2940 while (curpos + length < MAX_TEST) {
2941 char *current = correct + curpos;
2942 for (int i = 0; i < length; ++i) {
2943 char next = random() % 255;
2944 correct[curpos++] = next;
2945 }
2946 bl.append(current, length);
2947 length = random() % 5 > 0 ? random() % 1000 : 0;
2948 }
2949 ASSERT_EQ(memcmp(bl.c_str(), correct, curpos), 0);
2950 }
2951
2952 TEST(BufferList, TestCopyAll) {
2953 const static size_t BIG_SZ = 10737414;
2954 std::shared_ptr <unsigned char> big(
2955 (unsigned char*)malloc(BIG_SZ), free);
2956 unsigned char c = 0;
2957 for (size_t i = 0; i < BIG_SZ; ++i) {
2958 big.get()[i] = c++;
2959 }
2960 bufferlist bl;
2961 bl.append((const char*)big.get(), BIG_SZ);
2962 bufferlist::iterator i = bl.begin();
2963 bufferlist bl2;
2964 i.copy_all(bl2);
2965 ASSERT_EQ(bl2.length(), BIG_SZ);
2966 std::shared_ptr <unsigned char> big2(
2967 (unsigned char*)malloc(BIG_SZ), free);
2968 bl2.begin().copy(BIG_SZ, (char*)big2.get());
2969 ASSERT_EQ(memcmp(big.get(), big2.get(), BIG_SZ), 0);
2970 }
2971
2972 TEST(BufferList, InvalidateCrc) {
2973 const static size_t buffer_size = 262144;
2974 std::shared_ptr <unsigned char> big(
2975 (unsigned char*)malloc(buffer_size), free);
2976 unsigned char c = 0;
2977 char* ptr = (char*) big.get();
2978 char* inptr;
2979 for (size_t i = 0; i < buffer_size; ++i) {
2980 ptr[i] = c++;
2981 }
2982 bufferlist bl;
2983
2984 // test for crashes (shouldn't crash)
2985 bl.invalidate_crc();
2986
2987 // put data into bufferlist
2988 bl.append((const char*)big.get(), buffer_size);
2989
2990 // get its crc
2991 __u32 crc = bl.crc32c(0);
2992
2993 // modify data in bl without its knowledge
2994 inptr = (char*) bl.c_str();
2995 c = 0;
2996 for (size_t i = 0; i < buffer_size; ++i) {
2997 inptr[i] = c--;
2998 }
2999
3000 // make sure data in bl are now different than in big
3001 EXPECT_NE(memcmp((void*) ptr, (void*) inptr, buffer_size), 0);
3002
3003 // crc should remain the same
3004 __u32 new_crc = bl.crc32c(0);
3005 EXPECT_EQ(crc, new_crc);
3006
3007 // force crc invalidate, check if it is updated
3008 bl.invalidate_crc();
3009 EXPECT_NE(crc, bl.crc32c(0));
3010 }
3011
3012 TEST(BufferList, TestIsProvidedBuffer) {
3013 char buff[100];
3014 bufferlist bl;
3015 bl.push_back(buffer::create_static(100, buff));
3016 ASSERT_TRUE(bl.is_provided_buffer(buff));
3017 bl.append_zero(100);
3018 ASSERT_FALSE(bl.is_provided_buffer(buff));
3019 }
3020
3021 TEST(BufferList, DISABLED_DanglingLastP) {
3022 bufferlist bl;
3023 {
3024 // previously we're using the unsharable buffer type to distinguish
3025 // the last_p-specific problem from the generic crosstalk issues we
3026 // had since the very beginning:
3027 // https://gist.github.com/rzarzynski/aed18372e88aed392101adac3bd87bbc
3028 // this is no longer possible as `buffer::create_unsharable()` has
3029 // been dropped.
3030 bufferptr bp(buffer::create(10));
3031 bp.copy_in(0, 3, "XXX");
3032 bl.push_back(std::move(bp));
3033 EXPECT_EQ(0, ::memcmp("XXX", bl.c_str(), 3));
3034
3035 // let `copy_in` to set `last_p` member of bufferlist
3036 bl.begin().copy_in(2, "AB");
3037 EXPECT_EQ(0, ::memcmp("ABX", bl.c_str(), 3));
3038 }
3039
3040 bufferlist empty;
3041 // before the fix this would have left `last_p` unchanged leading to
3042 // the dangerous dangling state – keep in mind that the initial,
3043 // unsharable bptr will be freed.
3044 bl = const_cast<const bufferlist&>(empty);
3045 bl.append("123");
3046
3047 // we must continue from where the previous copy_in had finished.
3048 // Otherwise `bl::copy_in` will call `seek()` and refresh `last_p`.
3049 bl.begin(2).copy_in(1, "C");
3050 EXPECT_EQ(0, ::memcmp("12C", bl.c_str(), 3));
3051 }
3052
3053 TEST(BufferHash, all) {
3054 {
3055 bufferlist bl;
3056 bl.append("A");
3057 bufferhash hash;
3058 EXPECT_EQ((unsigned)0, hash.digest());
3059 hash.update(bl);
3060 EXPECT_EQ((unsigned)0xB3109EBF, hash.digest());
3061 hash.update(bl);
3062 EXPECT_EQ((unsigned)0x5FA5C0CC, hash.digest());
3063 }
3064 {
3065 bufferlist bl;
3066 bl.append("A");
3067 bufferhash hash;
3068 EXPECT_EQ((unsigned)0, hash.digest());
3069 bufferhash& returned_hash = hash << bl;
3070 EXPECT_EQ(&returned_hash, &hash);
3071 EXPECT_EQ((unsigned)0xB3109EBF, hash.digest());
3072 }
3073 }
3074
3075 /*
3076 * Local Variables:
3077 * compile-command: "cd .. ; make unittest_bufferlist &&
3078 * ulimit -s unlimited ; valgrind \
3079 * --max-stackframe=20000000 --tool=memcheck \
3080 * ./unittest_bufferlist # --gtest_filter=BufferList.constructors"
3081 * End:
3082 */
3083