]> git.proxmox.com Git - ceph.git/blame - ceph/src/osd/scrubber/scrub_machine.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / osd / scrubber / scrub_machine.h
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#pragma once
4
5#include <string>
6
7#include <boost/statechart/custom_reaction.hpp>
8#include <boost/statechart/deferral.hpp>
9#include <boost/statechart/event.hpp>
10#include <boost/statechart/event_base.hpp>
11#include <boost/statechart/in_state_reaction.hpp>
12#include <boost/statechart/simple_state.hpp>
13#include <boost/statechart/state.hpp>
14#include <boost/statechart/state_machine.hpp>
15#include <boost/statechart/transition.hpp>
16
17#include "common/version.h"
18#include "include/Context.h"
1e59de90 19#include "osd/scrubber_common.h"
f67539c2
TL
20
21#include "scrub_machine_lstnr.h"
f67539c2 22
1e59de90
TL
23/// a wrapper that sets the FSM state description used by the
24/// PgScrubber
25/// \todo consider using the full NamedState as in Peering
26struct NamedSimply {
27 explicit NamedSimply(ScrubMachineListener* scrubber, const char* name);
28};
f67539c2
TL
29
30class PG; // holding a pointer to that one - just for testing
31class PgScrubber;
1e59de90 32
f67539c2
TL
33namespace Scrub {
34
35namespace sc = ::boost::statechart;
36namespace mpl = ::boost::mpl;
37
38//
39// EVENTS
40//
41
42void on_event_creation(std::string_view nm);
43void on_event_discard(std::string_view nm);
44
20effc67
TL
45#define MEV(E) \
46 struct E : sc::event<E> { \
47 inline static int actv{0}; \
48 E() \
49 { \
50 if (!actv++) \
51 on_event_creation(#E); \
52 } \
53 ~E() \
54 { \
55 if (!--actv) \
56 on_event_discard(#E); \
57 } \
58 void print(std::ostream* out) const { *out << #E; } \
59 std::string_view print() const { return #E; } \
f67539c2
TL
60 };
61
1e59de90
TL
62/// all replicas have granted our reserve request
63MEV(RemotesReserved)
20effc67 64
1e59de90
TL
65/// a reservation request has failed
66MEV(ReservationFailure)
f67539c2 67
1e59de90
TL
68/// initiate a new scrubbing session (relevant if we are a Primary)
69MEV(StartScrub)
20effc67 70
1e59de90
TL
71/// initiate a new scrubbing session. Only triggered at Recovery completion
72MEV(AfterRepairScrub)
20effc67 73
1e59de90
TL
74/// triggered when the PG unblocked an object that was marked for scrubbing.
75/// Via the PGScrubUnblocked op
76MEV(Unblocked)
20effc67 77
f67539c2 78MEV(InternalSchedScrub)
20effc67 79
f67539c2 80MEV(SelectedChunkFree)
20effc67 81
f67539c2 82MEV(ChunkIsBusy)
20effc67 83
1e59de90
TL
84/// Update to active_pushes. 'active_pushes' represents recovery that
85/// is in-flight to the local ObjectStore
86MEV(ActivePushesUpd)
20effc67 87
1e59de90
TL
88/// (Primary only) all updates are committed
89MEV(UpdatesApplied)
20effc67 90
1e59de90
TL
91/// the internal counterpart of UpdatesApplied
92MEV(InternalAllUpdates)
20effc67 93
1e59de90
TL
94/// got a map from a replica
95MEV(GotReplicas)
f67539c2 96
1e59de90
TL
97/// internal - BuildMap preempted. Required, as detected within the ctor
98MEV(IntBmPreempted)
20effc67 99
f67539c2
TL
100MEV(InternalError)
101
102MEV(IntLocalMapDone)
103
1e59de90
TL
104/// external. called upon success of a MODIFY op. See
105/// scrub_snapshot_metadata()
106MEV(DigestUpdate)
20effc67 107
1e59de90
TL
108/// initiating replica scrub
109MEV(StartReplica)
20effc67 110
1e59de90
TL
111/// 'start replica' when there are no pending updates
112MEV(StartReplicaNoWait)
f67539c2
TL
113
114MEV(SchedReplica)
20effc67 115
1e59de90
TL
116/// Update to active_pushes. 'active_pushes' represents recovery
117/// that is in-flight to the local ObjectStore
118MEV(ReplicaPushesUpd)
f67539c2 119
1e59de90
TL
120/// guarantee that the FSM is in the quiescent state (i.e. NotActive)
121MEV(FullReset)
f67539c2 122
1e59de90
TL
123/// finished handling this chunk. Go get the next one
124MEV(NextChunk)
20effc67 125
1e59de90
TL
126/// all chunks handled
127MEV(ScrubFinished)
20effc67 128
1e59de90
TL
129//
130// STATES
131//
f67539c2
TL
132
133struct NotActive; ///< the quiescent state. No active scrubbing.
134struct ReservingReplicas; ///< securing scrub resources from replicas' OSDs
135struct ActiveScrubbing; ///< the active state for a Primary. A sub-machine.
1e59de90
TL
136struct ReplicaWaitUpdates; ///< an active state for a replica. Waiting for all
137 ///< active operations to finish.
f67539c2
TL
138struct ActiveReplica; ///< an active state for a replica.
139
140
141class ScrubMachine : public sc::state_machine<ScrubMachine, NotActive> {
142 public:
143 friend class PgScrubber;
144
145 public:
146 explicit ScrubMachine(PG* pg, ScrubMachineListener* pg_scrub);
147 ~ScrubMachine();
148
f67539c2
TL
149 spg_t m_pg_id;
150 ScrubMachineListener* m_scrbr;
20effc67 151 std::ostream& gen_prefix(std::ostream& out) const;
f67539c2 152
f67539c2
TL
153 void assert_not_active() const;
154 [[nodiscard]] bool is_reserving() const;
20effc67 155 [[nodiscard]] bool is_accepting_updates() const;
f67539c2
TL
156};
157
158/**
159 * The Scrubber's base (quiescent) state.
160 * Scrubbing is triggered by one of the following events:
1e59de90
TL
161 *
162 * - (standard scenario for a Primary): 'StartScrub'. Initiates the OSDs
163 * resources reservation process. Will be issued by PG::scrub(), following a
f67539c2 164 * queued "PGScrub" op.
20effc67 165 *
1e59de90
TL
166 * - a special end-of-recovery Primary scrub event ('AfterRepairScrub').
167 *
168 * - (for a replica) 'StartReplica' or 'StartReplicaNoWait', triggered by
169 * an incoming MOSDRepScrub message.
170 *
171 * note (20.8.21): originally, AfterRepairScrub was triggering a scrub without
172 * waiting for replica resources to be acquired. But once replicas started
173 * using the resource-request to identify and tag the scrub session, this
174 * bypass cannot be supported anymore.
f67539c2 175 */
1e59de90 176struct NotActive : sc::state<NotActive, ScrubMachine>, NamedSimply {
f67539c2
TL
177 explicit NotActive(my_context ctx);
178
1e59de90
TL
179 using reactions =
180 mpl::list<sc::custom_reaction<StartScrub>,
181 // a scrubbing that was initiated at recovery completion:
182 sc::custom_reaction<AfterRepairScrub>,
183 sc::transition<StartReplica, ReplicaWaitUpdates>,
184 sc::transition<StartReplicaNoWait, ActiveReplica>>;
20effc67 185 sc::result react(const StartScrub&);
39ae355f 186 sc::result react(const AfterRepairScrub&);
f67539c2
TL
187};
188
1e59de90
TL
189struct ReservingReplicas : sc::state<ReservingReplicas, ScrubMachine>,
190 NamedSimply {
f67539c2
TL
191
192 explicit ReservingReplicas(my_context ctx);
20effc67 193 ~ReservingReplicas();
f67539c2
TL
194 using reactions = mpl::list<sc::custom_reaction<FullReset>,
195 // all replicas granted our resources request
196 sc::transition<RemotesReserved, ActiveScrubbing>,
197 sc::custom_reaction<ReservationFailure>>;
198
199 sc::result react(const FullReset&);
200
201 /// at least one replica denied us the scrub resources we've requested
202 sc::result react(const ReservationFailure&);
203};
204
205
206// the "active" sub-states
207
1e59de90
TL
208/// the objects range is blocked
209struct RangeBlocked;
210
211/// either delaying the scrub by some time and requeuing, or just requeue
212struct PendingTimer;
213
214/// select a chunk to scrub, and verify its availability
215struct NewChunk;
216
f67539c2
TL
217struct WaitPushes;
218struct WaitLastUpdate;
219struct BuildMap;
1e59de90
TL
220
221/// a problem during BuildMap. Wait for all replicas to report, then restart.
222struct DrainReplMaps;
223
224/// wait for all replicas to report
225struct WaitReplicas;
226
20effc67 227struct WaitDigestUpdate;
f67539c2 228
1e59de90
TL
229struct ActiveScrubbing
230 : sc::state<ActiveScrubbing, ScrubMachine, PendingTimer>, NamedSimply {
f67539c2
TL
231
232 explicit ActiveScrubbing(my_context ctx);
233 ~ActiveScrubbing();
234
1e59de90
TL
235 using reactions = mpl::list<sc::custom_reaction<InternalError>,
236 sc::custom_reaction<FullReset>>;
f67539c2 237
f67539c2
TL
238 sc::result react(const FullReset&);
239 sc::result react(const InternalError&);
240};
241
1e59de90 242struct RangeBlocked : sc::state<RangeBlocked, ActiveScrubbing>, NamedSimply {
f67539c2
TL
243 explicit RangeBlocked(my_context ctx);
244 using reactions = mpl::list<sc::transition<Unblocked, PendingTimer>>;
20effc67
TL
245
246 Scrub::BlockedRangeWarning m_timeout;
f67539c2
TL
247};
248
1e59de90 249struct PendingTimer : sc::state<PendingTimer, ActiveScrubbing>, NamedSimply {
f67539c2
TL
250
251 explicit PendingTimer(my_context ctx);
252
253 using reactions = mpl::list<sc::transition<InternalSchedScrub, NewChunk>>;
254};
255
1e59de90 256struct NewChunk : sc::state<NewChunk, ActiveScrubbing>, NamedSimply {
f67539c2
TL
257
258 explicit NewChunk(my_context ctx);
259
260 using reactions = mpl::list<sc::transition<ChunkIsBusy, RangeBlocked>,
261 sc::custom_reaction<SelectedChunkFree>>;
262
263 sc::result react(const SelectedChunkFree&);
264};
265
266/**
267 * initiate the update process for this chunk
268 *
269 * Wait fo 'active_pushes' to clear.
1e59de90
TL
270 * 'active_pushes' represents recovery that is in-flight to the local
271 * Objectstore, hence scrub waits until the correct data is readable
272 * (in-flight data to the Objectstore is not readable until written to
273 * disk, termed 'applied' here)
f67539c2 274 */
1e59de90 275struct WaitPushes : sc::state<WaitPushes, ActiveScrubbing>, NamedSimply {
f67539c2
TL
276
277 explicit WaitPushes(my_context ctx);
278
279 using reactions = mpl::list<sc::custom_reaction<ActivePushesUpd>>;
280
281 sc::result react(const ActivePushesUpd&);
282};
283
1e59de90
TL
284struct WaitLastUpdate : sc::state<WaitLastUpdate, ActiveScrubbing>,
285 NamedSimply {
f67539c2
TL
286
287 explicit WaitLastUpdate(my_context ctx);
288
289 void on_new_updates(const UpdatesApplied&);
290
1e59de90
TL
291 using reactions =
292 mpl::list<sc::custom_reaction<InternalAllUpdates>,
293 sc::in_state_reaction<UpdatesApplied,
294 WaitLastUpdate,
295 &WaitLastUpdate::on_new_updates>>;
f67539c2
TL
296
297 sc::result react(const InternalAllUpdates&);
298};
299
1e59de90 300struct BuildMap : sc::state<BuildMap, ActiveScrubbing>, NamedSimply {
f67539c2
TL
301 explicit BuildMap(my_context ctx);
302
303 // possible error scenarios:
304 // - an error reported by the backend will trigger an 'InternalError' event,
305 // handled by our parent state;
306 // - if preempted, we switch to DrainReplMaps, where we will wait for all
307 // replicas to send their maps before acknowledging the preemption;
1e59de90
TL
308 // - an interval change will be handled by the relevant 'send-event'
309 // functions, and will translated into a 'FullReset' event.
310 using reactions = mpl::list<sc::transition<IntBmPreempted, DrainReplMaps>,
311 // looping, waiting for the backend to finish:
312 sc::transition<InternalSchedScrub, BuildMap>,
313 sc::custom_reaction<IntLocalMapDone>>;
f67539c2
TL
314
315 sc::result react(const IntLocalMapDone&);
316};
317
318/*
319 * "drain" scrub-maps responses from replicas
320 */
1e59de90 321struct DrainReplMaps : sc::state<DrainReplMaps, ActiveScrubbing>, NamedSimply {
f67539c2
TL
322 explicit DrainReplMaps(my_context ctx);
323
324 using reactions =
1e59de90
TL
325 // all replicas are accounted for:
326 mpl::list<sc::custom_reaction<GotReplicas>>;
f67539c2
TL
327
328 sc::result react(const GotReplicas&);
329};
330
1e59de90 331struct WaitReplicas : sc::state<WaitReplicas, ActiveScrubbing>, NamedSimply {
f67539c2
TL
332 explicit WaitReplicas(my_context ctx);
333
1e59de90
TL
334 using reactions = mpl::list<
335 // all replicas are accounted for:
336 sc::custom_reaction<GotReplicas>,
337 sc::custom_reaction<DigestUpdate>>;
f67539c2
TL
338
339 sc::result react(const GotReplicas&);
33c7a0ef 340 sc::result react(const DigestUpdate&);
20effc67 341 bool all_maps_already_called{false}; // see comment in react code
f67539c2
TL
342};
343
1e59de90
TL
344struct WaitDigestUpdate : sc::state<WaitDigestUpdate, ActiveScrubbing>,
345 NamedSimply {
f67539c2
TL
346 explicit WaitDigestUpdate(my_context ctx);
347
20effc67 348 using reactions = mpl::list<sc::custom_reaction<DigestUpdate>,
1e59de90
TL
349 sc::custom_reaction<ScrubFinished>,
350 sc::transition<NextChunk, PendingTimer>>;
f67539c2 351 sc::result react(const DigestUpdate&);
20effc67 352 sc::result react(const ScrubFinished&);
f67539c2
TL
353};
354
1e59de90 355// ----------------------------- the "replica active" states
f67539c2
TL
356
357/*
358 * Waiting for 'active_pushes' to complete
359 *
360 * When in this state:
361 * - the details of the Primary's request were internalized by PgScrubber;
362 * - 'active' scrubbing is set
363 */
1e59de90
TL
364struct ReplicaWaitUpdates : sc::state<ReplicaWaitUpdates, ScrubMachine>,
365 NamedSimply {
f67539c2 366 explicit ReplicaWaitUpdates(my_context ctx);
1e59de90
TL
367 using reactions = mpl::list<sc::custom_reaction<ReplicaPushesUpd>,
368 sc::custom_reaction<FullReset>>;
f67539c2
TL
369
370 sc::result react(const ReplicaPushesUpd&);
371 sc::result react(const FullReset&);
372};
373
374
1e59de90 375struct ActiveReplica : sc::state<ActiveReplica, ScrubMachine>, NamedSimply {
f67539c2 376 explicit ActiveReplica(my_context ctx);
20effc67 377 using reactions = mpl::list<sc::custom_reaction<SchedReplica>,
1e59de90 378 sc::custom_reaction<FullReset>>;
f67539c2
TL
379
380 sc::result react(const SchedReplica&);
381 sc::result react(const FullReset&);
382};
383
384} // namespace Scrub