]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
7c673cae FG |
22 | #include <limits.h> |
23 | #include <errno.h> | |
24 | #include <sys/uio.h> | |
25 | ||
26 | #include "include/buffer.h" | |
11fdf7f2 | 27 | #include "include/buffer_raw.h" |
f67539c2 | 28 | #include "include/compat.h" |
7c673cae FG |
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" | |
31f18b77 FG |
40 | #include "include/crc32c.h" |
41 | #include "common/sctp_crc32.h" | |
7c673cae FG |
42 | |
43 | #define MAX_TEST 1000000 | |
44 | #define FILENAME "bufferlist" | |
45 | ||
46 | static char cmd[128]; | |
47 | ||
9f95a23c TL |
48 | struct instrumented_bptr : public ceph::buffer::ptr { |
49 | const ceph::buffer::raw* get_raw() const { | |
50 | return _raw; | |
51 | } | |
52 | }; | |
53 | ||
7c673cae | 54 | TEST(Buffer, constructors) { |
7c673cae | 55 | unsigned len = 17; |
7c673cae FG |
56 | // |
57 | // buffer::create | |
58 | // | |
7c673cae FG |
59 | { |
60 | bufferptr ptr(buffer::create(len)); | |
7c673cae | 61 | EXPECT_EQ(len, ptr.length()); |
7c673cae FG |
62 | } |
63 | // | |
64 | // buffer::claim_char | |
65 | // | |
7c673cae FG |
66 | { |
67 | char* str = new char[len]; | |
68 | ::memset(str, 'X', len); | |
69 | bufferptr ptr(buffer::claim_char(len, str)); | |
7c673cae FG |
70 | EXPECT_EQ(len, ptr.length()); |
71 | EXPECT_EQ(str, ptr.c_str()); | |
72 | bufferptr clone = ptr.clone(); | |
7c673cae | 73 | EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); |
11fdf7f2 | 74 | delete [] str; |
7c673cae FG |
75 | } |
76 | // | |
77 | // buffer::create_static | |
78 | // | |
7c673cae FG |
79 | { |
80 | char* str = new char[len]; | |
81 | bufferptr ptr(buffer::create_static(len, str)); | |
7c673cae FG |
82 | EXPECT_EQ(len, ptr.length()); |
83 | EXPECT_EQ(str, ptr.c_str()); | |
84 | delete [] str; | |
85 | } | |
86 | // | |
87 | // buffer::create_malloc | |
88 | // | |
7c673cae FG |
89 | { |
90 | bufferptr ptr(buffer::create_malloc(len)); | |
7c673cae FG |
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 | // | |
7c673cae FG |
98 | { |
99 | char* str = (char*)malloc(len); | |
100 | ::memset(str, 'X', len); | |
101 | bufferptr ptr(buffer::claim_malloc(len, str)); | |
7c673cae FG |
102 | EXPECT_EQ(len, ptr.length()); |
103 | EXPECT_EQ(str, ptr.c_str()); | |
104 | bufferptr clone = ptr.clone(); | |
7c673cae FG |
105 | EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); |
106 | } | |
107 | // | |
108 | // buffer::copy | |
109 | // | |
7c673cae FG |
110 | { |
111 | const std::string expected(len, 'X'); | |
112 | bufferptr ptr(buffer::copy(expected.c_str(), expected.size())); | |
7c673cae FG |
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 | // | |
7c673cae FG |
119 | { |
120 | bufferptr ptr(buffer::create_page_aligned(len)); | |
7c673cae | 121 | ::memset(ptr.c_str(), 'X', len); |
7c673cae FG |
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(); | |
7c673cae | 128 | EXPECT_EQ(0, ::memcmp(clone.c_str(), ptr.c_str(), len)); |
7c673cae FG |
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; | |
9f95a23c | 156 | stream << *static_cast<instrumented_bptr&>(ptr).get_raw(); |
7c673cae FG |
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 | ||
7c673cae FG |
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()); | |
9f95a23c TL |
225 | EXPECT_EQ(static_cast<instrumented_bptr&>(original).get_raw(), |
226 | static_cast<instrumented_bptr&>(ptr).get_raw()); | |
7c673cae FG |
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()); | |
9f95a23c TL |
238 | EXPECT_EQ(static_cast<instrumented_bptr&>(original).get_raw(), |
239 | static_cast<instrumented_bptr&>(ptr).get_raw()); | |
7c673cae FG |
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); | |
9f95a23c | 291 | bufferptr same_raw(original); |
7c673cae FG |
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()); | |
9f95a23c TL |
298 | ASSERT_EQ(static_cast<instrumented_bptr&>(same_raw).get_raw(), |
299 | static_cast<instrumented_bptr&>(original).get_raw()); | |
7c673cae FG |
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); | |
9f95a23c TL |
309 | #pragma clang diagnostic push |
310 | #pragma clang diagnostic ignored "-Wself-assign-overloaded" | |
7c673cae | 311 | original = original; |
9f95a23c | 312 | #pragma clang diagnostic pop |
7c673cae FG |
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()); | |
9f95a23c TL |
330 | ASSERT_EQ(static_cast<instrumented_bptr&>(ptr).get_raw(), |
331 | static_cast<instrumented_bptr&>(original).get_raw()); | |
7c673cae FG |
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 | ||
7c673cae FG |
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 | ||
9f95a23c | 424 | EXPECT_NE((void*)nullptr, (void*)static_cast<instrumented_bptr&>(ptr).get_raw()); |
7c673cae FG |
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 | |
f67539c2 | 538 | << " with " << s << " byte copy_out in " |
7c673cae FG |
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) { | |
11fdf7f2 | 616 | bp.append(src + j, s); |
7c673cae FG |
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'; | |
7c673cae FG |
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(); | |
9f95a23c | 749 | bl.begin().copy(6, out); |
7c673cae FG |
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 | ||
9f95a23c TL |
758 | #pragma clang diagnostic push |
759 | #pragma clang diagnostic ignored "-Wself-assign-overloaded" | |
7c673cae | 760 | i = i; |
9f95a23c | 761 | #pragma clang diagnostic pop |
7c673cae FG |
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 | ||
11fdf7f2 TL |
795 | static void bench_bufferlistiter_deref(const size_t step, |
796 | const size_t bufsize, | |
797 | const size_t bufnum) { | |
f67539c2 | 798 | const std::string buf(bufsize, 'a'); |
11fdf7f2 TL |
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()) { | |
9f95a23c | 808 | iter += step; |
11fdf7f2 TL |
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 | ||
7c673cae FG |
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); | |
9f95a23c | 837 | EXPECT_THROW(i += 200u, buffer::end_of_buffer); |
7c673cae FG |
838 | } |
839 | { | |
840 | bufferlist::iterator i(&bl); | |
841 | EXPECT_EQ('A', *i); | |
9f95a23c | 842 | i += 1u; |
7c673cae | 843 | EXPECT_EQ('B', *i); |
9f95a23c | 844 | i += 3u; |
7c673cae | 845 | EXPECT_EQ('E', *i); |
7c673cae FG |
846 | } |
847 | } | |
848 | ||
11fdf7f2 TL |
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 | ||
9f95a23c | 857 | encode(int64_t(42), bl); |
11fdf7f2 TL |
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 | ||
9f95a23c | 873 | encode(int64_t(24), bl); |
11fdf7f2 TL |
874 | EXPECT_EQ(bl.get_num_buffers(), 5u); |
875 | ||
876 | auto i = bl.cbegin(); | |
9f95a23c | 877 | int64_t val; |
11fdf7f2 TL |
878 | decode(val, i); |
879 | EXPECT_EQ(val, 42l); | |
880 | ||
881 | decode(val, i); | |
882 | EXPECT_EQ(val, 24l); | |
883 | ||
884 | val = 0; | |
9f95a23c | 885 | i.seek(sizeof(val)); |
11fdf7f2 TL |
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 | ||
7c673cae FG |
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(); | |
11fdf7f2 | 907 | ASSERT_EQ(3u, p.get_ptr_and_advance(11u, &ptr)); |
7c673cae FG |
908 | ASSERT_EQ(bl.length() - 3u, p.get_remaining()); |
909 | ASSERT_EQ(0, memcmp(ptr, "one", 3)); | |
11fdf7f2 | 910 | ASSERT_EQ(2u, p.get_ptr_and_advance(2u, &ptr)); |
7c673cae | 911 | ASSERT_EQ(0, memcmp(ptr, "tw", 2)); |
11fdf7f2 | 912 | ASSERT_EQ(1u, p.get_ptr_and_advance(4u, &ptr)); |
7c673cae | 913 | ASSERT_EQ(0, memcmp(ptr, "o", 1)); |
11fdf7f2 | 914 | ASSERT_EQ(5u, p.get_ptr_and_advance(5u, &ptr)); |
7c673cae FG |
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(); | |
9f95a23c | 943 | it += 98u; |
7c673cae FG |
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(); | |
9f95a23c | 950 | it += 98u + 55u; |
7c673cae FG |
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); | |
9f95a23c | 974 | EXPECT_THROW(i += 200u, buffer::end_of_buffer); |
7c673cae FG |
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 | // | |
9f95a23c | 1066 | EXPECT_THROW(i += 200u, buffer::end_of_buffer); |
7c673cae FG |
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)); | |
11fdf7f2 | 1073 | free(copy); |
7c673cae FG |
1074 | } |
1075 | // | |
9f95a23c TL |
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 | // | |
7c673cae FG |
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 | // | |
9f95a23c | 1119 | EXPECT_THROW(i += 200u, buffer::end_of_buffer); |
7c673cae FG |
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 | // | |
9f95a23c TL |
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 | // | |
7c673cae FG |
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 | // | |
9f95a23c | 1152 | EXPECT_THROW(i += 200u, buffer::end_of_buffer); |
7c673cae FG |
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 | // | |
9f95a23c | 1168 | EXPECT_THROW(i += 200u, buffer::end_of_buffer); |
7c673cae FG |
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 | } | |
9f95a23c TL |
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 | } | |
7c673cae FG |
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 | // | |
9f95a23c | 1206 | EXPECT_THROW(i += 200u, buffer::end_of_buffer); |
7c673cae FG |
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 | // | |
9f95a23c TL |
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 | // | |
7c673cae FG |
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 | // | |
9f95a23c | 1233 | EXPECT_THROW(i += 200u, buffer::end_of_buffer); |
7c673cae FG |
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 | } | |
9f95a23c TL |
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 | } | |
7c673cae FG |
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 | ||
9f95a23c TL |
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 | ||
7c673cae FG |
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) | |
11fdf7f2 | 1332 | bl.push_back(buffer::ptr_node::create(buffer::create(size))); |
7c673cae FG |
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 | ||
11fdf7f2 TL |
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 | ||
f67539c2 TL |
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 | ||
7c673cae FG |
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; | |
9f95a23c | 1423 | bl.begin(1).copy(1, dest); |
7c673cae FG |
1424 | ASSERT_EQ('B', dest[0]); |
1425 | } | |
1426 | { | |
1427 | bufferlist copy = bl; | |
1428 | std::string dest; | |
9f95a23c | 1429 | copy.begin(1).copy(1, dest); |
7c673cae FG |
1430 | ASSERT_EQ('B', dest[0]); |
1431 | } | |
1432 | ||
1433 | // | |
1434 | // list& operator= (list&& other) | |
1435 | // | |
f67539c2 TL |
1436 | bufferlist move; |
1437 | move = std::move(bl); | |
7c673cae FG |
1438 | { |
1439 | std::string dest; | |
9f95a23c | 1440 | move.begin(1).copy(1, dest); |
7c673cae FG |
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 | ||
7c673cae FG |
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; | |
9f95a23c | 1482 | b1.begin().copy(1, s1); |
7c673cae FG |
1483 | ASSERT_EQ('B', s1[0]); |
1484 | ||
1485 | std::string s2; | |
9f95a23c | 1486 | b2.begin().copy(1, s2); |
7c673cae FG |
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 | ||
31f18b77 FG |
1608 | TEST(BufferList, page_aligned_appender) { |
1609 | bufferlist bl; | |
f67539c2 TL |
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 | } | |
31f18b77 FG |
1688 | } |
1689 | ||
7c673cae FG |
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()); | |
522d829b TL |
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 | } | |
7c673cae FG |
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 | } | |
31f18b77 FG |
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 | ||
7c673cae FG |
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 | ||
7c673cae FG |
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]); | |
9f95a23c TL |
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()); | |
7c673cae FG |
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()); | |
9f95a23c | 1823 | EXPECT_EQ((unsigned)0, bl.get_num_buffers()); |
7c673cae FG |
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()); | |
9f95a23c | 1832 | EXPECT_EQ((unsigned)2, bl.get_num_buffers()); |
7c673cae | 1833 | EXPECT_EQ('B', bl.buffers().back()[0]); |
9f95a23c | 1834 | EXPECT_FALSE(static_cast<instrumented_bptr&>(ptr).get_raw()); |
7c673cae FG |
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 | ||
7c673cae FG |
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 | ||
7c673cae FG |
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; | |
11fdf7f2 | 1996 | bl.append("AB"); |
7c673cae | 1997 | bufferlist::iterator i = bl.end(); |
11fdf7f2 TL |
1998 | bl.append("C"); |
1999 | EXPECT_EQ('C', bl[i.get_off()]); | |
7c673cae FG |
2000 | } |
2001 | ||
7c673cae FG |
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; | |
9f95a23c | 2115 | EXPECT_EQ((unsigned)0, bl.get_num_buffers()); |
7c673cae FG |
2116 | EXPECT_EQ((unsigned)0, bl.length()); |
2117 | { | |
2118 | bufferptr ptr; | |
2119 | bl.append(std::move(ptr)); | |
9f95a23c | 2120 | EXPECT_EQ((unsigned)0, bl.get_num_buffers()); |
7c673cae FG |
2121 | EXPECT_EQ((unsigned)0, bl.length()); |
2122 | } | |
2123 | { | |
2124 | bufferptr ptr(3); | |
2125 | bl.append(std::move(ptr)); | |
9f95a23c | 2126 | EXPECT_EQ((unsigned)1, bl.get_num_buffers()); |
7c673cae | 2127 | EXPECT_EQ((unsigned)3, bl.length()); |
9f95a23c | 2128 | EXPECT_FALSE(static_cast<instrumented_bptr&>(ptr).get_raw()); |
7c673cae FG |
2129 | } |
2130 | } | |
2131 | } | |
2132 | ||
11fdf7f2 TL |
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 | ||
7c673cae FG |
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); | |
11fdf7f2 | 2179 | EXPECT_EQ((unsigned)1, bl.get_num_buffers()); |
7c673cae FG |
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)); | |
f67539c2 TL |
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); | |
7c673cae FG |
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)); | |
f67539c2 | 2329 | #endif /* _WIN32 */ |
7c673cae FG |
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); | |
11fdf7f2 | 2346 | ASSERT_NE(-1, fd); |
7c673cae FG |
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)); | |
11fdf7f2 | 2363 | ASSERT_EQ(0, ::stat(FILENAME, &st)); |
f67539c2 | 2364 | #ifndef _WIN32 |
7c673cae | 2365 | EXPECT_EQ((unsigned)(mode | S_IFREG), st.st_mode); |
f67539c2 | 2366 | #endif |
7c673cae FG |
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); | |
11fdf7f2 | 2373 | ASSERT_NE(-1, fd); |
7c673cae FG |
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)); | |
11fdf7f2 | 2383 | ASSERT_EQ(0, ::stat(FILENAME, &st)); |
7c673cae FG |
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); | |
11fdf7f2 | 2391 | ASSERT_NE(-1, fd); |
7c673cae FG |
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)); | |
11fdf7f2 | 2402 | ASSERT_EQ(0, ::stat(FILENAME, &st)); |
7c673cae FG |
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 | ||
31f18b77 FG |
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 | ||
7c673cae FG |
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 | ||
11fdf7f2 TL |
2479 | [[maybe_unused]] int base_cached = buffer::get_cached_crc(); |
2480 | [[maybe_unused]] int base_cached_adjusted = buffer::get_cached_crc_adjusted(); | |
7c673cae FG |
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 | } | |
11fdf7f2 | 2494 | ceph_assert(buffer::get_cached_crc() == 0 + base_cached); |
7c673cae FG |
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 | } | |
11fdf7f2 | 2503 | ceph_assert(buffer::get_cached_crc() == 1 + base_cached); |
7c673cae FG |
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 | } | |
11fdf7f2 TL |
2513 | ceph_assert(buffer::get_cached_crc() == 1 + base_cached); |
2514 | ceph_assert(buffer::get_cached_crc_adjusted() == 1 + base_cached_adjusted); | |
7c673cae FG |
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 | } | |
11fdf7f2 TL |
2523 | ceph_assert(buffer::get_cached_crc() == 1 + base_cached); |
2524 | ceph_assert(buffer::get_cached_crc_adjusted() == 2 + base_cached_adjusted); | |
7c673cae FG |
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 | } | |
11fdf7f2 | 2533 | ceph_assert(buffer::get_cached_crc() == 1 + base_cached); |
7c673cae FG |
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 | } | |
11fdf7f2 | 2542 | ceph_assert(buffer::get_cached_crc() == 2 + base_cached); |
7c673cae FG |
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 | } | |
11fdf7f2 TL |
2555 | ceph_assert(buffer::get_cached_crc() == 3 + base_cached); |
2556 | ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted); | |
7c673cae FG |
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 | } | |
11fdf7f2 TL |
2568 | ceph_assert(buffer::get_cached_crc() == 4 + base_cached); |
2569 | ceph_assert(buffer::get_cached_crc_adjusted() == 3 + base_cached_adjusted); | |
7c673cae FG |
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 | } | |
11fdf7f2 TL |
2582 | ceph_assert(buffer::get_cached_crc() == 5 + base_cached); |
2583 | ceph_assert(buffer::get_cached_crc_adjusted() == 4 + base_cached_adjusted); | |
7c673cae FG |
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 | } | |
11fdf7f2 TL |
2592 | ceph_assert(buffer::get_cached_crc() == 5 + base_cached); |
2593 | ceph_assert(buffer::get_cached_crc_adjusted() == 6 + base_cached_adjusted); | |
7c673cae FG |
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"); | |
f67539c2 TL |
2602 | bufferlist ab; // AB in segments |
2603 | ab.append(bufferptr("A", 1)); | |
2604 | ab.append(bufferptr("B", 1)); | |
7c673cae FG |
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 | ||
11fdf7f2 TL |
2734 | TEST(BufferList, InternalCarriage) { |
2735 | ceph::bufferlist bl; | |
2736 | EXPECT_EQ(bl.get_num_buffers(), 0u); | |
2737 | ||
9f95a23c | 2738 | encode(int64_t(42), bl); |
11fdf7f2 TL |
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 | ||
9f95a23c | 2751 | encode(int64_t(24), bl); |
11fdf7f2 TL |
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 | ||
9f95a23c | 2763 | denc(int64_t(42), ap); |
11fdf7f2 TL |
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 | ||
9f95a23c | 2780 | denc(int64_t(24), ap); |
11fdf7f2 | 2781 | EXPECT_EQ(bl.get_num_buffers(), 3u); |
9f95a23c | 2782 | EXPECT_EQ(bl.length(), sizeof(int64_t) + 3u); |
11fdf7f2 | 2783 | } |
9f95a23c | 2784 | EXPECT_EQ(bl.length(), 2u * sizeof(int64_t) + 3u); |
11fdf7f2 TL |
2785 | } |
2786 | ||
7c673cae FG |
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 | ||
7c673cae FG |
2827 | TEST(BufferList, TestCopyAll) { |
2828 | const static size_t BIG_SZ = 10737414; | |
11fdf7f2 | 2829 | std::shared_ptr <unsigned char> big( |
7c673cae FG |
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); | |
11fdf7f2 | 2841 | std::shared_ptr <unsigned char> big2( |
7c673cae | 2842 | (unsigned char*)malloc(BIG_SZ), free); |
9f95a23c | 2843 | bl2.begin().copy(BIG_SZ, (char*)big2.get()); |
7c673cae FG |
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; | |
11fdf7f2 | 2849 | std::shared_ptr <unsigned char> big( |
7c673cae FG |
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 | ||
9f95a23c | 2896 | TEST(BufferList, DISABLED_DanglingLastP) { |
92f5a8d4 TL |
2897 | bufferlist bl; |
2898 | { | |
9f95a23c TL |
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: | |
92f5a8d4 | 2902 | // https://gist.github.com/rzarzynski/aed18372e88aed392101adac3bd87bbc |
9f95a23c TL |
2903 | // this is no longer possible as `buffer::create_unsharable()` has |
2904 | // been dropped. | |
2905 | bufferptr bp(buffer::create(10)); | |
92f5a8d4 TL |
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 | |
9f95a23c | 2911 | bl.begin().copy_in(2, "AB"); |
92f5a8d4 TL |
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`. | |
9f95a23c | 2924 | bl.begin(2).copy_in(1, "C"); |
92f5a8d4 TL |
2925 | EXPECT_EQ(0, ::memcmp("12C", bl.c_str(), 3)); |
2926 | } | |
2927 | ||
7c673cae FG |
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 && | |
11fdf7f2 | 2953 | * ulimit -s unlimited ; valgrind \ |
7c673cae FG |
2954 | * --max-stackframe=20000000 --tool=memcheck \ |
2955 | * ./unittest_bufferlist # --gtest_filter=BufferList.constructors" | |
2956 | * End: | |
2957 | */ | |
2958 |