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/environment.h"
33 #include "common/Clock.h"
34 #include "common/safe_io.h"
36 #include "gtest/gtest.h"
40 #include "include/crc32c.h"
41 #include "common/sctp_crc32.h"
43 #define MAX_TEST 1000000
44 #define FILENAME "bufferlist"
48 struct instrumented_bptr
: public ceph::buffer::ptr
{
49 const ceph::buffer::raw
* get_raw() const {
54 TEST(Buffer
, constructors
) {
60 bufferptr
ptr(buffer::create(len
));
61 EXPECT_EQ(len
, ptr
.length());
67 char* str
= new char[len
];
68 ::memset(str
, 'X', len
);
69 bufferptr
ptr(buffer::claim_char(len
, str
));
70 EXPECT_EQ(len
, ptr
.length());
71 EXPECT_EQ(str
, ptr
.c_str());
72 bufferptr clone
= ptr
.clone();
73 EXPECT_EQ(0, ::memcmp(clone
.c_str(), ptr
.c_str(), len
));
77 // buffer::create_static
80 char* str
= new char[len
];
81 bufferptr
ptr(buffer::create_static(len
, str
));
82 EXPECT_EQ(len
, ptr
.length());
83 EXPECT_EQ(str
, ptr
.c_str());
87 // buffer::create_malloc
90 bufferptr
ptr(buffer::create_malloc(len
));
91 EXPECT_EQ(len
, ptr
.length());
92 // this doesn't throw on my x86_64 wheezy box --sage
93 //EXPECT_THROW(buffer::create_malloc((unsigned)ULLONG_MAX), buffer::bad_alloc);
96 // buffer::claim_malloc
99 char* str
= (char*)malloc(len
);
100 ::memset(str
, 'X', len
);
101 bufferptr
ptr(buffer::claim_malloc(len
, str
));
102 EXPECT_EQ(len
, ptr
.length());
103 EXPECT_EQ(str
, ptr
.c_str());
104 bufferptr clone
= ptr
.clone();
105 EXPECT_EQ(0, ::memcmp(clone
.c_str(), ptr
.c_str(), len
));
111 const std::string
expected(len
, 'X');
112 bufferptr
ptr(buffer::copy(expected
.c_str(), expected
.size()));
113 EXPECT_NE(expected
.c_str(), ptr
.c_str());
114 EXPECT_EQ(0, ::memcmp(expected
.c_str(), ptr
.c_str(), len
));
117 // buffer::create_page_aligned
120 bufferptr
ptr(buffer::create_page_aligned(len
));
121 ::memset(ptr
.c_str(), 'X', len
);
122 // doesn't throw on my x86_64 wheezy box --sage
123 //EXPECT_THROW(buffer::create_page_aligned((unsigned)ULLONG_MAX), buffer::bad_alloc);
125 ASSERT_TRUE(ptr
.is_page_aligned());
127 bufferptr clone
= ptr
.clone();
128 EXPECT_EQ(0, ::memcmp(clone
.c_str(), ptr
.c_str(), len
));
132 void bench_buffer_alloc(int size
, int num
)
134 utime_t start
= ceph_clock_now();
135 for (int i
=0; i
<num
; ++i
) {
136 bufferptr p
= buffer::create(size
);
139 utime_t end
= ceph_clock_now();
140 cout
<< num
<< " alloc of size " << size
141 << " in " << (end
- start
) << std::endl
;
144 TEST(Buffer
, BenchAlloc
) {
145 bench_buffer_alloc(16384, 1000000);
146 bench_buffer_alloc(4096, 1000000);
147 bench_buffer_alloc(1024, 1000000);
148 bench_buffer_alloc(256, 1000000);
149 bench_buffer_alloc(32, 1000000);
150 bench_buffer_alloc(4, 1000000);
153 TEST(BufferRaw
, ostream
) {
155 std::ostringstream stream
;
156 stream
<< *static_cast<instrumented_bptr
&>(ptr
).get_raw();
157 EXPECT_GT(stream
.str().size(), stream
.str().find("buffer::raw("));
158 EXPECT_GT(stream
.str().size(), stream
.str().find("len 1 nref 1)"));
162 // +-----------+ +-----+
164 // | offset +----------------+ |
166 // | length +---- | |
168 // +-----------+ \---+ |
170 // +-----------+ | raw |
173 TEST(BufferPtr
, constructors
) {
180 EXPECT_FALSE(ptr
.have_raw());
181 EXPECT_EQ((unsigned)0, ptr
.offset());
182 EXPECT_EQ((unsigned)0, ptr
.length());
188 bufferptr
ptr(buffer::create(len
));
189 EXPECT_TRUE(ptr
.have_raw());
190 EXPECT_EQ((unsigned)0, ptr
.offset());
191 EXPECT_EQ(len
, ptr
.length());
192 EXPECT_EQ(ptr
.raw_length(), ptr
.length());
193 EXPECT_EQ(1, ptr
.raw_nref());
196 // ptr::ptr(unsigned l)
200 EXPECT_TRUE(ptr
.have_raw());
201 EXPECT_EQ((unsigned)0, ptr
.offset());
202 EXPECT_EQ(len
, ptr
.length());
203 EXPECT_EQ(1, ptr
.raw_nref());
206 // ptr(const char *d, unsigned l)
209 const std::string
str(len
, 'X');
210 bufferptr
ptr(str
.c_str(), len
);
211 EXPECT_TRUE(ptr
.have_raw());
212 EXPECT_EQ((unsigned)0, ptr
.offset());
213 EXPECT_EQ(len
, ptr
.length());
214 EXPECT_EQ(1, ptr
.raw_nref());
215 EXPECT_EQ(0, ::memcmp(str
.c_str(), ptr
.c_str(), len
));
221 const std::string
str(len
, 'X');
222 bufferptr
original(str
.c_str(), len
);
223 bufferptr
ptr(original
);
224 EXPECT_TRUE(ptr
.have_raw());
225 EXPECT_EQ(static_cast<instrumented_bptr
&>(original
).get_raw(),
226 static_cast<instrumented_bptr
&>(ptr
).get_raw());
227 EXPECT_EQ(2, ptr
.raw_nref());
228 EXPECT_EQ(0, ::memcmp(original
.c_str(), ptr
.c_str(), len
));
231 // ptr(const ptr& p, unsigned o, unsigned l)
234 const std::string
str(len
, 'X');
235 bufferptr
original(str
.c_str(), len
);
236 bufferptr
ptr(original
, 0, 0);
237 EXPECT_TRUE(ptr
.have_raw());
238 EXPECT_EQ(static_cast<instrumented_bptr
&>(original
).get_raw(),
239 static_cast<instrumented_bptr
&>(ptr
).get_raw());
240 EXPECT_EQ(2, ptr
.raw_nref());
241 EXPECT_EQ(0, ::memcmp(original
.c_str(), ptr
.c_str(), len
));
242 PrCtl unset_dumpable
;
243 EXPECT_DEATH(bufferptr(original
, 0, original
.length() + 1), "");
244 EXPECT_DEATH(bufferptr(bufferptr(), 0, 0), "");
250 const std::string
str(len
, 'X');
251 bufferptr
original(str
.c_str(), len
);
252 bufferptr
ptr(std::move(original
));
253 EXPECT_TRUE(ptr
.have_raw());
254 EXPECT_FALSE(original
.have_raw());
255 EXPECT_EQ(0, ::memcmp(str
.c_str(), ptr
.c_str(), len
));
256 EXPECT_EQ(1, ptr
.raw_nref());
260 TEST(BufferPtr
, operator_assign
) {
262 // ptr& operator= (const ptr& p)
265 ptr
.copy_in(0, 3, "ABC");
268 bufferptr copy
= ptr
;
269 copy
.copy_out(1, 1, dest
);
270 ASSERT_EQ('B', dest
[0]);
274 // ptr& operator= (ptr&& p)
276 bufferptr move
= std::move(ptr
);
278 move
.copy_out(1, 1, dest
);
279 ASSERT_EQ('B', dest
[0]);
281 EXPECT_FALSE(ptr
.have_raw());
284 TEST(BufferPtr
, assignment
) {
287 // override a bufferptr set with the same raw
290 bufferptr
original(len
);
291 bufferptr
same_raw(original
);
293 unsigned length
= len
- offset
;
294 original
.set_offset(offset
);
295 original
.set_length(length
);
297 ASSERT_EQ(2, original
.raw_nref());
298 ASSERT_EQ(static_cast<instrumented_bptr
&>(same_raw
).get_raw(),
299 static_cast<instrumented_bptr
&>(original
).get_raw());
300 ASSERT_EQ(same_raw
.offset(), original
.offset());
301 ASSERT_EQ(same_raw
.length(), original
.length());
305 // self assignment is a noop
308 bufferptr
original(len
);
309 #pragma clang diagnostic push
310 #pragma clang diagnostic ignored "-Wself-assign-overloaded"
312 #pragma clang diagnostic pop
313 ASSERT_EQ(1, original
.raw_nref());
314 ASSERT_EQ((unsigned)0, original
.offset());
315 ASSERT_EQ(len
, original
.length());
319 // a copy points to the same raw
322 bufferptr
original(len
);
324 unsigned length
= len
- offset
;
325 original
.set_offset(offset
);
326 original
.set_length(length
);
329 ASSERT_EQ(2, original
.raw_nref());
330 ASSERT_EQ(static_cast<instrumented_bptr
&>(ptr
).get_raw(),
331 static_cast<instrumented_bptr
&>(original
).get_raw());
332 ASSERT_EQ(original
.offset(), ptr
.offset());
333 ASSERT_EQ(original
.length(), ptr
.length());
337 TEST(BufferPtr
, clone
) {
340 ::memset(ptr
.c_str(), 'X', len
);
341 bufferptr clone
= ptr
.clone();
342 EXPECT_EQ(0, ::memcmp(clone
.c_str(), ptr
.c_str(), len
));
345 TEST(BufferPtr
, swap
) {
349 ::memset(ptr1
.c_str(), 'X', len
);
350 unsigned ptr1_offset
= 4;
351 ptr1
.set_offset(ptr1_offset
);
352 unsigned ptr1_length
= 3;
353 ptr1
.set_length(ptr1_length
);
356 ::memset(ptr2
.c_str(), 'Y', len
);
357 unsigned ptr2_offset
= 5;
358 ptr2
.set_offset(ptr2_offset
);
359 unsigned ptr2_length
= 7;
360 ptr2
.set_length(ptr2_length
);
364 EXPECT_EQ(ptr2_length
, ptr1
.length());
365 EXPECT_EQ(ptr2_offset
, ptr1
.offset());
366 EXPECT_EQ('Y', ptr1
[0]);
368 EXPECT_EQ(ptr1_length
, ptr2
.length());
369 EXPECT_EQ(ptr1_offset
, ptr2
.offset());
370 EXPECT_EQ('X', ptr2
[0]);
373 TEST(BufferPtr
, release
) {
378 bufferptr
ptr2(ptr1
);
379 EXPECT_EQ(2, ptr1
.raw_nref());
381 EXPECT_EQ(1, ptr1
.raw_nref());
384 TEST(BufferPtr
, have_raw
) {
387 EXPECT_FALSE(ptr
.have_raw());
391 EXPECT_TRUE(ptr
.have_raw());
395 TEST(BufferPtr
, is_n_page_sized
) {
397 bufferptr
ptr(CEPH_PAGE_SIZE
);
398 EXPECT_TRUE(ptr
.is_n_page_sized());
402 EXPECT_FALSE(ptr
.is_n_page_sized());
406 TEST(BufferPtr
, is_partial
) {
408 EXPECT_FALSE(a
.is_partial());
410 EXPECT_FALSE(b
.is_partial());
411 bufferptr
c(b
, 1, 9);
412 EXPECT_TRUE(c
.is_partial());
413 bufferptr
d(b
, 0, 9);
414 EXPECT_TRUE(d
.is_partial());
417 TEST(BufferPtr
, accessors
) {
420 ptr
.c_str()[0] = 'X';
422 const bufferptr
const_ptr(ptr
);
424 EXPECT_NE((void*)nullptr, (void*)static_cast<instrumented_bptr
&>(ptr
).get_raw());
425 EXPECT_EQ('X', ptr
.c_str()[0]);
428 PrCtl unset_dumpable
;
429 EXPECT_DEATH(ptr
.c_str(), "");
430 EXPECT_DEATH(ptr
[0], "");
432 EXPECT_EQ('X', const_ptr
.c_str()[0]);
434 const bufferptr const_ptr
;
435 PrCtl unset_dumpable
;
436 EXPECT_DEATH(const_ptr
.c_str(), "");
437 EXPECT_DEATH(const_ptr
[0], "");
439 EXPECT_EQ(len
, const_ptr
.length());
440 EXPECT_EQ((unsigned)0, const_ptr
.offset());
441 EXPECT_EQ((unsigned)0, const_ptr
.start());
442 EXPECT_EQ(len
, const_ptr
.end());
443 EXPECT_EQ(len
, const_ptr
.end());
447 ptr
.set_length(ptr
.length() - unused
);
448 EXPECT_EQ(unused
, ptr
.unused_tail_length());
452 EXPECT_EQ((unsigned)0, ptr
.unused_tail_length());
455 PrCtl unset_dumpable
;
456 EXPECT_DEATH(ptr
[len
], "");
457 EXPECT_DEATH(const_ptr
[len
], "");
460 const bufferptr const_ptr
;
461 PrCtl unset_dumpable
;
462 EXPECT_DEATH(const_ptr
.raw_c_str(), "");
463 EXPECT_DEATH(const_ptr
.raw_length(), "");
464 EXPECT_DEATH(const_ptr
.raw_nref(), "");
466 EXPECT_NE((const char *)NULL
, const_ptr
.raw_c_str());
467 EXPECT_EQ(len
, const_ptr
.raw_length());
468 EXPECT_EQ(2, const_ptr
.raw_nref());
472 ptr
.set_length(ptr
.length() - wasted
* 2);
473 ptr
.set_offset(wasted
);
474 EXPECT_EQ(wasted
* 2, ptr
.wasted());
478 TEST(BufferPtr
, cmp
) {
481 bufferptr
ab("AB", 2);
482 bufferptr
af("AF", 2);
483 bufferptr
acc("ACC", 3);
484 EXPECT_GE(-1, empty
.cmp(a
));
485 EXPECT_LE(1, a
.cmp(empty
));
486 EXPECT_GE(-1, a
.cmp(ab
));
487 EXPECT_LE(1, ab
.cmp(a
));
488 EXPECT_EQ(0, ab
.cmp(ab
));
489 EXPECT_GE(-1, ab
.cmp(af
));
490 EXPECT_LE(1, af
.cmp(ab
));
491 EXPECT_GE(-1, acc
.cmp(af
));
492 EXPECT_LE(1, af
.cmp(acc
));
495 TEST(BufferPtr
, is_zero
) {
496 char str
[2] = { '\0', 'X' };
498 const bufferptr
ptr(buffer::create_static(2, str
));
499 EXPECT_FALSE(ptr
.is_zero());
502 const bufferptr
ptr(buffer::create_static(1, str
));
503 EXPECT_TRUE(ptr
.is_zero());
507 TEST(BufferPtr
, copy_out
) {
510 PrCtl unset_dumpable
;
511 EXPECT_DEATH(ptr
.copy_out((unsigned)0, (unsigned)0, NULL
), "");
515 const bufferptr
ptr(buffer::create_static(strlen(in
), in
));
516 EXPECT_THROW(ptr
.copy_out((unsigned)0, strlen(in
) + 1, NULL
), buffer::end_of_buffer
);
517 EXPECT_THROW(ptr
.copy_out(strlen(in
) + 1, (unsigned)0, NULL
), buffer::end_of_buffer
);
518 char out
[1] = { 'X' };
519 ptr
.copy_out((unsigned)1, (unsigned)1, out
);
520 EXPECT_EQ('B', out
[0]);
524 TEST(BufferPtr
, copy_out_bench
) {
525 for (int s
=1; s
<=8; s
*=2) {
526 utime_t start
= ceph_clock_now();
527 int buflen
= 1048576;
530 for (int i
=0; i
<count
; ++i
) {
531 bufferptr
bp(buflen
);
532 for (int64_t j
=0; j
<buflen
; j
+= s
) {
533 bp
.copy_out(j
, s
, (char *)&v
);
536 utime_t end
= ceph_clock_now();
537 cout
<< count
<< " fills of buffer len " << buflen
538 << " with " << s
<< " byte copy_out in "
539 << (end
- start
) << std::endl
;
543 TEST(BufferPtr
, copy_in
) {
546 PrCtl unset_dumpable
;
547 EXPECT_DEATH(ptr
.copy_in((unsigned)0, (unsigned)0, NULL
), "");
553 PrCtl unset_dumpable
;
554 EXPECT_DEATH(ptr
.copy_in((unsigned)0, strlen(in
) + 1, NULL
), "");
555 EXPECT_DEATH(ptr
.copy_in(strlen(in
) + 1, (unsigned)0, NULL
), "");
557 ptr
.copy_in((unsigned)0, (unsigned)2, in
);
558 EXPECT_EQ(in
[0], ptr
[0]);
559 EXPECT_EQ(in
[1], ptr
[1]);
563 TEST(BufferPtr
, copy_in_bench
) {
564 for (int s
=1; s
<=8; s
*=2) {
565 utime_t start
= ceph_clock_now();
566 int buflen
= 1048576;
568 for (int i
=0; i
<count
; ++i
) {
569 bufferptr
bp(buflen
);
570 for (int64_t j
=0; j
<buflen
; j
+= s
) {
571 bp
.copy_in(j
, s
, (char *)&j
, false);
574 utime_t end
= ceph_clock_now();
575 cout
<< count
<< " fills of buffer len " << buflen
576 << " with " << s
<< " byte copy_in in "
577 << (end
- start
) << std::endl
;
581 TEST(BufferPtr
, append
) {
584 PrCtl unset_dumpable
;
585 EXPECT_DEATH(ptr
.append('A'), "");
586 EXPECT_DEATH(ptr
.append("B", (unsigned)1), "");
591 PrCtl unset_dumpable
;
592 EXPECT_DEATH(ptr
.append('A'), "");
593 EXPECT_DEATH(ptr
.append("B", (unsigned)1), "");
597 EXPECT_EQ((unsigned)1, ptr
.length());
598 EXPECT_EQ('A', ptr
[0]);
599 ptr
.append("B", (unsigned)1);
600 EXPECT_EQ((unsigned)2, ptr
.length());
601 EXPECT_EQ('B', ptr
[1]);
605 TEST(BufferPtr
, append_bench
) {
607 memset(src
, 0, sizeof(src
));
608 for (int s
=4; s
<=16384; s
*=4) {
609 utime_t start
= ceph_clock_now();
610 int buflen
= 1048576;
612 for (int i
=0; i
<count
; ++i
) {
613 bufferptr
bp(buflen
);
615 for (int64_t j
=0; j
<buflen
; j
+= s
) {
616 bp
.append(src
+ j
, s
);
619 utime_t end
= ceph_clock_now();
620 cout
<< count
<< " fills of buffer len " << buflen
621 << " with " << s
<< " byte appends in "
622 << (end
- start
) << std::endl
;
626 TEST(BufferPtr
, zero
) {
628 bufferptr
ptr(buffer::create_static(strlen(str
), str
));
630 PrCtl unset_dumpable
;
631 EXPECT_DEATH(ptr
.zero(ptr
.length() + 1, 0), "");
634 EXPECT_EQ('X', ptr
[0]);
635 EXPECT_EQ('\0', ptr
[1]);
636 EXPECT_EQ('X', ptr
[2]);
638 EXPECT_EQ('\0', ptr
[0]);
641 TEST(BufferPtr
, ostream
) {
644 std::ostringstream stream
;
646 EXPECT_GT(stream
.str().size(), stream
.str().find("buffer:ptr(0~0 no raw"));
650 bufferptr
ptr(buffer::create_static(strlen(str
), str
));
651 std::ostringstream stream
;
653 EXPECT_GT(stream
.str().size(), stream
.str().find("len 4 nref 1)"));
661 // +----------+ +-----+ | | | |
662 // | append_ >-------> >--------------------> | |
663 // | buffer | +-----+ | | | |
664 // +----------+ ptr | | | |
665 // | _len | list +-----+ | | | |
666 // +----------+ +------+ ,--->+ >-----> | |
667 // | _buffers >----> >----- +-----+ | +-----+ |
668 // +----------+ +----^-+ \ ptr | raw |
669 // | last_p | / `-->+-----+ | +-----+ |
670 // +--------+-+ / + >-----> | |
671 // | ,- ,--->+-----+ | | | |
674 // +-v--+-^--+--^+-------+ | | | |
675 // | bl | ls | p | p_off >--------------->| | |
676 // +----+----+-----+-----+ | +-----+ |
677 // | | off >------------->| raw |
678 // +---------------+-----+ | |
679 // iterator +---------+
681 TEST(BufferListIterator
, constructors
) {
686 buffer::list::iterator i
;
687 EXPECT_EQ((unsigned)0, i
.get_off());
691 // iterator(list *l, unsigned o=0)
698 bufferlist::iterator
i(&bl
);
699 EXPECT_EQ((unsigned)0, i
.get_off());
703 bufferlist::iterator
i(&bl
, 1);
705 EXPECT_EQ((unsigned)2, i
.get_remaining());
710 // iterator(list *l, unsigned o, std::list<ptr>::iterator ip, unsigned po)
711 // not tested because of http://tracker.ceph.com/issues/4101
714 // iterator(const iterator& other)
719 bufferlist::iterator
i(&bl
, 1);
720 bufferlist::iterator
j(i
);
730 // const_iterator(const iterator& other)
735 bufferlist::iterator
i(&bl
);
736 bufferlist::const_iterator
ci(i
);
737 EXPECT_EQ(0u, ci
.get_off());
742 TEST(BufferListIterator
, empty_create_append_copy
) {
743 bufferlist bl
, bl2
, bl3
, out
;
749 bl
.begin().copy(6, out
);
750 ASSERT_TRUE(out
.contents_equal(bl
));
753 TEST(BufferListIterator
, operator_assign
) {
756 bufferlist::iterator
i(&bl
, 1);
758 #pragma clang diagnostic push
759 #pragma clang diagnostic ignored "-Wself-assign-overloaded"
761 #pragma clang diagnostic pop
763 bufferlist::iterator j
;
768 TEST(BufferListIterator
, get_off
) {
771 bufferlist::iterator
i(&bl
, 1);
772 EXPECT_EQ((unsigned)1, i
.get_off());
775 TEST(BufferListIterator
, get_remaining
) {
778 bufferlist::iterator
i(&bl
, 1);
779 EXPECT_EQ((unsigned)2, i
.get_remaining());
782 TEST(BufferListIterator
, end
) {
785 bufferlist::iterator
i(&bl
);
786 EXPECT_TRUE(i
.end());
790 bufferlist::iterator
i(&bl
);
791 EXPECT_FALSE(i
.end());
795 static void bench_bufferlistiter_deref(const size_t step
,
796 const size_t bufsize
,
797 const size_t bufnum
) {
798 const std::string
buf(bufsize
, 'a');
801 for (size_t i
= 0; i
< bufnum
; i
++) {
802 bl
.append(ceph::bufferptr(buf
.c_str(), buf
.size()));
805 utime_t start
= ceph_clock_now();
806 bufferlist::iterator iter
= bl
.begin();
807 while (iter
!= bl
.end()) {
810 utime_t end
= ceph_clock_now();
811 cout
<< bufsize
* bufnum
<< " derefs over bl with " << bufnum
812 << " buffers, each " << bufsize
<< " bytes long"
813 << " in " << (end
- start
) << std::endl
;
816 TEST(BufferListIterator
, BenchDeref
) {
817 bench_bufferlistiter_deref(1, 1, 4096000);
818 bench_bufferlistiter_deref(1, 10, 409600);
819 bench_bufferlistiter_deref(1, 100, 40960);
820 bench_bufferlistiter_deref(1, 1000, 4096);
822 bench_bufferlistiter_deref(4, 1, 1024000);
823 bench_bufferlistiter_deref(4, 10, 102400);
824 bench_bufferlistiter_deref(4, 100, 10240);
825 bench_bufferlistiter_deref(4, 1000, 1024);
828 TEST(BufferListIterator
, advance
) {
830 const std::string
one("ABC");
831 bl
.append(bufferptr(one
.c_str(), one
.size()));
832 const std::string
two("DEF");
833 bl
.append(bufferptr(two
.c_str(), two
.size()));
836 bufferlist::iterator
i(&bl
);
837 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
840 bufferlist::iterator
i(&bl
);
849 TEST(BufferListIterator
, iterate_with_empties
) {
851 EXPECT_EQ(bl
.get_num_buffers(), 0u);
853 bl
.push_back(ceph::buffer::create(0));
854 EXPECT_EQ(bl
.length(), 0u);
855 EXPECT_EQ(bl
.get_num_buffers(), 1u);
857 encode(int64_t(42), bl
);
858 EXPECT_EQ(bl
.get_num_buffers(), 2u);
860 bl
.push_back(ceph::buffer::create(0));
861 EXPECT_EQ(bl
.get_num_buffers(), 3u);
863 // append bufferlist with single, 0-sized ptr inside
865 ceph::bufferlist bl_with_empty_ptr
;
866 bl_with_empty_ptr
.push_back(ceph::buffer::create(0));
867 EXPECT_EQ(bl_with_empty_ptr
.length(), 0u);
868 EXPECT_EQ(bl_with_empty_ptr
.get_num_buffers(), 1u);
870 bl
.append(bl_with_empty_ptr
);
873 encode(int64_t(24), bl
);
874 EXPECT_EQ(bl
.get_num_buffers(), 5u);
876 auto i
= bl
.cbegin();
888 EXPECT_TRUE(i
== bl
.end());
893 EXPECT_FALSE(i
== bl
.end());
896 TEST(BufferListIterator
, get_ptr_and_advance
)
898 bufferptr
a("one", 3);
899 bufferptr
b("two", 3);
900 bufferptr
c("three", 5);
906 bufferlist::iterator p
= bl
.begin();
907 ASSERT_EQ(3u, p
.get_ptr_and_advance(11u, &ptr
));
908 ASSERT_EQ(bl
.length() - 3u, p
.get_remaining());
909 ASSERT_EQ(0, memcmp(ptr
, "one", 3));
910 ASSERT_EQ(2u, p
.get_ptr_and_advance(2u, &ptr
));
911 ASSERT_EQ(0, memcmp(ptr
, "tw", 2));
912 ASSERT_EQ(1u, p
.get_ptr_and_advance(4u, &ptr
));
913 ASSERT_EQ(0, memcmp(ptr
, "o", 1));
914 ASSERT_EQ(5u, p
.get_ptr_and_advance(5u, &ptr
));
915 ASSERT_EQ(0, memcmp(ptr
, "three", 5));
916 ASSERT_EQ(0u, p
.get_remaining());
919 TEST(BufferListIterator
, iterator_crc32c
) {
934 bufferlist::iterator it
= bl2
.begin();
935 ASSERT_EQ(bl1
.crc32c(0), it
.crc32c(it
.get_remaining(), 0));
936 ASSERT_EQ(0u, it
.get_remaining());
939 ASSERT_EQ(bl2
.crc32c(0), it
.crc32c(it
.get_remaining(), 0));
941 bl3
.append(s
.substr(98, 55));
944 ASSERT_EQ(bl3
.crc32c(0), it
.crc32c(55, 0));
945 ASSERT_EQ(4u, it
.get_remaining());
948 bl3
.append(s
.substr(98 + 55));
951 ASSERT_EQ(bl3
.crc32c(0), it
.crc32c(10, 0));
952 ASSERT_EQ(0u, it
.get_remaining());
955 TEST(BufferListIterator
, seek
) {
958 bufferlist::iterator
i(&bl
, 1);
964 TEST(BufferListIterator
, operator_star
) {
967 bufferlist::iterator
i(&bl
);
968 EXPECT_THROW(*i
, buffer::end_of_buffer
);
972 bufferlist::iterator
i(&bl
);
974 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
975 EXPECT_THROW(*i
, buffer::end_of_buffer
);
979 TEST(BufferListIterator
, operator_equal
) {
983 bufferlist::iterator
i(&bl
);
984 bufferlist::iterator
j(&bl
);
988 bufferlist::const_iterator ci
= bl
.begin();
989 bufferlist::iterator i
= bl
.begin();
995 TEST(BufferListIterator
, operator_nequal
) {
999 bufferlist::iterator
i(&bl
);
1000 bufferlist::iterator
j(&bl
);
1004 bufferlist::const_iterator ci
= bl
.begin();
1005 bufferlist::const_iterator cj
= bl
.begin();
1008 bufferlist::iterator i
= bl
.begin();
1013 // tests begin(), end(), operator++() also
1017 EXPECT_EQ(s
[i
++], c
);
1022 TEST(BufferListIterator
, operator_plus_plus
) {
1025 bufferlist::iterator
i(&bl
);
1026 EXPECT_THROW(++i
, buffer::end_of_buffer
);
1028 bl
.append("ABC", 3);
1030 bufferlist::iterator
i(&bl
);
1036 TEST(BufferListIterator
, get_current_ptr
) {
1039 bufferlist::iterator
i(&bl
);
1040 EXPECT_THROW(++i
, buffer::end_of_buffer
);
1042 bl
.append("ABC", 3);
1044 bufferlist::iterator
i(&bl
, 1);
1045 const buffer::ptr ptr
= i
.get_current_ptr();
1046 EXPECT_EQ('B', ptr
[0]);
1047 EXPECT_EQ((unsigned)1, ptr
.offset());
1048 EXPECT_EQ((unsigned)2, ptr
.length());
1052 TEST(BufferListIterator
, copy
) {
1054 const char *expected
= "ABC";
1055 bl
.append(expected
, 3);
1057 // void copy(unsigned len, char *dest);
1060 char* copy
= (char*)malloc(3);
1061 ::memset(copy
, 'X', 3);
1062 bufferlist::iterator
i(&bl
);
1064 // demonstrates that it seeks back to offset if p == ls->end()
1066 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
1068 EXPECT_EQ(0, ::memcmp(copy
, expected
, 2));
1069 EXPECT_EQ('X', copy
[2]);
1072 EXPECT_EQ(0, ::memcmp(copy
, expected
, 3));
1076 // void copy(unsigned len, char *dest) via begin(size_t offset)
1080 EXPECT_THROW(bl
.begin((unsigned)100).copy((unsigned)100, (char*)0), buffer::end_of_buffer
);
1081 const char *expected
= "ABC";
1082 bl
.append(expected
);
1083 char *dest
= new char[2];
1084 bl
.begin(1).copy(2, dest
);
1085 EXPECT_EQ(0, ::memcmp(expected
+ 1, dest
, 2));
1089 // void buffer::list::iterator::copy_deep(unsigned len, ptr &dest)
1093 bufferlist::iterator
i(&bl
);
1094 i
.copy_deep(2, ptr
);
1095 EXPECT_EQ((unsigned)2, ptr
.length());
1096 EXPECT_EQ('A', ptr
[0]);
1097 EXPECT_EQ('B', ptr
[1]);
1100 // void buffer::list::iterator::copy_shallow(unsigned len, ptr &dest)
1104 bufferlist::iterator
i(&bl
);
1105 i
.copy_shallow(2, ptr
);
1106 EXPECT_EQ((unsigned)2, ptr
.length());
1107 EXPECT_EQ('A', ptr
[0]);
1108 EXPECT_EQ('B', ptr
[1]);
1111 // void buffer::list::iterator::copy(unsigned len, list &dest)
1115 bufferlist::iterator
i(&bl
);
1117 // demonstrates that it seeks back to offset if p == ls->end()
1119 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
1121 EXPECT_EQ(0, ::memcmp(copy
.c_str(), expected
, 2));
1124 EXPECT_EQ('A', copy
[0]);
1125 EXPECT_EQ('B', copy
[1]);
1126 EXPECT_EQ('A', copy
[2]);
1127 EXPECT_EQ('B', copy
[3]);
1128 EXPECT_EQ('C', copy
[4]);
1129 EXPECT_EQ((unsigned)(2 + 3), copy
.length());
1132 // void buffer::list::iterator::copy(unsigned len, list &dest) via begin(size_t offset)
1137 EXPECT_THROW(bl
.begin((unsigned)100).copy((unsigned)100, dest
), buffer::end_of_buffer
);
1138 const char *expected
= "ABC";
1139 bl
.append(expected
);
1140 bl
.begin(1).copy(2, dest
);
1141 EXPECT_EQ(0, ::memcmp(expected
+ 1, dest
.c_str(), 2));
1144 // void buffer::list::iterator::copy_all(list &dest)
1148 bufferlist::iterator
i(&bl
);
1150 // demonstrates that it seeks back to offset if p == ls->end()
1152 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
1154 EXPECT_EQ('A', copy
[0]);
1155 EXPECT_EQ('B', copy
[1]);
1156 EXPECT_EQ('C', copy
[2]);
1157 EXPECT_EQ((unsigned)3, copy
.length());
1160 // void copy(unsigned len, std::string &dest)
1164 bufferlist::iterator
i(&bl
);
1166 // demonstrates that it seeks back to offset if p == ls->end()
1168 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
1170 EXPECT_EQ(0, ::memcmp(copy
.c_str(), expected
, 2));
1173 EXPECT_EQ('A', copy
[0]);
1174 EXPECT_EQ('B', copy
[1]);
1175 EXPECT_EQ('A', copy
[2]);
1176 EXPECT_EQ('B', copy
[3]);
1177 EXPECT_EQ('C', copy
[4]);
1178 EXPECT_EQ((unsigned)(2 + 3), copy
.length());
1181 // void copy(unsigned len, std::string &dest) via begin(size_t offset)
1186 EXPECT_THROW(bl
.begin((unsigned)100).copy((unsigned)100, dest
), buffer::end_of_buffer
);
1187 const char *expected
= "ABC";
1188 bl
.append(expected
);
1189 bl
.begin(1).copy(2, dest
);
1190 EXPECT_EQ(0, ::memcmp(expected
+ 1, dest
.c_str(), 2));
1194 TEST(BufferListIterator
, copy_in
) {
1196 const char *existing
= "XXX";
1197 bl
.append(existing
, 3);
1199 // void buffer::list::iterator::copy_in(unsigned len, const char *src)
1202 bufferlist::iterator
i(&bl
);
1204 // demonstrates that it seeks back to offset if p == ls->end()
1206 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
1207 const char *expected
= "ABC";
1208 i
.copy_in(3, expected
);
1209 EXPECT_EQ(0, ::memcmp(bl
.c_str(), expected
, 3));
1210 EXPECT_EQ('A', bl
[0]);
1211 EXPECT_EQ('B', bl
[1]);
1212 EXPECT_EQ('C', bl
[2]);
1213 EXPECT_EQ((unsigned)3, bl
.length());
1216 // void copy_in(unsigned len, const char *src) via begin(size_t offset)
1221 EXPECT_THROW(bl
.begin((unsigned)100).copy_in((unsigned)100, (char*)0), buffer::end_of_buffer
);
1222 bl
.begin(1).copy_in(2, "AB");
1223 EXPECT_EQ(0, ::memcmp("XAB", bl
.c_str(), 3));
1226 // void buffer::list::iterator::copy_in(unsigned len, const list& otherl)
1229 bufferlist::iterator
i(&bl
);
1231 // demonstrates that it seeks back to offset if p == ls->end()
1233 EXPECT_THROW(i
+= 200u, buffer::end_of_buffer
);
1234 bufferlist expected
;
1235 expected
.append("ABC", 3);
1236 i
.copy_in(3, expected
);
1237 EXPECT_EQ(0, ::memcmp(bl
.c_str(), expected
.c_str(), 3));
1238 EXPECT_EQ('A', bl
[0]);
1239 EXPECT_EQ('B', bl
[1]);
1240 EXPECT_EQ('C', bl
[2]);
1241 EXPECT_EQ((unsigned)3, bl
.length());
1244 // void copy_in(unsigned len, const list& src) via begin(size_t offset)
1251 EXPECT_THROW(bl
.begin((unsigned)100).copy_in((unsigned)100, src
), buffer::end_of_buffer
);
1252 bl
.begin(1).copy_in(2, src
);
1253 EXPECT_EQ(0, ::memcmp("XAB", bl
.c_str(), 3));
1257 // iterator& buffer::list::const_iterator::operator++()
1258 TEST(BufferListConstIterator
, operator_plus_plus
) {
1261 bufferlist::const_iterator
i(&bl
);
1262 EXPECT_THROW(++i
, buffer::end_of_buffer
);
1264 bl
.append("ABC", 3);
1266 const bufferlist
const_bl(bl
);
1267 bufferlist::const_iterator
i(const_bl
.begin());
1274 TEST(BufferList
, constructors
) {
1280 ASSERT_EQ((unsigned)0, bl
.length());
1283 // list(unsigned prealloc)
1287 ASSERT_EQ((unsigned)0, bl
.length());
1289 ASSERT_EQ('A', bl
[0]);
1292 // list(const list& other)
1297 ASSERT_EQ('A', bl
[0]);
1298 bufferlist
copy(bl
);
1299 ASSERT_EQ('A', copy
[0]);
1302 // list(list&& other)
1307 bufferlist copy
= std::move(bl
);
1308 ASSERT_EQ(0U, bl
.length());
1309 ASSERT_EQ(1U, copy
.length());
1310 ASSERT_EQ('A', copy
[0]);
1314 TEST(BufferList
, append_after_move
) {
1316 bl
.append("ABC", 3);
1317 EXPECT_EQ(1, bl
.get_num_buffers());
1319 bufferlist
moved_to_bl(std::move(bl
));
1320 moved_to_bl
.append("123", 3);
1321 // it's expected that the list(list&&) ctor will preserve the _carriage
1322 EXPECT_EQ(1, moved_to_bl
.get_num_buffers());
1323 EXPECT_EQ(0, ::memcmp("ABC123", moved_to_bl
.c_str(), 6));
1326 void bench_bufferlist_alloc(int size
, int num
, int per
)
1328 utime_t start
= ceph_clock_now();
1329 for (int i
=0; i
<num
; ++i
) {
1331 for (int j
=0; j
<per
; ++j
)
1332 bl
.push_back(buffer::ptr_node::create(buffer::create(size
)));
1334 utime_t end
= ceph_clock_now();
1335 cout
<< num
<< " alloc of size " << size
1336 << " in " << (end
- start
) << std::endl
;
1339 TEST(BufferList
, BenchAlloc
) {
1340 bench_bufferlist_alloc(32768, 100000, 16);
1341 bench_bufferlist_alloc(25000, 100000, 16);
1342 bench_bufferlist_alloc(16384, 100000, 16);
1343 bench_bufferlist_alloc(10000, 100000, 16);
1344 bench_bufferlist_alloc(8192, 100000, 16);
1345 bench_bufferlist_alloc(6000, 100000, 16);
1346 bench_bufferlist_alloc(4096, 100000, 16);
1347 bench_bufferlist_alloc(1024, 100000, 16);
1348 bench_bufferlist_alloc(256, 100000, 16);
1349 bench_bufferlist_alloc(32, 100000, 16);
1350 bench_bufferlist_alloc(4, 100000, 16);
1353 TEST(BufferList
, append_bench_with_size_hint
) {
1354 std::array
<char, 1048576> src
= { 0, };
1356 for (size_t step
= 4; step
<= 16384; step
*= 4) {
1357 const utime_t start
= ceph_clock_now();
1359 constexpr size_t rounds
= 4000;
1360 for (size_t r
= 0; r
< rounds
; ++r
) {
1361 ceph::bufferlist
bl(std::size(src
));
1362 for (auto iter
= std::begin(src
);
1363 iter
!= std::end(src
);
1364 iter
= std::next(iter
, step
)) {
1365 bl
.append(&*iter
, step
);
1368 cout
<< rounds
<< " fills of buffer len " << src
.size()
1369 << " with " << step
<< " byte appends in "
1370 << (ceph_clock_now() - start
) << std::endl
;
1374 TEST(BufferList
, append_bench
) {
1375 std::array
<char, 1048576> src
= { 0, };
1377 for (size_t step
= 4; step
<= 16384; step
*= 4) {
1378 const utime_t start
= ceph_clock_now();
1380 constexpr size_t rounds
= 4000;
1381 for (size_t r
= 0; r
< rounds
; ++r
) {
1382 ceph::bufferlist bl
;
1383 for (auto iter
= std::begin(src
);
1384 iter
!= std::end(src
);
1385 iter
= std::next(iter
, step
)) {
1386 bl
.append(&*iter
, step
);
1389 cout
<< rounds
<< " fills of buffer len " << src
.size()
1390 << " with " << step
<< " byte appends in "
1391 << (ceph_clock_now() - start
) << std::endl
;
1395 TEST(BufferList
, operator_assign_rvalue
) {
1406 EXPECT_EQ((unsigned)4, to
.length());
1407 EXPECT_EQ((unsigned)1, to
.get_num_buffers());
1408 to
= std::move(from
);
1409 EXPECT_EQ((unsigned)2, to
.length());
1410 EXPECT_EQ((unsigned)1, to
.get_num_buffers());
1411 EXPECT_EQ((unsigned)0, from
.get_num_buffers());
1412 EXPECT_EQ((unsigned)0, from
.length());
1415 TEST(BufferList
, operator_equal
) {
1417 // list& operator= (const list& other)
1420 bl
.append("ABC", 3);
1423 bl
.begin(1).copy(1, dest
);
1424 ASSERT_EQ('B', dest
[0]);
1427 bufferlist copy
= bl
;
1429 copy
.begin(1).copy(1, dest
);
1430 ASSERT_EQ('B', dest
[0]);
1434 // list& operator= (list&& other)
1437 move
= std::move(bl
);
1440 move
.begin(1).copy(1, dest
);
1441 ASSERT_EQ('B', dest
[0]);
1443 EXPECT_TRUE(move
.length());
1444 EXPECT_TRUE(!bl
.length());
1447 TEST(BufferList
, buffers
) {
1449 ASSERT_EQ((unsigned)0, bl
.get_num_buffers());
1451 ASSERT_EQ((unsigned)1, bl
.get_num_buffers());
1454 TEST(BufferList
, to_str
) {
1458 ASSERT_EQ(bl
.to_str(), string("foo"));
1461 bufferptr
a("foobarbaz", 9);
1462 bufferptr
b("123456789", 9);
1463 bufferptr
c("ABCDEFGHI", 9);
1468 ASSERT_EQ(bl
.to_str(), string("foobarbaz123456789ABCDEFGHI"));
1472 TEST(BufferList
, swap
) {
1482 b1
.begin().copy(1, s1
);
1483 ASSERT_EQ('B', s1
[0]);
1486 b2
.begin().copy(1, s2
);
1487 ASSERT_EQ('A', s2
[0]);
1490 TEST(BufferList
, length
) {
1492 ASSERT_EQ((unsigned)0, bl
.length());
1494 ASSERT_EQ((unsigned)1, bl
.length());
1497 TEST(BufferList
, contents_equal
) {
1506 ASSERT_FALSE(bl1
.contents_equal(bl2
)); // different length
1509 ASSERT_TRUE(bl1
.contents_equal(bl2
)); // same length same content
1515 ASSERT_FALSE(bl1
.contents_equal(bl3
)); // same length different content
1518 TEST(BufferList
, is_aligned
) {
1519 const int SIMD_ALIGN
= 32;
1522 EXPECT_TRUE(bl
.is_aligned(SIMD_ALIGN
));
1526 bufferptr
ptr(buffer::create_aligned(2, SIMD_ALIGN
));
1530 EXPECT_FALSE(bl
.is_aligned(SIMD_ALIGN
));
1531 bl
.rebuild_aligned(SIMD_ALIGN
);
1532 EXPECT_TRUE(bl
.is_aligned(SIMD_ALIGN
));
1536 bufferptr
ptr(buffer::create_aligned(SIMD_ALIGN
+ 1, SIMD_ALIGN
));
1538 ptr
.set_length(SIMD_ALIGN
);
1540 EXPECT_FALSE(bl
.is_aligned(SIMD_ALIGN
));
1541 bl
.rebuild_aligned(SIMD_ALIGN
);
1542 EXPECT_TRUE(bl
.is_aligned(SIMD_ALIGN
));
1546 TEST(BufferList
, is_n_align_sized
) {
1547 const int SIMD_ALIGN
= 32;
1550 EXPECT_TRUE(bl
.is_n_align_sized(SIMD_ALIGN
));
1555 EXPECT_FALSE(bl
.is_n_align_sized(SIMD_ALIGN
));
1559 bl
.append_zero(SIMD_ALIGN
);
1560 EXPECT_TRUE(bl
.is_n_align_sized(SIMD_ALIGN
));
1564 TEST(BufferList
, is_page_aligned
) {
1567 EXPECT_TRUE(bl
.is_page_aligned());
1571 bufferptr
ptr(buffer::create_page_aligned(2));
1575 EXPECT_FALSE(bl
.is_page_aligned());
1576 bl
.rebuild_page_aligned();
1577 EXPECT_TRUE(bl
.is_page_aligned());
1581 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
+ 1));
1583 ptr
.set_length(CEPH_PAGE_SIZE
);
1585 EXPECT_FALSE(bl
.is_page_aligned());
1586 bl
.rebuild_page_aligned();
1587 EXPECT_TRUE(bl
.is_page_aligned());
1591 TEST(BufferList
, is_n_page_sized
) {
1594 EXPECT_TRUE(bl
.is_n_page_sized());
1599 EXPECT_FALSE(bl
.is_n_page_sized());
1603 bl
.append_zero(CEPH_PAGE_SIZE
);
1604 EXPECT_TRUE(bl
.is_n_page_sized());
1608 TEST(BufferList
, page_aligned_appender
) {
1611 auto a
= bl
.get_page_aligned_appender(5);
1612 a
.append("asdf", 4);
1613 cout
<< bl
<< std::endl
;
1614 ASSERT_EQ(1u, bl
.get_num_buffers());
1615 ASSERT_TRUE(bl
.contents_equal("asdf", 4));
1616 a
.append("asdf", 4);
1617 for (unsigned n
= 0; n
< 3 * CEPH_PAGE_SIZE
; ++n
) {
1620 cout
<< bl
<< std::endl
;
1621 ASSERT_EQ(1u, bl
.get_num_buffers());
1622 // verify the beginning
1625 t
.substr_of(bl
, 0, 10);
1626 ASSERT_TRUE(t
.contents_equal("asdfasdfxx", 10));
1628 for (unsigned n
= 0; n
< 3 * CEPH_PAGE_SIZE
; ++n
) {
1631 cout
<< bl
<< std::endl
;
1632 ASSERT_EQ(2u, bl
.get_num_buffers());
1635 // ensure append_zero didn't introduce a fragmentation
1636 ASSERT_EQ(2u, bl
.get_num_buffers());
1637 // verify the end is actually zeroed
1640 t
.substr_of(bl
, bl
.length() - 42, 42);
1641 ASSERT_TRUE(t
.is_zero());
1644 // let's check whether appending a bufferlist directly to `bl`
1645 // doesn't fragment further C string appends via appender.
1647 const auto& initial_back
= bl
.back();
1650 src
.append("abc", 3);
1651 bl
.claim_append(src
);
1652 // surely the extra `ptr_node` taken from `src` must get
1653 // reflected in the `bl` instance
1654 ASSERT_EQ(3u, bl
.get_num_buffers());
1657 // moreover, the next C string-taking `append()` had to
1658 // create anoter `ptr_node` instance but...
1660 ASSERT_EQ(4u, bl
.get_num_buffers());
1662 // ... it should point to the same `buffer::raw` instance
1663 // (to the same same block of memory).
1664 ASSERT_EQ(bl
.back().raw_c_str(), initial_back
.raw_c_str());
1667 // check whether it'll take the first byte only and whether
1668 // the auto-flushing works.
1669 for (unsigned n
= 0; n
< 10 * CEPH_PAGE_SIZE
- 3; ++n
) {
1670 a
.append("zasdf", 1);
1675 cout
<< bl
<< std::endl
;
1676 ASSERT_EQ(6u, bl
.get_num_buffers());
1679 // Verify that `page_aligned_appender` does respect the carrying
1680 // `_carriage` over multiple allocations. Although `append_zero()`
1681 // is used here, this affects other members of the append family.
1682 // This part would be crucial for e.g. `encode()`.
1685 cout
<< bl
<< std::endl
;
1686 ASSERT_EQ(6u, bl
.get_num_buffers());
1690 TEST(BufferList
, rebuild_aligned_size_and_memory
) {
1691 const unsigned SIMD_ALIGN
= 32;
1692 const unsigned BUFFER_SIZE
= 67;
1695 // These two must be concatenated into one memory + size aligned
1698 bufferptr
ptr(buffer::create_aligned(2, SIMD_ALIGN
));
1704 bufferptr
ptr(buffer::create_aligned(BUFFER_SIZE
- 1, SIMD_ALIGN
));
1707 // This one must be left alone
1709 bufferptr
ptr(buffer::create_aligned(BUFFER_SIZE
, SIMD_ALIGN
));
1712 // These two must be concatenated into one memory + size aligned
1715 bufferptr
ptr(buffer::create_aligned(2, SIMD_ALIGN
));
1721 bufferptr
ptr(buffer::create_aligned(BUFFER_SIZE
- 1, SIMD_ALIGN
));
1724 EXPECT_FALSE(bl
.is_aligned(SIMD_ALIGN
));
1725 EXPECT_FALSE(bl
.is_n_align_sized(BUFFER_SIZE
));
1726 EXPECT_EQ(BUFFER_SIZE
* 3, bl
.length());
1727 EXPECT_FALSE(bl
.front().is_aligned(SIMD_ALIGN
));
1728 EXPECT_FALSE(bl
.front().is_n_align_sized(BUFFER_SIZE
));
1729 EXPECT_EQ(5U, bl
.get_num_buffers());
1730 bl
.rebuild_aligned_size_and_memory(BUFFER_SIZE
, SIMD_ALIGN
);
1731 EXPECT_TRUE(bl
.is_aligned(SIMD_ALIGN
));
1732 EXPECT_TRUE(bl
.is_n_align_sized(BUFFER_SIZE
));
1733 EXPECT_EQ(3U, bl
.get_num_buffers());
1736 /* bug replicator, to test rebuild_aligned_size_and_memory() in the
1737 * scenario where the first bptr is both size and memory aligned and
1738 * the second is 0-length */
1740 bufferptr
ptr1(buffer::create_aligned(4096, 4096));
1743 /* bl.back().length() must be 0 */
1744 bl
.append(ptr
, 0, 0);
1745 EXPECT_EQ(bl
.get_num_buffers(), 2);
1746 EXPECT_EQ(bl
.back().length(), 0);
1747 /* rebuild_aligned() calls rebuild_aligned_size_and_memory() */
1748 bl
.rebuild_aligned(4096);
1749 EXPECT_EQ(bl
.get_num_buffers(), 1);
1753 TEST(BufferList
, is_zero
) {
1756 EXPECT_TRUE(bl
.is_zero());
1761 EXPECT_FALSE(bl
.is_zero());
1766 EXPECT_TRUE(bl
.is_zero());
1769 for (size_t i
= 1; i
<= 256; ++i
) {
1772 EXPECT_TRUE(bl
.is_zero());
1774 // ensure buffer is a single, contiguous before testing
1776 EXPECT_FALSE(bl
.is_zero());
1781 TEST(BufferList
, clear
) {
1784 bl
.append_zero(len
);
1786 EXPECT_EQ((unsigned)0, bl
.length());
1787 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
1790 TEST(BufferList
, push_back
) {
1792 // void push_back(ptr& bp)
1798 EXPECT_EQ((unsigned)0, bl
.length());
1799 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
1806 ptr
.c_str()[0] = 'B';
1808 EXPECT_EQ((unsigned)(1 + len
), bl
.length());
1809 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
1810 EXPECT_EQ('B', bl
.back()[0]);
1811 const bufferptr
& back_bp
= bl
.back();
1812 EXPECT_EQ(static_cast<instrumented_bptr
&>(ptr
).get_raw(),
1813 static_cast<const instrumented_bptr
&>(back_bp
).get_raw());
1816 // void push_back(ptr&& bp)
1821 bl
.push_back(std::move(ptr
));
1822 EXPECT_EQ((unsigned)0, bl
.length());
1823 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
1829 ptr
.c_str()[0] = 'B';
1830 bl
.push_back(std::move(ptr
));
1831 EXPECT_EQ((unsigned)(1 + len
), bl
.length());
1832 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
1833 EXPECT_EQ('B', bl
.buffers().back()[0]);
1834 EXPECT_FALSE(static_cast<instrumented_bptr
&>(ptr
).get_raw());
1838 TEST(BufferList
, is_contiguous
) {
1840 EXPECT_TRUE(bl
.is_contiguous());
1841 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
1843 EXPECT_TRUE(bl
.is_contiguous());
1844 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
1847 EXPECT_FALSE(bl
.is_contiguous());
1848 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
1851 TEST(BufferList
, rebuild
) {
1854 bufferptr
ptr(buffer::create_page_aligned(2));
1860 EXPECT_FALSE(bl
.is_page_aligned());
1862 EXPECT_EQ(1U, bl
.length());
1863 EXPECT_EQ('Y', *bl
.begin());
1867 const std::string
str(CEPH_PAGE_SIZE
, 'X');
1868 bl
.append(str
.c_str(), str
.size());
1869 bl
.append(str
.c_str(), str
.size());
1870 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
1871 //EXPECT_TRUE(bl.is_aligned(CEPH_BUFFER_APPEND_SIZE));
1873 EXPECT_TRUE(bl
.is_page_aligned());
1874 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
1883 EXPECT_EQ((unsigned)1, bl
.length());
1884 bufferlist::iterator p
= bl
.begin();
1887 EXPECT_EQ(0, memcmp(dst
, "X", 1));
1891 TEST(BufferList
, rebuild_page_aligned
) {
1895 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
+ 1));
1897 ptr
.set_length(CEPH_PAGE_SIZE
);
1900 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
1901 EXPECT_FALSE(bl
.is_page_aligned());
1902 bl
.rebuild_page_aligned();
1903 EXPECT_TRUE(bl
.is_page_aligned());
1904 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
1908 bufferptr
ptr(buffer::create_page_aligned(1));
1909 char *p
= ptr
.c_str();
1911 bl
.rebuild_page_aligned();
1912 EXPECT_EQ(p
, bl
.front().c_str());
1917 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
));
1918 EXPECT_TRUE(ptr
.is_page_aligned());
1919 EXPECT_TRUE(ptr
.is_n_page_sized());
1923 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
+ 1));
1924 EXPECT_TRUE(ptr
.is_page_aligned());
1925 EXPECT_FALSE(ptr
.is_n_page_sized());
1929 bufferptr
ptr(buffer::create_page_aligned(2));
1932 EXPECT_FALSE(ptr
.is_page_aligned());
1933 EXPECT_FALSE(ptr
.is_n_page_sized());
1937 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
- 2));
1938 EXPECT_TRUE(ptr
.is_page_aligned());
1939 EXPECT_FALSE(ptr
.is_n_page_sized());
1943 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
));
1944 EXPECT_TRUE(ptr
.is_page_aligned());
1945 EXPECT_TRUE(ptr
.is_n_page_sized());
1949 bufferptr
ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE
+ 1));
1951 ptr
.set_length(CEPH_PAGE_SIZE
);
1952 EXPECT_FALSE(ptr
.is_page_aligned());
1953 EXPECT_TRUE(ptr
.is_n_page_sized());
1956 EXPECT_EQ((unsigned)6, bl
.get_num_buffers());
1957 EXPECT_TRUE((bl
.length() & ~CEPH_PAGE_MASK
) == 0);
1958 EXPECT_FALSE(bl
.is_page_aligned());
1959 bl
.rebuild_page_aligned();
1960 EXPECT_TRUE(bl
.is_page_aligned());
1961 EXPECT_EQ((unsigned)4, bl
.get_num_buffers());
1965 TEST(BufferList
, claim_append
) {
1976 EXPECT_EQ((unsigned)4, to
.length());
1977 EXPECT_EQ((unsigned)1, to
.get_num_buffers());
1978 to
.claim_append(from
);
1979 EXPECT_EQ((unsigned)(4 + 2), to
.length());
1980 EXPECT_EQ((unsigned)4, to
.front().length());
1981 EXPECT_EQ((unsigned)2, to
.back().length());
1982 EXPECT_EQ((unsigned)2, to
.get_num_buffers());
1983 EXPECT_EQ((unsigned)0, from
.get_num_buffers());
1984 EXPECT_EQ((unsigned)0, from
.length());
1987 TEST(BufferList
, begin
) {
1990 bufferlist::iterator i
= bl
.begin();
1994 TEST(BufferList
, end
) {
1997 bufferlist::iterator i
= bl
.end();
1999 EXPECT_EQ('C', bl
[i
.get_off()]);
2002 TEST(BufferList
, append
) {
2004 // void append(char c);
2008 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2010 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2011 //EXPECT_TRUE(bl.is_aligned(CEPH_BUFFER_APPEND_SIZE));
2014 // void append(const char *data, unsigned len);
2017 bufferlist
bl(CEPH_PAGE_SIZE
);
2018 std::string
str(CEPH_PAGE_SIZE
* 2, 'X');
2019 bl
.append(str
.c_str(), str
.size());
2020 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
2021 EXPECT_EQ(CEPH_PAGE_SIZE
, bl
.front().length());
2022 EXPECT_EQ(CEPH_PAGE_SIZE
, bl
.back().length());
2025 // void append(const std::string& s);
2028 bufferlist
bl(CEPH_PAGE_SIZE
);
2029 std::string
str(CEPH_PAGE_SIZE
* 2, 'X');
2031 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
2032 EXPECT_EQ(CEPH_PAGE_SIZE
, bl
.front().length());
2033 EXPECT_EQ(CEPH_PAGE_SIZE
, bl
.back().length());
2036 // void append(const ptr& bp);
2040 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2041 EXPECT_EQ((unsigned)0, bl
.length());
2045 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2046 EXPECT_EQ((unsigned)0, bl
.length());
2051 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2052 EXPECT_EQ((unsigned)3, bl
.length());
2056 // void append(const ptr& bp, unsigned off, unsigned len);
2061 bufferptr
back(bl
.back());
2063 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2064 EXPECT_EQ((unsigned)1, bl
.length());
2066 PrCtl unset_dumpable
;
2067 EXPECT_DEATH(bl
.append(in
, (unsigned)100, (unsigned)100), "");
2069 EXPECT_LT((unsigned)0, in
.unused_tail_length());
2071 bl
.append(in
, back
.end(), 1);
2072 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2073 EXPECT_EQ((unsigned)2, bl
.length());
2074 EXPECT_EQ('B', bl
[1]);
2078 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2079 EXPECT_EQ((unsigned)0, bl
.length());
2082 ptr
.append("AB", 2);
2083 bl
.append(ptr
, 1, 1);
2084 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2085 EXPECT_EQ((unsigned)1, bl
.length());
2088 // void append(const list& bl);
2096 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
2097 EXPECT_EQ('B', bl
[1]);
2100 // void append(std::istream& in);
2104 std::string
expected("ABC\nDEF\n");
2105 std::istringstream
is("ABC\n\nDEF");
2107 EXPECT_EQ(0, ::memcmp(expected
.c_str(), bl
.c_str(), expected
.size()));
2108 EXPECT_EQ(expected
.size(), bl
.length());
2111 // void append(ptr&& bp);
2115 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2116 EXPECT_EQ((unsigned)0, bl
.length());
2119 bl
.append(std::move(ptr
));
2120 EXPECT_EQ((unsigned)0, bl
.get_num_buffers());
2121 EXPECT_EQ((unsigned)0, bl
.length());
2125 bl
.append(std::move(ptr
));
2126 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2127 EXPECT_EQ((unsigned)3, bl
.length());
2128 EXPECT_FALSE(static_cast<instrumented_bptr
&>(ptr
).get_raw());
2133 TEST(BufferList
, append_hole
) {
2136 auto filler
= bl
.append_hole(1);
2137 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2138 EXPECT_EQ((unsigned)1, bl
.length());
2141 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2142 EXPECT_EQ((unsigned)3, bl
.length());
2145 filler
.copy_in((unsigned)1, &a
);
2146 EXPECT_EQ((unsigned)3, bl
.length());
2148 EXPECT_EQ(0, ::memcmp("ABC", bl
.c_str(), 3));
2154 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2155 EXPECT_EQ((unsigned)1, bl
.length());
2157 auto filler
= bl
.append_hole(1);
2158 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2159 EXPECT_EQ((unsigned)2, bl
.length());
2162 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2163 EXPECT_EQ((unsigned)3, bl
.length());
2166 filler
.copy_in((unsigned)1, &b
);
2167 EXPECT_EQ((unsigned)3, bl
.length());
2169 EXPECT_EQ(0, ::memcmp("ABC", bl
.c_str(), 3));
2173 TEST(BufferList
, append_zero
) {
2176 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2177 EXPECT_EQ((unsigned)1, bl
.length());
2179 EXPECT_EQ((unsigned)1, bl
.get_num_buffers());
2180 EXPECT_EQ((unsigned)2, bl
.length());
2181 EXPECT_EQ('\0', bl
[1]);
2184 TEST(BufferList
, operator_brackets
) {
2186 EXPECT_THROW(bl
[1], buffer::end_of_buffer
);
2191 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
2192 EXPECT_EQ('B', bl
[1]);
2195 TEST(BufferList
, c_str
) {
2197 EXPECT_EQ((const char*)NULL
, bl
.c_str());
2202 EXPECT_EQ((unsigned)2, bl
.get_num_buffers());
2203 EXPECT_EQ(0, ::memcmp("AB", bl
.c_str(), 2));
2206 TEST(BufferList
, substr_of
) {
2208 EXPECT_THROW(bl
.substr_of(bl
, 1, 1), buffer::end_of_buffer
);
2215 for (unsigned i
= 0; i
< 4; i
++) {
2216 bufferptr
ptr(s
[i
], strlen(s
[i
]));
2219 EXPECT_EQ((unsigned)4, bl
.get_num_buffers());
2222 other
.append("TO BE CLEARED");
2223 other
.substr_of(bl
, 4, 4);
2224 EXPECT_EQ((unsigned)2, other
.get_num_buffers());
2225 EXPECT_EQ((unsigned)4, other
.length());
2226 EXPECT_EQ(0, ::memcmp("EFGH", other
.c_str(), 4));
2229 TEST(BufferList
, splice
) {
2231 EXPECT_THROW(bl
.splice(1, 1), buffer::end_of_buffer
);
2238 for (unsigned i
= 0; i
< 4; i
++) {
2239 bufferptr
ptr(s
[i
], strlen(s
[i
]));
2242 EXPECT_EQ((unsigned)4, bl
.get_num_buffers());
2247 bl
.splice(4, 4, &other
);
2248 EXPECT_EQ((unsigned)3, other
.get_num_buffers());
2249 EXPECT_EQ((unsigned)5, other
.length());
2250 EXPECT_EQ(0, ::memcmp("XEFGH", other
.c_str(), other
.length()));
2251 EXPECT_EQ((unsigned)8, bl
.length());
2254 EXPECT_EQ(0, ::memcmp("ABCDIJKL", tmp
.c_str(), tmp
.length()));
2258 EXPECT_EQ((unsigned)4, bl
.length());
2259 EXPECT_EQ(0, ::memcmp("ABCD", bl
.c_str(), bl
.length()));
2263 bufferptr
ptr1("0123456789", 10);
2265 bufferptr
ptr2("abcdefghij", 10);
2266 bl
.append(ptr2
, 5, 5);
2268 bl
.splice(10, 4, &other
);
2269 EXPECT_EQ((unsigned)11, bl
.length());
2270 EXPECT_EQ(0, ::memcmp("fghi", other
.c_str(), other
.length()));
2274 TEST(BufferList
, write
) {
2275 std::ostringstream stream
;
2278 bl
.write(1, 2, stream
);
2279 EXPECT_EQ("BC", stream
.str());
2282 TEST(BufferList
, encode_base64
) {
2286 bl
.encode_base64(other
);
2287 const char *expected
= "QUJDRA==";
2288 EXPECT_EQ(0, ::memcmp(expected
, other
.c_str(), strlen(expected
)));
2291 TEST(BufferList
, decode_base64
) {
2293 bl
.append("QUJDRA==");
2295 other
.decode_base64(bl
);
2296 const char *expected
= "ABCD";
2297 EXPECT_EQ(0, ::memcmp(expected
, other
.c_str(), strlen(expected
)));
2298 bufferlist malformed
;
2299 malformed
.append("QUJDRA");
2300 EXPECT_THROW(other
.decode_base64(malformed
), buffer::malformed_input
);
2303 TEST(BufferList
, hexdump
) {
2305 std::ostringstream stream
;
2306 bl
.append("013245678901234\0006789012345678901234", 32);
2308 EXPECT_EQ("00000000 30 31 33 32 34 35 36 37 38 39 30 31 32 33 34 00 |013245678901234.|\n"
2309 "00000010 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 |6789012345678901|\n"
2314 TEST(BufferList
, read_file
) {
2318 EXPECT_EQ(-ENOENT
, bl
.read_file("UNLIKELY", &error
));
2319 snprintf(cmd
, sizeof(cmd
), "echo ABC> %s", FILENAME
);
2320 EXPECT_EQ(0, ::system(cmd
));
2322 snprintf(cmd
, sizeof(cmd
), "chmod 0 %s", FILENAME
);
2323 EXPECT_EQ(0, ::system(cmd
));
2324 if (getuid() != 0) {
2325 EXPECT_EQ(-EACCES
, bl
.read_file(FILENAME
, &error
));
2327 snprintf(cmd
, sizeof(cmd
), "chmod +r %s", FILENAME
);
2328 EXPECT_EQ(0, ::system(cmd
));
2330 EXPECT_EQ(0, bl
.read_file(FILENAME
, &error
));
2332 EXPECT_EQ((unsigned)4, bl
.length());
2333 std::string
actual(bl
.c_str(), bl
.length());
2334 EXPECT_EQ("ABC\n", actual
);
2337 TEST(BufferList
, read_fd
) {
2340 snprintf(cmd
, sizeof(cmd
), "echo ABC > %s", FILENAME
);
2341 EXPECT_EQ(0, ::system(cmd
));
2344 EXPECT_EQ(-EBADF
, bl
.read_fd(fd
, len
));
2345 fd
= ::open(FILENAME
, O_RDONLY
);
2347 EXPECT_EQ(len
, (unsigned)bl
.read_fd(fd
, len
));
2348 //EXPECT_EQ(CEPH_BUFFER_APPEND_SIZE - len, bl.front().unused_tail_length());
2349 EXPECT_EQ(len
, bl
.length());
2354 TEST(BufferList
, write_file
) {
2358 EXPECT_EQ(-ENOENT
, bl
.write_file("un/like/ly", mode
));
2360 EXPECT_EQ(0, bl
.write_file(FILENAME
, mode
));
2362 memset(&st
, 0, sizeof(st
));
2363 ASSERT_EQ(0, ::stat(FILENAME
, &st
));
2365 EXPECT_EQ((unsigned)(mode
| S_IFREG
), st
.st_mode
);
2370 TEST(BufferList
, write_fd
) {
2372 int fd
= ::open(FILENAME
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
2375 for (unsigned i
= 0; i
< IOV_MAX
* 2; i
++) {
2376 bufferptr
ptr("A", 1);
2379 EXPECT_EQ(0, bl
.write_fd(fd
));
2382 memset(&st
, 0, sizeof(st
));
2383 ASSERT_EQ(0, ::stat(FILENAME
, &st
));
2384 EXPECT_EQ(IOV_MAX
* 2, st
.st_size
);
2388 TEST(BufferList
, write_fd_offset
) {
2390 int fd
= ::open(FILENAME
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600);
2393 for (unsigned i
= 0; i
< IOV_MAX
* 2; i
++) {
2394 bufferptr
ptr("A", 1);
2397 uint64_t offset
= 200;
2398 EXPECT_EQ(0, bl
.write_fd(fd
, offset
));
2401 memset(&st
, 0, sizeof(st
));
2402 ASSERT_EQ(0, ::stat(FILENAME
, &st
));
2403 EXPECT_EQ(IOV_MAX
* 2 + offset
, (unsigned)st
.st_size
);
2407 TEST(BufferList
, crc32c
) {
2411 crc
= bl
.crc32c(crc
);
2412 EXPECT_EQ((unsigned)0xB3109EBF, crc
);
2413 crc
= bl
.crc32c(crc
);
2414 EXPECT_EQ((unsigned)0x5FA5C0CC, crc
);
2417 TEST(BufferList
, crc32c_append
) {
2421 for (int j
= 0; j
< 200; ++j
) {
2423 for (int i
= 0; i
< 200; ++i
) {
2428 bl
.crc32c(rand()); // mess with the cached bufferptr crc values
2431 ASSERT_EQ(bl1
.crc32c(0), bl2
.crc32c(0));
2434 TEST(BufferList
, crc32c_zeros
) {
2435 char buffer
[4*1024];
2436 for (size_t i
=0; i
< sizeof(buffer
); i
++)
2444 for (size_t j
=0; j
< 1000; j
++)
2446 bufferptr
a(buffer
, sizeof(buffer
));
2449 uint32_t crca
= bla
.crc32c(111);
2452 uint32_t crcb
= ceph_crc32c(111, (unsigned char*)blb
.c_str(), blb
.length());
2454 EXPECT_EQ(crca
, crcb
);
2458 TEST(BufferList
, crc32c_append_perf
) {
2459 int len
= 256 * 1024 * 1024;
2464 std::cout
<< "populating large buffers (a, b=c=d)" << std::endl
;
2465 char *pa
= a
.c_str();
2466 char *pb
= b
.c_str();
2467 char *pc
= c
.c_str();
2468 char *pd
= c
.c_str();
2469 for (int i
=0; i
<len
; i
++) {
2470 pa
[i
] = (i
& 0xff) ^ 73;
2471 pb
[i
] = (i
& 0xff) ^ 123;
2472 pc
[i
] = (i
& 0xff) ^ 123;
2473 pd
[i
] = (i
& 0xff) ^ 123;
2476 // track usage of cached crcs
2477 buffer::track_cached_crc(true);
2479 [[maybe_unused
]] int base_cached
= buffer::get_cached_crc();
2480 [[maybe_unused
]] int base_cached_adjusted
= buffer::get_cached_crc_adjusted();
2487 utime_t start
= ceph_clock_now();
2488 uint32_t r
= bla
.crc32c(0);
2489 utime_t end
= ceph_clock_now();
2490 float rate
= (float)len
/ (float)(1024*1024) / (float)(end
- start
);
2491 std::cout
<< "a.crc32c(0) = " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2492 ASSERT_EQ(r
, 1138817026u);
2494 ceph_assert(buffer::get_cached_crc() == 0 + base_cached
);
2496 utime_t start
= ceph_clock_now();
2497 uint32_t r
= bla
.crc32c(0);
2498 utime_t end
= ceph_clock_now();
2499 float rate
= (float)len
/ (float)(1024*1024) / (float)(end
- start
);
2500 std::cout
<< "a.crc32c(0) (again) = " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2501 ASSERT_EQ(r
, 1138817026u);
2503 ceph_assert(buffer::get_cached_crc() == 1 + base_cached
);
2506 utime_t start
= ceph_clock_now();
2507 uint32_t r
= bla
.crc32c(5);
2508 utime_t end
= ceph_clock_now();
2509 float rate
= (float)len
/ (float)(1024*1024) / (float)(end
- start
);
2510 std::cout
<< "a.crc32c(5) = " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2511 ASSERT_EQ(r
, 3239494520u);
2513 ceph_assert(buffer::get_cached_crc() == 1 + base_cached
);
2514 ceph_assert(buffer::get_cached_crc_adjusted() == 1 + base_cached_adjusted
);
2516 utime_t start
= ceph_clock_now();
2517 uint32_t r
= bla
.crc32c(5);
2518 utime_t end
= ceph_clock_now();
2519 float rate
= (float)len
/ (float)(1024*1024) / (float)(end
- start
);
2520 std::cout
<< "a.crc32c(5) (again) = " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2521 ASSERT_EQ(r
, 3239494520u);
2523 ceph_assert(buffer::get_cached_crc() == 1 + base_cached
);
2524 ceph_assert(buffer::get_cached_crc_adjusted() == 2 + base_cached_adjusted
);
2526 utime_t start
= ceph_clock_now();
2527 uint32_t r
= blb
.crc32c(0);
2528 utime_t end
= ceph_clock_now();
2529 float rate
= (float)len
/ (float)(1024*1024) / (float)(end
- start
);
2530 std::cout
<< "b.crc32c(0) = " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2531 ASSERT_EQ(r
, 2481791210u);
2533 ceph_assert(buffer::get_cached_crc() == 1 + base_cached
);
2535 utime_t start
= ceph_clock_now();
2536 uint32_t r
= blb
.crc32c(0);
2537 utime_t end
= ceph_clock_now();
2538 float rate
= (float)len
/ (float)(1024*1024) / (float)(end
- start
);
2539 std::cout
<< "b.crc32c(0) (again)= " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2540 ASSERT_EQ(r
, 2481791210u);
2542 ceph_assert(buffer::get_cached_crc() == 2 + base_cached
);
2548 utime_t start
= ceph_clock_now();
2549 uint32_t r
= ab
.crc32c(0);
2550 utime_t end
= ceph_clock_now();
2551 float rate
= (float)ab
.length() / (float)(1024*1024) / (float)(end
- start
);
2552 std::cout
<< "ab.crc32c(0) = " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2553 ASSERT_EQ(r
, 2988268779u);
2555 ceph_assert(buffer::get_cached_crc() == 3 + base_cached
);
2556 ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted
);
2561 utime_t start
= ceph_clock_now();
2562 uint32_t r
= ac
.crc32c(0);
2563 utime_t end
= ceph_clock_now();
2564 float rate
= (float)ac
.length() / (float)(1024*1024) / (float)(end
- start
);
2565 std::cout
<< "ac.crc32c(0) = " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2566 ASSERT_EQ(r
, 2988268779u);
2568 ceph_assert(buffer::get_cached_crc() == 4 + base_cached
);
2569 ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted
);
2575 utime_t start
= ceph_clock_now();
2576 uint32_t r
= ba
.crc32c(0);
2577 utime_t end
= ceph_clock_now();
2578 float rate
= (float)ba
.length() / (float)(1024*1024) / (float)(end
- start
);
2579 std::cout
<< "ba.crc32c(0) = " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2580 ASSERT_EQ(r
, 169240695u);
2582 ceph_assert(buffer::get_cached_crc() == 5 + base_cached
);
2583 ceph_assert(buffer::get_cached_crc_adjusted() == 4 + base_cached_adjusted
);
2585 utime_t start
= ceph_clock_now();
2586 uint32_t r
= ba
.crc32c(5);
2587 utime_t end
= ceph_clock_now();
2588 float rate
= (float)ba
.length() / (float)(1024*1024) / (float)(end
- start
);
2589 std::cout
<< "ba.crc32c(5) = " << r
<< " at " << rate
<< " MB/sec" << std::endl
;
2590 ASSERT_EQ(r
, 1265464778u);
2592 ceph_assert(buffer::get_cached_crc() == 5 + base_cached
);
2593 ceph_assert(buffer::get_cached_crc_adjusted() == 6 + base_cached_adjusted
);
2595 cout
<< "crc cache hits (same start) = " << buffer::get_cached_crc() << std::endl
;
2596 cout
<< "crc cache hits (adjusted) = " << buffer::get_cached_crc_adjusted() << std::endl
;
2599 TEST(BufferList
, compare
) {
2602 bufferlist ab
; // AB in segments
2603 ab
.append(bufferptr("A", 1));
2604 ab
.append(bufferptr("B", 1));
2608 // bool operator>(bufferlist& l, bufferlist& r)
2610 ASSERT_FALSE(a
> ab
);
2611 ASSERT_TRUE(ab
> a
);
2612 ASSERT_TRUE(ac
> ab
);
2613 ASSERT_FALSE(ab
> ac
);
2614 ASSERT_FALSE(ab
> ab
);
2616 // bool operator>=(bufferlist& l, bufferlist& r)
2618 ASSERT_FALSE(a
>= ab
);
2619 ASSERT_TRUE(ab
>= a
);
2620 ASSERT_TRUE(ac
>= ab
);
2621 ASSERT_FALSE(ab
>= ac
);
2622 ASSERT_TRUE(ab
>= ab
);
2624 // bool operator<(bufferlist& l, bufferlist& r)
2626 ASSERT_TRUE(a
< ab
);
2627 ASSERT_FALSE(ab
< a
);
2628 ASSERT_FALSE(ac
< ab
);
2629 ASSERT_TRUE(ab
< ac
);
2630 ASSERT_FALSE(ab
< ab
);
2632 // bool operator<=(bufferlist& l, bufferlist& r)
2634 ASSERT_TRUE(a
<= ab
);
2635 ASSERT_FALSE(ab
<= a
);
2636 ASSERT_FALSE(ac
<= ab
);
2637 ASSERT_TRUE(ab
<= ac
);
2638 ASSERT_TRUE(ab
<= ab
);
2640 // bool operator==(bufferlist &l, bufferlist &r)
2642 ASSERT_FALSE(a
== ab
);
2643 ASSERT_FALSE(ac
== ab
);
2644 ASSERT_TRUE(ab
== ab
);
2647 TEST(BufferList
, ostream
) {
2648 std::ostringstream stream
;
2654 for (unsigned i
= 0; i
< 2; i
++) {
2655 bufferptr
ptr(s
[i
], strlen(s
[i
]));
2659 std::cerr
<< stream
.str() << std::endl
;
2660 EXPECT_GT(stream
.str().size(), stream
.str().find("list(len=6,"));
2661 EXPECT_GT(stream
.str().size(), stream
.str().find("len 3 nref 1),\n"));
2662 EXPECT_GT(stream
.str().size(), stream
.str().find("len 3 nref 1)\n"));
2665 TEST(BufferList
, zero
) {
2672 EXPECT_EQ('A', bl
[0]);
2674 EXPECT_EQ('\0', bl
[0]);
2677 // void zero(unsigned o, unsigned l)
2687 bufferptr
ptr(s
[0], strlen(s
[0]));
2689 bl
.zero((unsigned)0, (unsigned)1);
2690 EXPECT_EQ(0, ::memcmp("\0BC", bl
.c_str(), 3));
2694 for (unsigned i
= 0; i
< 4; i
++) {
2695 bufferptr
ptr(s
[i
], strlen(s
[i
]));
2699 PrCtl unset_dumpable
;
2700 EXPECT_DEATH(bl
.zero((unsigned)0, (unsigned)2000), "");
2702 bl
.zero((unsigned)2, (unsigned)5);
2703 EXPECT_EQ(0, ::memcmp("AB\0\0\0\0\0HIKLM", bl
.c_str(), 9));
2707 for (unsigned i
= 0; i
< 4; i
++) {
2708 bufferptr
ptr(s
[i
], strlen(s
[i
]));
2711 bl
.zero((unsigned)3, (unsigned)3);
2712 EXPECT_EQ(0, ::memcmp("ABC\0\0\0GHIKLM", bl
.c_str(), 9));
2718 memset(ptr1
.c_str(), 'a', 4);
2719 memset(ptr2
.c_str(), 'b', 4);
2722 bl
.zero((unsigned)2, (unsigned)4);
2723 EXPECT_EQ(0, ::memcmp("aa\0\0\0\0bb", bl
.c_str(), 8));
2727 TEST(BufferList
, EmptyAppend
) {
2731 ASSERT_EQ(bl
.begin().end(), 1);
2734 TEST(BufferList
, InternalCarriage
) {
2735 ceph::bufferlist bl
;
2736 EXPECT_EQ(bl
.get_num_buffers(), 0u);
2738 encode(int64_t(42), bl
);
2739 EXPECT_EQ(bl
.get_num_buffers(), 1u);
2742 ceph::bufferlist bl_with_foo
;
2743 bl_with_foo
.append("foo", 3);
2744 EXPECT_EQ(bl_with_foo
.length(), 3u);
2745 EXPECT_EQ(bl_with_foo
.get_num_buffers(), 1u);
2747 bl
.append(bl_with_foo
);
2748 EXPECT_EQ(bl
.get_num_buffers(), 2u);
2751 encode(int64_t(24), bl
);
2752 EXPECT_EQ(bl
.get_num_buffers(), 3u);
2755 TEST(BufferList
, ContiguousAppender
) {
2756 ceph::bufferlist bl
;
2757 EXPECT_EQ(bl
.get_num_buffers(), 0u);
2759 // we expect a flush in ~contiguous_appender
2761 auto ap
= bl
.get_contiguous_appender(100);
2763 denc(int64_t(42), ap
);
2764 EXPECT_EQ(bl
.get_num_buffers(), 1u);
2766 // append bufferlist with single ptr inside. This should
2767 // commit changes to bl::_len and the underlying bp::len.
2769 ceph::bufferlist bl_with_foo
;
2770 bl_with_foo
.append("foo", 3);
2771 EXPECT_EQ(bl_with_foo
.length(), 3u);
2772 EXPECT_EQ(bl_with_foo
.get_num_buffers(), 1u);
2774 ap
.append(bl_with_foo
);
2775 // 3 as the ap::append(const bl&) splits the bp with free
2777 EXPECT_EQ(bl
.get_num_buffers(), 3u);
2780 denc(int64_t(24), ap
);
2781 EXPECT_EQ(bl
.get_num_buffers(), 3u);
2782 EXPECT_EQ(bl
.length(), sizeof(int64_t) + 3u);
2784 EXPECT_EQ(bl
.length(), 2u * sizeof(int64_t) + 3u);
2787 TEST(BufferList
, TestPtrAppend
) {
2789 char correct
[MAX_TEST
];
2791 int length
= random() % 5 > 0 ? random() % 1000 : 0;
2792 while (curpos
+ length
< MAX_TEST
) {
2797 char *current
= correct
+ curpos
;
2798 for (int i
= 0; i
< length
; ++i
) {
2799 char next
= random() % 255;
2800 correct
[curpos
++] = next
;
2802 bufferptr
ptr(current
, length
);
2805 length
= random() % 5 > 0 ? random() % 1000 : 0;
2807 ASSERT_EQ(memcmp(bl
.c_str(), correct
, curpos
), 0);
2810 TEST(BufferList
, TestDirectAppend
) {
2812 char correct
[MAX_TEST
];
2814 int length
= random() % 5 > 0 ? random() % 1000 : 0;
2815 while (curpos
+ length
< MAX_TEST
) {
2816 char *current
= correct
+ curpos
;
2817 for (int i
= 0; i
< length
; ++i
) {
2818 char next
= random() % 255;
2819 correct
[curpos
++] = next
;
2821 bl
.append(current
, length
);
2822 length
= random() % 5 > 0 ? random() % 1000 : 0;
2824 ASSERT_EQ(memcmp(bl
.c_str(), correct
, curpos
), 0);
2827 TEST(BufferList
, TestCopyAll
) {
2828 const static size_t BIG_SZ
= 10737414;
2829 std::shared_ptr
<unsigned char> big(
2830 (unsigned char*)malloc(BIG_SZ
), free
);
2831 unsigned char c
= 0;
2832 for (size_t i
= 0; i
< BIG_SZ
; ++i
) {
2836 bl
.append((const char*)big
.get(), BIG_SZ
);
2837 bufferlist::iterator i
= bl
.begin();
2840 ASSERT_EQ(bl2
.length(), BIG_SZ
);
2841 std::shared_ptr
<unsigned char> big2(
2842 (unsigned char*)malloc(BIG_SZ
), free
);
2843 bl2
.begin().copy(BIG_SZ
, (char*)big2
.get());
2844 ASSERT_EQ(memcmp(big
.get(), big2
.get(), BIG_SZ
), 0);
2847 TEST(BufferList
, InvalidateCrc
) {
2848 const static size_t buffer_size
= 262144;
2849 std::shared_ptr
<unsigned char> big(
2850 (unsigned char*)malloc(buffer_size
), free
);
2851 unsigned char c
= 0;
2852 char* ptr
= (char*) big
.get();
2854 for (size_t i
= 0; i
< buffer_size
; ++i
) {
2859 // test for crashes (shouldn't crash)
2860 bl
.invalidate_crc();
2862 // put data into bufferlist
2863 bl
.append((const char*)big
.get(), buffer_size
);
2866 __u32 crc
= bl
.crc32c(0);
2868 // modify data in bl without its knowledge
2869 inptr
= (char*) bl
.c_str();
2871 for (size_t i
= 0; i
< buffer_size
; ++i
) {
2875 // make sure data in bl are now different than in big
2876 EXPECT_NE(memcmp((void*) ptr
, (void*) inptr
, buffer_size
), 0);
2878 // crc should remain the same
2879 __u32 new_crc
= bl
.crc32c(0);
2880 EXPECT_EQ(crc
, new_crc
);
2882 // force crc invalidate, check if it is updated
2883 bl
.invalidate_crc();
2884 EXPECT_NE(crc
, bl
.crc32c(0));
2887 TEST(BufferList
, TestIsProvidedBuffer
) {
2890 bl
.push_back(buffer::create_static(100, buff
));
2891 ASSERT_TRUE(bl
.is_provided_buffer(buff
));
2892 bl
.append_zero(100);
2893 ASSERT_FALSE(bl
.is_provided_buffer(buff
));
2896 TEST(BufferList
, DISABLED_DanglingLastP
) {
2899 // previously we're using the unsharable buffer type to distinguish
2900 // the last_p-specific problem from the generic crosstalk issues we
2901 // had since the very beginning:
2902 // https://gist.github.com/rzarzynski/aed18372e88aed392101adac3bd87bbc
2903 // this is no longer possible as `buffer::create_unsharable()` has
2905 bufferptr
bp(buffer::create(10));
2906 bp
.copy_in(0, 3, "XXX");
2907 bl
.push_back(std::move(bp
));
2908 EXPECT_EQ(0, ::memcmp("XXX", bl
.c_str(), 3));
2910 // let `copy_in` to set `last_p` member of bufferlist
2911 bl
.begin().copy_in(2, "AB");
2912 EXPECT_EQ(0, ::memcmp("ABX", bl
.c_str(), 3));
2916 // before the fix this would have left `last_p` unchanged leading to
2917 // the dangerous dangling state – keep in mind that the initial,
2918 // unsharable bptr will be freed.
2919 bl
= const_cast<const bufferlist
&>(empty
);
2922 // we must continue from where the previous copy_in had finished.
2923 // Otherwise `bl::copy_in` will call `seek()` and refresh `last_p`.
2924 bl
.begin(2).copy_in(1, "C");
2925 EXPECT_EQ(0, ::memcmp("12C", bl
.c_str(), 3));
2928 TEST(BufferHash
, all
) {
2933 EXPECT_EQ((unsigned)0, hash
.digest());
2935 EXPECT_EQ((unsigned)0xB3109EBF, hash
.digest());
2937 EXPECT_EQ((unsigned)0x5FA5C0CC, hash
.digest());
2943 EXPECT_EQ((unsigned)0, hash
.digest());
2944 bufferhash
& returned_hash
= hash
<< bl
;
2945 EXPECT_EQ(&returned_hash
, &hash
);
2946 EXPECT_EQ((unsigned)0xB3109EBF, hash
.digest());
2952 * compile-command: "cd .. ; make unittest_bufferlist &&
2953 * ulimit -s unlimited ; valgrind \
2954 * --max-stackframe=20000000 --tool=memcheck \
2955 * ./unittest_bufferlist # --gtest_filter=BufferList.constructors"