]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/bufferlist.cc
import ceph 16.2.6
[ceph.git] / ceph / src / test / bufferlist.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
7 *
8 * Author: Loic Dachary <loic@dachary.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library Public License for more details.
19 *
20 */
21
22 #include <limits.h>
23 #include <errno.h>
24 #include <sys/uio.h>
25
26 #include "include/buffer.h"
27 #include "include/buffer_raw.h"
28 #include "include/compat.h"
29 #include "include/utime.h"
30 #include "include/coredumpctl.h"
31 #include "include/encoding.h"
32 #include "common/environment.h"
33 #include "common/Clock.h"
34 #include "common/safe_io.h"
35
36 #include "gtest/gtest.h"
37 #include "stdlib.h"
38 #include "fcntl.h"
39 #include "sys/stat.h"
40 #include "include/crc32c.h"
41 #include "common/sctp_crc32.h"
42
43 #define MAX_TEST 1000000
44 #define FILENAME "bufferlist"
45
46 static char cmd[128];
47
48 struct instrumented_bptr : public ceph::buffer::ptr {
49 const ceph::buffer::raw* get_raw() const {
50 return _raw;
51 }
52 };
53
54 TEST(Buffer, constructors) {
55 unsigned len = 17;
56 //
57 // buffer::create
58 //
59 {
60 bufferptr ptr(buffer::create(len));
61 EXPECT_EQ(len, ptr.length());
62 }
63 //
64 // buffer::claim_char
65 //
66 {
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));
74 delete [] str;
75 }
76 //
77 // buffer::create_static
78 //
79 {
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());
84 delete [] str;
85 }
86 //
87 // buffer::create_malloc
88 //
89 {
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);
94 }
95 //
96 // buffer::claim_malloc
97 //
98 {
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));
106 }
107 //
108 // buffer::copy
109 //
110 {
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));
115 }
116 //
117 // buffer::create_page_aligned
118 //
119 {
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);
124 #ifndef DARWIN
125 ASSERT_TRUE(ptr.is_page_aligned());
126 #endif // DARWIN
127 bufferptr clone = ptr.clone();
128 EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len));
129 }
130 }
131
132 void bench_buffer_alloc(int size, int num)
133 {
134 utime_t start = ceph_clock_now();
135 for (int i=0; i<num; ++i) {
136 bufferptr p = buffer::create(size);
137 p.zero();
138 }
139 utime_t end = ceph_clock_now();
140 cout << num << " alloc of size " << size
141 << " in " << (end - start) << std::endl;
142 }
143
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);
151 }
152
153 TEST(BufferRaw, ostream) {
154 bufferptr ptr(1);
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)"));
159 }
160
161 //
162 // +-----------+ +-----+
163 // | | | |
164 // | offset +----------------+ |
165 // | | | |
166 // | length +---- | |
167 // | | \------- | |
168 // +-----------+ \---+ |
169 // | ptr | +-----+
170 // +-----------+ | raw |
171 // +-----+
172 //
173 TEST(BufferPtr, constructors) {
174 unsigned len = 17;
175 //
176 // ptr::ptr()
177 //
178 {
179 buffer::ptr ptr;
180 EXPECT_FALSE(ptr.have_raw());
181 EXPECT_EQ((unsigned)0, ptr.offset());
182 EXPECT_EQ((unsigned)0, ptr.length());
183 }
184 //
185 // ptr::ptr(raw *r)
186 //
187 {
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());
194 }
195 //
196 // ptr::ptr(unsigned l)
197 //
198 {
199 bufferptr ptr(len);
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());
204 }
205 //
206 // ptr(const char *d, unsigned l)
207 //
208 {
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));
216 }
217 //
218 // ptr(const ptr& p)
219 //
220 {
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));
229 }
230 //
231 // ptr(const ptr& p, unsigned o, unsigned l)
232 //
233 {
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), "");
245 }
246 //
247 // ptr(ptr&& p)
248 //
249 {
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());
257 }
258 }
259
260 TEST(BufferPtr, operator_assign) {
261 //
262 // ptr& operator= (const ptr& p)
263 //
264 bufferptr ptr(10);
265 ptr.copy_in(0, 3, "ABC");
266 char dest[1];
267 {
268 bufferptr copy = ptr;
269 copy.copy_out(1, 1, dest);
270 ASSERT_EQ('B', dest[0]);
271 }
272
273 //
274 // ptr& operator= (ptr&& p)
275 //
276 bufferptr move = std::move(ptr);
277 {
278 move.copy_out(1, 1, dest);
279 ASSERT_EQ('B', dest[0]);
280 }
281 EXPECT_FALSE(ptr.have_raw());
282 }
283
284 TEST(BufferPtr, assignment) {
285 unsigned len = 17;
286 //
287 // override a bufferptr set with the same raw
288 //
289 {
290 bufferptr original(len);
291 bufferptr same_raw(original);
292 unsigned offset = 5;
293 unsigned length = len - offset;
294 original.set_offset(offset);
295 original.set_length(length);
296 same_raw = original;
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());
302 }
303
304 //
305 // self assignment is a noop
306 //
307 {
308 bufferptr original(len);
309 #pragma clang diagnostic push
310 #pragma clang diagnostic ignored "-Wself-assign-overloaded"
311 original = original;
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());
316 }
317
318 //
319 // a copy points to the same raw
320 //
321 {
322 bufferptr original(len);
323 unsigned offset = 5;
324 unsigned length = len - offset;
325 original.set_offset(offset);
326 original.set_length(length);
327 bufferptr ptr;
328 ptr = original;
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());
334 }
335 }
336
337 TEST(BufferPtr, clone) {
338 unsigned len = 17;
339 bufferptr ptr(len);
340 ::memset(ptr.c_str(), 'X', len);
341 bufferptr clone = ptr.clone();
342 EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len));
343 }
344
345 TEST(BufferPtr, swap) {
346 unsigned len = 17;
347
348 bufferptr ptr1(len);
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);
354
355 bufferptr ptr2(len);
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);
361
362 ptr1.swap(ptr2);
363
364 EXPECT_EQ(ptr2_length, ptr1.length());
365 EXPECT_EQ(ptr2_offset, ptr1.offset());
366 EXPECT_EQ('Y', ptr1[0]);
367
368 EXPECT_EQ(ptr1_length, ptr2.length());
369 EXPECT_EQ(ptr1_offset, ptr2.offset());
370 EXPECT_EQ('X', ptr2[0]);
371 }
372
373 TEST(BufferPtr, release) {
374 unsigned len = 17;
375
376 bufferptr ptr1(len);
377 {
378 bufferptr ptr2(ptr1);
379 EXPECT_EQ(2, ptr1.raw_nref());
380 }
381 EXPECT_EQ(1, ptr1.raw_nref());
382 }
383
384 TEST(BufferPtr, have_raw) {
385 {
386 bufferptr ptr;
387 EXPECT_FALSE(ptr.have_raw());
388 }
389 {
390 bufferptr ptr(1);
391 EXPECT_TRUE(ptr.have_raw());
392 }
393 }
394
395 TEST(BufferPtr, is_n_page_sized) {
396 {
397 bufferptr ptr(CEPH_PAGE_SIZE);
398 EXPECT_TRUE(ptr.is_n_page_sized());
399 }
400 {
401 bufferptr ptr(1);
402 EXPECT_FALSE(ptr.is_n_page_sized());
403 }
404 }
405
406 TEST(BufferPtr, is_partial) {
407 bufferptr a;
408 EXPECT_FALSE(a.is_partial());
409 bufferptr b(10);
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());
415 }
416
417 TEST(BufferPtr, accessors) {
418 unsigned len = 17;
419 bufferptr ptr(len);
420 ptr.c_str()[0] = 'X';
421 ptr[1] = 'Y';
422 const bufferptr const_ptr(ptr);
423
424 EXPECT_NE((void*)nullptr, (void*)static_cast<instrumented_bptr&>(ptr).get_raw());
425 EXPECT_EQ('X', ptr.c_str()[0]);
426 {
427 bufferptr ptr;
428 PrCtl unset_dumpable;
429 EXPECT_DEATH(ptr.c_str(), "");
430 EXPECT_DEATH(ptr[0], "");
431 }
432 EXPECT_EQ('X', const_ptr.c_str()[0]);
433 {
434 const bufferptr const_ptr;
435 PrCtl unset_dumpable;
436 EXPECT_DEATH(const_ptr.c_str(), "");
437 EXPECT_DEATH(const_ptr[0], "");
438 }
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());
444 {
445 bufferptr ptr(len);
446 unsigned unused = 1;
447 ptr.set_length(ptr.length() - unused);
448 EXPECT_EQ(unused, ptr.unused_tail_length());
449 }
450 {
451 bufferptr ptr;
452 EXPECT_EQ((unsigned)0, ptr.unused_tail_length());
453 }
454 {
455 PrCtl unset_dumpable;
456 EXPECT_DEATH(ptr[len], "");
457 EXPECT_DEATH(const_ptr[len], "");
458 }
459 {
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(), "");
465 }
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());
469 {
470 bufferptr ptr(len);
471 unsigned wasted = 1;
472 ptr.set_length(ptr.length() - wasted * 2);
473 ptr.set_offset(wasted);
474 EXPECT_EQ(wasted * 2, ptr.wasted());
475 }
476 }
477
478 TEST(BufferPtr, cmp) {
479 bufferptr empty;
480 bufferptr a("A", 1);
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));
493 }
494
495 TEST(BufferPtr, is_zero) {
496 char str[2] = { '\0', 'X' };
497 {
498 const bufferptr ptr(buffer::create_static(2, str));
499 EXPECT_FALSE(ptr.is_zero());
500 }
501 {
502 const bufferptr ptr(buffer::create_static(1, str));
503 EXPECT_TRUE(ptr.is_zero());
504 }
505 }
506
507 TEST(BufferPtr, copy_out) {
508 {
509 const bufferptr ptr;
510 PrCtl unset_dumpable;
511 EXPECT_DEATH(ptr.copy_out((unsigned)0, (unsigned)0, NULL), "");
512 }
513 {
514 char in[] = "ABC";
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]);
521 }
522 }
523
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;
528 int count = 1000;
529 uint64_t v;
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);
534 }
535 }
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;
540 }
541 }
542
543 TEST(BufferPtr, copy_in) {
544 {
545 bufferptr ptr;
546 PrCtl unset_dumpable;
547 EXPECT_DEATH(ptr.copy_in((unsigned)0, (unsigned)0, NULL), "");
548 }
549 {
550 char in[] = "ABCD";
551 bufferptr ptr(2);
552 {
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), "");
556 }
557 ptr.copy_in((unsigned)0, (unsigned)2, in);
558 EXPECT_EQ(in[0], ptr[0]);
559 EXPECT_EQ(in[1], ptr[1]);
560 }
561 }
562
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;
567 int count = 1000;
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);
572 }
573 }
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;
578 }
579 }
580
581 TEST(BufferPtr, append) {
582 {
583 bufferptr ptr;
584 PrCtl unset_dumpable;
585 EXPECT_DEATH(ptr.append('A'), "");
586 EXPECT_DEATH(ptr.append("B", (unsigned)1), "");
587 }
588 {
589 bufferptr ptr(2);
590 {
591 PrCtl unset_dumpable;
592 EXPECT_DEATH(ptr.append('A'), "");
593 EXPECT_DEATH(ptr.append("B", (unsigned)1), "");
594 }
595 ptr.set_length(0);
596 ptr.append('A');
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]);
602 }
603 }
604
605 TEST(BufferPtr, append_bench) {
606 char src[1048576];
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;
611 int count = 4000;
612 for (int i=0; i<count; ++i) {
613 bufferptr bp(buflen);
614 bp.set_length(0);
615 for (int64_t j=0; j<buflen; j += s) {
616 bp.append(src + j, s);
617 }
618 }
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;
623 }
624 }
625
626 TEST(BufferPtr, zero) {
627 char str[] = "XXXX";
628 bufferptr ptr(buffer::create_static(strlen(str), str));
629 {
630 PrCtl unset_dumpable;
631 EXPECT_DEATH(ptr.zero(ptr.length() + 1, 0), "");
632 }
633 ptr.zero(1, 1);
634 EXPECT_EQ('X', ptr[0]);
635 EXPECT_EQ('\0', ptr[1]);
636 EXPECT_EQ('X', ptr[2]);
637 ptr.zero();
638 EXPECT_EQ('\0', ptr[0]);
639 }
640
641 TEST(BufferPtr, ostream) {
642 {
643 bufferptr ptr;
644 std::ostringstream stream;
645 stream << ptr;
646 EXPECT_GT(stream.str().size(), stream.str().find("buffer:ptr(0~0 no raw"));
647 }
648 {
649 char str[] = "XXXX";
650 bufferptr ptr(buffer::create_static(strlen(str), str));
651 std::ostringstream stream;
652 stream << ptr;
653 EXPECT_GT(stream.str().size(), stream.str().find("len 4 nref 1)"));
654 }
655 }
656
657 //
658 // +---------+
659 // | +-----+ |
660 // list ptr | | | |
661 // +----------+ +-----+ | | | |
662 // | append_ >-------> >--------------------> | |
663 // | buffer | +-----+ | | | |
664 // +----------+ ptr | | | |
665 // | _len | list +-----+ | | | |
666 // +----------+ +------+ ,--->+ >-----> | |
667 // | _buffers >----> >----- +-----+ | +-----+ |
668 // +----------+ +----^-+ \ ptr | raw |
669 // | last_p | / `-->+-----+ | +-----+ |
670 // +--------+-+ / + >-----> | |
671 // | ,- ,--->+-----+ | | | |
672 // | / ,--- | | | |
673 // | / ,--- | | | |
674 // +-v--+-^--+--^+-------+ | | | |
675 // | bl | ls | p | p_off >--------------->| | |
676 // +----+----+-----+-----+ | +-----+ |
677 // | | off >------------->| raw |
678 // +---------------+-----+ | |
679 // iterator +---------+
680 //
681 TEST(BufferListIterator, constructors) {
682 //
683 // iterator()
684 //
685 {
686 buffer::list::iterator i;
687 EXPECT_EQ((unsigned)0, i.get_off());
688 }
689
690 //
691 // iterator(list *l, unsigned o=0)
692 //
693 {
694 bufferlist bl;
695 bl.append("ABC", 3);
696
697 {
698 bufferlist::iterator i(&bl);
699 EXPECT_EQ((unsigned)0, i.get_off());
700 EXPECT_EQ('A', *i);
701 }
702 {
703 bufferlist::iterator i(&bl, 1);
704 EXPECT_EQ('B', *i);
705 EXPECT_EQ((unsigned)2, i.get_remaining());
706 }
707 }
708
709 //
710 // iterator(list *l, unsigned o, std::list<ptr>::iterator ip, unsigned po)
711 // not tested because of http://tracker.ceph.com/issues/4101
712
713 //
714 // iterator(const iterator& other)
715 //
716 {
717 bufferlist bl;
718 bl.append("ABC", 3);
719 bufferlist::iterator i(&bl, 1);
720 bufferlist::iterator j(i);
721 EXPECT_EQ(*i, *j);
722 ++j;
723 EXPECT_NE(*i, *j);
724 EXPECT_EQ('B', *i);
725 EXPECT_EQ('C', *j);
726 bl.c_str()[1] = 'X';
727 }
728
729 //
730 // const_iterator(const iterator& other)
731 //
732 {
733 bufferlist bl;
734 bl.append("ABC", 3);
735 bufferlist::iterator i(&bl);
736 bufferlist::const_iterator ci(i);
737 EXPECT_EQ(0u, ci.get_off());
738 EXPECT_EQ('A', *ci);
739 }
740 }
741
742 TEST(BufferListIterator, empty_create_append_copy) {
743 bufferlist bl, bl2, bl3, out;
744 bl2.append("bar");
745 bl.swap(bl2);
746 bl2.append("xxx");
747 bl.append(bl2);
748 bl.rebuild();
749 bl.begin().copy(6, out);
750 ASSERT_TRUE(out.contents_equal(bl));
751 }
752
753 TEST(BufferListIterator, operator_assign) {
754 bufferlist bl;
755 bl.append("ABC", 3);
756 bufferlist::iterator i(&bl, 1);
757
758 #pragma clang diagnostic push
759 #pragma clang diagnostic ignored "-Wself-assign-overloaded"
760 i = i;
761 #pragma clang diagnostic pop
762 EXPECT_EQ('B', *i);
763 bufferlist::iterator j;
764 j = i;
765 EXPECT_EQ('B', *j);
766 }
767
768 TEST(BufferListIterator, get_off) {
769 bufferlist bl;
770 bl.append("ABC", 3);
771 bufferlist::iterator i(&bl, 1);
772 EXPECT_EQ((unsigned)1, i.get_off());
773 }
774
775 TEST(BufferListIterator, get_remaining) {
776 bufferlist bl;
777 bl.append("ABC", 3);
778 bufferlist::iterator i(&bl, 1);
779 EXPECT_EQ((unsigned)2, i.get_remaining());
780 }
781
782 TEST(BufferListIterator, end) {
783 bufferlist bl;
784 {
785 bufferlist::iterator i(&bl);
786 EXPECT_TRUE(i.end());
787 }
788 bl.append("ABC", 3);
789 {
790 bufferlist::iterator i(&bl);
791 EXPECT_FALSE(i.end());
792 }
793 }
794
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');
799 ceph::bufferlist bl;
800
801 for (size_t i = 0; i < bufnum; i++) {
802 bl.append(ceph::bufferptr(buf.c_str(), buf.size()));
803 }
804
805 utime_t start = ceph_clock_now();
806 bufferlist::iterator iter = bl.begin();
807 while (iter != bl.end()) {
808 iter += step;
809 }
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;
814 }
815
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);
821
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);
826 }
827
828 TEST(BufferListIterator, advance) {
829 bufferlist bl;
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()));
834
835 {
836 bufferlist::iterator i(&bl);
837 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
838 }
839 {
840 bufferlist::iterator i(&bl);
841 EXPECT_EQ('A', *i);
842 i += 1u;
843 EXPECT_EQ('B', *i);
844 i += 3u;
845 EXPECT_EQ('E', *i);
846 }
847 }
848
849 TEST(BufferListIterator, iterate_with_empties) {
850 ceph::bufferlist bl;
851 EXPECT_EQ(bl.get_num_buffers(), 0u);
852
853 bl.push_back(ceph::buffer::create(0));
854 EXPECT_EQ(bl.length(), 0u);
855 EXPECT_EQ(bl.get_num_buffers(), 1u);
856
857 encode(int64_t(42), bl);
858 EXPECT_EQ(bl.get_num_buffers(), 2u);
859
860 bl.push_back(ceph::buffer::create(0));
861 EXPECT_EQ(bl.get_num_buffers(), 3u);
862
863 // append bufferlist with single, 0-sized ptr inside
864 {
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);
869
870 bl.append(bl_with_empty_ptr);
871 }
872
873 encode(int64_t(24), bl);
874 EXPECT_EQ(bl.get_num_buffers(), 5u);
875
876 auto i = bl.cbegin();
877 int64_t val;
878 decode(val, i);
879 EXPECT_EQ(val, 42l);
880
881 decode(val, i);
882 EXPECT_EQ(val, 24l);
883
884 val = 0;
885 i.seek(sizeof(val));
886 decode(val, i);
887 EXPECT_EQ(val, 24l);
888 EXPECT_TRUE(i == bl.end());
889
890 i.seek(0);
891 decode(val, i);
892 EXPECT_EQ(val, 42);
893 EXPECT_FALSE(i == bl.end());
894 }
895
896 TEST(BufferListIterator, get_ptr_and_advance)
897 {
898 bufferptr a("one", 3);
899 bufferptr b("two", 3);
900 bufferptr c("three", 5);
901 bufferlist bl;
902 bl.append(a);
903 bl.append(b);
904 bl.append(c);
905 const char *ptr;
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());
917 }
918
919 TEST(BufferListIterator, iterator_crc32c) {
920 bufferlist bl1;
921 bufferlist bl2;
922 bufferlist bl3;
923
924 string s1(100, 'a');
925 string s2(50, 'b');
926 string s3(7, 'c');
927 string s;
928 bl1.append(s1);
929 bl1.append(s2);
930 bl1.append(s3);
931 s = s1 + s2 + s3;
932 bl2.append(s);
933
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());
937
938 it = bl1.begin();
939 ASSERT_EQ(bl2.crc32c(0), it.crc32c(it.get_remaining(), 0));
940
941 bl3.append(s.substr(98, 55));
942 it = bl1.begin();
943 it += 98u;
944 ASSERT_EQ(bl3.crc32c(0), it.crc32c(55, 0));
945 ASSERT_EQ(4u, it.get_remaining());
946
947 bl3.clear();
948 bl3.append(s.substr(98 + 55));
949 it = bl1.begin();
950 it += 98u + 55u;
951 ASSERT_EQ(bl3.crc32c(0), it.crc32c(10, 0));
952 ASSERT_EQ(0u, it.get_remaining());
953 }
954
955 TEST(BufferListIterator, seek) {
956 bufferlist bl;
957 bl.append("ABC", 3);
958 bufferlist::iterator i(&bl, 1);
959 EXPECT_EQ('B', *i);
960 i.seek(2);
961 EXPECT_EQ('C', *i);
962 }
963
964 TEST(BufferListIterator, operator_star) {
965 bufferlist bl;
966 {
967 bufferlist::iterator i(&bl);
968 EXPECT_THROW(*i, buffer::end_of_buffer);
969 }
970 bl.append("ABC", 3);
971 {
972 bufferlist::iterator i(&bl);
973 EXPECT_EQ('A', *i);
974 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
975 EXPECT_THROW(*i, buffer::end_of_buffer);
976 }
977 }
978
979 TEST(BufferListIterator, operator_equal) {
980 bufferlist bl;
981 bl.append("ABC", 3);
982 {
983 bufferlist::iterator i(&bl);
984 bufferlist::iterator j(&bl);
985 EXPECT_EQ(i, j);
986 }
987 {
988 bufferlist::const_iterator ci = bl.begin();
989 bufferlist::iterator i = bl.begin();
990 EXPECT_EQ(i, ci);
991 EXPECT_EQ(ci, i);
992 }
993 }
994
995 TEST(BufferListIterator, operator_nequal) {
996 bufferlist bl;
997 bl.append("ABC", 3);
998 {
999 bufferlist::iterator i(&bl);
1000 bufferlist::iterator j(&bl);
1001 EXPECT_NE(++i, j);
1002 }
1003 {
1004 bufferlist::const_iterator ci = bl.begin();
1005 bufferlist::const_iterator cj = bl.begin();
1006 ++ci;
1007 EXPECT_NE(ci, cj);
1008 bufferlist::iterator i = bl.begin();
1009 EXPECT_NE(i, ci);
1010 EXPECT_NE(ci, i);
1011 }
1012 {
1013 // tests begin(), end(), operator++() also
1014 string s("ABC");
1015 int i = 0;
1016 for (auto c : bl) {
1017 EXPECT_EQ(s[i++], c);
1018 }
1019 }
1020 }
1021
1022 TEST(BufferListIterator, operator_plus_plus) {
1023 bufferlist bl;
1024 {
1025 bufferlist::iterator i(&bl);
1026 EXPECT_THROW(++i, buffer::end_of_buffer);
1027 }
1028 bl.append("ABC", 3);
1029 {
1030 bufferlist::iterator i(&bl);
1031 ++i;
1032 EXPECT_EQ('B', *i);
1033 }
1034 }
1035
1036 TEST(BufferListIterator, get_current_ptr) {
1037 bufferlist bl;
1038 {
1039 bufferlist::iterator i(&bl);
1040 EXPECT_THROW(++i, buffer::end_of_buffer);
1041 }
1042 bl.append("ABC", 3);
1043 {
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());
1049 }
1050 }
1051
1052 TEST(BufferListIterator, copy) {
1053 bufferlist bl;
1054 const char *expected = "ABC";
1055 bl.append(expected, 3);
1056 //
1057 // void copy(unsigned len, char *dest);
1058 //
1059 {
1060 char* copy = (char*)malloc(3);
1061 ::memset(copy, 'X', 3);
1062 bufferlist::iterator i(&bl);
1063 //
1064 // demonstrates that it seeks back to offset if p == ls->end()
1065 //
1066 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1067 i.copy(2, copy);
1068 EXPECT_EQ(0, ::memcmp(copy, expected, 2));
1069 EXPECT_EQ('X', copy[2]);
1070 i.seek(0);
1071 i.copy(3, copy);
1072 EXPECT_EQ(0, ::memcmp(copy, expected, 3));
1073 free(copy);
1074 }
1075 //
1076 // void copy(unsigned len, char *dest) via begin(size_t offset)
1077 //
1078 {
1079 bufferlist bl;
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));
1086 delete [] dest;
1087 }
1088 //
1089 // void buffer::list::iterator::copy_deep(unsigned len, ptr &dest)
1090 //
1091 {
1092 bufferptr ptr;
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]);
1098 }
1099 //
1100 // void buffer::list::iterator::copy_shallow(unsigned len, ptr &dest)
1101 //
1102 {
1103 bufferptr ptr;
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]);
1109 }
1110 //
1111 // void buffer::list::iterator::copy(unsigned len, list &dest)
1112 //
1113 {
1114 bufferlist copy;
1115 bufferlist::iterator i(&bl);
1116 //
1117 // demonstrates that it seeks back to offset if p == ls->end()
1118 //
1119 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1120 i.copy(2, copy);
1121 EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2));
1122 i.seek(0);
1123 i.copy(3, copy);
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());
1130 }
1131 //
1132 // void buffer::list::iterator::copy(unsigned len, list &dest) via begin(size_t offset)
1133 //
1134 {
1135 bufferlist bl;
1136 bufferlist dest;
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));
1142 }
1143 //
1144 // void buffer::list::iterator::copy_all(list &dest)
1145 //
1146 {
1147 bufferlist copy;
1148 bufferlist::iterator i(&bl);
1149 //
1150 // demonstrates that it seeks back to offset if p == ls->end()
1151 //
1152 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1153 i.copy_all(copy);
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());
1158 }
1159 //
1160 // void copy(unsigned len, std::string &dest)
1161 //
1162 {
1163 std::string copy;
1164 bufferlist::iterator i(&bl);
1165 //
1166 // demonstrates that it seeks back to offset if p == ls->end()
1167 //
1168 EXPECT_THROW(i += 200u, buffer::end_of_buffer);
1169 i.copy(2, copy);
1170 EXPECT_EQ(0, ::memcmp(copy.c_str(), expected, 2));
1171 i.seek(0);
1172 i.copy(3, copy);
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());
1179 }
1180 //
1181 // void copy(unsigned len, std::string &dest) via begin(size_t offset)
1182 //
1183 {
1184 bufferlist bl;
1185 std::string dest;
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));
1191 }
1192 }
1193
1194 TEST(BufferListIterator, copy_in) {
1195 bufferlist bl;
1196 const char *existing = "XXX";
1197 bl.append(existing, 3);
1198 //
1199 // void buffer::list::iterator::copy_in(unsigned len, const char *src)
1200 //
1201 {
1202 bufferlist::iterator i(&bl);
1203 //
1204 // demonstrates that it seeks back to offset if p == ls->end()
1205 //
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());
1214 }
1215 //
1216 // void copy_in(unsigned len, const char *src) via begin(size_t offset)
1217 //
1218 {
1219 bufferlist bl;
1220 bl.append("XXX");
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));
1224 }
1225 //
1226 // void buffer::list::iterator::copy_in(unsigned len, const list& otherl)
1227 //
1228 {
1229 bufferlist::iterator i(&bl);
1230 //
1231 // demonstrates that it seeks back to offset if p == ls->end()
1232 //
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());
1242 }
1243 //
1244 // void copy_in(unsigned len, const list& src) via begin(size_t offset)
1245 //
1246 {
1247 bufferlist bl;
1248 bl.append("XXX");
1249 bufferlist src;
1250 src.append("ABC");
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));
1254 }
1255 }
1256
1257 // iterator& buffer::list::const_iterator::operator++()
1258 TEST(BufferListConstIterator, operator_plus_plus) {
1259 bufferlist bl;
1260 {
1261 bufferlist::const_iterator i(&bl);
1262 EXPECT_THROW(++i, buffer::end_of_buffer);
1263 }
1264 bl.append("ABC", 3);
1265 {
1266 const bufferlist const_bl(bl);
1267 bufferlist::const_iterator i(const_bl.begin());
1268 ++i;
1269 EXPECT_EQ('B', *i);
1270 }
1271
1272 }
1273
1274 TEST(BufferList, constructors) {
1275 //
1276 // list()
1277 //
1278 {
1279 bufferlist bl;
1280 ASSERT_EQ((unsigned)0, bl.length());
1281 }
1282 //
1283 // list(unsigned prealloc)
1284 //
1285 {
1286 bufferlist bl(1);
1287 ASSERT_EQ((unsigned)0, bl.length());
1288 bl.append('A');
1289 ASSERT_EQ('A', bl[0]);
1290 }
1291 //
1292 // list(const list& other)
1293 //
1294 {
1295 bufferlist bl(1);
1296 bl.append('A');
1297 ASSERT_EQ('A', bl[0]);
1298 bufferlist copy(bl);
1299 ASSERT_EQ('A', copy[0]);
1300 }
1301 //
1302 // list(list&& other)
1303 //
1304 {
1305 bufferlist bl(1);
1306 bl.append('A');
1307 bufferlist copy = std::move(bl);
1308 ASSERT_EQ(0U, bl.length());
1309 ASSERT_EQ(1U, copy.length());
1310 ASSERT_EQ('A', copy[0]);
1311 }
1312 }
1313
1314 TEST(BufferList, append_after_move) {
1315 bufferlist bl(6);
1316 bl.append("ABC", 3);
1317 EXPECT_EQ(1, bl.get_num_buffers());
1318
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));
1324 }
1325
1326 void bench_bufferlist_alloc(int size, int num, int per)
1327 {
1328 utime_t start = ceph_clock_now();
1329 for (int i=0; i<num; ++i) {
1330 bufferlist bl;
1331 for (int j=0; j<per; ++j)
1332 bl.push_back(buffer::ptr_node::create(buffer::create(size)));
1333 }
1334 utime_t end = ceph_clock_now();
1335 cout << num << " alloc of size " << size
1336 << " in " << (end - start) << std::endl;
1337 }
1338
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);
1351 }
1352
1353 TEST(BufferList, append_bench_with_size_hint) {
1354 std::array<char, 1048576> src = { 0, };
1355
1356 for (size_t step = 4; step <= 16384; step *= 4) {
1357 const utime_t start = ceph_clock_now();
1358
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);
1366 }
1367 }
1368 cout << rounds << " fills of buffer len " << src.size()
1369 << " with " << step << " byte appends in "
1370 << (ceph_clock_now() - start) << std::endl;
1371 }
1372 }
1373
1374 TEST(BufferList, append_bench) {
1375 std::array<char, 1048576> src = { 0, };
1376
1377 for (size_t step = 4; step <= 16384; step *= 4) {
1378 const utime_t start = ceph_clock_now();
1379
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);
1387 }
1388 }
1389 cout << rounds << " fills of buffer len " << src.size()
1390 << " with " << step << " byte appends in "
1391 << (ceph_clock_now() - start) << std::endl;
1392 }
1393 }
1394
1395 TEST(BufferList, operator_assign_rvalue) {
1396 bufferlist from;
1397 {
1398 bufferptr ptr(2);
1399 from.append(ptr);
1400 }
1401 bufferlist to;
1402 {
1403 bufferptr ptr(4);
1404 to.append(ptr);
1405 }
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());
1413 }
1414
1415 TEST(BufferList, operator_equal) {
1416 //
1417 // list& operator= (const list& other)
1418 //
1419 bufferlist bl;
1420 bl.append("ABC", 3);
1421 {
1422 std::string dest;
1423 bl.begin(1).copy(1, dest);
1424 ASSERT_EQ('B', dest[0]);
1425 }
1426 {
1427 bufferlist copy = bl;
1428 std::string dest;
1429 copy.begin(1).copy(1, dest);
1430 ASSERT_EQ('B', dest[0]);
1431 }
1432
1433 //
1434 // list& operator= (list&& other)
1435 //
1436 bufferlist move;
1437 move = std::move(bl);
1438 {
1439 std::string dest;
1440 move.begin(1).copy(1, dest);
1441 ASSERT_EQ('B', dest[0]);
1442 }
1443 EXPECT_TRUE(move.length());
1444 EXPECT_TRUE(!bl.length());
1445 }
1446
1447 TEST(BufferList, buffers) {
1448 bufferlist bl;
1449 ASSERT_EQ((unsigned)0, bl.get_num_buffers());
1450 bl.append('A');
1451 ASSERT_EQ((unsigned)1, bl.get_num_buffers());
1452 }
1453
1454 TEST(BufferList, to_str) {
1455 {
1456 bufferlist bl;
1457 bl.append("foo");
1458 ASSERT_EQ(bl.to_str(), string("foo"));
1459 }
1460 {
1461 bufferptr a("foobarbaz", 9);
1462 bufferptr b("123456789", 9);
1463 bufferptr c("ABCDEFGHI", 9);
1464 bufferlist bl;
1465 bl.append(a);
1466 bl.append(b);
1467 bl.append(c);
1468 ASSERT_EQ(bl.to_str(), string("foobarbaz123456789ABCDEFGHI"));
1469 }
1470 }
1471
1472 TEST(BufferList, swap) {
1473 bufferlist b1;
1474 b1.append('A');
1475
1476 bufferlist b2;
1477 b2.append('B');
1478
1479 b1.swap(b2);
1480
1481 std::string s1;
1482 b1.begin().copy(1, s1);
1483 ASSERT_EQ('B', s1[0]);
1484
1485 std::string s2;
1486 b2.begin().copy(1, s2);
1487 ASSERT_EQ('A', s2[0]);
1488 }
1489
1490 TEST(BufferList, length) {
1491 bufferlist bl;
1492 ASSERT_EQ((unsigned)0, bl.length());
1493 bl.append('A');
1494 ASSERT_EQ((unsigned)1, bl.length());
1495 }
1496
1497 TEST(BufferList, contents_equal) {
1498 //
1499 // A BB
1500 // AB B
1501 //
1502 bufferlist bl1;
1503 bl1.append("A");
1504 bl1.append("BB");
1505 bufferlist bl2;
1506 ASSERT_FALSE(bl1.contents_equal(bl2)); // different length
1507 bl2.append("AB");
1508 bl2.append("B");
1509 ASSERT_TRUE(bl1.contents_equal(bl2)); // same length same content
1510 //
1511 // ABC
1512 //
1513 bufferlist bl3;
1514 bl3.append("ABC");
1515 ASSERT_FALSE(bl1.contents_equal(bl3)); // same length different content
1516 }
1517
1518 TEST(BufferList, is_aligned) {
1519 const int SIMD_ALIGN = 32;
1520 {
1521 bufferlist bl;
1522 EXPECT_TRUE(bl.is_aligned(SIMD_ALIGN));
1523 }
1524 {
1525 bufferlist bl;
1526 bufferptr ptr(buffer::create_aligned(2, SIMD_ALIGN));
1527 ptr.set_offset(1);
1528 ptr.set_length(1);
1529 bl.append(ptr);
1530 EXPECT_FALSE(bl.is_aligned(SIMD_ALIGN));
1531 bl.rebuild_aligned(SIMD_ALIGN);
1532 EXPECT_TRUE(bl.is_aligned(SIMD_ALIGN));
1533 }
1534 {
1535 bufferlist bl;
1536 bufferptr ptr(buffer::create_aligned(SIMD_ALIGN + 1, SIMD_ALIGN));
1537 ptr.set_offset(1);
1538 ptr.set_length(SIMD_ALIGN);
1539 bl.append(ptr);
1540 EXPECT_FALSE(bl.is_aligned(SIMD_ALIGN));
1541 bl.rebuild_aligned(SIMD_ALIGN);
1542 EXPECT_TRUE(bl.is_aligned(SIMD_ALIGN));
1543 }
1544 }
1545
1546 TEST(BufferList, is_n_align_sized) {
1547 const int SIMD_ALIGN = 32;
1548 {
1549 bufferlist bl;
1550 EXPECT_TRUE(bl.is_n_align_sized(SIMD_ALIGN));
1551 }
1552 {
1553 bufferlist bl;
1554 bl.append_zero(1);
1555 EXPECT_FALSE(bl.is_n_align_sized(SIMD_ALIGN));
1556 }
1557 {
1558 bufferlist bl;
1559 bl.append_zero(SIMD_ALIGN);
1560 EXPECT_TRUE(bl.is_n_align_sized(SIMD_ALIGN));
1561 }
1562 }
1563
1564 TEST(BufferList, is_page_aligned) {
1565 {
1566 bufferlist bl;
1567 EXPECT_TRUE(bl.is_page_aligned());
1568 }
1569 {
1570 bufferlist bl;
1571 bufferptr ptr(buffer::create_page_aligned(2));
1572 ptr.set_offset(1);
1573 ptr.set_length(1);
1574 bl.append(ptr);
1575 EXPECT_FALSE(bl.is_page_aligned());
1576 bl.rebuild_page_aligned();
1577 EXPECT_TRUE(bl.is_page_aligned());
1578 }
1579 {
1580 bufferlist bl;
1581 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1));
1582 ptr.set_offset(1);
1583 ptr.set_length(CEPH_PAGE_SIZE);
1584 bl.append(ptr);
1585 EXPECT_FALSE(bl.is_page_aligned());
1586 bl.rebuild_page_aligned();
1587 EXPECT_TRUE(bl.is_page_aligned());
1588 }
1589 }
1590
1591 TEST(BufferList, is_n_page_sized) {
1592 {
1593 bufferlist bl;
1594 EXPECT_TRUE(bl.is_n_page_sized());
1595 }
1596 {
1597 bufferlist bl;
1598 bl.append_zero(1);
1599 EXPECT_FALSE(bl.is_n_page_sized());
1600 }
1601 {
1602 bufferlist bl;
1603 bl.append_zero(CEPH_PAGE_SIZE);
1604 EXPECT_TRUE(bl.is_n_page_sized());
1605 }
1606 }
1607
1608 TEST(BufferList, page_aligned_appender) {
1609 bufferlist bl;
1610 {
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) {
1618 a.append("x", 1);
1619 }
1620 cout << bl << std::endl;
1621 ASSERT_EQ(1u, bl.get_num_buffers());
1622 // verify the beginning
1623 {
1624 bufferlist t;
1625 t.substr_of(bl, 0, 10);
1626 ASSERT_TRUE(t.contents_equal("asdfasdfxx", 10));
1627 }
1628 for (unsigned n = 0; n < 3 * CEPH_PAGE_SIZE; ++n) {
1629 a.append("y", 1);
1630 }
1631 cout << bl << std::endl;
1632 ASSERT_EQ(2u, bl.get_num_buffers());
1633
1634 a.append_zero(42);
1635 // ensure append_zero didn't introduce a fragmentation
1636 ASSERT_EQ(2u, bl.get_num_buffers());
1637 // verify the end is actually zeroed
1638 {
1639 bufferlist t;
1640 t.substr_of(bl, bl.length() - 42, 42);
1641 ASSERT_TRUE(t.is_zero());
1642 }
1643
1644 // let's check whether appending a bufferlist directly to `bl`
1645 // doesn't fragment further C string appends via appender.
1646 {
1647 const auto& initial_back = bl.back();
1648 {
1649 bufferlist src;
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());
1655 }
1656
1657 // moreover, the next C string-taking `append()` had to
1658 // create anoter `ptr_node` instance but...
1659 a.append("xyz", 3);
1660 ASSERT_EQ(4u, bl.get_num_buffers());
1661
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());
1665 }
1666
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);
1671 }
1672 }
1673
1674 {
1675 cout << bl << std::endl;
1676 ASSERT_EQ(6u, bl.get_num_buffers());
1677 }
1678
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()`.
1683 {
1684 bl.append_zero(42);
1685 cout << bl << std::endl;
1686 ASSERT_EQ(6u, bl.get_num_buffers());
1687 }
1688 }
1689
1690 TEST(BufferList, rebuild_aligned_size_and_memory) {
1691 const unsigned SIMD_ALIGN = 32;
1692 const unsigned BUFFER_SIZE = 67;
1693
1694 bufferlist bl;
1695 // These two must be concatenated into one memory + size aligned
1696 // bufferptr
1697 {
1698 bufferptr ptr(buffer::create_aligned(2, SIMD_ALIGN));
1699 ptr.set_offset(1);
1700 ptr.set_length(1);
1701 bl.append(ptr);
1702 }
1703 {
1704 bufferptr ptr(buffer::create_aligned(BUFFER_SIZE - 1, SIMD_ALIGN));
1705 bl.append(ptr);
1706 }
1707 // This one must be left alone
1708 {
1709 bufferptr ptr(buffer::create_aligned(BUFFER_SIZE, SIMD_ALIGN));
1710 bl.append(ptr);
1711 }
1712 // These two must be concatenated into one memory + size aligned
1713 // bufferptr
1714 {
1715 bufferptr ptr(buffer::create_aligned(2, SIMD_ALIGN));
1716 ptr.set_offset(1);
1717 ptr.set_length(1);
1718 bl.append(ptr);
1719 }
1720 {
1721 bufferptr ptr(buffer::create_aligned(BUFFER_SIZE - 1, SIMD_ALIGN));
1722 bl.append(ptr);
1723 }
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());
1734
1735 {
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 */
1739 bl.clear();
1740 bufferptr ptr1(buffer::create_aligned(4096, 4096));
1741 bl.append(ptr1);
1742 bufferptr ptr(10);
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);
1750 }
1751 }
1752
1753 TEST(BufferList, is_zero) {
1754 {
1755 bufferlist bl;
1756 EXPECT_TRUE(bl.is_zero());
1757 }
1758 {
1759 bufferlist bl;
1760 bl.append('A');
1761 EXPECT_FALSE(bl.is_zero());
1762 }
1763 {
1764 bufferlist bl;
1765 bl.append_zero(1);
1766 EXPECT_TRUE(bl.is_zero());
1767 }
1768
1769 for (size_t i = 1; i <= 256; ++i) {
1770 bufferlist bl;
1771 bl.append_zero(i);
1772 EXPECT_TRUE(bl.is_zero());
1773 bl.append('A');
1774 // ensure buffer is a single, contiguous before testing
1775 bl.rebuild();
1776 EXPECT_FALSE(bl.is_zero());
1777 }
1778
1779 }
1780
1781 TEST(BufferList, clear) {
1782 bufferlist bl;
1783 unsigned len = 17;
1784 bl.append_zero(len);
1785 bl.clear();
1786 EXPECT_EQ((unsigned)0, bl.length());
1787 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
1788 }
1789
1790 TEST(BufferList, push_back) {
1791 //
1792 // void push_back(ptr& bp)
1793 //
1794 {
1795 bufferlist bl;
1796 bufferptr ptr;
1797 bl.push_back(ptr);
1798 EXPECT_EQ((unsigned)0, bl.length());
1799 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
1800 }
1801 unsigned len = 17;
1802 {
1803 bufferlist bl;
1804 bl.append('A');
1805 bufferptr ptr(len);
1806 ptr.c_str()[0] = 'B';
1807 bl.push_back(ptr);
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());
1814 }
1815 //
1816 // void push_back(ptr&& bp)
1817 //
1818 {
1819 bufferlist bl;
1820 bufferptr ptr;
1821 bl.push_back(std::move(ptr));
1822 EXPECT_EQ((unsigned)0, bl.length());
1823 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
1824 }
1825 {
1826 bufferlist bl;
1827 bl.append('A');
1828 bufferptr ptr(len);
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());
1835 }
1836 }
1837
1838 TEST(BufferList, is_contiguous) {
1839 bufferlist bl;
1840 EXPECT_TRUE(bl.is_contiguous());
1841 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
1842 bl.append('A');
1843 EXPECT_TRUE(bl.is_contiguous());
1844 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
1845 bufferptr ptr(1);
1846 bl.push_back(ptr);
1847 EXPECT_FALSE(bl.is_contiguous());
1848 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
1849 }
1850
1851 TEST(BufferList, rebuild) {
1852 {
1853 bufferlist bl;
1854 bufferptr ptr(buffer::create_page_aligned(2));
1855 ptr[0] = 'X';
1856 ptr[1] = 'Y';
1857 ptr.set_offset(1);
1858 ptr.set_length(1);
1859 bl.append(ptr);
1860 EXPECT_FALSE(bl.is_page_aligned());
1861 bl.rebuild();
1862 EXPECT_EQ(1U, bl.length());
1863 EXPECT_EQ('Y', *bl.begin());
1864 }
1865 {
1866 bufferlist bl;
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));
1872 bl.rebuild();
1873 EXPECT_TRUE(bl.is_page_aligned());
1874 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
1875 }
1876 {
1877 bufferlist bl;
1878 char t1[] = "X";
1879 bufferlist a2;
1880 a2.append(t1, 1);
1881 bl.rebuild();
1882 bl.append(a2);
1883 EXPECT_EQ((unsigned)1, bl.length());
1884 bufferlist::iterator p = bl.begin();
1885 char dst[1];
1886 p.copy(1, dst);
1887 EXPECT_EQ(0, memcmp(dst, "X", 1));
1888 }
1889 }
1890
1891 TEST(BufferList, rebuild_page_aligned) {
1892 {
1893 bufferlist bl;
1894 {
1895 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1));
1896 ptr.set_offset(1);
1897 ptr.set_length(CEPH_PAGE_SIZE);
1898 bl.append(ptr);
1899 }
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());
1905 }
1906 {
1907 bufferlist bl;
1908 bufferptr ptr(buffer::create_page_aligned(1));
1909 char *p = ptr.c_str();
1910 bl.append(ptr);
1911 bl.rebuild_page_aligned();
1912 EXPECT_EQ(p, bl.front().c_str());
1913 }
1914 {
1915 bufferlist bl;
1916 {
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());
1920 bl.append(ptr);
1921 }
1922 {
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());
1926 bl.append(ptr);
1927 }
1928 {
1929 bufferptr ptr(buffer::create_page_aligned(2));
1930 ptr.set_offset(1);
1931 ptr.set_length(1);
1932 EXPECT_FALSE(ptr.is_page_aligned());
1933 EXPECT_FALSE(ptr.is_n_page_sized());
1934 bl.append(ptr);
1935 }
1936 {
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());
1940 bl.append(ptr);
1941 }
1942 {
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());
1946 bl.append(ptr);
1947 }
1948 {
1949 bufferptr ptr(buffer::create_page_aligned(CEPH_PAGE_SIZE + 1));
1950 ptr.set_offset(1);
1951 ptr.set_length(CEPH_PAGE_SIZE);
1952 EXPECT_FALSE(ptr.is_page_aligned());
1953 EXPECT_TRUE(ptr.is_n_page_sized());
1954 bl.append(ptr);
1955 }
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());
1962 }
1963 }
1964
1965 TEST(BufferList, claim_append) {
1966 bufferlist from;
1967 {
1968 bufferptr ptr(2);
1969 from.append(ptr);
1970 }
1971 bufferlist to;
1972 {
1973 bufferptr ptr(4);
1974 to.append(ptr);
1975 }
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());
1985 }
1986
1987 TEST(BufferList, begin) {
1988 bufferlist bl;
1989 bl.append("ABC");
1990 bufferlist::iterator i = bl.begin();
1991 EXPECT_EQ('A', *i);
1992 }
1993
1994 TEST(BufferList, end) {
1995 bufferlist bl;
1996 bl.append("AB");
1997 bufferlist::iterator i = bl.end();
1998 bl.append("C");
1999 EXPECT_EQ('C', bl[i.get_off()]);
2000 }
2001
2002 TEST(BufferList, append) {
2003 //
2004 // void append(char c);
2005 //
2006 {
2007 bufferlist bl;
2008 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2009 bl.append('A');
2010 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2011 //EXPECT_TRUE(bl.is_aligned(CEPH_BUFFER_APPEND_SIZE));
2012 }
2013 //
2014 // void append(const char *data, unsigned len);
2015 //
2016 {
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());
2023 }
2024 //
2025 // void append(const std::string& s);
2026 //
2027 {
2028 bufferlist bl(CEPH_PAGE_SIZE);
2029 std::string str(CEPH_PAGE_SIZE * 2, 'X');
2030 bl.append(str);
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());
2034 }
2035 //
2036 // void append(const ptr& bp);
2037 //
2038 {
2039 bufferlist bl;
2040 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2041 EXPECT_EQ((unsigned)0, bl.length());
2042 {
2043 bufferptr ptr;
2044 bl.append(ptr);
2045 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2046 EXPECT_EQ((unsigned)0, bl.length());
2047 }
2048 {
2049 bufferptr ptr(3);
2050 bl.append(ptr);
2051 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2052 EXPECT_EQ((unsigned)3, bl.length());
2053 }
2054 }
2055 //
2056 // void append(const ptr& bp, unsigned off, unsigned len);
2057 //
2058 {
2059 bufferlist bl;
2060 bl.append('A');
2061 bufferptr back(bl.back());
2062 bufferptr in(back);
2063 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2064 EXPECT_EQ((unsigned)1, bl.length());
2065 {
2066 PrCtl unset_dumpable;
2067 EXPECT_DEATH(bl.append(in, (unsigned)100, (unsigned)100), "");
2068 }
2069 EXPECT_LT((unsigned)0, in.unused_tail_length());
2070 in.append('B');
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]);
2075 }
2076 {
2077 bufferlist bl;
2078 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2079 EXPECT_EQ((unsigned)0, bl.length());
2080 bufferptr ptr(2);
2081 ptr.set_length(0);
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());
2086 }
2087 //
2088 // void append(const list& bl);
2089 //
2090 {
2091 bufferlist bl;
2092 bl.append('A');
2093 bufferlist other;
2094 other.append('B');
2095 bl.append(other);
2096 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
2097 EXPECT_EQ('B', bl[1]);
2098 }
2099 //
2100 // void append(std::istream& in);
2101 //
2102 {
2103 bufferlist bl;
2104 std::string expected("ABC\nDEF\n");
2105 std::istringstream is("ABC\n\nDEF");
2106 bl.append(is);
2107 EXPECT_EQ(0, ::memcmp(expected.c_str(), bl.c_str(), expected.size()));
2108 EXPECT_EQ(expected.size(), bl.length());
2109 }
2110 //
2111 // void append(ptr&& bp);
2112 //
2113 {
2114 bufferlist bl;
2115 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2116 EXPECT_EQ((unsigned)0, bl.length());
2117 {
2118 bufferptr ptr;
2119 bl.append(std::move(ptr));
2120 EXPECT_EQ((unsigned)0, bl.get_num_buffers());
2121 EXPECT_EQ((unsigned)0, bl.length());
2122 }
2123 {
2124 bufferptr ptr(3);
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());
2129 }
2130 }
2131 }
2132
2133 TEST(BufferList, append_hole) {
2134 {
2135 bufferlist bl;
2136 auto filler = bl.append_hole(1);
2137 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2138 EXPECT_EQ((unsigned)1, bl.length());
2139
2140 bl.append("BC", 2);
2141 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2142 EXPECT_EQ((unsigned)3, bl.length());
2143
2144 const char a = 'A';
2145 filler.copy_in((unsigned)1, &a);
2146 EXPECT_EQ((unsigned)3, bl.length());
2147
2148 EXPECT_EQ(0, ::memcmp("ABC", bl.c_str(), 3));
2149 }
2150
2151 {
2152 bufferlist bl;
2153 bl.append('A');
2154 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2155 EXPECT_EQ((unsigned)1, bl.length());
2156
2157 auto filler = bl.append_hole(1);
2158 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2159 EXPECT_EQ((unsigned)2, bl.length());
2160
2161 bl.append('C');
2162 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2163 EXPECT_EQ((unsigned)3, bl.length());
2164
2165 const char b = 'B';
2166 filler.copy_in((unsigned)1, &b);
2167 EXPECT_EQ((unsigned)3, bl.length());
2168
2169 EXPECT_EQ(0, ::memcmp("ABC", bl.c_str(), 3));
2170 }
2171 }
2172
2173 TEST(BufferList, append_zero) {
2174 bufferlist bl;
2175 bl.append('A');
2176 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2177 EXPECT_EQ((unsigned)1, bl.length());
2178 bl.append_zero(1);
2179 EXPECT_EQ((unsigned)1, bl.get_num_buffers());
2180 EXPECT_EQ((unsigned)2, bl.length());
2181 EXPECT_EQ('\0', bl[1]);
2182 }
2183
2184 TEST(BufferList, operator_brackets) {
2185 bufferlist bl;
2186 EXPECT_THROW(bl[1], buffer::end_of_buffer);
2187 bl.append('A');
2188 bufferlist other;
2189 other.append('B');
2190 bl.append(other);
2191 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
2192 EXPECT_EQ('B', bl[1]);
2193 }
2194
2195 TEST(BufferList, c_str) {
2196 bufferlist bl;
2197 EXPECT_EQ((const char*)NULL, bl.c_str());
2198 bl.append('A');
2199 bufferlist other;
2200 other.append('B');
2201 bl.append(other);
2202 EXPECT_EQ((unsigned)2, bl.get_num_buffers());
2203 EXPECT_EQ(0, ::memcmp("AB", bl.c_str(), 2));
2204 }
2205
2206 TEST(BufferList, substr_of) {
2207 bufferlist bl;
2208 EXPECT_THROW(bl.substr_of(bl, 1, 1), buffer::end_of_buffer);
2209 const char *s[] = {
2210 "ABC",
2211 "DEF",
2212 "GHI",
2213 "JKL"
2214 };
2215 for (unsigned i = 0; i < 4; i++) {
2216 bufferptr ptr(s[i], strlen(s[i]));
2217 bl.push_back(ptr);
2218 }
2219 EXPECT_EQ((unsigned)4, bl.get_num_buffers());
2220
2221 bufferlist other;
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));
2227 }
2228
2229 TEST(BufferList, splice) {
2230 bufferlist bl;
2231 EXPECT_THROW(bl.splice(1, 1), buffer::end_of_buffer);
2232 const char *s[] = {
2233 "ABC",
2234 "DEF",
2235 "GHI",
2236 "JKL"
2237 };
2238 for (unsigned i = 0; i < 4; i++) {
2239 bufferptr ptr(s[i], strlen(s[i]));
2240 bl.push_back(ptr);
2241 }
2242 EXPECT_EQ((unsigned)4, bl.get_num_buffers());
2243 bl.splice(0, 0);
2244
2245 bufferlist other;
2246 other.append('X');
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());
2252 {
2253 bufferlist tmp(bl);
2254 EXPECT_EQ(0, ::memcmp("ABCDIJKL", tmp.c_str(), tmp.length()));
2255 }
2256
2257 bl.splice(4, 4);
2258 EXPECT_EQ((unsigned)4, bl.length());
2259 EXPECT_EQ(0, ::memcmp("ABCD", bl.c_str(), bl.length()));
2260
2261 {
2262 bl.clear();
2263 bufferptr ptr1("0123456789", 10);
2264 bl.push_back(ptr1);
2265 bufferptr ptr2("abcdefghij", 10);
2266 bl.append(ptr2, 5, 5);
2267 other.clear();
2268 bl.splice(10, 4, &other);
2269 EXPECT_EQ((unsigned)11, bl.length());
2270 EXPECT_EQ(0, ::memcmp("fghi", other.c_str(), other.length()));
2271 }
2272 }
2273
2274 TEST(BufferList, write) {
2275 std::ostringstream stream;
2276 bufferlist bl;
2277 bl.append("ABC");
2278 bl.write(1, 2, stream);
2279 EXPECT_EQ("BC", stream.str());
2280 }
2281
2282 TEST(BufferList, encode_base64) {
2283 bufferlist bl;
2284 bl.append("ABCD");
2285 bufferlist other;
2286 bl.encode_base64(other);
2287 const char *expected = "QUJDRA==";
2288 EXPECT_EQ(0, ::memcmp(expected, other.c_str(), strlen(expected)));
2289 }
2290
2291 TEST(BufferList, decode_base64) {
2292 bufferlist bl;
2293 bl.append("QUJDRA==");
2294 bufferlist other;
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);
2301 }
2302
2303 TEST(BufferList, hexdump) {
2304 bufferlist bl;
2305 std::ostringstream stream;
2306 bl.append("013245678901234\0006789012345678901234", 32);
2307 bl.hexdump(stream);
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"
2310 "00000020\n",
2311 stream.str());
2312 }
2313
2314 TEST(BufferList, read_file) {
2315 std::string error;
2316 bufferlist bl;
2317 ::unlink(FILENAME);
2318 EXPECT_EQ(-ENOENT, bl.read_file("UNLIKELY", &error));
2319 snprintf(cmd, sizeof(cmd), "echo ABC> %s", FILENAME);
2320 EXPECT_EQ(0, ::system(cmd));
2321 #ifndef _WIN32
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));
2326 }
2327 snprintf(cmd, sizeof(cmd), "chmod +r %s", FILENAME);
2328 EXPECT_EQ(0, ::system(cmd));
2329 #endif /* _WIN32 */
2330 EXPECT_EQ(0, bl.read_file(FILENAME, &error));
2331 ::unlink(FILENAME);
2332 EXPECT_EQ((unsigned)4, bl.length());
2333 std::string actual(bl.c_str(), bl.length());
2334 EXPECT_EQ("ABC\n", actual);
2335 }
2336
2337 TEST(BufferList, read_fd) {
2338 unsigned len = 4;
2339 ::unlink(FILENAME);
2340 snprintf(cmd, sizeof(cmd), "echo ABC > %s", FILENAME);
2341 EXPECT_EQ(0, ::system(cmd));
2342 int fd = -1;
2343 bufferlist bl;
2344 EXPECT_EQ(-EBADF, bl.read_fd(fd, len));
2345 fd = ::open(FILENAME, O_RDONLY);
2346 ASSERT_NE(-1, fd);
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());
2350 ::close(fd);
2351 ::unlink(FILENAME);
2352 }
2353
2354 TEST(BufferList, write_file) {
2355 ::unlink(FILENAME);
2356 int mode = 0600;
2357 bufferlist bl;
2358 EXPECT_EQ(-ENOENT, bl.write_file("un/like/ly", mode));
2359 bl.append("ABC");
2360 EXPECT_EQ(0, bl.write_file(FILENAME, mode));
2361 struct stat st;
2362 memset(&st, 0, sizeof(st));
2363 ASSERT_EQ(0, ::stat(FILENAME, &st));
2364 #ifndef _WIN32
2365 EXPECT_EQ((unsigned)(mode | S_IFREG), st.st_mode);
2366 #endif
2367 ::unlink(FILENAME);
2368 }
2369
2370 TEST(BufferList, write_fd) {
2371 ::unlink(FILENAME);
2372 int fd = ::open(FILENAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
2373 ASSERT_NE(-1, fd);
2374 bufferlist bl;
2375 for (unsigned i = 0; i < IOV_MAX * 2; i++) {
2376 bufferptr ptr("A", 1);
2377 bl.push_back(ptr);
2378 }
2379 EXPECT_EQ(0, bl.write_fd(fd));
2380 ::close(fd);
2381 struct stat st;
2382 memset(&st, 0, sizeof(st));
2383 ASSERT_EQ(0, ::stat(FILENAME, &st));
2384 EXPECT_EQ(IOV_MAX * 2, st.st_size);
2385 ::unlink(FILENAME);
2386 }
2387
2388 TEST(BufferList, write_fd_offset) {
2389 ::unlink(FILENAME);
2390 int fd = ::open(FILENAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
2391 ASSERT_NE(-1, fd);
2392 bufferlist bl;
2393 for (unsigned i = 0; i < IOV_MAX * 2; i++) {
2394 bufferptr ptr("A", 1);
2395 bl.push_back(ptr);
2396 }
2397 uint64_t offset = 200;
2398 EXPECT_EQ(0, bl.write_fd(fd, offset));
2399 ::close(fd);
2400 struct stat st;
2401 memset(&st, 0, sizeof(st));
2402 ASSERT_EQ(0, ::stat(FILENAME, &st));
2403 EXPECT_EQ(IOV_MAX * 2 + offset, (unsigned)st.st_size);
2404 ::unlink(FILENAME);
2405 }
2406
2407 TEST(BufferList, crc32c) {
2408 bufferlist bl;
2409 __u32 crc = 0;
2410 bl.append("A");
2411 crc = bl.crc32c(crc);
2412 EXPECT_EQ((unsigned)0xB3109EBF, crc);
2413 crc = bl.crc32c(crc);
2414 EXPECT_EQ((unsigned)0x5FA5C0CC, crc);
2415 }
2416
2417 TEST(BufferList, crc32c_append) {
2418 bufferlist bl1;
2419 bufferlist bl2;
2420
2421 for (int j = 0; j < 200; ++j) {
2422 bufferlist bl;
2423 for (int i = 0; i < 200; ++i) {
2424 char x = rand();
2425 bl.append(x);
2426 bl1.append(x);
2427 }
2428 bl.crc32c(rand()); // mess with the cached bufferptr crc values
2429 bl2.append(bl);
2430 }
2431 ASSERT_EQ(bl1.crc32c(0), bl2.crc32c(0));
2432 }
2433
2434 TEST(BufferList, crc32c_zeros) {
2435 char buffer[4*1024];
2436 for (size_t i=0; i < sizeof(buffer); i++)
2437 {
2438 buffer[i] = i;
2439 }
2440
2441 bufferlist bla;
2442 bufferlist blb;
2443
2444 for (size_t j=0; j < 1000; j++)
2445 {
2446 bufferptr a(buffer, sizeof(buffer));
2447
2448 bla.push_back(a);
2449 uint32_t crca = bla.crc32c(111);
2450
2451 blb.push_back(a);
2452 uint32_t crcb = ceph_crc32c(111, (unsigned char*)blb.c_str(), blb.length());
2453
2454 EXPECT_EQ(crca, crcb);
2455 }
2456 }
2457
2458 TEST(BufferList, crc32c_append_perf) {
2459 int len = 256 * 1024 * 1024;
2460 bufferptr a(len);
2461 bufferptr b(len);
2462 bufferptr c(len);
2463 bufferptr d(len);
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;
2474 }
2475
2476 // track usage of cached crcs
2477 buffer::track_cached_crc(true);
2478
2479 [[maybe_unused]] int base_cached = buffer::get_cached_crc();
2480 [[maybe_unused]] int base_cached_adjusted = buffer::get_cached_crc_adjusted();
2481
2482 bufferlist bla;
2483 bla.push_back(a);
2484 bufferlist blb;
2485 blb.push_back(b);
2486 {
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);
2493 }
2494 ceph_assert(buffer::get_cached_crc() == 0 + base_cached);
2495 {
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);
2502 }
2503 ceph_assert(buffer::get_cached_crc() == 1 + base_cached);
2504
2505 {
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);
2512 }
2513 ceph_assert(buffer::get_cached_crc() == 1 + base_cached);
2514 ceph_assert(buffer::get_cached_crc_adjusted() == 1 + base_cached_adjusted);
2515 {
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);
2522 }
2523 ceph_assert(buffer::get_cached_crc() == 1 + base_cached);
2524 ceph_assert(buffer::get_cached_crc_adjusted() == 2 + base_cached_adjusted);
2525 {
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);
2532 }
2533 ceph_assert(buffer::get_cached_crc() == 1 + base_cached);
2534 {
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);
2541 }
2542 ceph_assert(buffer::get_cached_crc() == 2 + base_cached);
2543
2544 bufferlist ab;
2545 ab.push_back(a);
2546 ab.push_back(b);
2547 {
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);
2554 }
2555 ceph_assert(buffer::get_cached_crc() == 3 + base_cached);
2556 ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted);
2557 bufferlist ac;
2558 ac.push_back(a);
2559 ac.push_back(c);
2560 {
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);
2567 }
2568 ceph_assert(buffer::get_cached_crc() == 4 + base_cached);
2569 ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted);
2570
2571 bufferlist ba;
2572 ba.push_back(b);
2573 ba.push_back(a);
2574 {
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);
2581 }
2582 ceph_assert(buffer::get_cached_crc() == 5 + base_cached);
2583 ceph_assert(buffer::get_cached_crc_adjusted() == 4 + base_cached_adjusted);
2584 {
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);
2591 }
2592 ceph_assert(buffer::get_cached_crc() == 5 + base_cached);
2593 ceph_assert(buffer::get_cached_crc_adjusted() == 6 + base_cached_adjusted);
2594
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;
2597 }
2598
2599 TEST(BufferList, compare) {
2600 bufferlist a;
2601 a.append("A");
2602 bufferlist ab; // AB in segments
2603 ab.append(bufferptr("A", 1));
2604 ab.append(bufferptr("B", 1));
2605 bufferlist ac;
2606 ac.append("AC");
2607 //
2608 // bool operator>(bufferlist& l, bufferlist& r)
2609 //
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);
2615 //
2616 // bool operator>=(bufferlist& l, bufferlist& r)
2617 //
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);
2623 //
2624 // bool operator<(bufferlist& l, bufferlist& r)
2625 //
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);
2631 //
2632 // bool operator<=(bufferlist& l, bufferlist& r)
2633 //
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);
2639 //
2640 // bool operator==(bufferlist &l, bufferlist &r)
2641 //
2642 ASSERT_FALSE(a == ab);
2643 ASSERT_FALSE(ac == ab);
2644 ASSERT_TRUE(ab == ab);
2645 }
2646
2647 TEST(BufferList, ostream) {
2648 std::ostringstream stream;
2649 bufferlist bl;
2650 const char *s[] = {
2651 "ABC",
2652 "DEF"
2653 };
2654 for (unsigned i = 0; i < 2; i++) {
2655 bufferptr ptr(s[i], strlen(s[i]));
2656 bl.push_back(ptr);
2657 }
2658 stream << bl;
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"));
2663 }
2664
2665 TEST(BufferList, zero) {
2666 //
2667 // void zero()
2668 //
2669 {
2670 bufferlist bl;
2671 bl.append('A');
2672 EXPECT_EQ('A', bl[0]);
2673 bl.zero();
2674 EXPECT_EQ('\0', bl[0]);
2675 }
2676 //
2677 // void zero(unsigned o, unsigned l)
2678 //
2679 const char *s[] = {
2680 "ABC",
2681 "DEF",
2682 "GHI",
2683 "KLM"
2684 };
2685 {
2686 bufferlist bl;
2687 bufferptr ptr(s[0], strlen(s[0]));
2688 bl.push_back(ptr);
2689 bl.zero((unsigned)0, (unsigned)1);
2690 EXPECT_EQ(0, ::memcmp("\0BC", bl.c_str(), 3));
2691 }
2692 {
2693 bufferlist bl;
2694 for (unsigned i = 0; i < 4; i++) {
2695 bufferptr ptr(s[i], strlen(s[i]));
2696 bl.push_back(ptr);
2697 }
2698 {
2699 PrCtl unset_dumpable;
2700 EXPECT_DEATH(bl.zero((unsigned)0, (unsigned)2000), "");
2701 }
2702 bl.zero((unsigned)2, (unsigned)5);
2703 EXPECT_EQ(0, ::memcmp("AB\0\0\0\0\0HIKLM", bl.c_str(), 9));
2704 }
2705 {
2706 bufferlist bl;
2707 for (unsigned i = 0; i < 4; i++) {
2708 bufferptr ptr(s[i], strlen(s[i]));
2709 bl.push_back(ptr);
2710 }
2711 bl.zero((unsigned)3, (unsigned)3);
2712 EXPECT_EQ(0, ::memcmp("ABC\0\0\0GHIKLM", bl.c_str(), 9));
2713 }
2714 {
2715 bufferlist bl;
2716 bufferptr ptr1(4);
2717 bufferptr ptr2(4);
2718 memset(ptr1.c_str(), 'a', 4);
2719 memset(ptr2.c_str(), 'b', 4);
2720 bl.append(ptr1);
2721 bl.append(ptr2);
2722 bl.zero((unsigned)2, (unsigned)4);
2723 EXPECT_EQ(0, ::memcmp("aa\0\0\0\0bb", bl.c_str(), 8));
2724 }
2725 }
2726
2727 TEST(BufferList, EmptyAppend) {
2728 bufferlist bl;
2729 bufferptr ptr;
2730 bl.push_back(ptr);
2731 ASSERT_EQ(bl.begin().end(), 1);
2732 }
2733
2734 TEST(BufferList, InternalCarriage) {
2735 ceph::bufferlist bl;
2736 EXPECT_EQ(bl.get_num_buffers(), 0u);
2737
2738 encode(int64_t(42), bl);
2739 EXPECT_EQ(bl.get_num_buffers(), 1u);
2740
2741 {
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);
2746
2747 bl.append(bl_with_foo);
2748 EXPECT_EQ(bl.get_num_buffers(), 2u);
2749 }
2750
2751 encode(int64_t(24), bl);
2752 EXPECT_EQ(bl.get_num_buffers(), 3u);
2753 }
2754
2755 TEST(BufferList, ContiguousAppender) {
2756 ceph::bufferlist bl;
2757 EXPECT_EQ(bl.get_num_buffers(), 0u);
2758
2759 // we expect a flush in ~contiguous_appender
2760 {
2761 auto ap = bl.get_contiguous_appender(100);
2762
2763 denc(int64_t(42), ap);
2764 EXPECT_EQ(bl.get_num_buffers(), 1u);
2765
2766 // append bufferlist with single ptr inside. This should
2767 // commit changes to bl::_len and the underlying bp::len.
2768 {
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);
2773
2774 ap.append(bl_with_foo);
2775 // 3 as the ap::append(const bl&) splits the bp with free
2776 // space.
2777 EXPECT_EQ(bl.get_num_buffers(), 3u);
2778 }
2779
2780 denc(int64_t(24), ap);
2781 EXPECT_EQ(bl.get_num_buffers(), 3u);
2782 EXPECT_EQ(bl.length(), sizeof(int64_t) + 3u);
2783 }
2784 EXPECT_EQ(bl.length(), 2u * sizeof(int64_t) + 3u);
2785 }
2786
2787 TEST(BufferList, TestPtrAppend) {
2788 bufferlist bl;
2789 char correct[MAX_TEST];
2790 int curpos = 0;
2791 int length = random() % 5 > 0 ? random() % 1000 : 0;
2792 while (curpos + length < MAX_TEST) {
2793 if (!length) {
2794 bufferptr ptr;
2795 bl.push_back(ptr);
2796 } else {
2797 char *current = correct + curpos;
2798 for (int i = 0; i < length; ++i) {
2799 char next = random() % 255;
2800 correct[curpos++] = next;
2801 }
2802 bufferptr ptr(current, length);
2803 bl.append(ptr);
2804 }
2805 length = random() % 5 > 0 ? random() % 1000 : 0;
2806 }
2807 ASSERT_EQ(memcmp(bl.c_str(), correct, curpos), 0);
2808 }
2809
2810 TEST(BufferList, TestDirectAppend) {
2811 bufferlist bl;
2812 char correct[MAX_TEST];
2813 int curpos = 0;
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;
2820 }
2821 bl.append(current, length);
2822 length = random() % 5 > 0 ? random() % 1000 : 0;
2823 }
2824 ASSERT_EQ(memcmp(bl.c_str(), correct, curpos), 0);
2825 }
2826
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) {
2833 big.get()[i] = c++;
2834 }
2835 bufferlist bl;
2836 bl.append((const char*)big.get(), BIG_SZ);
2837 bufferlist::iterator i = bl.begin();
2838 bufferlist bl2;
2839 i.copy_all(bl2);
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);
2845 }
2846
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();
2853 char* inptr;
2854 for (size_t i = 0; i < buffer_size; ++i) {
2855 ptr[i] = c++;
2856 }
2857 bufferlist bl;
2858
2859 // test for crashes (shouldn't crash)
2860 bl.invalidate_crc();
2861
2862 // put data into bufferlist
2863 bl.append((const char*)big.get(), buffer_size);
2864
2865 // get its crc
2866 __u32 crc = bl.crc32c(0);
2867
2868 // modify data in bl without its knowledge
2869 inptr = (char*) bl.c_str();
2870 c = 0;
2871 for (size_t i = 0; i < buffer_size; ++i) {
2872 inptr[i] = c--;
2873 }
2874
2875 // make sure data in bl are now different than in big
2876 EXPECT_NE(memcmp((void*) ptr, (void*) inptr, buffer_size), 0);
2877
2878 // crc should remain the same
2879 __u32 new_crc = bl.crc32c(0);
2880 EXPECT_EQ(crc, new_crc);
2881
2882 // force crc invalidate, check if it is updated
2883 bl.invalidate_crc();
2884 EXPECT_NE(crc, bl.crc32c(0));
2885 }
2886
2887 TEST(BufferList, TestIsProvidedBuffer) {
2888 char buff[100];
2889 bufferlist bl;
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));
2894 }
2895
2896 TEST(BufferList, DISABLED_DanglingLastP) {
2897 bufferlist bl;
2898 {
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
2904 // been dropped.
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));
2909
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));
2913 }
2914
2915 bufferlist empty;
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);
2920 bl.append("123");
2921
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));
2926 }
2927
2928 TEST(BufferHash, all) {
2929 {
2930 bufferlist bl;
2931 bl.append("A");
2932 bufferhash hash;
2933 EXPECT_EQ((unsigned)0, hash.digest());
2934 hash.update(bl);
2935 EXPECT_EQ((unsigned)0xB3109EBF, hash.digest());
2936 hash.update(bl);
2937 EXPECT_EQ((unsigned)0x5FA5C0CC, hash.digest());
2938 }
2939 {
2940 bufferlist bl;
2941 bl.append("A");
2942 bufferhash hash;
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());
2947 }
2948 }
2949
2950 /*
2951 * Local Variables:
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"
2956 * End:
2957 */
2958