]> git.proxmox.com Git - ceph.git/blob - ceph/src/crimson/os/seastore/seastore.cc
import ceph quincy 17.2.4
[ceph.git] / ceph / src / crimson / os / seastore / seastore.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "seastore.h"
5
6 #include <algorithm>
7
8 #include <boost/algorithm/string/trim.hpp>
9 #include <fmt/format.h>
10 #include <fmt/ostream.h>
11
12 #include <seastar/core/file.hh>
13 #include <seastar/core/fstream.hh>
14 #include <seastar/core/shared_mutex.hh>
15
16 #include "common/safe_io.h"
17 #include "include/stringify.h"
18 #include "os/Transaction.h"
19
20 #include "crimson/common/buffer_io.h"
21
22 #include "crimson/os/futurized_collection.h"
23
24 #include "crimson/os/seastore/segment_cleaner.h"
25 #include "crimson/os/seastore/segment_manager.h"
26 #include "crimson/os/seastore/segment_manager/block.h"
27 #include "crimson/os/seastore/collection_manager/flat_collection_manager.h"
28 #include "crimson/os/seastore/onode_manager/staged-fltree/fltree_onode_manager.h"
29 #include "crimson/os/seastore/omap_manager/btree/btree_omap_manager.h"
30 #include "crimson/os/seastore/segment_manager/ephemeral.h"
31 #include "crimson/os/seastore/onode_manager.h"
32 #include "crimson/os/seastore/object_data_handler.h"
33
34
35 using std::string;
36 using crimson::common::local_conf;
37
38 template <> struct fmt::formatter<crimson::os::seastore::SeaStore::op_type_t>
39 : fmt::formatter<std::string_view> {
40 using op_type_t = crimson::os::seastore::SeaStore::op_type_t;
41 // parse is inherited from formatter<string_view>.
42 template <typename FormatContext>
43 auto format(op_type_t op, FormatContext& ctx) {
44 std::string_view name = "unknown";
45 switch (op) {
46 case op_type_t::TRANSACTION:
47 name = "transaction";
48 break;
49 case op_type_t::READ:
50 name = "read";
51 break;
52 case op_type_t::WRITE:
53 name = "write";
54 break;
55 case op_type_t::GET_ATTR:
56 name = "get_attr";
57 break;
58 case op_type_t::GET_ATTRS:
59 name = "get_attrs";
60 break;
61 case op_type_t::STAT:
62 name = "stat";
63 break;
64 case op_type_t::OMAP_GET_VALUES:
65 name = "omap_get_values";
66 break;
67 case op_type_t::OMAP_LIST:
68 name = "omap_list";
69 break;
70 case op_type_t::MAX:
71 name = "unknown";
72 break;
73 }
74 return formatter<string_view>::format(name, ctx);
75 }
76 };
77
78 SET_SUBSYS(seastore);
79
80 namespace crimson::os::seastore {
81
82 class FileMDStore final : public SeaStore::MDStore {
83 std::string root;
84 public:
85 FileMDStore(const std::string& root) : root(root) {}
86
87 write_meta_ret write_meta(
88 const std::string& key, const std::string& value) final {
89 std::string path = fmt::format("{}/{}", root, key);
90 ceph::bufferlist bl;
91 bl.append(value + "\n");
92 return crimson::write_file(std::move(bl), path);
93 }
94
95 read_meta_ret read_meta(const std::string& key) final {
96 std::string path = fmt::format("{}/{}", root, key);
97 return seastar::file_exists(
98 path
99 ).then([path] (bool exist) {
100 if (exist) {
101 return crimson::read_file(path)
102 .then([] (auto tmp_buf) {
103 std::string v = {tmp_buf.get(), tmp_buf.size()};
104 std::size_t pos = v.find("\n");
105 std::string str = v.substr(0, pos);
106 return seastar::make_ready_future<std::optional<std::string>>(str);
107 });
108 } else {
109 return seastar::make_ready_future<std::optional<std::string>>(std::nullopt);
110 }
111 });
112 }
113 };
114
115 using crimson::common::get_conf;
116
117 SeaStore::SeaStore(
118 const std::string& root,
119 MDStoreRef mdstore,
120 SegmentManagerRef sm,
121 TransactionManagerRef tm,
122 CollectionManagerRef cm,
123 OnodeManagerRef om)
124 : root(root),
125 mdstore(std::move(mdstore)),
126 segment_manager(std::move(sm)),
127 transaction_manager(std::move(tm)),
128 collection_manager(std::move(cm)),
129 onode_manager(std::move(om)),
130 max_object_size(
131 get_conf<uint64_t>("seastore_default_max_object_size"))
132 {
133 register_metrics();
134 }
135
136 SeaStore::SeaStore(
137 const std::string& root,
138 SegmentManagerRef sm,
139 TransactionManagerRef tm,
140 CollectionManagerRef cm,
141 OnodeManagerRef om)
142 : SeaStore(
143 root,
144 std::make_unique<FileMDStore>(root),
145 std::move(sm), std::move(tm), std::move(cm), std::move(om)) {}
146
147 SeaStore::~SeaStore() = default;
148
149 void SeaStore::register_metrics()
150 {
151 namespace sm = seastar::metrics;
152 using op_type_t = SeaStore::op_type_t;
153 auto lat_label = sm::label("latency");
154 std::pair<op_type_t, sm::label_instance> labels_by_op_type[] = {
155 {op_type_t::TRANSACTION, lat_label("TRANSACTION")},
156 {op_type_t::READ, lat_label("READ")},
157 {op_type_t::WRITE, lat_label("WRITE")},
158 {op_type_t::GET_ATTR, lat_label("GET_ATTR")},
159 {op_type_t::GET_ATTRS, lat_label("GET_ATTRS")},
160 {op_type_t::STAT, lat_label("STAT")},
161 {op_type_t::OMAP_GET_VALUES, lat_label("OMAP_GET_VALUES")},
162 {op_type_t::OMAP_LIST, lat_label("OMAP_LIST")},
163 };
164
165 for (auto& [op_type, label] : labels_by_op_type) {
166 auto desc = fmt::format("latency of seastore operation (optype={})",
167 op_type);
168 metrics.add_group(
169 "seastore",
170 {
171 sm::make_histogram(
172 "op_lat", [this, op_type=op_type] {
173 return get_latency(op_type);
174 },
175 sm::description(desc),
176 {label}
177 ),
178 }
179 );
180 }
181 }
182
183 seastar::future<> SeaStore::stop()
184 {
185 return seastar::now();
186 }
187
188 SeaStore::mount_ertr::future<> SeaStore::mount()
189 {
190 return segment_manager->mount(
191 ).safe_then([this] {
192 transaction_manager->add_segment_manager(segment_manager.get());
193 auto sec_devices = segment_manager->get_secondary_devices();
194 return crimson::do_for_each(sec_devices, [this](auto& device_entry) {
195 device_id_t id = device_entry.first;
196 magic_t magic = device_entry.second.magic;
197 device_type_t dtype = device_entry.second.dtype;
198 std::ostringstream oss;
199 oss << root << "/block." << dtype << "." << std::to_string(id);
200 auto sm = std::make_unique<
201 segment_manager::block::BlockSegmentManager>(oss.str());
202 return sm->mount().safe_then([this, sm=std::move(sm), magic]() mutable {
203 assert(sm->get_magic() == magic);
204 transaction_manager->add_segment_manager(sm.get());
205 secondaries.emplace_back(std::move(sm));
206 return seastar::now();
207 });
208 });
209 }).safe_then([this] {
210 return transaction_manager->mount();
211 }).handle_error(
212 crimson::ct_error::assert_all{
213 "Invalid error in SeaStore::mount"
214 }
215 );
216 }
217
218 seastar::future<> SeaStore::umount()
219 {
220 return transaction_manager->close(
221 ).safe_then([this] {
222 return crimson::do_for_each(
223 secondaries,
224 [](auto& sm) -> SegmentManager::close_ertr::future<> {
225 return sm->close();
226 });
227 }).safe_then([this] {
228 return segment_manager->close();
229 }).handle_error(
230 crimson::ct_error::assert_all{
231 "Invalid error in SeaStore::umount"
232 }
233 );
234 }
235
236 seastar::future<> SeaStore::write_fsid(uuid_d new_osd_fsid)
237 {
238 LOG_PREFIX(SeaStore::write_fsid);
239 return read_meta("fsid").then([this, FNAME, new_osd_fsid] (auto tuple) {
240 auto [ret, fsid] = tuple;
241 std::string str_fsid = stringify(new_osd_fsid);
242 if (ret == -1) {
243 return write_meta("fsid", stringify(new_osd_fsid));
244 } else if (ret == 0 && fsid != str_fsid) {
245 ERROR("on-disk fsid {} != provided {}",
246 fsid, stringify(new_osd_fsid));
247 throw std::runtime_error("store fsid error");
248 } else {
249 return seastar::now();
250 }
251 });
252 }
253
254 SeaStore::mkfs_ertr::future<> SeaStore::mkfs(uuid_d new_osd_fsid)
255 {
256 return read_meta("mkfs_done").then([this, new_osd_fsid] (auto tuple) {
257 auto [done, value] = tuple;
258 if (done == 0) {
259 return seastar::now();
260 } else {
261 return seastar::do_with(
262 secondary_device_set_t(),
263 [this, new_osd_fsid](auto& sds) {
264 auto fut = seastar::now();
265 LOG_PREFIX(SeaStore::mkfs);
266 DEBUG("root: {}", root);
267 if (!root.empty()) {
268 fut = seastar::open_directory(root).then(
269 [this, &sds, new_osd_fsid](seastar::file rdir) mutable {
270 std::unique_ptr<seastar::file> root_f =
271 std::make_unique<seastar::file>(std::move(rdir));
272 auto sub = root_f->list_directory(
273 [this, &sds, new_osd_fsid](auto de) mutable
274 -> seastar::future<> {
275 LOG_PREFIX(SeaStore::mkfs);
276 DEBUG("found file: {}", de.name);
277 if (de.name.find("block.") == 0
278 && de.name.length() > 6 /* 6 for "block." */) {
279 std::string entry_name = de.name;
280 auto dtype_end = entry_name.find_first_of('.', 6);
281 device_type_t dtype =
282 string_to_device_type(
283 entry_name.substr(6, dtype_end - 6));
284 if (dtype == device_type_t::NONE) {
285 // invalid device type
286 return seastar::now();
287 }
288 auto id = std::stoi(entry_name.substr(dtype_end + 1));
289 auto sm = std::make_unique<
290 segment_manager::block::BlockSegmentManager
291 >(root + "/" + entry_name);
292 magic_t magic = (magic_t)std::rand();
293 sds.emplace(
294 (device_id_t)id,
295 device_spec_t{
296 magic,
297 dtype,
298 (device_id_t)id});
299 return sm->mkfs(
300 segment_manager_config_t{
301 false,
302 magic,
303 dtype,
304 (device_id_t)id,
305 seastore_meta_t{new_osd_fsid},
306 secondary_device_set_t()}
307 ).safe_then([this, sm=std::move(sm), id]() mutable {
308 LOG_PREFIX(SeaStore::mkfs);
309 DEBUG("mkfs: finished for segment manager {}", id);
310 secondaries.emplace_back(std::move(sm));
311 return seastar::now();
312 }).handle_error(crimson::ct_error::assert_all{"not possible"});
313 }
314 return seastar::now();
315 });
316 return sub.done().then(
317 [root_f=std::move(root_f)] {
318 return seastar::now();
319 });
320 });
321 }
322 return fut.then([this, &sds, new_osd_fsid] {
323 return segment_manager->mkfs(
324 segment_manager_config_t{
325 true,
326 (magic_t)std::rand(),
327 device_type_t::SEGMENTED,
328 0,
329 seastore_meta_t{new_osd_fsid},
330 sds}
331 );
332 }).safe_then([this] {
333 return crimson::do_for_each(secondaries, [this](auto& sec_sm) {
334 return sec_sm->mount().safe_then([this, &sec_sm] {
335 transaction_manager->add_segment_manager(sec_sm.get());
336 return seastar::now();
337 });
338 });
339 });
340 }).safe_then([this] {
341 return segment_manager->mount();
342 }).safe_then([this] {
343 transaction_manager->add_segment_manager(segment_manager.get());
344 return transaction_manager->mkfs();
345 }).safe_then([this] {
346 return transaction_manager->mount();
347 }).safe_then([this] {
348 return repeat_eagain([this] {
349 return transaction_manager->with_transaction_intr(
350 Transaction::src_t::MUTATE,
351 "mkfs_seastore",
352 [this](auto& t)
353 {
354 return onode_manager->mkfs(t
355 ).si_then([this, &t] {
356 return collection_manager->mkfs(t);
357 }).si_then([this, &t](auto coll_root) {
358 transaction_manager->write_collection_root(
359 t, coll_root);
360 return transaction_manager->submit_transaction(t);
361 });
362 });
363 });
364 }).safe_then([this, new_osd_fsid] {
365 return write_fsid(new_osd_fsid);
366 }).safe_then([this] {
367 return read_meta("type").then([this] (auto tuple) {
368 auto [ret, type] = tuple;
369 if (ret == 0 && type == "seastore") {
370 return seastar::now();
371 } else if (ret == 0 && type != "seastore") {
372 LOG_PREFIX(SeaStore::mkfs);
373 ERROR("expected seastore, but type is {}", type);
374 throw std::runtime_error("store type error");
375 } else {
376 return write_meta("type", "seastore");
377 }
378 });
379 }).safe_then([this] {
380 return write_meta("mkfs_done", "yes");
381 }).safe_then([this] {
382 return umount();
383 }).handle_error(
384 crimson::ct_error::assert_all{
385 "Invalid error in SeaStore::mkfs"
386 }
387 );
388 }
389 });
390 }
391
392 seastar::future<store_statfs_t> SeaStore::stat() const
393 {
394 LOG_PREFIX(SeaStore::stat);
395 DEBUG("");
396 return seastar::make_ready_future<store_statfs_t>(
397 transaction_manager->store_stat()
398 );
399 }
400
401 seastar::future<std::tuple<std::vector<ghobject_t>, ghobject_t>>
402 SeaStore::list_objects(CollectionRef ch,
403 const ghobject_t& start,
404 const ghobject_t& end,
405 uint64_t limit) const
406 {
407 using RetType = typename OnodeManager::list_onodes_bare_ret;
408 return seastar::do_with(
409 RetType(),
410 [this, start, end, limit] (auto& ret) {
411 return repeat_eagain([this, start, end, limit, &ret] {
412 return transaction_manager->with_transaction_intr(
413 Transaction::src_t::READ,
414 "list_objects",
415 [this, start, end, limit](auto &t)
416 {
417 return onode_manager->list_onodes(t, start, end, limit);
418 }).safe_then([&ret](auto&& _ret) {
419 ret = std::move(_ret);
420 });
421 }).safe_then([&ret] {
422 return std::move(ret);
423 }).handle_error(
424 crimson::ct_error::assert_all{
425 "Invalid error in SeaStore::list_objects"
426 }
427 );
428 });
429 }
430
431 seastar::future<CollectionRef> SeaStore::create_new_collection(const coll_t& cid)
432 {
433 LOG_PREFIX(SeaStore::create_new_collection);
434 DEBUG("{}", cid);
435 return seastar::make_ready_future<CollectionRef>(_get_collection(cid));
436 }
437
438 seastar::future<CollectionRef> SeaStore::open_collection(const coll_t& cid)
439 {
440 LOG_PREFIX(SeaStore::open_collection);
441 DEBUG("{}", cid);
442 return list_collections().then([cid, this] (auto colls) {
443 if (auto found = std::find(colls.begin(), colls.end(), cid);
444 found != colls.end()) {
445 return seastar::make_ready_future<CollectionRef>(_get_collection(cid));
446 } else {
447 return seastar::make_ready_future<CollectionRef>();
448 }
449 });
450 }
451
452 seastar::future<std::vector<coll_t>> SeaStore::list_collections()
453 {
454 return seastar::do_with(
455 std::vector<coll_t>(),
456 [this](auto &ret) {
457 return repeat_eagain([this, &ret] {
458 return transaction_manager->with_transaction_intr(
459 Transaction::src_t::READ,
460 "list_collections",
461 [this, &ret](auto& t)
462 {
463 return transaction_manager->read_collection_root(t
464 ).si_then([this, &t](auto coll_root) {
465 return collection_manager->list(coll_root, t);
466 }).si_then([&ret](auto colls) {
467 ret.resize(colls.size());
468 std::transform(
469 colls.begin(), colls.end(), ret.begin(),
470 [](auto p) { return p.first; });
471 });
472 });
473 }).safe_then([&ret] {
474 return seastar::make_ready_future<std::vector<coll_t>>(ret);
475 });
476 }
477 ).handle_error(
478 crimson::ct_error::assert_all{
479 "Invalid error in SeaStore::list_collections"
480 }
481 );
482 }
483
484 SeaStore::read_errorator::future<ceph::bufferlist> SeaStore::read(
485 CollectionRef ch,
486 const ghobject_t& oid,
487 uint64_t offset,
488 size_t len,
489 uint32_t op_flags)
490 {
491 LOG_PREFIX(SeaStore::read);
492 DEBUG("oid {} offset {} len {}", oid, offset, len);
493 return repeat_with_onode<ceph::bufferlist>(
494 ch,
495 oid,
496 Transaction::src_t::READ,
497 "read_obj",
498 op_type_t::READ,
499 [=](auto &t, auto &onode) -> ObjectDataHandler::read_ret {
500 size_t size = onode.get_layout().size;
501
502 if (offset >= size) {
503 return seastar::make_ready_future<ceph::bufferlist>();
504 }
505
506 size_t corrected_len = (len == 0) ?
507 size - offset :
508 std::min(size - offset, len);
509
510 return ObjectDataHandler(max_object_size).read(
511 ObjectDataHandler::context_t{
512 *transaction_manager,
513 t,
514 onode,
515 },
516 offset,
517 corrected_len);
518 });
519 }
520
521 SeaStore::read_errorator::future<ceph::bufferlist> SeaStore::readv(
522 CollectionRef ch,
523 const ghobject_t& oid,
524 interval_set<uint64_t>& m,
525 uint32_t op_flags)
526 {
527 return read_errorator::make_ready_future<ceph::bufferlist>();
528 }
529
530 using crimson::os::seastore::omap_manager::BtreeOMapManager;
531
532 SeaStore::get_attr_errorator::future<ceph::bufferlist> SeaStore::get_attr(
533 CollectionRef ch,
534 const ghobject_t& oid,
535 std::string_view name) const
536 {
537 auto c = static_cast<SeastoreCollection*>(ch.get());
538 LOG_PREFIX(SeaStore::get_attr);
539 DEBUG("{} {}", c->get_cid(), oid);
540 return repeat_with_onode<ceph::bufferlist>(
541 c,
542 oid,
543 Transaction::src_t::READ,
544 "get_attr",
545 op_type_t::GET_ATTR,
546 [=](auto &t, auto& onode) -> _omap_get_value_ret {
547 auto& layout = onode.get_layout();
548 if (name == OI_ATTR && layout.oi_size) {
549 ceph::bufferlist bl;
550 bl.append(ceph::bufferptr(&layout.oi[0], layout.oi_size));
551 return seastar::make_ready_future<ceph::bufferlist>(std::move(bl));
552 }
553 if (name == SS_ATTR && layout.ss_size) {
554 ceph::bufferlist bl;
555 bl.append(ceph::bufferptr(&layout.ss[0], layout.ss_size));
556 return seastar::make_ready_future<ceph::bufferlist>(std::move(bl));
557 }
558 return _omap_get_value(
559 t,
560 layout.xattr_root.get(onode.get_metadata_hint()),
561 name);
562 }
563 ).handle_error(crimson::ct_error::input_output_error::handle([FNAME] {
564 ERROR("EIO when getting attrs");
565 abort();
566 }), crimson::ct_error::pass_further_all{});
567 }
568
569 SeaStore::get_attrs_ertr::future<SeaStore::attrs_t> SeaStore::get_attrs(
570 CollectionRef ch,
571 const ghobject_t& oid)
572 {
573 LOG_PREFIX(SeaStore::get_attrs);
574 auto c = static_cast<SeastoreCollection*>(ch.get());
575 DEBUG("{} {}", c->get_cid(), oid);
576 return repeat_with_onode<attrs_t>(
577 c,
578 oid,
579 Transaction::src_t::READ,
580 "get_addrs",
581 op_type_t::GET_ATTRS,
582 [=](auto &t, auto& onode) {
583 auto& layout = onode.get_layout();
584 return _omap_list(onode, layout.xattr_root, t, std::nullopt,
585 OMapManager::omap_list_config_t::with_inclusive(false)
586 ).si_then([&layout](auto p) {
587 auto& attrs = std::get<1>(p);
588 ceph::bufferlist bl;
589 if (layout.oi_size) {
590 bl.append(ceph::bufferptr(&layout.oi[0], layout.oi_size));
591 attrs.emplace(OI_ATTR, std::move(bl));
592 }
593 if (layout.ss_size) {
594 bl.clear();
595 bl.append(ceph::bufferptr(&layout.ss[0], layout.ss_size));
596 attrs.emplace(SS_ATTR, std::move(bl));
597 }
598 return seastar::make_ready_future<omap_values_t>(std::move(attrs));
599 });
600 }
601 ).handle_error(crimson::ct_error::input_output_error::handle([FNAME] {
602 ERROR("EIO when getting attrs");
603 abort();
604 }), crimson::ct_error::pass_further_all{});
605 }
606
607 seastar::future<struct stat> SeaStore::stat(
608 CollectionRef c,
609 const ghobject_t& oid)
610 {
611 LOG_PREFIX(SeaStore::stat);
612 return repeat_with_onode<struct stat>(
613 c,
614 oid,
615 Transaction::src_t::READ,
616 "stat",
617 op_type_t::STAT,
618 [=, &oid](auto &t, auto &onode) {
619 struct stat st;
620 auto &olayout = onode.get_layout();
621 st.st_size = olayout.size;
622 st.st_blksize = transaction_manager->get_block_size();
623 st.st_blocks = (st.st_size + st.st_blksize - 1) / st.st_blksize;
624 st.st_nlink = 1;
625 DEBUGT("cid {}, oid {}, return size {}", t, c->get_cid(), oid, st.st_size);
626 return seastar::make_ready_future<struct stat>(st);
627 }
628 ).handle_error(
629 crimson::ct_error::assert_all{
630 "Invalid error in SeaStore::stat"
631 }
632 );
633 }
634
635 auto
636 SeaStore::omap_get_header(
637 CollectionRef c,
638 const ghobject_t& oid)
639 -> read_errorator::future<bufferlist>
640 {
641 return seastar::make_ready_future<bufferlist>();
642 }
643
644 SeaStore::read_errorator::future<SeaStore::omap_values_t>
645 SeaStore::omap_get_values(
646 CollectionRef ch,
647 const ghobject_t &oid,
648 const omap_keys_t &keys)
649 {
650 auto c = static_cast<SeastoreCollection*>(ch.get());
651 return repeat_with_onode<omap_values_t>(
652 c,
653 oid,
654 Transaction::src_t::READ,
655 "omap_get_values",
656 op_type_t::OMAP_GET_VALUES,
657 [this, keys](auto &t, auto &onode) {
658 omap_root_t omap_root = onode.get_layout().omap_root.get(
659 onode.get_metadata_hint());
660 return _omap_get_values(
661 t,
662 std::move(omap_root),
663 keys);
664 });
665 }
666
667 SeaStore::_omap_get_value_ret SeaStore::_omap_get_value(
668 Transaction &t,
669 omap_root_t &&root,
670 std::string_view key) const
671 {
672 return seastar::do_with(
673 BtreeOMapManager(*transaction_manager),
674 std::move(root),
675 std::string(key),
676 [&t](auto &manager, auto& root, auto& key) -> _omap_get_value_ret {
677 if (root.is_null()) {
678 return crimson::ct_error::enodata::make();
679 }
680 return manager.omap_get_value(root, t, key
681 ).si_then([](auto opt) -> _omap_get_value_ret {
682 if (!opt) {
683 return crimson::ct_error::enodata::make();
684 }
685 return seastar::make_ready_future<ceph::bufferlist>(std::move(*opt));
686 });
687 }
688 );
689 }
690
691 SeaStore::_omap_get_values_ret SeaStore::_omap_get_values(
692 Transaction &t,
693 omap_root_t &&omap_root,
694 const omap_keys_t &keys) const
695 {
696 if (omap_root.is_null()) {
697 return seastar::make_ready_future<omap_values_t>();
698 }
699 return seastar::do_with(
700 BtreeOMapManager(*transaction_manager),
701 std::move(omap_root),
702 omap_values_t(),
703 [&](auto &manager, auto &root, auto &ret) {
704 return trans_intr::do_for_each(
705 keys.begin(),
706 keys.end(),
707 [&](auto &key) {
708 return manager.omap_get_value(
709 root,
710 t,
711 key
712 ).si_then([&ret, &key](auto &&p) {
713 if (p) {
714 bufferlist bl;
715 bl.append(*p);
716 ret.emplace(
717 std::move(key),
718 std::move(bl));
719 }
720 return seastar::now();
721 });
722 }
723 ).si_then([&ret] {
724 return std::move(ret);
725 });
726 }
727 );
728 }
729
730 SeaStore::_omap_list_ret SeaStore::_omap_list(
731 Onode &onode,
732 const omap_root_le_t& omap_root,
733 Transaction& t,
734 const std::optional<std::string>& start,
735 OMapManager::omap_list_config_t config) const
736 {
737 auto root = omap_root.get(onode.get_metadata_hint());
738 if (root.is_null()) {
739 return seastar::make_ready_future<_omap_list_bare_ret>(
740 true, omap_values_t{}
741 );
742 }
743 return seastar::do_with(
744 BtreeOMapManager(*transaction_manager),
745 root,
746 start,
747 [&t, config](auto &manager, auto& root, auto& start) {
748 return manager.omap_list(root, t, start, config);
749 });
750 }
751
752 SeaStore::omap_get_values_ret_t SeaStore::omap_list(
753 CollectionRef ch,
754 const ghobject_t &oid,
755 const std::optional<string> &start,
756 OMapManager::omap_list_config_t config)
757 {
758 auto c = static_cast<SeastoreCollection*>(ch.get());
759 LOG_PREFIX(SeaStore::omap_list);
760 DEBUG("{} {}", c->get_cid(), oid);
761 using ret_bare_t = std::tuple<bool, SeaStore::omap_values_t>;
762 return repeat_with_onode<ret_bare_t>(
763 c,
764 oid,
765 Transaction::src_t::READ,
766 "omap_list",
767 op_type_t::OMAP_LIST,
768 [this, config, &start](auto &t, auto &onode) {
769 return _omap_list(
770 onode,
771 onode.get_layout().omap_root,
772 t, start, config
773 );
774 });
775 }
776
777 SeaStore::omap_get_values_ret_t SeaStore::omap_get_values(
778 CollectionRef ch,
779 const ghobject_t &oid,
780 const std::optional<string> &start)
781 {
782 return seastar::do_with(oid, start,
783 [this, ch=std::move(ch)](auto& oid, auto& start) {
784 return omap_list(
785 ch, oid, start,
786 OMapManager::omap_list_config_t::with_inclusive(false));
787 });
788 }
789
790 class SeaStoreOmapIterator : public FuturizedStore::OmapIterator {
791 using omap_values_t = FuturizedStore::omap_values_t;
792
793 SeaStore &seastore;
794 CollectionRef ch;
795 const ghobject_t oid;
796
797 omap_values_t current;
798 omap_values_t::iterator iter;
799
800 seastar::future<> repopulate_from(
801 std::optional<std::string> from,
802 bool inclusive) {
803 return seastar::do_with(
804 from,
805 [this, inclusive](auto &from) {
806 return seastore.omap_list(
807 ch,
808 oid,
809 from,
810 OMapManager::omap_list_config_t::with_inclusive(inclusive)
811 ).safe_then([this](auto p) {
812 auto &[complete, values] = p;
813 current.swap(values);
814 if (current.empty()) {
815 assert(complete);
816 }
817 iter = current.begin();
818 });
819 }).handle_error(
820 crimson::ct_error::assert_all{
821 "Invalid error in SeaStoreOmapIterator::repopulate_from"
822 }
823 );
824 }
825 public:
826 SeaStoreOmapIterator(
827 SeaStore &seastore,
828 CollectionRef ch,
829 const ghobject_t &oid) :
830 seastore(seastore),
831 ch(ch),
832 oid(oid),
833 iter(current.begin())
834 {}
835
836 seastar::future<> seek_to_first() final {
837 return repopulate_from(
838 std::nullopt,
839 false);
840 }
841 seastar::future<> upper_bound(const std::string &after) final {
842 return repopulate_from(
843 after,
844 false);
845 }
846 seastar::future<> lower_bound(const std::string &from) final {
847 return repopulate_from(
848 from,
849 true);
850 }
851 bool valid() const {
852 return iter != current.end();
853 }
854 seastar::future<> next() final {
855 assert(valid());
856 auto prev = iter++;
857 if (iter == current.end()) {
858 return repopulate_from(
859 prev->first,
860 false);
861 } else {
862 return seastar::now();
863 }
864 }
865 std::string key() {
866 return iter->first;
867 }
868 ceph::buffer::list value() {
869 return iter->second;
870 }
871 int status() const {
872 return 0;
873 }
874 ~SeaStoreOmapIterator() {}
875 };
876
877 seastar::future<FuturizedStore::OmapIteratorRef> SeaStore::get_omap_iterator(
878 CollectionRef ch,
879 const ghobject_t& oid)
880 {
881 LOG_PREFIX(SeaStore::get_omap_iterator);
882 DEBUG("oid: {}", oid);
883 auto ret = FuturizedStore::OmapIteratorRef(
884 new SeaStoreOmapIterator(
885 *this,
886 ch,
887 oid));
888 return ret->seek_to_first(
889 ).then([ret]() mutable {
890 return std::move(ret);
891 });
892 }
893
894 seastar::future<std::map<uint64_t, uint64_t>> SeaStore::fiemap(
895 CollectionRef ch,
896 const ghobject_t& oid,
897 uint64_t off,
898 uint64_t len)
899 {
900 return seastar::make_ready_future<std::map<uint64_t, uint64_t>>();
901 }
902
903 void SeaStore::on_error(ceph::os::Transaction &t) {
904 LOG_PREFIX(SeaStore::on_error);
905 ERROR(" transaction dump:\n");
906 JSONFormatter f(true);
907 f.open_object_section("transaction");
908 t.dump(&f);
909 f.close_section();
910 std::stringstream str;
911 f.flush(str);
912 ERROR("{}", str.str());
913 abort();
914 }
915
916 seastar::future<> SeaStore::do_transaction(
917 CollectionRef _ch,
918 ceph::os::Transaction&& _t)
919 {
920 // repeat_with_internal_context ensures ordering via collection lock
921 return repeat_with_internal_context(
922 _ch,
923 std::move(_t),
924 Transaction::src_t::MUTATE,
925 "do_transaction",
926 op_type_t::TRANSACTION,
927 [this](auto &ctx) {
928 return with_trans_intr(*ctx.transaction, [&, this](auto &t) {
929 return onode_manager->get_or_create_onodes(
930 *ctx.transaction, ctx.iter.get_objects()
931 ).si_then([this, &ctx](auto &&onodes) {
932 return seastar::do_with(std::move(onodes), [this, &ctx](auto& onodes) {
933 return trans_intr::repeat(
934 [this, &ctx, &onodes]() -> tm_iertr::future<seastar::stop_iteration>
935 {
936 if (ctx.iter.have_op()) {
937 return _do_transaction_step(
938 ctx, ctx.ch, onodes, ctx.iter
939 ).si_then([] {
940 return seastar::make_ready_future<seastar::stop_iteration>(
941 seastar::stop_iteration::no);
942 });
943 } else {
944 return seastar::make_ready_future<seastar::stop_iteration>(
945 seastar::stop_iteration::yes);
946 };
947 }).si_then([this, &ctx, &onodes] {
948 return onode_manager->write_dirty(*ctx.transaction, onodes);
949 });
950 });
951 }).si_then([this, &ctx] {
952 return transaction_manager->submit_transaction(*ctx.transaction);
953 });
954 }).safe_then([&ctx]() {
955 for (auto i : {
956 ctx.ext_transaction.get_on_applied(),
957 ctx.ext_transaction.get_on_commit(),
958 ctx.ext_transaction.get_on_applied_sync()}) {
959 if (i) {
960 i->complete(0);
961 }
962 }
963 return seastar::now();
964 });
965 });
966 }
967
968 SeaStore::tm_ret SeaStore::_do_transaction_step(
969 internal_context_t &ctx,
970 CollectionRef &col,
971 std::vector<OnodeRef> &onodes,
972 ceph::os::Transaction::iterator &i)
973 {
974 LOG_PREFIX(SeaStore::_do_transaction_step);
975 auto get_onode = [&onodes](size_t i) -> OnodeRef& {
976 ceph_assert(i < onodes.size());
977 return onodes[i];
978 };
979
980 using ceph::os::Transaction;
981 try {
982 switch (auto op = i.decode_op(); op->op) {
983 case Transaction::OP_NOP:
984 return tm_iertr::now();
985 case Transaction::OP_REMOVE:
986 {
987 return _remove(ctx, get_onode(op->oid));
988 }
989 break;
990 case Transaction::OP_TOUCH:
991 {
992 return _touch(ctx, get_onode(op->oid));
993 }
994 break;
995 case Transaction::OP_WRITE:
996 {
997 uint64_t off = op->off;
998 uint64_t len = op->len;
999 uint32_t fadvise_flags = i.get_fadvise_flags();
1000 ceph::bufferlist bl;
1001 i.decode_bl(bl);
1002 return _write(
1003 ctx, get_onode(op->oid), off, len, std::move(bl),
1004 fadvise_flags);
1005 }
1006 break;
1007 case Transaction::OP_TRUNCATE:
1008 {
1009 uint64_t off = op->off;
1010 return _truncate(ctx, get_onode(op->oid), off);
1011 }
1012 break;
1013 case Transaction::OP_SETATTR:
1014 {
1015 std::string name = i.decode_string();
1016 std::map<std::string, bufferlist> to_set;
1017 ceph::bufferlist& bl = to_set[name];
1018 i.decode_bl(bl);
1019 return _setattrs(ctx, get_onode(op->oid), std::move(to_set));
1020 }
1021 break;
1022 case Transaction::OP_MKCOLL:
1023 {
1024 coll_t cid = i.get_cid(op->cid);
1025 return _create_collection(ctx, cid, op->split_bits);
1026 }
1027 break;
1028 case Transaction::OP_RMCOLL:
1029 {
1030 coll_t cid = i.get_cid(op->cid);
1031 return _remove_collection(ctx, cid);
1032 }
1033 break;
1034 case Transaction::OP_OMAP_SETKEYS:
1035 {
1036 std::map<std::string, ceph::bufferlist> aset;
1037 i.decode_attrset(aset);
1038 return _omap_set_values(ctx, get_onode(op->oid), std::move(aset));
1039 }
1040 break;
1041 case Transaction::OP_OMAP_SETHEADER:
1042 {
1043 ceph::bufferlist bl;
1044 i.decode_bl(bl);
1045 return _omap_set_header(ctx, get_onode(op->oid), std::move(bl));
1046 }
1047 break;
1048 case Transaction::OP_OMAP_RMKEYS:
1049 {
1050 omap_keys_t keys;
1051 i.decode_keyset(keys);
1052 return _omap_rmkeys(ctx, get_onode(op->oid), std::move(keys));
1053 }
1054 break;
1055 case Transaction::OP_OMAP_RMKEYRANGE:
1056 {
1057 string first, last;
1058 first = i.decode_string();
1059 last = i.decode_string();
1060 return _omap_rmkeyrange(
1061 ctx, get_onode(op->oid),
1062 std::move(first), std::move(last));
1063 }
1064 break;
1065 case Transaction::OP_COLL_HINT:
1066 {
1067 ceph::bufferlist hint;
1068 i.decode_bl(hint);
1069 return tm_iertr::now();
1070 }
1071 default:
1072 ERROR("bad op {}", static_cast<unsigned>(op->op));
1073 return crimson::ct_error::input_output_error::make();
1074 }
1075 } catch (std::exception &e) {
1076 ERROR("got exception {}", e);
1077 return crimson::ct_error::input_output_error::make();
1078 }
1079 }
1080
1081 SeaStore::tm_ret SeaStore::_remove(
1082 internal_context_t &ctx,
1083 OnodeRef &onode)
1084 {
1085 LOG_PREFIX(SeaStore::_remove);
1086 DEBUGT("onode={}", *ctx.transaction, *onode);
1087 return onode_manager->erase_onode(*ctx.transaction, onode);
1088 }
1089
1090 SeaStore::tm_ret SeaStore::_touch(
1091 internal_context_t &ctx,
1092 OnodeRef &onode)
1093 {
1094 LOG_PREFIX(SeaStore::_touch);
1095 DEBUGT("onode={}", *ctx.transaction, *onode);
1096 return tm_iertr::now();
1097 }
1098
1099 SeaStore::tm_ret SeaStore::_write(
1100 internal_context_t &ctx,
1101 OnodeRef &onode,
1102 uint64_t offset, size_t len,
1103 ceph::bufferlist &&_bl,
1104 uint32_t fadvise_flags)
1105 {
1106 LOG_PREFIX(SeaStore::_write);
1107 DEBUGT("onode={} {}~{}", *ctx.transaction, *onode, offset, len);
1108 {
1109 auto &object_size = onode->get_mutable_layout(*ctx.transaction).size;
1110 object_size = std::max<uint64_t>(
1111 offset + len,
1112 object_size);
1113 }
1114 return seastar::do_with(
1115 std::move(_bl),
1116 [=, &ctx, &onode](auto &bl) {
1117 return ObjectDataHandler(max_object_size).write(
1118 ObjectDataHandler::context_t{
1119 *transaction_manager,
1120 *ctx.transaction,
1121 *onode,
1122 },
1123 offset,
1124 bl);
1125 });
1126 }
1127
1128 SeaStore::omap_set_kvs_ret
1129 SeaStore::_omap_set_kvs(
1130 OnodeRef &onode,
1131 const omap_root_le_t& omap_root,
1132 Transaction& t,
1133 omap_root_le_t& mutable_omap_root,
1134 std::map<std::string, ceph::bufferlist>&& kvs)
1135 {
1136 return seastar::do_with(
1137 BtreeOMapManager(*transaction_manager),
1138 omap_root.get(onode->get_metadata_hint()),
1139 [&, keys=std::move(kvs)](auto &omap_manager, auto &root) {
1140 tm_iertr::future<> maybe_create_root =
1141 !root.is_null() ?
1142 tm_iertr::now() :
1143 omap_manager.initialize_omap(
1144 t, onode->get_metadata_hint()
1145 ).si_then([&root](auto new_root) {
1146 root = new_root;
1147 });
1148 return maybe_create_root.si_then(
1149 [&, keys=std::move(keys)]() mutable {
1150 return omap_manager.omap_set_keys(root, t, std::move(keys));
1151 }).si_then([&] {
1152 return tm_iertr::make_ready_future<omap_root_t>(std::move(root));
1153 }).si_then([&mutable_omap_root](auto root) {
1154 if (root.must_update()) {
1155 mutable_omap_root.update(root);
1156 }
1157 });
1158 }
1159 );
1160 }
1161
1162 SeaStore::tm_ret SeaStore::_omap_set_values(
1163 internal_context_t &ctx,
1164 OnodeRef &onode,
1165 std::map<std::string, ceph::bufferlist> &&aset)
1166 {
1167 LOG_PREFIX(SeaStore::_omap_set_values);
1168 DEBUGT("{} {} keys", *ctx.transaction, *onode, aset.size());
1169 return _omap_set_kvs(
1170 onode,
1171 onode->get_layout().omap_root,
1172 *ctx.transaction,
1173 onode->get_mutable_layout(*ctx.transaction).omap_root,
1174 std::move(aset));
1175 }
1176
1177 SeaStore::tm_ret SeaStore::_omap_set_header(
1178 internal_context_t &ctx,
1179 OnodeRef &onode,
1180 ceph::bufferlist &&header)
1181 {
1182 LOG_PREFIX(SeaStore::_omap_set_header);
1183 DEBUGT("{} {} bytes", *ctx.transaction, *onode, header.length());
1184 assert(0 == "not supported yet");
1185 return tm_iertr::now();
1186 }
1187
1188 SeaStore::tm_ret SeaStore::_omap_rmkeys(
1189 internal_context_t &ctx,
1190 OnodeRef &onode,
1191 omap_keys_t &&keys)
1192 {
1193 LOG_PREFIX(SeaStore::_omap_rmkeys);
1194 DEBUGT("{} {} keys", *ctx.transaction, *onode, keys.size());
1195 auto omap_root = onode->get_layout().omap_root.get(onode->get_metadata_hint());
1196 if (omap_root.is_null()) {
1197 return seastar::now();
1198 } else {
1199 return seastar::do_with(
1200 BtreeOMapManager(*transaction_manager),
1201 onode->get_layout().omap_root.get(onode->get_metadata_hint()),
1202 std::move(keys),
1203 [&ctx, &onode](
1204 auto &omap_manager,
1205 auto &omap_root,
1206 auto &keys) {
1207 return trans_intr::do_for_each(
1208 keys.begin(),
1209 keys.end(),
1210 [&](auto &p) {
1211 return omap_manager.omap_rm_key(
1212 omap_root,
1213 *ctx.transaction,
1214 p);
1215 }
1216 ).si_then([&] {
1217 if (omap_root.must_update()) {
1218 onode->get_mutable_layout(*ctx.transaction
1219 ).omap_root.update(omap_root);
1220 }
1221 });
1222 }
1223 );
1224 }
1225 }
1226
1227 SeaStore::tm_ret SeaStore::_omap_rmkeyrange(
1228 internal_context_t &ctx,
1229 OnodeRef &onode,
1230 std::string first,
1231 std::string last)
1232 {
1233 LOG_PREFIX(SeaStore::_omap_rmkeyrange);
1234 DEBUGT("{} first={} last={}", *ctx.transaction, *onode, first, last);
1235 assert(0 == "not supported yet");
1236 return tm_iertr::now();
1237 }
1238
1239 SeaStore::tm_ret SeaStore::_truncate(
1240 internal_context_t &ctx,
1241 OnodeRef &onode,
1242 uint64_t size)
1243 {
1244 LOG_PREFIX(SeaStore::_truncate);
1245 DEBUGT("onode={} size={}", *ctx.transaction, *onode, size);
1246 onode->get_mutable_layout(*ctx.transaction).size = size;
1247 return ObjectDataHandler(max_object_size).truncate(
1248 ObjectDataHandler::context_t{
1249 *transaction_manager,
1250 *ctx.transaction,
1251 *onode
1252 },
1253 size);
1254 }
1255
1256 SeaStore::tm_ret SeaStore::_setattrs(
1257 internal_context_t &ctx,
1258 OnodeRef &onode,
1259 std::map<std::string, bufferlist>&& aset)
1260 {
1261 LOG_PREFIX(SeaStore::_setattrs);
1262 DEBUGT("onode={}", *ctx.transaction, *onode);
1263 auto& layout = onode->get_mutable_layout(*ctx.transaction);
1264 if (auto it = aset.find(OI_ATTR); it != aset.end()) {
1265 auto& val = it->second;
1266 if (likely(val.length() <= onode_layout_t::MAX_OI_LENGTH)) {
1267 layout.oi_size = val.length();
1268 maybe_inline_memcpy(
1269 &layout.oi[0],
1270 val.c_str(),
1271 val.length(),
1272 onode_layout_t::MAX_OI_LENGTH);
1273 aset.erase(it);
1274 } else {
1275 layout.oi_size = 0;
1276 }
1277 }
1278
1279 if (auto it = aset.find(SS_ATTR); it != aset.end()) {
1280 auto& val = it->second;
1281 if (likely(val.length() <= onode_layout_t::MAX_SS_LENGTH)) {
1282 layout.ss_size = val.length();
1283 maybe_inline_memcpy(
1284 &layout.ss[0],
1285 val.c_str(),
1286 val.length(),
1287 onode_layout_t::MAX_SS_LENGTH);
1288 it = aset.erase(it);
1289 } else {
1290 layout.ss_size = 0;
1291 }
1292 }
1293
1294 if (aset.empty()) {
1295 return tm_iertr::now();
1296 }
1297
1298 return _omap_set_kvs(
1299 onode,
1300 onode->get_layout().xattr_root,
1301 *ctx.transaction,
1302 layout.xattr_root,
1303 std::move(aset));
1304 }
1305
1306 SeaStore::tm_ret SeaStore::_create_collection(
1307 internal_context_t &ctx,
1308 const coll_t& cid, int bits)
1309 {
1310 return transaction_manager->read_collection_root(
1311 *ctx.transaction
1312 ).si_then([=, &ctx](auto _cmroot) {
1313 return seastar::do_with(
1314 _cmroot,
1315 [=, &ctx](auto &cmroot) {
1316 return collection_manager->create(
1317 cmroot,
1318 *ctx.transaction,
1319 cid,
1320 bits
1321 ).si_then([=, &ctx, &cmroot] {
1322 if (cmroot.must_update()) {
1323 transaction_manager->write_collection_root(
1324 *ctx.transaction,
1325 cmroot);
1326 }
1327 });
1328 }
1329 );
1330 }).handle_error_interruptible(
1331 tm_iertr::pass_further{},
1332 crimson::ct_error::assert_all{
1333 "Invalid error in SeaStore::_create_collection"
1334 }
1335 );
1336 }
1337
1338 SeaStore::tm_ret SeaStore::_remove_collection(
1339 internal_context_t &ctx,
1340 const coll_t& cid)
1341 {
1342 return transaction_manager->read_collection_root(
1343 *ctx.transaction
1344 ).si_then([=, &ctx](auto _cmroot) {
1345 return seastar::do_with(
1346 _cmroot,
1347 [=, &ctx](auto &cmroot) {
1348 return collection_manager->remove(
1349 cmroot,
1350 *ctx.transaction,
1351 cid
1352 ).si_then([=, &ctx, &cmroot] {
1353 // param here denotes whether it already existed, probably error
1354 if (cmroot.must_update()) {
1355 transaction_manager->write_collection_root(
1356 *ctx.transaction,
1357 cmroot);
1358 }
1359 });
1360 });
1361 }).handle_error_interruptible(
1362 tm_iertr::pass_further{},
1363 crimson::ct_error::assert_all{
1364 "Invalid error in SeaStore::_create_collection"
1365 }
1366 );
1367 }
1368
1369 boost::intrusive_ptr<SeastoreCollection> SeaStore::_get_collection(const coll_t& cid)
1370 {
1371 return new SeastoreCollection{cid};
1372 }
1373
1374 seastar::future<> SeaStore::write_meta(const std::string& key,
1375 const std::string& value)
1376 {
1377 LOG_PREFIX(SeaStore::write_meta);
1378 DEBUG("key: {}; value: {}", key, value);
1379 return seastar::do_with(
1380 key, value,
1381 [this, FNAME](auto& key, auto& value) {
1382 return repeat_eagain([this, FNAME, &key, &value] {
1383 return transaction_manager->with_transaction_intr(
1384 Transaction::src_t::MUTATE,
1385 "write_meta",
1386 [this, FNAME, &key, &value](auto& t)
1387 {
1388 DEBUGT("Have transaction, key: {}; value: {}", t, key, value);
1389 return transaction_manager->update_root_meta(
1390 t, key, value
1391 ).si_then([this, &t] {
1392 return transaction_manager->submit_transaction(t);
1393 });
1394 });
1395 }).safe_then([this, &key, &value] {
1396 return mdstore->write_meta(key, value);
1397 });
1398 }).handle_error(
1399 crimson::ct_error::assert_all{"Invalid error in SeaStore::write_meta"}
1400 );
1401 }
1402
1403 seastar::future<std::tuple<int, std::string>> SeaStore::read_meta(const std::string& key)
1404 {
1405 LOG_PREFIX(SeaStore::read_meta);
1406 DEBUG("key: {}", key);
1407 return mdstore->read_meta(key).safe_then([](auto v) {
1408 if (v) {
1409 return std::make_tuple(0, std::move(*v));
1410 } else {
1411 return std::make_tuple(-1, std::string(""));
1412 }
1413 }).handle_error(
1414 crimson::ct_error::assert_all{
1415 "Invalid error in SeaStore::read_meta"
1416 }
1417 );
1418 }
1419
1420 uuid_d SeaStore::get_fsid() const
1421 {
1422 return segment_manager->get_meta().seastore_id;
1423 }
1424
1425 seastar::future<std::unique_ptr<SeaStore>> make_seastore(
1426 const std::string &device,
1427 const ConfigValues &config)
1428 {
1429 return SegmentManager::get_segment_manager(
1430 device
1431 ).then([&device](auto sm) {
1432 auto scanner = std::make_unique<ExtentReader>();
1433 auto& scanner_ref = *scanner.get();
1434 auto segment_cleaner = std::make_unique<SegmentCleaner>(
1435 SegmentCleaner::config_t::get_default(),
1436 std::move(scanner),
1437 false /* detailed */);
1438
1439 auto journal = std::make_unique<Journal>(*sm, scanner_ref);
1440 auto cache = std::make_unique<Cache>(scanner_ref);
1441 auto lba_manager = lba_manager::create_lba_manager(*sm, *cache);
1442
1443 auto epm = std::make_unique<ExtentPlacementManager>(*cache, *lba_manager);
1444
1445 journal->set_segment_provider(&*segment_cleaner);
1446
1447 auto tm = std::make_unique<TransactionManager>(
1448 *sm,
1449 std::move(segment_cleaner),
1450 std::move(journal),
1451 std::move(cache),
1452 std::move(lba_manager),
1453 std::move(epm),
1454 scanner_ref);
1455
1456 auto cm = std::make_unique<collection_manager::FlatCollectionManager>(*tm);
1457 return std::make_unique<SeaStore>(
1458 device,
1459 std::move(sm),
1460 std::move(tm),
1461 std::move(cm),
1462 std::make_unique<crimson::os::seastore::onode::FLTreeOnodeManager>(*tm));
1463 });
1464 }
1465
1466 }