]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/crimson/seastore/test_seastore_journal.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / crimson / seastore / test_seastore_journal.cc
CommitLineData
f67539c2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "test/crimson/gtest_seastar.h"
5
6#include <random>
7
8#include "crimson/common/log.h"
1e59de90 9#include "crimson/os/seastore/async_cleaner.h"
f67539c2
TL
10#include "crimson/os/seastore/journal.h"
11#include "crimson/os/seastore/segment_manager/ephemeral.h"
12
13using namespace crimson;
14using namespace crimson::os;
15using namespace crimson::os::seastore;
16
17namespace {
18 [[maybe_unused]] seastar::logger& logger() {
19 return crimson::get_logger(ceph_subsys_test);
20 }
21}
22
23struct record_validator_t {
24 record_t record;
25 paddr_t record_final_offset;
26
27 template <typename... T>
28 record_validator_t(T&&... record) : record(std::forward<T>(record)...) {}
29
30 void validate(SegmentManager &manager) {
31 paddr_t addr = make_record_relative_paddr(0);
32 for (auto &&block : record.extents) {
33 auto test = manager.read(
34 record_final_offset.add_relative(addr),
35 block.bl.length()).unsafe_get0();
1e59de90 36 addr = addr.add_offset(block.bl.length());
f67539c2
TL
37 bufferlist bl;
38 bl.push_back(test);
39 ASSERT_EQ(
40 bl.length(),
41 block.bl.length());
42 ASSERT_EQ(
43 bl.begin().crc32c(bl.length(), 1),
44 block.bl.begin().crc32c(block.bl.length(), 1));
45 }
46 }
47
48 auto get_replay_handler() {
49 auto checker = [this, iter=record.deltas.begin()] (
50 paddr_t base,
51 const delta_info_t &di) mutable {
52 EXPECT_EQ(base, record_final_offset);
53 ceph_assert(iter != record.deltas.end());
54 EXPECT_EQ(di, *iter++);
55 EXPECT_EQ(base, record_final_offset);
56 return iter != record.deltas.end();
57 };
58 if (record.deltas.size()) {
59 return std::make_optional(std::move(checker));
60 } else {
61 return std::optional<decltype(checker)>();
62 }
63 }
64};
65
1e59de90 66struct journal_test_t : seastar_test_suite_t, SegmentProvider, JournalTrimmer {
f67539c2 67 segment_manager::EphemeralSegmentManagerRef segment_manager;
20effc67 68 WritePipeline pipeline;
1e59de90 69 JournalRef journal;
f67539c2
TL
70
71 std::vector<record_validator_t> records;
72
73 std::default_random_engine generator;
74
1e59de90 75 extent_len_t block_size;
f67539c2 76
1e59de90 77 SegmentManagerGroupRef sms;
20effc67
TL
78
79 segment_id_t next;
80
1e59de90
TL
81 std::map<segment_id_t, segment_seq_t> segment_seqs;
82 std::map<segment_id_t, segment_type_t> segment_types;
83
84 journal_seq_t dummy_tail;
85
86 mutable segment_info_t tmp_info;
87
20effc67
TL
88 journal_test_t() = default;
89
1e59de90
TL
90 /*
91 * JournalTrimmer interfaces
92 */
93 journal_seq_t get_journal_head() const final { return dummy_tail; }
94
95 void set_journal_head(journal_seq_t) final {}
96
97 journal_seq_t get_dirty_tail() const final { return dummy_tail; }
f67539c2 98
1e59de90
TL
99 journal_seq_t get_alloc_tail() const final { return dummy_tail; }
100
101 void update_journal_tails(journal_seq_t, journal_seq_t) final {}
102
103 bool try_reserve_inline_usage(std::size_t) final { return true; }
104
105 void release_inline_usage(std::size_t) final {}
106
107 std::size_t get_trim_size_per_cycle() const final {
108 return 0;
109 }
110
111 /*
112 * SegmentProvider interfaces
113 */
114 const segment_info_t& get_seg_info(segment_id_t id) const final {
115 tmp_info = {};
116 tmp_info.seq = segment_seqs.at(id);
117 tmp_info.type = segment_types.at(id);
118 return tmp_info;
119 }
120
121 segment_id_t allocate_segment(
122 segment_seq_t seq,
123 segment_type_t type,
124 data_category_t,
125 rewrite_gen_t
126 ) final {
20effc67
TL
127 auto ret = next;
128 next = segment_id_t{
1e59de90 129 segment_manager->get_device_id(),
20effc67 130 next.device_segment_id() + 1};
1e59de90
TL
131 segment_seqs[ret] = seq;
132 segment_types[ret] = type;
133 return ret;
f67539c2
TL
134 }
135
1e59de90
TL
136 void close_segment(segment_id_t) final {}
137
138 void update_segment_avail_bytes(segment_type_t, paddr_t) final {}
139
140 void update_modify_time(segment_id_t, sea_time_point, std::size_t) final {}
141
142 SegmentManagerGroup* get_segment_manager_group() final { return sms.get(); }
f67539c2
TL
143
144 seastar::future<> set_up_fut() final {
20effc67 145 segment_manager = segment_manager::create_test_ephemeral();
f67539c2
TL
146 return segment_manager->init(
147 ).safe_then([this] {
1e59de90
TL
148 return segment_manager->mkfs(
149 segment_manager::get_ephemeral_device_config(0, 1, 0));
150 }).safe_then([this] {
151 block_size = segment_manager->get_block_size();
152 sms.reset(new SegmentManagerGroup());
153 next = segment_id_t(segment_manager->get_device_id(), 0);
154 journal = journal::make_segmented(*this, *this);
155 journal->set_write_pipeline(&pipeline);
156 sms->add_segment_manager(segment_manager.get());
157 return journal->open_for_mkfs();
158 }).safe_then([this](auto) {
159 dummy_tail = journal_seq_t{0,
160 paddr_t::make_seg_paddr(segment_id_t(segment_manager->get_device_id(), 0), 0)};
161 }, crimson::ct_error::all_same_way([] {
162 ASSERT_FALSE("Unable to mount");
163 }));
f67539c2
TL
164 }
165
20effc67
TL
166 seastar::future<> tear_down_fut() final {
167 return journal->close(
168 ).safe_then([this] {
169 segment_manager.reset();
1e59de90 170 sms.reset();
20effc67
TL
171 journal.reset();
172 }).handle_error(
173 crimson::ct_error::all_same_way([](auto e) {
174 ASSERT_FALSE("Unable to close");
175 })
176 );
177 }
178
f67539c2
TL
179 template <typename T>
180 auto replay(T &&f) {
181 return journal->close(
182 ).safe_then([this, f=std::move(f)]() mutable {
1e59de90 183 journal = journal::make_segmented(*this, *this);
20effc67 184 journal->set_write_pipeline(&pipeline);
1e59de90
TL
185 return journal->replay(std::forward<T>(std::move(f)));
186 }).safe_then([this] {
187 return journal->open_for_mount();
f67539c2
TL
188 });
189 }
190
191 auto replay_and_check() {
192 auto record_iter = records.begin();
193 decltype(record_iter->get_replay_handler()) delta_checker = std::nullopt;
194 auto advance = [this, &record_iter, &delta_checker] {
195 ceph_assert(!delta_checker);
196 while (record_iter != records.end()) {
197 auto checker = record_iter->get_replay_handler();
198 record_iter++;
199 if (checker) {
200 delta_checker.emplace(std::move(*checker));
201 break;
202 }
203 }
204 };
205 advance();
206 replay(
207 [&advance,
208 &delta_checker]
1e59de90
TL
209 (const auto &offsets,
210 const auto &di,
211 const journal_seq_t &,
212 const journal_seq_t &,
213 auto t) mutable {
f67539c2
TL
214 if (!delta_checker) {
215 EXPECT_FALSE("No Deltas Left");
216 }
20effc67 217 if (!(*delta_checker)(offsets.record_block_base, di)) {
f67539c2
TL
218 delta_checker = std::nullopt;
219 advance();
220 }
1e59de90 221 return Journal::replay_ertr::make_ready_future<bool>(true);
f67539c2
TL
222 }).unsafe_get0();
223 ASSERT_EQ(record_iter, records.end());
224 for (auto &i : records) {
225 i.validate(*segment_manager);
226 }
227 }
228
229 template <typename... T>
230 auto submit_record(T&&... _record) {
231 auto record{std::forward<T>(_record)...};
232 records.push_back(record);
20effc67
TL
233 OrderingHandle handle = get_dummy_ordering_handle();
234 auto [addr, _] = journal->submit_record(
235 std::move(record),
236 handle).unsafe_get0();
f67539c2
TL
237 records.back().record_final_offset = addr;
238 return addr;
239 }
240
f67539c2
TL
241 extent_t generate_extent(size_t blocks) {
242 std::uniform_int_distribution<char> distribution(
243 std::numeric_limits<char>::min(),
244 std::numeric_limits<char>::max()
245 );
246 char contents = distribution(generator);
247 bufferlist bl;
248 bl.append(buffer::ptr(buffer::create(blocks * block_size, contents)));
1e59de90
TL
249 return extent_t{
250 extent_types_t::TEST_BLOCK,
251 L_ADDR_NULL,
252 bl};
f67539c2
TL
253 }
254
255 delta_info_t generate_delta(size_t bytes) {
256 std::uniform_int_distribution<char> distribution(
257 std::numeric_limits<char>::min(),
258 std::numeric_limits<char>::max()
259 );
260 char contents = distribution(generator);
261 bufferlist bl;
262 bl.append(buffer::ptr(buffer::create(bytes, contents)));
263 return delta_info_t{
264 extent_types_t::TEST_BLOCK,
265 paddr_t{},
266 L_ADDR_NULL,
267 0, 0,
268 block_size,
269 1,
1e59de90
TL
270 MAX_SEG_SEQ,
271 segment_type_t::NULL_SEG,
f67539c2
TL
272 bl
273 };
274 }
275};
276
277TEST_F(journal_test_t, replay_one_journal_segment)
278{
279 run_async([this] {
280 submit_record(record_t{
281 { generate_extent(1), generate_extent(2) },
282 { generate_delta(23), generate_delta(30) }
283 });
284 replay_and_check();
285 });
286}
287
288TEST_F(journal_test_t, replay_two_records)
289{
290 run_async([this] {
291 submit_record(record_t{
292 { generate_extent(1), generate_extent(2) },
293 { generate_delta(23), generate_delta(30) }
294 });
295 submit_record(record_t{
296 { generate_extent(4), generate_extent(1) },
297 { generate_delta(23), generate_delta(400) }
298 });
299 replay_and_check();
300 });
301}
302
303TEST_F(journal_test_t, replay_twice)
304{
305 run_async([this] {
306 submit_record(record_t{
307 { generate_extent(1), generate_extent(2) },
308 { generate_delta(23), generate_delta(30) }
309 });
310 submit_record(record_t{
311 { generate_extent(4), generate_extent(1) },
312 { generate_delta(23), generate_delta(400) }
313 });
314 replay_and_check();
315 submit_record(record_t{
316 { generate_extent(2), generate_extent(5) },
317 { generate_delta(230), generate_delta(40) }
318 });
319 replay_and_check();
320 });
321}
322
323TEST_F(journal_test_t, roll_journal_and_replay)
324{
325 run_async([this] {
326 paddr_t current = submit_record(
327 record_t{
328 { generate_extent(1), generate_extent(2) },
329 { generate_delta(23), generate_delta(30) }
330 });
20effc67 331 auto starting_segment = current.as_seg_paddr().get_segment_id();
f67539c2 332 unsigned so_far = 0;
20effc67 333 while (current.as_seg_paddr().get_segment_id() == starting_segment) {
f67539c2
TL
334 current = submit_record(record_t{
335 { generate_extent(512), generate_extent(512) },
336 { generate_delta(23), generate_delta(400) }
337 });
338 ++so_far;
339 ASSERT_FALSE(so_far > 10);
340 }
341 replay_and_check();
342 });
343}