]>
Commit | Line | Data |
---|---|---|
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 <seastar/core/future.hh> | |
20effc67 | 5 | #include <seastar/core/sleep.hh> |
f67539c2 TL |
6 | |
7 | #include "messages/MOSDOp.h" | |
8 | ||
9 | #include "crimson/osd/pg.h" | |
10 | #include "crimson/osd/shard_services.h" | |
11 | #include "common/Formatter.h" | |
12 | #include "crimson/osd/osd_operations/background_recovery.h" | |
13 | ||
14 | namespace { | |
15 | seastar::logger& logger() { | |
16 | return crimson::get_logger(ceph_subsys_osd); | |
17 | } | |
18 | } | |
19 | ||
20 | namespace crimson::osd { | |
21 | ||
22 | BackgroundRecovery::BackgroundRecovery( | |
23 | Ref<PG> pg, | |
24 | ShardServices &ss, | |
25 | epoch_t epoch_started, | |
20effc67 TL |
26 | crimson::osd::scheduler::scheduler_class_t scheduler_class, |
27 | float delay) | |
f67539c2 TL |
28 | : pg(pg), |
29 | epoch_started(epoch_started), | |
20effc67 | 30 | delay(delay), |
f67539c2 TL |
31 | ss(ss), |
32 | scheduler_class(scheduler_class) | |
33 | {} | |
34 | ||
35 | void BackgroundRecovery::print(std::ostream &lhs) const | |
36 | { | |
37 | lhs << "BackgroundRecovery(" << pg->get_pgid() << ")"; | |
38 | } | |
39 | ||
40 | void BackgroundRecovery::dump_detail(Formatter *f) const | |
41 | { | |
42 | f->dump_stream("pgid") << pg->get_pgid(); | |
43 | f->open_object_section("recovery_detail"); | |
44 | { | |
45 | // TODO pg->dump_recovery_state(f); | |
46 | } | |
47 | f->close_section(); | |
48 | } | |
49 | ||
50 | seastar::future<> BackgroundRecovery::start() | |
51 | { | |
52 | logger().debug("{}: start", *this); | |
53 | ||
54 | IRef ref = this; | |
20effc67 TL |
55 | auto maybe_delay = seastar::now(); |
56 | if (delay) { | |
57 | maybe_delay = seastar::sleep( | |
58 | std::chrono::milliseconds(std::lround(delay * 1000))); | |
59 | } | |
60 | return maybe_delay.then([ref, this] { | |
61 | return ss.throttler.with_throttle_while( | |
62 | this, get_scheduler_params(), [this] { | |
63 | return interruptor::with_interruption([this] { | |
64 | return do_recovery(); | |
65 | }, [](std::exception_ptr) { | |
66 | return seastar::make_ready_future<bool>(false); | |
67 | }, pg); | |
68 | }).handle_exception_type([ref, this](const std::system_error& err) { | |
69 | if (err.code() == std::make_error_code(std::errc::interrupted)) { | |
70 | logger().debug("{} recovery interruped: {}", *pg, err.what()); | |
71 | return seastar::now(); | |
72 | } | |
73 | return seastar::make_exception_future<>(err); | |
74 | }); | |
75 | }); | |
f67539c2 TL |
76 | } |
77 | ||
20effc67 TL |
78 | UrgentRecovery::interruptible_future<bool> |
79 | UrgentRecovery::do_recovery() | |
f67539c2 | 80 | { |
20effc67 | 81 | logger().debug("{}: {}", __func__, *this); |
f67539c2 | 82 | if (!pg->has_reset_since(epoch_started)) { |
20effc67 | 83 | return with_blocking_future_interruptible<interruptor::condition>( |
f67539c2 | 84 | pg->get_recovery_handler()->recover_missing(soid, need) |
20effc67 | 85 | ).then_interruptible([] { |
f67539c2 TL |
86 | return seastar::make_ready_future<bool>(false); |
87 | }); | |
88 | } | |
89 | return seastar::make_ready_future<bool>(false); | |
90 | } | |
91 | ||
92 | void UrgentRecovery::print(std::ostream &lhs) const | |
93 | { | |
94 | lhs << "UrgentRecovery(" << pg->get_pgid() << ", " | |
20effc67 TL |
95 | << soid << ", v" << need << ", epoch_started: " |
96 | << epoch_started << ")"; | |
f67539c2 TL |
97 | } |
98 | ||
99 | void UrgentRecovery::dump_detail(Formatter *f) const | |
100 | { | |
101 | f->dump_stream("pgid") << pg->get_pgid(); | |
102 | f->open_object_section("recovery_detail"); | |
103 | { | |
104 | f->dump_stream("oid") << soid; | |
105 | f->dump_stream("version") << need; | |
106 | } | |
107 | f->close_section(); | |
108 | } | |
109 | ||
110 | PglogBasedRecovery::PglogBasedRecovery( | |
111 | Ref<PG> pg, | |
112 | ShardServices &ss, | |
20effc67 TL |
113 | const epoch_t epoch_started, |
114 | float delay) | |
f67539c2 TL |
115 | : BackgroundRecovery( |
116 | std::move(pg), | |
117 | ss, | |
118 | epoch_started, | |
20effc67 TL |
119 | crimson::osd::scheduler::scheduler_class_t::background_recovery, |
120 | delay) | |
f67539c2 TL |
121 | {} |
122 | ||
20effc67 TL |
123 | PglogBasedRecovery::interruptible_future<bool> |
124 | PglogBasedRecovery::do_recovery() | |
f67539c2 | 125 | { |
20effc67 | 126 | if (pg->has_reset_since(epoch_started)) { |
f67539c2 | 127 | return seastar::make_ready_future<bool>(false); |
20effc67 TL |
128 | } |
129 | return with_blocking_future_interruptible<interruptor::condition>( | |
f67539c2 TL |
130 | pg->get_recovery_handler()->start_recovery_ops( |
131 | crimson::common::local_conf()->osd_recovery_max_single_start)); | |
132 | } | |
133 | ||
134 | BackfillRecovery::BackfillRecoveryPipeline &BackfillRecovery::bp(PG &pg) | |
135 | { | |
136 | return pg.backfill_pipeline; | |
137 | } | |
138 | ||
20effc67 TL |
139 | BackfillRecovery::interruptible_future<bool> |
140 | BackfillRecovery::do_recovery() | |
f67539c2 TL |
141 | { |
142 | logger().debug("{}", __func__); | |
143 | ||
144 | if (pg->has_reset_since(epoch_started)) { | |
145 | logger().debug("{}: pg got reset since epoch_started={}", | |
146 | __func__, epoch_started); | |
147 | return seastar::make_ready_future<bool>(false); | |
148 | } | |
149 | // TODO: limits | |
20effc67 | 150 | return with_blocking_future_interruptible<interruptor::condition>( |
f67539c2 TL |
151 | // process_event() of our boost::statechart machine is non-reentrant. |
152 | // with the backfill_pipeline we protect it from a second entry from | |
153 | // the implementation of BackfillListener. | |
154 | // additionally, this stage serves to synchronize with PeeringEvent. | |
155 | handle.enter(bp(*pg).process) | |
20effc67 | 156 | ).then_interruptible([this] { |
f67539c2 TL |
157 | pg->get_recovery_handler()->dispatch_backfill_event(std::move(evt)); |
158 | return seastar::make_ready_future<bool>(false); | |
159 | }); | |
160 | } | |
161 | ||
162 | } // namespace crimson::osd |