1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
8 * Author: Loic Dachary <loic@dachary.org>
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)
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.
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"
37 #include "gtest/gtest.h"
41 #include "include/crc32c.h"
42 #include "common/sctp_crc32.h"
44 #define MAX_TEST 1000000
45 #define FILENAME "bufferlist"
51 using ceph::buffer_instrumentation::instrumented_bptr
;
53 TEST(Buffer
, constructors
) {
59 bufferptr
ptr(buffer::create(len
));
60 EXPECT_EQ(len
, ptr
.length());
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
));
75 // buffer::create_static
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());
85 // buffer::create_malloc
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);
94 // buffer::claim_malloc
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
));
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
));
114 // buffer::create_page_aligned
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);
122 ASSERT_TRUE(ptr
.is_page_aligned());
127 void bench_buffer_alloc(int size
, int num
)
129 utime_t start
= ceph_clock_now();
130 for (int i
=0; i
<num
; ++i
) {
131 bufferptr p
= buffer::create(size
);
134 utime_t end
= ceph_clock_now();
135 cout
<< num
<< " alloc of size " << size
136 << " in " << (end
- start
) << std::endl
;
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);
148 TEST(BufferRaw
, ostream
) {
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)"));
157 // +-----------+ +-----+
159 // | offset +----------------+ |
161 // | length +---- | |
163 // +-----------+ \---+ |
165 // +-----------+ | raw |
168 TEST(BufferPtr
, constructors
) {
175 EXPECT_FALSE(ptr
.have_raw());
176 EXPECT_EQ((unsigned)0, ptr
.offset());
177 EXPECT_EQ((unsigned)0, ptr
.length());
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());
191 // ptr::ptr(unsigned l)
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());
201 // ptr(const char *d, unsigned l)
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
));
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
));
226 // ptr(const ptr& p, unsigned o, unsigned l)
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), "");
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());
255 TEST(BufferPtr
, operator_assign
) {
257 // ptr& operator= (const ptr& p)
260 ptr
.copy_in(0, 3, "ABC");
263 bufferptr copy
= ptr
;
264 copy
.copy_out(1, 1, dest
);
265 ASSERT_EQ('B', dest
[0]);
269 // ptr& operator= (ptr&& p)
271 bufferptr move
= std::move(ptr
);
273 move
.copy_out(1, 1, dest
);
274 ASSERT_EQ('B', dest
[0]);
276 EXPECT_FALSE(ptr
.have_raw());
279 TEST(BufferPtr
, assignment
) {
282 // override a bufferptr set with the same raw
285 bufferptr
original(len
);
286 bufferptr
same_raw(original
);
288 unsigned length
= len
- offset
;
289 original
.set_offset(offset
);
290 original
.set_length(length
);
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());
300 // self assignment is a noop
303 bufferptr
original(len
);
304 #pragma clang diagnostic push
305 #pragma clang diagnostic ignored "-Wself-assign-overloaded"
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());
314 // a copy points to the same raw
317 bufferptr
original(len
);
319 unsigned length
= len
- offset
;
320 original
.set_offset(offset
);
321 original
.set_length(length
);
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());
332 TEST(BufferPtr
, swap
) {
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
);
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
);
351 EXPECT_EQ(ptr2_length
, ptr1
.length());
352 EXPECT_EQ(ptr2_offset
, ptr1
.offset());
353 EXPECT_EQ('Y', ptr1
[0]);
355 EXPECT_EQ(ptr1_length
, ptr2
.length());
356 EXPECT_EQ(ptr1_offset
, ptr2
.offset());
357 EXPECT_EQ('X', ptr2
[0]);
360 TEST(BufferPtr
, release
) {
365 bufferptr
ptr2(ptr1
);
366 EXPECT_EQ(2, ptr1
.raw_nref());
368 EXPECT_EQ(1, ptr1
.raw_nref());
371 TEST(BufferPtr
, have_raw
) {
374 EXPECT_FALSE(ptr
.have_raw());
378 EXPECT_TRUE(ptr
.have_raw());
382 TEST(BufferPtr
, is_n_page_sized
) {
384 bufferptr
ptr(CEPH_PAGE_SIZE
);
385 EXPECT_TRUE(ptr
.is_n_page_sized());
389 EXPECT_FALSE(ptr
.is_n_page_sized());
393 TEST(BufferPtr
, is_partial
) {
395 EXPECT_FALSE(a
.is_partial());
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());
404 TEST(BufferPtr
, accessors
) {
407 ptr
.c_str()[0] = 'X';
409 const bufferptr
const_ptr(ptr
);
411 EXPECT_NE((void*)nullptr, (void*)static_cast<instrumented_bptr
&>(ptr
).get_raw());
412 EXPECT_EQ('X', ptr
.c_str()[0]);
415 PrCtl unset_dumpable
;
416 EXPECT_DEATH(ptr
.c_str(), "");
417 EXPECT_DEATH(ptr
[0], "");
419 EXPECT_EQ('X', const_ptr
.c_str()[0]);
421 const bufferptr const_ptr
;
422 PrCtl unset_dumpable
;
423 EXPECT_DEATH(const_ptr
.c_str(), "");
424 EXPECT_DEATH(const_ptr
[0], "");
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());
434 ptr
.set_length(ptr
.length() - unused
);
435 EXPECT_EQ(unused
, ptr
.unused_tail_length());
439 EXPECT_EQ((unsigned)0, ptr
.unused_tail_length());
442 PrCtl unset_dumpable
;
443 EXPECT_DEATH(ptr
[len
], "");
444 EXPECT_DEATH(const_ptr
[len
], "");
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(), "");
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());
459 ptr
.set_length(ptr
.length() - wasted
* 2);
460 ptr
.set_offset(wasted
);
461 EXPECT_EQ(wasted
* 2, ptr
.wasted());
465 TEST(BufferPtr
, cmp
) {
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
));
482 TEST(BufferPtr
, is_zero
) {
483 char str
[2] = { '\0', 'X' };
485 const bufferptr
ptr(buffer::create_static(2, str
));
486 EXPECT_FALSE(ptr
.is_zero());
489 const bufferptr
ptr(buffer::create_static(1, str
));
490 EXPECT_TRUE(ptr
.is_zero());
494 TEST(BufferPtr
, copy_out
) {
497 PrCtl unset_dumpable
;
498 EXPECT_DEATH(ptr
.copy_out((unsigned)0, (unsigned)0, NULL
), "");
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]);
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;
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
);
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
;
530 TEST(BufferPtr
, copy_in
) {
533 PrCtl unset_dumpable
;
534 EXPECT_DEATH(ptr
.copy_in((unsigned)0, (unsigned)0, NULL
), "");
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
), "");
544 ptr
.copy_in((unsigned)0, (unsigned)2, in
);
545 EXPECT_EQ(in
[0], ptr
[0]);
546 EXPECT_EQ(in
[1], ptr
[1]);
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;
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);
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
;
568 TEST(BufferPtr
, append
) {
571 PrCtl unset_dumpable
;
572 EXPECT_DEATH(ptr
.append('A'), "");
573 EXPECT_DEATH(ptr
.append("B", (unsigned)1), "");
578 PrCtl unset_dumpable
;
579 EXPECT_DEATH(ptr
.append('A'), "");
580 EXPECT_DEATH(ptr
.append("B", (unsigned)1), "");
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]);
592 TEST(BufferPtr
, append_bench
) {
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;
599 for (int i
=0; i
<count
; ++i
) {
600 bufferptr
bp(buflen
);
602 for (int64_t j
=0; j
<buflen
; j
+= s
) {
603 bp
.append(src
+ j
, s
);
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
;
613 TEST(BufferPtr
, zero
) {
615 bufferptr
ptr(buffer::create_static(strlen(str
), str
));
617 PrCtl unset_dumpable
;
618 EXPECT_DEATH(ptr
.zero(ptr
.length() + 1, 0), "");
621 EXPECT_EQ('X', ptr
[0]);
622 EXPECT_EQ('\0', ptr
[1]);
623 EXPECT_EQ('X', ptr
[2]);
625 EXPECT_EQ('\0', ptr
[0]);
628 TEST(BufferPtr
, ostream
) {
631 std::ostringstream stream
;
633 EXPECT_GT(stream
.str().size(), stream
.str().find("buffer:ptr(0~0 no raw"));
637 bufferptr
ptr(buffer::create_static(strlen(str
), str
));
638 std::ostringstream stream
;
640 EXPECT_GT(stream
.str().size(), stream
.str().find("len 4 nref 1)"));
648 // +----------+ +-----+ | | | |
649 // | append_ >-------> >--------------------> | |
650 // | buffer | +-----+ | | | |
651 // +----------+ ptr | | | |
652 // | _len | list +-----+ | | | |
653 // +----------+ +------+ ,--->+ >-----> | |
654 // | _buffers >----> >----- +-----+ | +-----+ |
655 // +----------+ +----^-+ \ ptr | raw |
656 // | last_p | / `-->+-----+ | +-----+ |
657 // +--------+-+ / + >-----> | |
658 // | ,- ,--->+-----+ | | | |
661 // +-v--+-^--+--^+-------+ | | | |
662 // | bl | ls | p | p_off >--------------->| | |
663 // +----+----+-----+-----+ | +-----+ |
664 // | | off >------------->| raw |
665 // +---------------+-----+ | |
666 // iterator +---------+
668 TEST(BufferListIterator
, constructors
) {
673 buffer::list::iterator i
;
674 EXPECT_EQ((unsigned)0, i
.get_off());
678 // iterator(list *l, unsigned o=0)
685 bufferlist::iterator
i(&bl
);
686 EXPECT_EQ((unsigned)0, i
.get_off());
690 bufferlist::iterator
i(&bl
, 1);
692 EXPECT_EQ((unsigned)2, i
.get_remaining());
697 // iterator(list *l, unsigned o, std::list<ptr>::iterator ip, unsigned po)
698 // not tested because of http://tracker.ceph.com/issues/4101
701 // iterator(const iterator& other)
706 bufferlist::iterator
i(&bl
, 1);
707 bufferlist::iterator
j(i
);
717 // const_iterator(const iterator& other)
722 bufferlist::iterator
i(&bl
);
723 bufferlist::const_iterator
ci(i
);
724 EXPECT_EQ(0u, ci
.get_off());
729 TEST(BufferListIterator
, empty_create_append_copy
) {
730 bufferlist bl
, bl2
, bl3
, out
;
736 bl
.begin().copy(6, out
);
737 ASSERT_TRUE(out
.contents_equal(bl
));
740 TEST(BufferListIterator
, operator_assign
) {
743 bufferlist::iterator
i(&bl
, 1);
745 #pragma clang diagnostic push
746 #pragma clang diagnostic ignored "-Wself-assign-overloaded"
748 #pragma clang diagnostic pop
750 bufferlist::iterator j
;
755 TEST(BufferListIterator
, get_off
) {
758 bufferlist::iterator
i(&bl
, 1);
759 EXPECT_EQ((unsigned)1, i
.get_off());
762 TEST(BufferListIterator
, get_remaining
) {
765 bufferlist::iterator
i(&bl
, 1);
766 EXPECT_EQ((unsigned)2, i
.get_remaining());
769 TEST(BufferListIterator
, end
) {
772 bufferlist::iterator
i(&bl
);
773 EXPECT_TRUE(i
.end());
777 bufferlist::iterator
i(&bl
);
778 EXPECT_FALSE(i
.end());
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');
788 for (size_t i
= 0; i
< bufnum
; i
++) {
789 bl
.append(ceph::bufferptr(buf
.c_str(), buf
.size()));
792 utime_t start
= ceph_clock_now();
793 bufferlist::iterator iter
= bl
.begin();
794 while (iter
!= bl
.end()) {
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
;
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);
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);
815 TEST(BufferListIterator
, advance
) {
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()));
823 bufferlist::iterator
i(&bl
);
824 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
827 bufferlist::iterator
i(&bl
);
836 TEST(BufferListIterator
, iterate_with_empties
) {
838 EXPECT_EQ(bl
.get_num_buffers(), 0u);
840 bl
.push_back(ceph::buffer::create(0));
841 EXPECT_EQ(bl
.length(), 0u);
842 EXPECT_EQ(bl
.get_num_buffers(), 1u);
844 encode(int64_t(42), bl
);
845 EXPECT_EQ(bl
.get_num_buffers(), 2u);
847 bl
.push_back(ceph::buffer::create(0));
848 EXPECT_EQ(bl
.get_num_buffers(), 3u);
850 // append bufferlist with single, 0-sized ptr inside
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);
857 bl
.append(bl_with_empty_ptr
);
860 encode(int64_t(24), bl
);
861 EXPECT_EQ(bl
.get_num_buffers(), 5u);
863 auto i
= bl
.cbegin();
875 EXPECT_TRUE(i
== bl
.end());
880 EXPECT_FALSE(i
== bl
.end());
883 TEST(BufferListIterator
, get_ptr_and_advance
)
885 bufferptr
a("one", 3);
886 bufferptr
b("two", 3);
887 bufferptr
c("three", 5);
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());
906 TEST(BufferListIterator
, iterator_crc32c
) {
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());
926 ASSERT_EQ(bl2
.crc32c(0), it
.crc32c(it
.get_remaining(), 0));
928 bl3
.append(s
.substr(98, 55));
931 ASSERT_EQ(bl3
.crc32c(0), it
.crc32c(55, 0));
932 ASSERT_EQ(4u, it
.get_remaining());
935 bl3
.append(s
.substr(98 + 55));
938 ASSERT_EQ(bl3
.crc32c(0), it
.crc32c(10, 0));
939 ASSERT_EQ(0u, it
.get_remaining());
942 TEST(BufferListIterator
, seek
) {
945 bufferlist::iterator
i(&bl
, 1);
951 TEST(BufferListIterator
, operator_star
) {
954 bufferlist::iterator
i(&bl
);
955 EXPECT_THROW(*i
, buffer::end_of_buffer
);
959 bufferlist::iterator
i(&bl
);
961 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
962 EXPECT_THROW(*i
, buffer::end_of_buffer
);
966 TEST(BufferListIterator
, operator_equal
) {
970 bufferlist::iterator
i(&bl
);
971 bufferlist::iterator
j(&bl
);
975 bufferlist::const_iterator ci
= bl
.begin();
976 bufferlist::iterator i
= bl
.begin();
982 TEST(BufferListIterator
, operator_nequal
) {
986 bufferlist::iterator
i(&bl
);
987 bufferlist::iterator
j(&bl
);
991 bufferlist::const_iterator ci
= bl
.begin();
992 bufferlist::const_iterator cj
= bl
.begin();
995 bufferlist::iterator i
= bl
.begin();
1000 // tests begin(), end(), operator++() also
1004 EXPECT_EQ(s
[i
++], c
);
1009 TEST(BufferListIterator
, operator_plus_plus
) {
1012 bufferlist::iterator
i(&bl
);
1013 EXPECT_THROW(++i
, buffer::end_of_buffer
);
1015 bl
.append("ABC", 3);
1017 bufferlist::iterator
i(&bl
);
1023 TEST(BufferListIterator
, get_current_ptr
) {
1026 bufferlist::iterator
i(&bl
);
1027 EXPECT_THROW(++i
, buffer::end_of_buffer
);
1029 bl
.append("ABC", 3);
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());
1039 TEST(BufferListIterator
, copy
) {
1041 const char *expected
= "ABC";
1042 bl
.append(expected
, 3);
1044 // void copy(unsigned len, char *dest);
1047 char* copy
= (char*)malloc(3);
1048 ::memset(copy
, 'X', 3);
1049 bufferlist::iterator
i(&bl
);
1051 // demonstrates that it seeks back to offset if p == ls->end()
1053 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
1055 EXPECT_EQ(0, ::memcmp(copy
, expected
, 2));
1056 EXPECT_EQ('X', copy
[2]);
1059 EXPECT_EQ(0, ::memcmp(copy
, expected
, 3));
1063 // void copy(unsigned len, char *dest) via begin(size_t offset)
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));
1076 // void buffer::list::iterator::copy_deep(unsigned len, ptr &dest)
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]);
1087 // void buffer::list::iterator::copy_shallow(unsigned len, ptr &dest)
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]);
1098 // void buffer::list::iterator::copy(unsigned len, list &dest)
1102 bufferlist::iterator
i(&bl
);
1104 // demonstrates that it seeks back to offset if p == ls->end()
1106 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
1108 EXPECT_EQ(0, ::memcmp(copy
.c_str(), expected
, 2));
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());
1119 // void buffer::list::iterator::copy(unsigned len, list &dest) via begin(size_t offset)
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));
1131 // void buffer::list::iterator::copy_all(list &dest)
1135 bufferlist::iterator
i(&bl
);
1137 // demonstrates that it seeks back to offset if p == ls->end()
1139 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
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());
1147 // void copy(unsigned len, std::string &dest)
1151 bufferlist::iterator
i(&bl
);
1153 // demonstrates that it seeks back to offset if p == ls->end()
1155 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
1157 EXPECT_EQ(0, ::memcmp(copy
.c_str(), expected
, 2));
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());
1168 // void copy(unsigned len, std::string &dest) via begin(size_t offset)
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));
1181 TEST(BufferListIterator
, copy_in
) {
1183 const char *existing
= "XXX";
1184 bl
.append(existing
, 3);
1186 // void buffer::list::iterator::copy_in(unsigned len, const char *src)
1189 bufferlist::iterator
i(&bl
);
1191 // demonstrates that it seeks back to offset if p == ls->end()
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());
1203 // void copy_in(unsigned len, const char *src) via begin(size_t offset)
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));
1213 // void buffer::list::iterator::copy_in(unsigned len, const list& otherl)
1216 bufferlist::iterator
i(&bl
);
1218 // demonstrates that it seeks back to offset if p == ls->end()
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());
1231 // void copy_in(unsigned len, const list& src) via begin(size_t offset)
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));
1244 // iterator& buffer::list::const_iterator::operator++()
1245 TEST(BufferListConstIterator
, operator_plus_plus
) {
1248 bufferlist::const_iterator
i(&bl
);
1249 EXPECT_THROW(++i
, buffer::end_of_buffer
);
1251 bl
.append("ABC", 3);
1253 const bufferlist
const_bl(bl
);
1254 bufferlist::const_iterator
i(const_bl
.begin());
1261 TEST(BufferList
, constructors
) {
1267 ASSERT_EQ((unsigned)0, bl
.length());
1270 // list(unsigned prealloc)
1274 ASSERT_EQ((unsigned)0, bl
.length());
1276 ASSERT_EQ('A', bl
[0]);
1279 // list(const list& other)
1284 ASSERT_EQ('A', bl
[0]);
1285 bufferlist
copy(bl
);
1286 ASSERT_EQ('A', copy
[0]);
1289 // list(list&& other)
1294 bufferlist copy
= std::move(bl
);
1295 ASSERT_EQ(0U, bl
.length());
1296 ASSERT_EQ(1U, copy
.length());
1297 ASSERT_EQ('A', copy
[0]);
1301 TEST(BufferList
, append_after_move
) {
1303 bl
.append("ABC", 3);
1304 EXPECT_EQ(1, bl
.get_num_buffers());
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));
1313 void bench_bufferlist_alloc(int size
, int num
, int per
)
1315 utime_t start
= ceph_clock_now();
1316 for (int i
=0; i
<num
; ++i
) {
1318 for (int j
=0; j
<per
; ++j
)
1319 bl
.push_back(buffer::ptr_node::create(buffer::create(size
)));
1321 utime_t end
= ceph_clock_now();
1322 cout
<< num
<< " alloc of size " << size
1323 << " in " << (end
- start
) << std::endl
;
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);
1341 * append_bench tests now have multiple variants:
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.
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.
1356 TEST(BufferList
, append_bench_with_size_hint
) {
1357 std::array
<char, 1048576> src
= { 0, };
1359 for (size_t step
= 4; step
<= 16384; step
*= 4) {
1360 const utime_t start
= ceph_clock_now();
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
);
1371 cout
<< rounds
<< " fills of buffer len " << src
.size()
1372 << " with " << step
<< " byte appends in "
1373 << (ceph_clock_now() - start
) << std::endl
;
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
);
1383 for (int i
= 0; i
< conc_bl
; i
++) {
1384 bls
[i
] = new ceph::bufferlist
;
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
);
1397 cout
<< rounds
<< " fills of buffer len " << src
.size()
1398 << " with " << step
<< " byte appends in "
1399 << (ceph_clock_now() - start
) << std::endl
;
1401 for (int i
= 0; i
< conc_bl
; i
++) {
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
);
1419 cout
<< rounds
<< " fills of buffer len " << src
.size()
1420 << " with " << step
<< " byte appends in "
1421 << (ceph_clock_now() - start
) << std::endl
;
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
);
1431 for (int i
= 0; i
< conc_bl
; i
++) {
1432 bls
[i
] = new ceph::bufferlist
;
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
);
1445 cout
<< rounds
<< " fills of buffer len " << src
.size()
1446 << " with " << step
<< " byte appends in "
1447 << (ceph_clock_now() - start
) << std::endl
;
1449 for (int i
= 0; i
< conc_bl
; i
++) {
1454 TEST(BufferList
, append_hole_bench
) {
1455 constexpr size_t targeted_bl_size
= 1048576;
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
);
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
;
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
);
1478 for (int i
= 0; i
< conc_bl
; i
++) {
1479 bls
[i
] = new ceph::bufferlist
;
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
);
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
;
1494 for (int i
= 0; i
< conc_bl
; i
++) {
1499 TEST(BufferList
, operator_assign_rvalue
) {
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());
1519 TEST(BufferList
, operator_equal
) {
1521 // list& operator= (const list& other)
1524 bl
.append("ABC", 3);
1527 bl
.begin(1).copy(1, dest
);
1528 ASSERT_EQ('B', dest
[0]);
1531 bufferlist copy
= bl
;
1533 copy
.begin(1).copy(1, dest
);
1534 ASSERT_EQ('B', dest
[0]);
1538 // list& operator= (list&& other)
1541 move
= std::move(bl
);
1544 move
.begin(1).copy(1, dest
);
1545 ASSERT_EQ('B', dest
[0]);
1547 EXPECT_TRUE(move
.length());
1548 EXPECT_TRUE(!bl
.length());
1551 TEST(BufferList
, buffers
) {
1553 ASSERT_EQ((unsigned)0, bl
.get_num_buffers());
1555 ASSERT_EQ((unsigned)1, bl
.get_num_buffers());
1558 TEST(BufferList
, to_str
) {
1562 ASSERT_EQ(bl
.to_str(), string("foo"));
1565 bufferptr
a("foobarbaz", 9);
1566 bufferptr
b("123456789", 9);
1567 bufferptr
c("ABCDEFGHI", 9);
1572 ASSERT_EQ(bl
.to_str(), string("foobarbaz123456789ABCDEFGHI"));
1576 TEST(BufferList
, swap
) {
1586 b1
.begin().copy(1, s1
);
1587 ASSERT_EQ('B', s1
[0]);
1590 b2
.begin().copy(1, s2
);
1591 ASSERT_EQ('A', s2
[0]);
1594 TEST(BufferList
, length
) {
1596 ASSERT_EQ((unsigned)0, bl
.length());
1598 ASSERT_EQ((unsigned)1, bl
.length());
1601 TEST(BufferList
, contents_equal
) {
1610 ASSERT_FALSE(bl1
.contents_equal(bl2
)); // different length
1613 ASSERT_TRUE(bl1
.contents_equal(bl2
)); // same length same content
1619 ASSERT_FALSE(bl1
.contents_equal(bl3
)); // same length different content
1622 TEST(BufferList
, is_aligned
) {
1623 const int SIMD_ALIGN
= 32;
1626 EXPECT_TRUE(bl
.is_aligned(SIMD_ALIGN
));
1630 bufferptr
ptr(buffer::create_aligned(2, SIMD_ALIGN
));
1634 EXPECT_FALSE(bl
.is_aligned(SIMD_ALIGN
));
1635 bl
.rebuild_aligned(SIMD_ALIGN
);
1636 EXPECT_TRUE(bl
.is_aligned(SIMD_ALIGN
));
1640 bufferptr
ptr(buffer::create_aligned(SIMD_ALIGN
+ 1, SIMD_ALIGN
));
1642 ptr
.set_length(SIMD_ALIGN
);
1644 EXPECT_FALSE(bl
.is_aligned(SIMD_ALIGN
));
1645 bl
.rebuild_aligned(SIMD_ALIGN
);
1646 EXPECT_TRUE(bl
.is_aligned(SIMD_ALIGN
));
1650 TEST(BufferList
, is_n_align_sized
) {
1651 const int SIMD_ALIGN
= 32;
1654 EXPECT_TRUE(bl
.is_n_align_sized(SIMD_ALIGN
));
1659 EXPECT_FALSE(bl
.is_n_align_sized(SIMD_ALIGN
));
1663 bl
.append_zero(SIMD_ALIGN
);
1664 EXPECT_TRUE(bl
.is_n_align_sized(SIMD_ALIGN
));
1668 TEST(BufferList
, is_page_aligned
) {
1671 EXPECT_TRUE(bl
.is_page_aligned());
1675 bufferptr
ptr(buffer::create_page_aligned(2));
1679 EXPECT_FALSE(bl
.is_page_aligned());
1680 bl
.rebuild_page_aligned();
1681 EXPECT_TRUE(bl
.is_page_aligned());
1685 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
+ 1));
1687 ptr
.set_length(CEPH_PAGE_SIZE
);
1689 EXPECT_FALSE(bl
.is_page_aligned());
1690 bl
.rebuild_page_aligned();
1691 EXPECT_TRUE(bl
.is_page_aligned());
1695 TEST(BufferList
, is_n_page_sized
) {
1698 EXPECT_TRUE(bl
.is_n_page_sized());
1703 EXPECT_FALSE(bl
.is_n_page_sized());
1707 bl
.append_zero(CEPH_PAGE_SIZE
);
1708 EXPECT_TRUE(bl
.is_n_page_sized());
1712 TEST(BufferList
, page_aligned_appender
) {
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
) {
1724 cout
<< bl
<< std::endl
;
1725 ASSERT_EQ(1u, bl
.get_num_buffers());
1726 // verify the beginning
1729 t
.substr_of(bl
, 0, 10);
1730 ASSERT_TRUE(t
.contents_equal("asdfasdfxx", 10));
1732 for (unsigned n
= 0; n
< 3 * CEPH_PAGE_SIZE
; ++n
) {
1735 cout
<< bl
<< std::endl
;
1736 ASSERT_EQ(2u, bl
.get_num_buffers());
1739 // ensure append_zero didn't introduce a fragmentation
1740 ASSERT_EQ(2u, bl
.get_num_buffers());
1741 // verify the end is actually zeroed
1744 t
.substr_of(bl
, bl
.length() - 42, 42);
1745 ASSERT_TRUE(t
.is_zero());
1748 // let's check whether appending a bufferlist directly to `bl`
1749 // doesn't fragment further C string appends via appender.
1751 const auto& initial_back
= bl
.back();
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());
1761 // moreover, the next C string-taking `append()` had to
1762 // create anoter `ptr_node` instance but...
1764 ASSERT_EQ(4u, bl
.get_num_buffers());
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());
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);
1779 cout
<< bl
<< std::endl
;
1780 ASSERT_EQ(6u, bl
.get_num_buffers());
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()`.
1789 cout
<< bl
<< std::endl
;
1790 ASSERT_EQ(6u, bl
.get_num_buffers());
1794 TEST(BufferList
, rebuild_aligned_size_and_memory
) {
1795 const unsigned SIMD_ALIGN
= 32;
1796 const unsigned BUFFER_SIZE
= 67;
1799 // These two must be concatenated into one memory + size aligned
1802 bufferptr
ptr(buffer::create_aligned(2, SIMD_ALIGN
));
1808 bufferptr
ptr(buffer::create_aligned(BUFFER_SIZE
- 1, SIMD_ALIGN
));
1811 // This one must be left alone
1813 bufferptr
ptr(buffer::create_aligned(BUFFER_SIZE
, SIMD_ALIGN
));
1816 // These two must be concatenated into one memory + size aligned
1819 bufferptr
ptr(buffer::create_aligned(2, SIMD_ALIGN
));
1825 bufferptr
ptr(buffer::create_aligned(BUFFER_SIZE
- 1, SIMD_ALIGN
));
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());
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 */
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);
1859 TEST(BufferList
, is_zero
) {
1862 EXPECT_TRUE(bl
.is_zero());
1867 EXPECT_FALSE(bl
.is_zero());
1872 EXPECT_TRUE(bl
.is_zero());
1875 for (size_t i
= 1; i
<= 256; ++i
) {
1878 EXPECT_TRUE(bl
.is_zero());
1880 // ensure buffer is a single, contiguous before testing
1882 EXPECT_FALSE(bl
.is_zero());
1887 TEST(BufferList
, clear
) {
1890 bl
.append_zero(len
);
1892 EXPECT_EQ((unsigned)0, bl
.length());
1893 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
1896 TEST(BufferList
, push_back
) {
1898 // void push_back(ptr& bp)
1904 EXPECT_EQ((unsigned)0, bl
.length());
1905 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
1912 ptr
.c_str()[0] = 'B';
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());
1922 // void push_back(ptr&& bp)
1927 bl
.push_back(std::move(ptr
));
1928 EXPECT_EQ((unsigned)0, bl
.length());
1929 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
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());
1944 TEST(BufferList
, is_contiguous
) {
1946 EXPECT_TRUE(bl
.is_contiguous());
1947 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
1949 EXPECT_TRUE(bl
.is_contiguous());
1950 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
1953 EXPECT_FALSE(bl
.is_contiguous());
1954 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
1957 TEST(BufferList
, rebuild
) {
1960 bufferptr
ptr(buffer::create_page_aligned(2));
1966 EXPECT_FALSE(bl
.is_page_aligned());
1968 EXPECT_EQ(1U, bl
.length());
1969 EXPECT_EQ('Y', *bl
.begin());
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));
1979 EXPECT_TRUE(bl
.is_page_aligned());
1980 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
1989 EXPECT_EQ((unsigned)1, bl
.length());
1990 bufferlist::iterator p
= bl
.begin();
1993 EXPECT_EQ(0, memcmp(dst
, "X", 1));
1997 TEST(BufferList
, rebuild_page_aligned
) {
2001 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
+ 1));
2003 ptr
.set_length(CEPH_PAGE_SIZE
);
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());
2014 bufferptr
ptr(buffer::create_page_aligned(1));
2015 char *p
= ptr
.c_str();
2017 bl
.rebuild_page_aligned();
2018 EXPECT_EQ(p
, bl
.front().c_str());
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());
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());
2035 bufferptr
ptr(buffer::create_page_aligned(2));
2038 EXPECT_FALSE(ptr
.is_page_aligned());
2039 EXPECT_FALSE(ptr
.is_n_page_sized());
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());
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());
2055 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
+ 1));
2057 ptr
.set_length(CEPH_PAGE_SIZE
);
2058 EXPECT_FALSE(ptr
.is_page_aligned());
2059 EXPECT_TRUE(ptr
.is_n_page_sized());
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());
2071 TEST(BufferList
, claim_append
) {
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());
2093 TEST(BufferList
, begin
) {
2096 bufferlist::iterator i
= bl
.begin();
2100 TEST(BufferList
, end
) {
2103 bufferlist::iterator i
= bl
.end();
2105 EXPECT_EQ('C', bl
[i
.get_off()]);
2108 TEST(BufferList
, append
) {
2110 // void append(char c);
2114 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2116 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2117 //EXPECT_TRUE(bl.is_aligned(CEPH_BUFFER_APPEND_SIZE));
2120 // void append(const char *data, unsigned len);
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());
2131 // void append(const std::string& s);
2134 bufferlist
bl(CEPH_PAGE_SIZE
);
2135 std::string
str(CEPH_PAGE_SIZE
* 2, 'X');
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());
2142 // void append(const ptr& bp);
2146 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2147 EXPECT_EQ((unsigned)0, bl
.length());
2151 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2152 EXPECT_EQ((unsigned)0, bl
.length());
2157 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2158 EXPECT_EQ((unsigned)3, bl
.length());
2162 // void append(const ptr& bp, unsigned off, unsigned len);
2167 bufferptr
back(bl
.back());
2169 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2170 EXPECT_EQ((unsigned)1, bl
.length());
2172 PrCtl unset_dumpable
;
2173 EXPECT_DEATH(bl
.append(in
, (unsigned)100, (unsigned)100), "");
2175 EXPECT_LT((unsigned)0, in
.unused_tail_length());
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]);
2184 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2185 EXPECT_EQ((unsigned)0, bl
.length());
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());
2194 // void append(const list& bl);
2202 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
2203 EXPECT_EQ('B', bl
[1]);
2206 // void append(std::istream& in);
2210 std::string
expected("ABC\nDEF\n");
2211 std::istringstream
is("ABC\n\nDEF");
2213 EXPECT_EQ(0, ::memcmp(expected
.c_str(), bl
.c_str(), expected
.size()));
2214 EXPECT_EQ(expected
.size(), bl
.length());
2217 // void append(ptr&& bp);
2221 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2222 EXPECT_EQ((unsigned)0, bl
.length());
2225 bl
.append(std::move(ptr
));
2226 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2227 EXPECT_EQ((unsigned)0, bl
.length());
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());
2239 TEST(BufferList
, append_hole
) {
2242 auto filler
= bl
.append_hole(1);
2243 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2244 EXPECT_EQ((unsigned)1, bl
.length());
2247 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2248 EXPECT_EQ((unsigned)3, bl
.length());
2251 filler
.copy_in((unsigned)1, &a
);
2252 EXPECT_EQ((unsigned)3, bl
.length());
2254 EXPECT_EQ(0, ::memcmp("ABC", bl
.c_str(), 3));
2260 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2261 EXPECT_EQ((unsigned)1, bl
.length());
2263 auto filler
= bl
.append_hole(1);
2264 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2265 EXPECT_EQ((unsigned)2, bl
.length());
2268 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2269 EXPECT_EQ((unsigned)3, bl
.length());
2272 filler
.copy_in((unsigned)1, &b
);
2273 EXPECT_EQ((unsigned)3, bl
.length());
2275 EXPECT_EQ(0, ::memcmp("ABC", bl
.c_str(), 3));
2279 TEST(BufferList
, append_zero
) {
2282 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2283 EXPECT_EQ((unsigned)1, bl
.length());
2285 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2286 EXPECT_EQ((unsigned)2, bl
.length());
2287 EXPECT_EQ('\0', bl
[1]);
2290 TEST(BufferList
, operator_brackets
) {
2292 EXPECT_THROW(bl
[1], buffer::end_of_buffer
);
2297 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
2298 EXPECT_EQ('B', bl
[1]);
2301 TEST(BufferList
, c_str
) {
2303 EXPECT_EQ((const char*)NULL
, bl
.c_str());
2308 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
2309 EXPECT_EQ(0, ::memcmp("AB", bl
.c_str(), 2));
2312 TEST(BufferList
, c_str_carriage
) {
2313 // verify the c_str() optimization for carriage handling
2314 buffer::ptr
bp("A", 1);
2318 EXPECT_EQ(2U, bl
.get_num_buffers());
2319 EXPECT_EQ(2U, bl
.length());
2321 // this should leave an empty bptr for carriage at the end of the bl
2323 EXPECT_EQ(2U, bl
.get_num_buffers());
2324 EXPECT_EQ(1U, bl
.length());
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());
2331 TEST(BufferList
, substr_of
) {
2333 EXPECT_THROW(bl
.substr_of(bl
, 1, 1), buffer::end_of_buffer
);
2340 for (unsigned i
= 0; i
< 4; i
++) {
2341 bufferptr
ptr(s
[i
], strlen(s
[i
]));
2344 EXPECT_EQ((unsigned)4, bl
.get_num_buffers());
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));
2354 TEST(BufferList
, splice
) {
2356 EXPECT_THROW(bl
.splice(1, 1), buffer::end_of_buffer
);
2363 for (unsigned i
= 0; i
< 4; i
++) {
2364 bufferptr
ptr(s
[i
], strlen(s
[i
]));
2367 EXPECT_EQ((unsigned)4, bl
.get_num_buffers());
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());
2379 EXPECT_EQ(0, ::memcmp("ABCDIJKL", tmp
.c_str(), tmp
.length()));
2383 EXPECT_EQ((unsigned)4, bl
.length());
2384 EXPECT_EQ(0, ::memcmp("ABCD", bl
.c_str(), bl
.length()));
2388 bufferptr
ptr1("0123456789", 10);
2390 bufferptr
ptr2("abcdefghij", 10);
2391 bl
.append(ptr2
, 5, 5);
2393 bl
.splice(10, 4, &other
);
2394 EXPECT_EQ((unsigned)11, bl
.length());
2395 EXPECT_EQ(0, ::memcmp("fghi", other
.c_str(), other
.length()));
2399 TEST(BufferList
, write
) {
2400 std::ostringstream stream
;
2403 bl
.write(1, 2, stream
);
2404 EXPECT_EQ("BC", stream
.str());
2407 TEST(BufferList
, encode_base64
) {
2411 bl
.encode_base64(other
);
2412 const char *expected
= "QUJDRA==";
2413 EXPECT_EQ(0, ::memcmp(expected
, other
.c_str(), strlen(expected
)));
2416 TEST(BufferList
, decode_base64
) {
2418 bl
.append("QUJDRA==");
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
);
2428 TEST(BufferList
, hexdump
) {
2430 std::ostringstream stream
;
2431 bl
.append("013245678901234\0006789012345678901234", 32);
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"
2439 TEST(BufferList
, read_file
) {
2443 EXPECT_EQ(-ENOENT
, bl
.read_file("UNLIKELY", &error
));
2444 snprintf(cmd
, sizeof(cmd
), "echo ABC> %s", FILENAME
);
2445 EXPECT_EQ(0, ::system(cmd
));
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
));
2452 snprintf(cmd
, sizeof(cmd
), "chmod +r %s", FILENAME
);
2453 EXPECT_EQ(0, ::system(cmd
));
2455 EXPECT_EQ(0, bl
.read_file(FILENAME
, &error
));
2457 EXPECT_EQ((unsigned)4, bl
.length());
2458 std::string
actual(bl
.c_str(), bl
.length());
2459 EXPECT_EQ("ABC\n", actual
);
2462 TEST(BufferList
, read_fd
) {
2465 snprintf(cmd
, sizeof(cmd
), "echo ABC > %s", FILENAME
);
2466 EXPECT_EQ(0, ::system(cmd
));
2469 EXPECT_EQ(-EBADF
, bl
.read_fd(fd
, len
));
2470 fd
= ::open(FILENAME
, O_RDONLY
);
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());
2479 TEST(BufferList
, write_file
) {
2483 EXPECT_EQ(-ENOENT
, bl
.write_file("un/like/ly", mode
));
2485 EXPECT_EQ(0, bl
.write_file(FILENAME
, mode
));
2487 memset(&st
, 0, sizeof(st
));
2488 ASSERT_EQ(0, ::stat(FILENAME
, &st
));
2490 EXPECT_EQ((unsigned)(mode
| S_IFREG
), st
.st_mode
);
2495 TEST(BufferList
, write_fd
) {
2497 int fd
= ::open(FILENAME
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
2500 for (unsigned i
= 0; i
< IOV_MAX
* 2; i
++) {
2501 bufferptr
ptr("A", 1);
2504 EXPECT_EQ(0, bl
.write_fd(fd
));
2507 memset(&st
, 0, sizeof(st
));
2508 ASSERT_EQ(0, ::stat(FILENAME
, &st
));
2509 EXPECT_EQ(IOV_MAX
* 2, st
.st_size
);
2513 TEST(BufferList
, write_fd_offset
) {
2515 int fd
= ::open(FILENAME
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
2518 for (unsigned i
= 0; i
< IOV_MAX
* 2; i
++) {
2519 bufferptr
ptr("A", 1);
2522 uint64_t offset
= 200;
2523 EXPECT_EQ(0, bl
.write_fd(fd
, offset
));
2526 memset(&st
, 0, sizeof(st
));
2527 ASSERT_EQ(0, ::stat(FILENAME
, &st
));
2528 EXPECT_EQ(IOV_MAX
* 2 + offset
, (unsigned)st
.st_size
);
2532 TEST(BufferList
, crc32c
) {
2536 crc
= bl
.crc32c(crc
);
2537 EXPECT_EQ((unsigned)0xB3109EBF, crc
);
2538 crc
= bl
.crc32c(crc
);
2539 EXPECT_EQ((unsigned)0x5FA5C0CC, crc
);
2542 TEST(BufferList
, crc32c_append
) {
2546 for (int j
= 0; j
< 200; ++j
) {
2548 for (int i
= 0; i
< 200; ++i
) {
2553 bl
.crc32c(rand()); // mess with the cached bufferptr crc values
2556 ASSERT_EQ(bl1
.crc32c(0), bl2
.crc32c(0));
2559 TEST(BufferList
, crc32c_zeros
) {
2560 char buffer
[4*1024];
2561 for (size_t i
=0; i
< sizeof(buffer
); i
++)
2569 for (size_t j
=0; j
< 1000; j
++)
2571 bufferptr
a(buffer
, sizeof(buffer
));
2574 uint32_t crca
= bla
.crc32c(111);
2577 uint32_t crcb
= ceph_crc32c(111, (unsigned char*)blb
.c_str(), blb
.length());
2579 EXPECT_EQ(crca
, crcb
);
2583 TEST(BufferList
, crc32c_append_perf
) {
2584 int len
= 256 * 1024 * 1024;
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;
2601 // track usage of cached crcs
2602 buffer::track_cached_crc(true);
2604 [[maybe_unused
]] int base_cached
= buffer::get_cached_crc();
2605 [[maybe_unused
]] int base_cached_adjusted
= buffer::get_cached_crc_adjusted();
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);
2619 ceph_assert(buffer::get_cached_crc() == 0 + base_cached
);
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);
2628 ceph_assert(buffer::get_cached_crc() == 1 + base_cached
);
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);
2638 ceph_assert(buffer::get_cached_crc() == 1 + base_cached
);
2639 ceph_assert(buffer::get_cached_crc_adjusted() == 1 + base_cached_adjusted
);
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);
2648 ceph_assert(buffer::get_cached_crc() == 1 + base_cached
);
2649 ceph_assert(buffer::get_cached_crc_adjusted() == 2 + base_cached_adjusted
);
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);
2658 ceph_assert(buffer::get_cached_crc() == 1 + base_cached
);
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);
2667 ceph_assert(buffer::get_cached_crc() == 2 + base_cached
);
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);
2680 ceph_assert(buffer::get_cached_crc() == 3 + base_cached
);
2681 ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted
);
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);
2693 ceph_assert(buffer::get_cached_crc() == 4 + base_cached
);
2694 ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted
);
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);
2707 ceph_assert(buffer::get_cached_crc() == 5 + base_cached
);
2708 ceph_assert(buffer::get_cached_crc_adjusted() == 4 + base_cached_adjusted
);
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);
2717 ceph_assert(buffer::get_cached_crc() == 5 + base_cached
);
2718 ceph_assert(buffer::get_cached_crc_adjusted() == 6 + base_cached_adjusted
);
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
;
2724 TEST(BufferList
, compare
) {
2727 bufferlist ab
; // AB in segments
2728 ab
.append(bufferptr("A", 1));
2729 ab
.append(bufferptr("B", 1));
2733 // bool operator>(bufferlist& l, bufferlist& r)
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
);
2741 // bool operator>=(bufferlist& l, bufferlist& r)
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
);
2749 // bool operator<(bufferlist& l, bufferlist& r)
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
);
2757 // bool operator<=(bufferlist& l, bufferlist& r)
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
);
2765 // bool operator==(bufferlist &l, bufferlist &r)
2767 ASSERT_FALSE(a
== ab
);
2768 ASSERT_FALSE(ac
== ab
);
2769 ASSERT_TRUE(ab
== ab
);
2772 TEST(BufferList
, ostream
) {
2773 std::ostringstream stream
;
2779 for (unsigned i
= 0; i
< 2; i
++) {
2780 bufferptr
ptr(s
[i
], strlen(s
[i
]));
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"));
2790 TEST(BufferList
, zero
) {
2797 EXPECT_EQ('A', bl
[0]);
2799 EXPECT_EQ('\0', bl
[0]);
2802 // void zero(unsigned o, unsigned l)
2812 bufferptr
ptr(s
[0], strlen(s
[0]));
2814 bl
.zero((unsigned)0, (unsigned)1);
2815 EXPECT_EQ(0, ::memcmp("\0BC", bl
.c_str(), 3));
2819 for (unsigned i
= 0; i
< 4; i
++) {
2820 bufferptr
ptr(s
[i
], strlen(s
[i
]));
2824 PrCtl unset_dumpable
;
2825 EXPECT_DEATH(bl
.zero((unsigned)0, (unsigned)2000), "");
2827 bl
.zero((unsigned)2, (unsigned)5);
2828 EXPECT_EQ(0, ::memcmp("AB\0\0\0\0\0HIKLM", bl
.c_str(), 9));
2832 for (unsigned i
= 0; i
< 4; i
++) {
2833 bufferptr
ptr(s
[i
], strlen(s
[i
]));
2836 bl
.zero((unsigned)3, (unsigned)3);
2837 EXPECT_EQ(0, ::memcmp("ABC\0\0\0GHIKLM", bl
.c_str(), 9));
2843 memset(ptr1
.c_str(), 'a', 4);
2844 memset(ptr2
.c_str(), 'b', 4);
2847 bl
.zero((unsigned)2, (unsigned)4);
2848 EXPECT_EQ(0, ::memcmp("aa\0\0\0\0bb", bl
.c_str(), 8));
2852 TEST(BufferList
, EmptyAppend
) {
2856 ASSERT_EQ(bl
.begin().end(), 1);
2859 TEST(BufferList
, InternalCarriage
) {
2860 ceph::bufferlist bl
;
2861 EXPECT_EQ(bl
.get_num_buffers(), 0u);
2863 encode(int64_t(42), bl
);
2864 EXPECT_EQ(bl
.get_num_buffers(), 1u);
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);
2872 bl
.append(bl_with_foo
);
2873 EXPECT_EQ(bl
.get_num_buffers(), 2u);
2876 encode(int64_t(24), bl
);
2877 EXPECT_EQ(bl
.get_num_buffers(), 3u);
2880 TEST(BufferList
, ContiguousAppender
) {
2881 ceph::bufferlist bl
;
2882 EXPECT_EQ(bl
.get_num_buffers(), 0u);
2884 // we expect a flush in ~contiguous_appender
2886 auto ap
= bl
.get_contiguous_appender(100);
2888 denc(int64_t(42), ap
);
2889 EXPECT_EQ(bl
.get_num_buffers(), 1u);
2891 // append bufferlist with single ptr inside. This should
2892 // commit changes to bl::_len and the underlying bp::len.
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);
2899 ap
.append(bl_with_foo
);
2900 // 3 as the ap::append(const bl&) splits the bp with free
2902 EXPECT_EQ(bl
.get_num_buffers(), 3u);
2905 denc(int64_t(24), ap
);
2906 EXPECT_EQ(bl
.get_num_buffers(), 3u);
2907 EXPECT_EQ(bl
.length(), sizeof(int64_t) + 3u);
2909 EXPECT_EQ(bl
.length(), 2u * sizeof(int64_t) + 3u);
2912 TEST(BufferList
, TestPtrAppend
) {
2914 char correct
[MAX_TEST
];
2916 int length
= random() % 5 > 0 ? random() % 1000 : 0;
2917 while (curpos
+ length
< MAX_TEST
) {
2922 char *current
= correct
+ curpos
;
2923 for (int i
= 0; i
< length
; ++i
) {
2924 char next
= random() % 255;
2925 correct
[curpos
++] = next
;
2927 bufferptr
ptr(current
, length
);
2930 length
= random() % 5 > 0 ? random() % 1000 : 0;
2932 ASSERT_EQ(memcmp(bl
.c_str(), correct
, curpos
), 0);
2935 TEST(BufferList
, TestDirectAppend
) {
2937 char correct
[MAX_TEST
];
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
;
2946 bl
.append(current
, length
);
2947 length
= random() % 5 > 0 ? random() % 1000 : 0;
2949 ASSERT_EQ(memcmp(bl
.c_str(), correct
, curpos
), 0);
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
) {
2961 bl
.append((const char*)big
.get(), BIG_SZ
);
2962 bufferlist::iterator i
= bl
.begin();
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);
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();
2979 for (size_t i
= 0; i
< buffer_size
; ++i
) {
2984 // test for crashes (shouldn't crash)
2985 bl
.invalidate_crc();
2987 // put data into bufferlist
2988 bl
.append((const char*)big
.get(), buffer_size
);
2991 __u32 crc
= bl
.crc32c(0);
2993 // modify data in bl without its knowledge
2994 inptr
= (char*) bl
.c_str();
2996 for (size_t i
= 0; i
< buffer_size
; ++i
) {
3000 // make sure data in bl are now different than in big
3001 EXPECT_NE(memcmp((void*) ptr
, (void*) inptr
, buffer_size
), 0);
3003 // crc should remain the same
3004 __u32 new_crc
= bl
.crc32c(0);
3005 EXPECT_EQ(crc
, new_crc
);
3007 // force crc invalidate, check if it is updated
3008 bl
.invalidate_crc();
3009 EXPECT_NE(crc
, bl
.crc32c(0));
3012 TEST(BufferList
, TestIsProvidedBuffer
) {
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
));
3021 TEST(BufferList
, DISABLED_DanglingLastP
) {
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
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));
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));
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
);
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));
3053 TEST(BufferHash
, all
) {
3058 EXPECT_EQ((unsigned)0, hash
.digest());
3060 EXPECT_EQ((unsigned)0xB3109EBF, hash
.digest());
3062 EXPECT_EQ((unsigned)0x5FA5C0CC, hash
.digest());
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());
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"