]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/rgw/test_cls_fifo_legacy.cc
26d9e9a9253e4e67f069481d75b3c8c49fac7ed0
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2019 Red Hat, Inc.
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
17 #include <string_view>
19 #include "include/scope_guard.h"
20 #include "include/types.h"
21 #include "include/rados/librados.hpp"
23 #include "cls/fifo/cls_fifo_ops.h"
24 #include "test/librados/test_cxx.h"
25 #include "global/global_context.h"
27 #include "rgw/rgw_tools.h"
28 #include "rgw/cls_fifo_legacy.h"
30 #include "gtest/gtest.h"
32 namespace R
= librados
;
33 namespace cb
= ceph::buffer
;
34 namespace fifo
= rados::cls::fifo
;
35 namespace RCf
= rgw::cls::fifo
;
38 int fifo_create(R::IoCtx
& ioctx
,
39 const std::string
& oid
,
42 std::optional
<fifo::objv
> objv
= std::nullopt
,
43 std::optional
<std::string_view
> oid_prefix
= std::nullopt
,
44 bool exclusive
= false,
45 std::uint64_t max_part_size
= RCf::default_max_part_size
,
46 std::uint64_t max_entry_size
= RCf::default_max_entry_size
)
48 R::ObjectWriteOperation op
;
49 RCf::create_meta(&op
, id
, objv
, oid_prefix
, exclusive
, max_part_size
,
51 return rgw_rados_operate(ioctx
, oid
, &op
, y
);
55 class LegacyFIFO
: public testing::Test
{
57 const std::string pool_name
= get_temp_pool_name();
58 const std::string fifo_id
= "fifo";
60 librados::IoCtx ioctx
;
62 void SetUp() override
{
63 ASSERT_EQ("", create_one_pool_pp(pool_name
, rados
));
64 ASSERT_EQ(0, rados
.ioctx_create(pool_name
.c_str(), ioctx
));
66 void TearDown() override
{
67 destroy_one_pool_pp(pool_name
, rados
);
71 using LegacyClsFIFO
= LegacyFIFO
;
72 using AioLegacyFIFO
= LegacyFIFO
;
75 TEST_F(LegacyClsFIFO
, TestCreate
)
77 auto r
= fifo_create(ioctx
, fifo_id
, ""s
, null_yield
);
78 EXPECT_EQ(-EINVAL
, r
);
79 r
= fifo_create(ioctx
, fifo_id
, fifo_id
, null_yield
, std::nullopt
,
80 std::nullopt
, false, 0);
81 EXPECT_EQ(-EINVAL
, r
);
82 r
= fifo_create(ioctx
, fifo_id
, {}, null_yield
,
83 std::nullopt
, std::nullopt
,
84 false, RCf::default_max_part_size
, 0);
85 EXPECT_EQ(-EINVAL
, r
);
86 r
= fifo_create(ioctx
, fifo_id
, fifo_id
, null_yield
);
89 ioctx
.stat(fifo_id
, &size
, nullptr);
91 /* test idempotency */
92 r
= fifo_create(ioctx
, fifo_id
, fifo_id
, null_yield
);
94 r
= fifo_create(ioctx
, fifo_id
, {}, null_yield
, std::nullopt
,
96 EXPECT_EQ(-EINVAL
, r
);
97 r
= fifo_create(ioctx
, fifo_id
, {}, null_yield
, std::nullopt
,
99 EXPECT_EQ(-EINVAL
, r
);
100 r
= fifo_create(ioctx
, fifo_id
, "foo"sv
, null_yield
,
101 std::nullopt
, std::nullopt
, false);
102 EXPECT_EQ(-EEXIST
, r
);
105 TEST_F(LegacyClsFIFO
, TestGetInfo
)
107 auto r
= fifo_create(ioctx
, fifo_id
, fifo_id
, null_yield
);
109 std::uint32_t part_header_size
;
110 std::uint32_t part_entry_overhead
;
111 r
= RCf::get_meta(ioctx
, fifo_id
, std::nullopt
, &info
, &part_header_size
,
112 &part_entry_overhead
, 0, null_yield
);
114 EXPECT_GT(part_header_size
, 0);
115 EXPECT_GT(part_entry_overhead
, 0);
116 EXPECT_FALSE(info
.version
.instance
.empty());
118 r
= RCf::get_meta(ioctx
, fifo_id
, info
.version
, &info
, &part_header_size
,
119 &part_entry_overhead
, 0, null_yield
);
122 objv
.instance
= "foo";
124 r
= RCf::get_meta(ioctx
, fifo_id
, objv
, &info
, &part_header_size
,
125 &part_entry_overhead
, 0, null_yield
);
126 EXPECT_EQ(-ECANCELED
, r
);
129 TEST_F(LegacyFIFO
, TestOpenDefault
)
131 std::unique_ptr
<RCf::FIFO
> fifo
;
132 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &fifo
, null_yield
);
134 // force reading from backend
135 r
= fifo
->read_meta(null_yield
);
137 auto info
= fifo
->meta();
138 EXPECT_EQ(info
.id
, fifo_id
);
141 TEST_F(LegacyFIFO
, TestOpenParams
)
143 const std::uint64_t max_part_size
= 10 * 1024;
144 const std::uint64_t max_entry_size
= 128;
145 auto oid_prefix
= "foo.123."sv
;
147 objv
.instance
= "fooz"s
;
150 /* first successful create */
151 std::unique_ptr
<RCf::FIFO
> f
;
152 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, objv
, oid_prefix
,
153 false, max_part_size
, max_entry_size
);
156 /* force reading from backend */
157 r
= f
->read_meta(null_yield
);
158 auto info
= f
->meta();
159 EXPECT_EQ(info
.id
, fifo_id
);
160 EXPECT_EQ(info
.params
.max_part_size
, max_part_size
);
161 EXPECT_EQ(info
.params
.max_entry_size
, max_entry_size
);
162 EXPECT_EQ(info
.version
, objv
);
167 std::pair
<T
, std::string
> decode_entry(const RCf::list_entry
& entry
)
170 auto iter
= entry
.data
.cbegin();
172 return std::make_pair(std::move(val
), entry
.marker
);
177 TEST_F(LegacyFIFO
, TestPushListTrim
)
179 std::unique_ptr
<RCf::FIFO
> f
;
180 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
);
182 static constexpr auto max_entries
= 10u;
183 for (uint32_t i
= 0; i
< max_entries
; ++i
) {
186 r
= f
->push(bl
, null_yield
);
190 std::optional
<std::string
> marker
;
191 /* get entries one by one */
192 std::vector
<RCf::list_entry
> result
;
194 for (auto i
= 0u; i
< max_entries
; ++i
) {
196 r
= f
->list(1, marker
, &result
, &more
, null_yield
);
199 bool expected_more
= (i
!= (max_entries
- 1));
200 ASSERT_EQ(expected_more
, more
);
201 ASSERT_EQ(1, result
.size());
204 std::tie(val
, marker
) = decode_entry
<std::uint32_t>(result
.front());
210 /* get all entries at once */
211 std::string markers
[max_entries
];
212 std::uint32_t min_entry
= 0;
213 r
= f
->list(max_entries
* 10, std::nullopt
, &result
, &more
, null_yield
);
217 ASSERT_EQ(max_entries
, result
.size());
218 for (auto i
= 0u; i
< max_entries
; ++i
) {
220 std::tie(val
, markers
[i
]) = decode_entry
<std::uint32_t>(result
[i
]);
225 r
= f
->trim(markers
[min_entry
], false, null_yield
);
229 r
= f
->list(max_entries
* 10, std::nullopt
, &result
, &more
, null_yield
);
232 ASSERT_EQ(max_entries
- min_entry
, result
.size());
234 for (auto i
= min_entry
; i
< max_entries
; ++i
) {
236 std::tie(val
, markers
[i
- min_entry
]) =
237 decode_entry
<std::uint32_t>(result
[i
- min_entry
]);
243 TEST_F(LegacyFIFO
, TestPushTooBig
)
245 static constexpr auto max_part_size
= 2048ull;
246 static constexpr auto max_entry_size
= 128ull;
248 std::unique_ptr
<RCf::FIFO
> f
;
249 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, std::nullopt
,
250 std::nullopt
, false, max_part_size
, max_entry_size
);
253 char buf
[max_entry_size
+ 1];
254 memset(buf
, 0, sizeof(buf
));
257 bl
.append(buf
, sizeof(buf
));
259 r
= f
->push(bl
, null_yield
);
260 EXPECT_EQ(-E2BIG
, r
);
264 TEST_F(LegacyFIFO
, TestMultipleParts
)
266 static constexpr auto max_part_size
= 2048ull;
267 static constexpr auto max_entry_size
= 128ull;
268 std::unique_ptr
<RCf::FIFO
> f
;
269 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, std::nullopt
,
270 std::nullopt
, false, max_part_size
,
274 char buf
[max_entry_size
];
275 memset(buf
, 0, sizeof(buf
));
276 const auto [part_header_size
, part_entry_overhead
] =
277 f
->get_part_layout_info();
278 const auto entries_per_part
= ((max_part_size
- part_header_size
) /
279 (max_entry_size
+ part_entry_overhead
));
280 const auto max_entries
= entries_per_part
* 4 + 1;
281 /* push enough entries */
282 for (auto i
= 0u; i
< max_entries
; ++i
) {
285 bl
.append(buf
, sizeof(buf
));
286 r
= f
->push(bl
, null_yield
);
290 auto info
= f
->meta();
291 ASSERT_EQ(info
.id
, fifo_id
);
292 /* head should have advanced */
293 ASSERT_GT(info
.head_part_num
, 0);
295 /* list all at once */
296 std::vector
<RCf::list_entry
> result
;
298 r
= f
->list(max_entries
, std::nullopt
, &result
, &more
, null_yield
);
300 EXPECT_EQ(false, more
);
301 ASSERT_EQ(max_entries
, result
.size());
303 for (auto i
= 0u; i
< max_entries
; ++i
) {
304 auto& bl
= result
[i
].data
;
305 ASSERT_EQ(i
, *(int *)bl
.c_str());
308 std::optional
<std::string
> marker
;
309 /* get entries one by one */
311 for (auto i
= 0u; i
< max_entries
; ++i
) {
312 r
= f
->list(1, marker
, &result
, &more
, null_yield
);
314 ASSERT_EQ(result
.size(), 1);
315 const bool expected_more
= (i
!= (max_entries
- 1));
316 ASSERT_EQ(expected_more
, more
);
319 std::tie(val
, marker
) = decode_entry
<std::uint32_t>(result
.front());
321 auto& entry
= result
.front();
322 auto& bl
= entry
.data
;
323 ASSERT_EQ(i
, *(int *)bl
.c_str());
324 marker
= entry
.marker
;
327 /* trim one at a time */
329 for (auto i
= 0u; i
< max_entries
; ++i
) {
330 /* read single entry */
331 r
= f
->list(1, marker
, &result
, &more
, null_yield
);
333 ASSERT_EQ(result
.size(), 1);
334 const bool expected_more
= (i
!= (max_entries
- 1));
335 ASSERT_EQ(expected_more
, more
);
337 marker
= result
.front().marker
;
338 r
= f
->trim(*marker
, false, null_yield
);
343 ASSERT_EQ(info
.tail_part_num
, i
/ entries_per_part
);
345 /* try to read all again, see how many entries left */
346 r
= f
->list(max_entries
, marker
, &result
, &more
, null_yield
);
347 ASSERT_EQ(max_entries
- i
- 1, result
.size());
348 ASSERT_EQ(false, more
);
351 /* tail now should point at head */
353 ASSERT_EQ(info
.head_part_num
, info
.tail_part_num
);
355 RCf::part_info partinfo
;
356 /* check old tails are removed */
357 for (auto i
= 0; i
< info
.tail_part_num
; ++i
) {
358 r
= f
->get_part_info(i
, &partinfo
, null_yield
);
359 ASSERT_EQ(-ENOENT
, r
);
361 /* check current tail exists */
362 r
= f
->get_part_info(info
.tail_part_num
, &partinfo
, null_yield
);
366 TEST_F(LegacyFIFO
, TestTwoPushers
)
368 static constexpr auto max_part_size
= 2048ull;
369 static constexpr auto max_entry_size
= 128ull;
371 std::unique_ptr
<RCf::FIFO
> f
;
372 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, std::nullopt
,
373 std::nullopt
, false, max_part_size
,
376 char buf
[max_entry_size
];
377 memset(buf
, 0, sizeof(buf
));
379 auto [part_header_size
, part_entry_overhead
] = f
->get_part_layout_info();
380 const auto entries_per_part
= ((max_part_size
- part_header_size
) /
381 (max_entry_size
+ part_entry_overhead
));
382 const auto max_entries
= entries_per_part
* 4 + 1;
383 std::unique_ptr
<RCf::FIFO
> f2
;
384 r
= RCf::FIFO::open(ioctx
, fifo_id
, &f2
, null_yield
);
385 std::vector fifos
{&f
, &f2
};
387 for (auto i
= 0u; i
< max_entries
; ++i
) {
390 bl
.append(buf
, sizeof(buf
));
391 auto& f
= *fifos
[i
% fifos
.size()];
392 r
= f
->push(bl
, null_yield
);
396 /* list all by both */
397 std::vector
<RCf::list_entry
> result
;
399 r
= f2
->list(max_entries
, std::nullopt
, &result
, &more
, null_yield
);
401 ASSERT_EQ(false, more
);
402 ASSERT_EQ(max_entries
, result
.size());
404 r
= f2
->list(max_entries
, std::nullopt
, &result
, &more
, null_yield
);
406 ASSERT_EQ(false, more
);
407 ASSERT_EQ(max_entries
, result
.size());
409 for (auto i
= 0u; i
< max_entries
; ++i
) {
410 auto& bl
= result
[i
].data
;
411 ASSERT_EQ(i
, *(int *)bl
.c_str());
415 TEST_F(LegacyFIFO
, TestTwoPushersTrim
)
417 static constexpr auto max_part_size
= 2048ull;
418 static constexpr auto max_entry_size
= 128ull;
419 std::unique_ptr
<RCf::FIFO
> f1
;
420 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f1
, null_yield
, std::nullopt
,
421 std::nullopt
, false, max_part_size
,
425 char buf
[max_entry_size
];
426 memset(buf
, 0, sizeof(buf
));
428 auto [part_header_size
, part_entry_overhead
] = f1
->get_part_layout_info();
429 const auto entries_per_part
= ((max_part_size
- part_header_size
) /
430 (max_entry_size
+ part_entry_overhead
));
431 const auto max_entries
= entries_per_part
* 4 + 1;
433 std::unique_ptr
<RCf::FIFO
> f2
;
434 r
= RCf::FIFO::open(ioctx
, fifo_id
, &f2
, null_yield
);
437 /* push one entry to f2 and the rest to f1 */
438 for (auto i
= 0u; i
< max_entries
; ++i
) {
441 bl
.append(buf
, sizeof(buf
));
442 auto& f
= (i
< 1 ? f2
: f1
);
443 r
= f
->push(bl
, null_yield
);
447 /* trim half by fifo1 */
448 auto num
= max_entries
/ 2;
450 std::vector
<RCf::list_entry
> result
;
452 r
= f1
->list(num
, std::nullopt
, &result
, &more
, null_yield
);
454 ASSERT_EQ(true, more
);
455 ASSERT_EQ(num
, result
.size());
457 for (auto i
= 0u; i
< num
; ++i
) {
458 auto& bl
= result
[i
].data
;
459 ASSERT_EQ(i
, *(int *)bl
.c_str());
462 auto& entry
= result
[num
- 1];
463 marker
= entry
.marker
;
464 r
= f1
->trim(marker
, false, null_yield
);
465 /* list what's left by fifo2 */
467 const auto left
= max_entries
- num
;
468 f2
->list(left
, marker
, &result
, &more
, null_yield
);
469 ASSERT_EQ(left
, result
.size());
470 ASSERT_EQ(false, more
);
472 for (auto i
= num
; i
< max_entries
; ++i
) {
473 auto& bl
= result
[i
- num
].data
;
474 ASSERT_EQ(i
, *(int *)bl
.c_str());
478 TEST_F(LegacyFIFO
, TestPushBatch
)
480 static constexpr auto max_part_size
= 2048ull;
481 static constexpr auto max_entry_size
= 128ull;
483 std::unique_ptr
<RCf::FIFO
> f
;
484 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, std::nullopt
,
485 std::nullopt
, false, max_part_size
,
489 char buf
[max_entry_size
];
490 memset(buf
, 0, sizeof(buf
));
491 auto [part_header_size
, part_entry_overhead
] = f
->get_part_layout_info();
492 auto entries_per_part
= ((max_part_size
- part_header_size
) /
493 (max_entry_size
+ part_entry_overhead
));
494 auto max_entries
= entries_per_part
* 4 + 1; /* enough entries to span multiple parts */
495 std::vector
<cb::list
> bufs
;
496 for (auto i
= 0u; i
< max_entries
; ++i
) {
499 bl
.append(buf
, sizeof(buf
));
502 ASSERT_EQ(max_entries
, bufs
.size());
504 r
= f
->push(bufs
, null_yield
);
509 std::vector
<RCf::list_entry
> result
;
511 r
= f
->list(max_entries
, std::nullopt
, &result
, &more
, null_yield
);
513 ASSERT_EQ(false, more
);
514 ASSERT_EQ(max_entries
, result
.size());
515 for (auto i
= 0u; i
< max_entries
; ++i
) {
516 auto& bl
= result
[i
].data
;
517 ASSERT_EQ(i
, *(int *)bl
.c_str());
519 auto& info
= f
->meta();
520 ASSERT_EQ(info
.head_part_num
, 4);
523 TEST_F(LegacyFIFO
, TestAioTrim
)
525 static constexpr auto max_part_size
= 2048ull;
526 static constexpr auto max_entry_size
= 128ull;
527 std::unique_ptr
<RCf::FIFO
> f
;
528 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, std::nullopt
,
529 std::nullopt
, false, max_part_size
,
533 char buf
[max_entry_size
];
534 memset(buf
, 0, sizeof(buf
));
535 const auto [part_header_size
, part_entry_overhead
] =
536 f
->get_part_layout_info();
537 const auto entries_per_part
= ((max_part_size
- part_header_size
) /
538 (max_entry_size
+ part_entry_overhead
));
539 const auto max_entries
= entries_per_part
* 4 + 1;
540 /* push enough entries */
541 std::vector
<cb::list
> bufs
;
542 for (auto i
= 0u; i
< max_entries
; ++i
) {
545 bl
.append(buf
, sizeof(buf
));
546 bufs
.push_back(std::move(bl
));
548 ASSERT_EQ(max_entries
, bufs
.size());
550 r
= f
->push(bufs
, null_yield
);
553 auto info
= f
->meta();
554 ASSERT_EQ(info
.id
, fifo_id
);
555 /* head should have advanced */
556 ASSERT_GT(info
.head_part_num
, 0);
558 /* list all at once */
559 std::vector
<RCf::list_entry
> result
;
561 r
= f
->list(max_entries
, std::nullopt
, &result
, &more
, null_yield
);
563 ASSERT_EQ(false, more
);
564 ASSERT_EQ(max_entries
, result
.size());
566 std::optional
<std::string
> marker
;
567 /* trim one at a time */
571 for (auto i
= 0u; i
< max_entries
; ++i
) {
572 /* read single entry */
573 r
= f
->list(1, marker
, &result
, &more
, null_yield
);
575 ASSERT_EQ(result
.size(), 1);
576 const bool expected_more
= (i
!= (max_entries
- 1));
577 ASSERT_EQ(expected_more
, more
);
579 marker
= result
.front().marker
;
580 std::unique_ptr
<R::AioCompletion
> c(rados
.aio_create_completion(nullptr,
582 f
->trim(*marker
, false, c
.get());
583 c
->wait_for_complete();
584 r
= c
->get_return_value();
589 ASSERT_EQ(info
.tail_part_num
, i
/ entries_per_part
);
591 /* try to read all again, see how many entries left */
592 r
= f
->list(max_entries
, marker
, &result
, &more
, null_yield
);
593 ASSERT_EQ(max_entries
- i
- 1, result
.size());
594 ASSERT_EQ(false, more
);
597 /* tail now should point at head */
599 ASSERT_EQ(info
.head_part_num
, info
.tail_part_num
);
601 RCf::part_info partinfo
;
602 /* check old tails are removed */
603 for (auto i
= 0; i
< info
.tail_part_num
; ++i
) {
604 r
= f
->get_part_info(i
, &partinfo
, null_yield
);
605 ASSERT_EQ(-ENOENT
, r
);
607 /* check current tail exists */
608 r
= f
->get_part_info(info
.tail_part_num
, &partinfo
, null_yield
);
612 TEST_F(LegacyFIFO
, TestTrimExclusive
) {
613 std::unique_ptr
<RCf::FIFO
> f
;
614 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
);
616 std::vector
<RCf::list_entry
> result
;
619 static constexpr auto max_entries
= 10u;
620 for (uint32_t i
= 0; i
< max_entries
; ++i
) {
623 f
->push(bl
, null_yield
);
626 f
->list(1, std::nullopt
, &result
, &more
, null_yield
);
627 auto [val
, marker
] = decode_entry
<std::uint32_t>(result
.front());
629 f
->trim(marker
, true, null_yield
);
632 f
->list(max_entries
, std::nullopt
, &result
, &more
, null_yield
);
633 std::tie(val
, marker
) = decode_entry
<std::uint32_t>(result
.front());
635 f
->trim(result
[4].marker
, true, null_yield
);
638 f
->list(max_entries
, std::nullopt
, &result
, &more
, null_yield
);
639 std::tie(val
, marker
) = decode_entry
<std::uint32_t>(result
.front());
641 f
->trim(result
.back().marker
, true, null_yield
);
644 f
->list(max_entries
, std::nullopt
, &result
, &more
, null_yield
);
645 std::tie(val
, marker
) = decode_entry
<std::uint32_t>(result
.front());
646 ASSERT_EQ(result
.size(), 1);
647 ASSERT_EQ(max_entries
- 1, val
);
650 TEST_F(AioLegacyFIFO
, TestPushListTrim
)
652 std::unique_ptr
<RCf::FIFO
> f
;
653 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
);
655 static constexpr auto max_entries
= 10u;
656 for (uint32_t i
= 0; i
< max_entries
; ++i
) {
659 auto c
= R::Rados::aio_create_completion();
661 c
->wait_for_complete();
662 r
= c
->get_return_value();
667 std::optional
<std::string
> marker
;
668 /* get entries one by one */
669 std::vector
<RCf::list_entry
> result
;
671 for (auto i
= 0u; i
< max_entries
; ++i
) {
672 auto c
= R::Rados::aio_create_completion();
673 f
->list(1, marker
, &result
, &more
, c
);
674 c
->wait_for_complete();
675 r
= c
->get_return_value();
679 bool expected_more
= (i
!= (max_entries
- 1));
680 ASSERT_EQ(expected_more
, more
);
681 ASSERT_EQ(1, result
.size());
684 std::tie(val
, marker
) = decode_entry
<std::uint32_t>(result
.front());
690 /* get all entries at once */
691 std::string markers
[max_entries
];
692 std::uint32_t min_entry
= 0;
693 auto c
= R::Rados::aio_create_completion();
694 f
->list(max_entries
* 10, std::nullopt
, &result
, &more
, c
);
695 c
->wait_for_complete();
696 r
= c
->get_return_value();
701 ASSERT_EQ(max_entries
, result
.size());
702 for (auto i
= 0u; i
< max_entries
; ++i
) {
704 std::tie(val
, markers
[i
]) = decode_entry
<std::uint32_t>(result
[i
]);
709 c
= R::Rados::aio_create_completion();
710 f
->trim(markers
[min_entry
], false, c
);
711 c
->wait_for_complete();
712 r
= c
->get_return_value();
717 c
= R::Rados::aio_create_completion();
718 f
->list(max_entries
* 10, std::nullopt
, &result
, &more
, c
);
719 c
->wait_for_complete();
720 r
= c
->get_return_value();
724 ASSERT_EQ(max_entries
- min_entry
, result
.size());
726 for (auto i
= min_entry
; i
< max_entries
; ++i
) {
728 std::tie(val
, markers
[i
- min_entry
]) =
729 decode_entry
<std::uint32_t>(result
[i
- min_entry
]);
735 TEST_F(AioLegacyFIFO
, TestPushTooBig
)
737 static constexpr auto max_part_size
= 2048ull;
738 static constexpr auto max_entry_size
= 128ull;
740 std::unique_ptr
<RCf::FIFO
> f
;
741 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, std::nullopt
,
742 std::nullopt
, false, max_part_size
, max_entry_size
);
745 char buf
[max_entry_size
+ 1];
746 memset(buf
, 0, sizeof(buf
));
749 bl
.append(buf
, sizeof(buf
));
751 auto c
= R::Rados::aio_create_completion();
753 c
->wait_for_complete();
754 r
= c
->get_return_value();
755 ASSERT_EQ(-E2BIG
, r
);
758 c
= R::Rados::aio_create_completion();
759 f
->push(std::vector
<cb::list
>{}, c
);
760 c
->wait_for_complete();
761 r
= c
->get_return_value();
767 TEST_F(AioLegacyFIFO
, TestMultipleParts
)
769 static constexpr auto max_part_size
= 2048ull;
770 static constexpr auto max_entry_size
= 128ull;
771 std::unique_ptr
<RCf::FIFO
> f
;
772 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, std::nullopt
,
773 std::nullopt
, false, max_part_size
,
778 auto c
= R::Rados::aio_create_completion();
779 f
->get_head_info([&](int r
, RCf::part_info
&& p
) {
780 ASSERT_TRUE(p
.tag
.empty());
781 ASSERT_EQ(0, p
.magic
);
782 ASSERT_EQ(0, p
.min_ofs
);
783 ASSERT_EQ(0, p
.last_ofs
);
784 ASSERT_EQ(0, p
.next_ofs
);
785 ASSERT_EQ(0, p
.min_index
);
786 ASSERT_EQ(0, p
.max_index
);
787 ASSERT_EQ(ceph::real_time
{}, p
.max_time
);
789 c
->wait_for_complete();
790 r
= c
->get_return_value();
794 char buf
[max_entry_size
];
795 memset(buf
, 0, sizeof(buf
));
796 const auto [part_header_size
, part_entry_overhead
] =
797 f
->get_part_layout_info();
798 const auto entries_per_part
= ((max_part_size
- part_header_size
) /
799 (max_entry_size
+ part_entry_overhead
));
800 const auto max_entries
= entries_per_part
* 4 + 1;
801 /* push enough entries */
802 for (auto i
= 0u; i
< max_entries
; ++i
) {
805 bl
.append(buf
, sizeof(buf
));
806 auto c
= R::Rados::aio_create_completion();
808 c
->wait_for_complete();
809 r
= c
->get_return_value();
814 auto info
= f
->meta();
815 ASSERT_EQ(info
.id
, fifo_id
);
816 /* head should have advanced */
817 ASSERT_GT(info
.head_part_num
, 0);
819 /* list all at once */
820 std::vector
<RCf::list_entry
> result
;
822 auto c
= R::Rados::aio_create_completion();
823 f
->list(max_entries
, std::nullopt
, &result
, &more
, c
);
824 c
->wait_for_complete();
825 r
= c
->get_return_value();
828 EXPECT_EQ(false, more
);
829 ASSERT_EQ(max_entries
, result
.size());
831 for (auto i
= 0u; i
< max_entries
; ++i
) {
832 auto& bl
= result
[i
].data
;
833 ASSERT_EQ(i
, *(int *)bl
.c_str());
836 std::optional
<std::string
> marker
;
837 /* get entries one by one */
839 for (auto i
= 0u; i
< max_entries
; ++i
) {
840 c
= R::Rados::aio_create_completion();
841 f
->list(1, marker
, &result
, &more
, c
);
842 c
->wait_for_complete();
843 r
= c
->get_return_value();
846 ASSERT_EQ(result
.size(), 1);
847 const bool expected_more
= (i
!= (max_entries
- 1));
848 ASSERT_EQ(expected_more
, more
);
851 std::tie(val
, marker
) = decode_entry
<std::uint32_t>(result
.front());
853 auto& entry
= result
.front();
854 auto& bl
= entry
.data
;
855 ASSERT_EQ(i
, *(int *)bl
.c_str());
856 marker
= entry
.marker
;
859 /* trim one at a time */
861 for (auto i
= 0u; i
< max_entries
; ++i
) {
862 /* read single entry */
863 c
= R::Rados::aio_create_completion();
864 f
->list(1, marker
, &result
, &more
, c
);
865 c
->wait_for_complete();
866 r
= c
->get_return_value();
869 ASSERT_EQ(result
.size(), 1);
870 const bool expected_more
= (i
!= (max_entries
- 1));
871 ASSERT_EQ(expected_more
, more
);
873 marker
= result
.front().marker
;
874 c
= R::Rados::aio_create_completion();
875 f
->trim(*marker
, false, c
);
876 c
->wait_for_complete();
877 r
= c
->get_return_value();
880 ASSERT_EQ(result
.size(), 1);
884 ASSERT_EQ(info
.tail_part_num
, i
/ entries_per_part
);
886 /* try to read all again, see how many entries left */
887 c
= R::Rados::aio_create_completion();
888 f
->list(max_entries
, marker
, &result
, &more
, c
);
889 c
->wait_for_complete();
890 r
= c
->get_return_value();
893 ASSERT_EQ(max_entries
- i
- 1, result
.size());
894 ASSERT_EQ(false, more
);
897 /* tail now should point at head */
899 ASSERT_EQ(info
.head_part_num
, info
.tail_part_num
);
901 /* check old tails are removed */
902 for (auto i
= 0; i
< info
.tail_part_num
; ++i
) {
903 c
= R::Rados::aio_create_completion();
904 RCf::part_info partinfo
;
905 f
->get_part_info(i
, &partinfo
, c
);
906 c
->wait_for_complete();
907 r
= c
->get_return_value();
909 ASSERT_EQ(-ENOENT
, r
);
911 /* check current tail exists */
912 std::uint64_t next_ofs
;
914 c
= R::Rados::aio_create_completion();
915 RCf::part_info partinfo
;
916 f
->get_part_info(info
.tail_part_num
, &partinfo
, c
);
917 c
->wait_for_complete();
918 r
= c
->get_return_value();
920 next_ofs
= partinfo
.next_ofs
;
924 c
= R::Rados::aio_create_completion();
925 f
->get_head_info([&](int r
, RCf::part_info
&& p
) {
926 ASSERT_EQ(next_ofs
, p
.next_ofs
);
928 c
->wait_for_complete();
929 r
= c
->get_return_value();
934 TEST_F(AioLegacyFIFO
, TestTwoPushers
)
936 static constexpr auto max_part_size
= 2048ull;
937 static constexpr auto max_entry_size
= 128ull;
939 std::unique_ptr
<RCf::FIFO
> f
;
940 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, std::nullopt
,
941 std::nullopt
, false, max_part_size
,
944 char buf
[max_entry_size
];
945 memset(buf
, 0, sizeof(buf
));
947 auto [part_header_size
, part_entry_overhead
] = f
->get_part_layout_info();
948 const auto entries_per_part
= ((max_part_size
- part_header_size
) /
949 (max_entry_size
+ part_entry_overhead
));
950 const auto max_entries
= entries_per_part
* 4 + 1;
951 std::unique_ptr
<RCf::FIFO
> f2
;
952 r
= RCf::FIFO::open(ioctx
, fifo_id
, &f2
, null_yield
);
953 std::vector fifos
{&f
, &f2
};
955 for (auto i
= 0u; i
< max_entries
; ++i
) {
958 bl
.append(buf
, sizeof(buf
));
959 auto& f
= *fifos
[i
% fifos
.size()];
960 auto c
= R::Rados::aio_create_completion();
962 c
->wait_for_complete();
963 r
= c
->get_return_value();
968 /* list all by both */
969 std::vector
<RCf::list_entry
> result
;
971 auto c
= R::Rados::aio_create_completion();
972 f2
->list(max_entries
, std::nullopt
, &result
, &more
, c
);
973 c
->wait_for_complete();
974 r
= c
->get_return_value();
977 ASSERT_EQ(false, more
);
978 ASSERT_EQ(max_entries
, result
.size());
980 c
= R::Rados::aio_create_completion();
981 f2
->list(max_entries
, std::nullopt
, &result
, &more
, c
);
982 c
->wait_for_complete();
983 r
= c
->get_return_value();
986 ASSERT_EQ(false, more
);
987 ASSERT_EQ(max_entries
, result
.size());
989 for (auto i
= 0u; i
< max_entries
; ++i
) {
990 auto& bl
= result
[i
].data
;
991 ASSERT_EQ(i
, *(int *)bl
.c_str());
995 TEST_F(AioLegacyFIFO
, TestTwoPushersTrim
)
997 static constexpr auto max_part_size
= 2048ull;
998 static constexpr auto max_entry_size
= 128ull;
999 std::unique_ptr
<RCf::FIFO
> f1
;
1000 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f1
, null_yield
, std::nullopt
,
1001 std::nullopt
, false, max_part_size
,
1005 char buf
[max_entry_size
];
1006 memset(buf
, 0, sizeof(buf
));
1008 auto [part_header_size
, part_entry_overhead
] = f1
->get_part_layout_info();
1009 const auto entries_per_part
= ((max_part_size
- part_header_size
) /
1010 (max_entry_size
+ part_entry_overhead
));
1011 const auto max_entries
= entries_per_part
* 4 + 1;
1013 std::unique_ptr
<RCf::FIFO
> f2
;
1014 r
= RCf::FIFO::open(ioctx
, fifo_id
, &f2
, null_yield
);
1017 /* push one entry to f2 and the rest to f1 */
1018 for (auto i
= 0u; i
< max_entries
; ++i
) {
1021 bl
.append(buf
, sizeof(buf
));
1022 auto& f
= (i
< 1 ? f2
: f1
);
1023 auto c
= R::Rados::aio_create_completion();
1025 c
->wait_for_complete();
1026 r
= c
->get_return_value();
1031 /* trim half by fifo1 */
1032 auto num
= max_entries
/ 2;
1034 std::vector
<RCf::list_entry
> result
;
1036 auto c
= R::Rados::aio_create_completion();
1037 f1
->list(num
, std::nullopt
, &result
, &more
, c
);
1038 c
->wait_for_complete();
1039 r
= c
->get_return_value();
1042 ASSERT_EQ(true, more
);
1043 ASSERT_EQ(num
, result
.size());
1045 for (auto i
= 0u; i
< num
; ++i
) {
1046 auto& bl
= result
[i
].data
;
1047 ASSERT_EQ(i
, *(int *)bl
.c_str());
1050 auto& entry
= result
[num
- 1];
1051 marker
= entry
.marker
;
1052 c
= R::Rados::aio_create_completion();
1053 f1
->trim(marker
, false, c
);
1054 c
->wait_for_complete();
1055 r
= c
->get_return_value();
1058 /* list what's left by fifo2 */
1060 const auto left
= max_entries
- num
;
1061 c
= R::Rados::aio_create_completion();
1062 f2
->list(left
, marker
, &result
, &more
, c
);
1063 c
->wait_for_complete();
1064 r
= c
->get_return_value();
1067 ASSERT_EQ(left
, result
.size());
1068 ASSERT_EQ(false, more
);
1070 for (auto i
= num
; i
< max_entries
; ++i
) {
1071 auto& bl
= result
[i
- num
].data
;
1072 ASSERT_EQ(i
, *(int *)bl
.c_str());
1076 TEST_F(AioLegacyFIFO
, TestPushBatch
)
1078 static constexpr auto max_part_size
= 2048ull;
1079 static constexpr auto max_entry_size
= 128ull;
1081 std::unique_ptr
<RCf::FIFO
> f
;
1082 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
, std::nullopt
,
1083 std::nullopt
, false, max_part_size
,
1087 char buf
[max_entry_size
];
1088 memset(buf
, 0, sizeof(buf
));
1089 auto [part_header_size
, part_entry_overhead
] = f
->get_part_layout_info();
1090 auto entries_per_part
= ((max_part_size
- part_header_size
) /
1091 (max_entry_size
+ part_entry_overhead
));
1092 auto max_entries
= entries_per_part
* 4 + 1; /* enough entries to span multiple parts */
1093 std::vector
<cb::list
> bufs
;
1094 for (auto i
= 0u; i
< max_entries
; ++i
) {
1097 bl
.append(buf
, sizeof(buf
));
1100 ASSERT_EQ(max_entries
, bufs
.size());
1102 auto c
= R::Rados::aio_create_completion();
1104 c
->wait_for_complete();
1105 r
= c
->get_return_value();
1111 std::vector
<RCf::list_entry
> result
;
1113 c
= R::Rados::aio_create_completion();
1114 f
->list(max_entries
, std::nullopt
, &result
, &more
, c
);
1115 c
->wait_for_complete();
1116 r
= c
->get_return_value();
1119 ASSERT_EQ(false, more
);
1120 ASSERT_EQ(max_entries
, result
.size());
1121 for (auto i
= 0u; i
< max_entries
; ++i
) {
1122 auto& bl
= result
[i
].data
;
1123 ASSERT_EQ(i
, *(int *)bl
.c_str());
1125 auto& info
= f
->meta();
1126 ASSERT_EQ(info
.head_part_num
, 4);
1129 TEST_F(LegacyFIFO
, TrimAll
)
1131 std::unique_ptr
<RCf::FIFO
> f
;
1132 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
);
1134 static constexpr auto max_entries
= 10u;
1135 for (uint32_t i
= 0; i
< max_entries
; ++i
) {
1138 r
= f
->push(bl
, null_yield
);
1142 /* trim one entry */
1143 r
= f
->trim(RCf::marker::max().to_string(), false, null_yield
);
1144 ASSERT_EQ(-ENODATA
, r
);
1146 std::vector
<RCf::list_entry
> result
;
1148 r
= f
->list(1, std::nullopt
, &result
, &more
, null_yield
);
1150 ASSERT_TRUE(result
.empty());
1153 TEST_F(LegacyFIFO
, AioTrimAll
)
1155 std::unique_ptr
<RCf::FIFO
> f
;
1156 auto r
= RCf::FIFO::create(ioctx
, fifo_id
, &f
, null_yield
);
1158 static constexpr auto max_entries
= 10u;
1159 for (uint32_t i
= 0; i
< max_entries
; ++i
) {
1162 r
= f
->push(bl
, null_yield
);
1166 auto c
= R::Rados::aio_create_completion();
1167 f
->trim(RCf::marker::max().to_string(), false, c
);
1168 c
->wait_for_complete();
1169 r
= c
->get_return_value();
1171 ASSERT_EQ(-ENODATA
, r
);
1173 std::vector
<RCf::list_entry
> result
;
1175 r
= f
->list(1, std::nullopt
, &result
, &more
, null_yield
);
1177 ASSERT_TRUE(result
.empty());