]> git.proxmox.com Git - ceph.git/blob - ceph/src/osd/PeeringState.h
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / osd / PeeringState.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #pragma once
5
6 #include <boost/statechart/custom_reaction.hpp>
7 #include <boost/statechart/event.hpp>
8 #include <boost/statechart/simple_state.hpp>
9 #include <boost/statechart/state.hpp>
10 #include <boost/statechart/state_machine.hpp>
11 #include <boost/statechart/transition.hpp>
12 #include <boost/statechart/event_base.hpp>
13 #include <string>
14 #include <atomic>
15
16 #include "include/ceph_assert.h"
17 #include "include/common_fwd.h"
18
19 #include "PGLog.h"
20 #include "PGStateUtils.h"
21 #include "PGPeeringEvent.h"
22 #include "osd_types.h"
23 #include "osd_types_fmt.h"
24 #include "os/ObjectStore.h"
25 #include "OSDMap.h"
26 #include "MissingLoc.h"
27 #include "osd/osd_perf_counters.h"
28 #include "common/ostream_temp.h"
29
30 struct PGPool {
31 epoch_t cached_epoch;
32 int64_t id;
33 std::string name;
34
35 pg_pool_t info;
36 SnapContext snapc; // the default pool snapc, ready to go.
37
38 PGPool(OSDMapRef map, int64_t i, const pg_pool_t& info,
39 const std::string& name)
40 : cached_epoch(map->get_epoch()),
41 id(i),
42 name(name),
43 info(info) {
44 snapc = info.get_snap_context();
45 }
46
47 void update(OSDMapRef map);
48
49 ceph::timespan get_readable_interval(ConfigProxy &conf) const {
50 double v = 0;
51 if (info.opts.get(pool_opts_t::READ_LEASE_INTERVAL, &v)) {
52 return ceph::make_timespan(v);
53 } else {
54 auto hbi = conf->osd_heartbeat_grace;
55 auto fac = conf->osd_pool_default_read_lease_ratio;
56 return ceph::make_timespan(hbi * fac);
57 }
58 }
59 };
60
61 template <>
62 struct fmt::formatter<PGPool> {
63 template <typename ParseContext>
64 constexpr auto parse(ParseContext& ctx) { return ctx.begin(); }
65
66 template <typename FormatContext>
67 auto format(const PGPool& pool, FormatContext& ctx)
68 {
69 return fmt::format_to(ctx.out(),
70 "{}/{}({})",
71 pool.id,
72 pool.name,
73 pool.info);
74 }
75 };
76
77 struct PeeringCtx;
78
79 // [primary only] content recovery state
80 struct BufferedRecoveryMessages {
81 #if defined(WITH_SEASTAR)
82 std::map<int, std::vector<MessageURef>> message_map;
83 #else
84 std::map<int, std::vector<MessageRef>> message_map;
85 #endif
86
87 BufferedRecoveryMessages() = default;
88 BufferedRecoveryMessages(PeeringCtx &ctx);
89
90 void accept_buffered_messages(BufferedRecoveryMessages &m) {
91 for (auto &[target, ls] : m.message_map) {
92 auto &ovec = message_map[target];
93 // put buffered messages in front
94 ls.reserve(ls.size() + ovec.size());
95 ls.insert(ls.end(), std::make_move_iterator(ovec.begin()), std::make_move_iterator(ovec.end()));
96 ovec.clear();
97 ovec.swap(ls);
98 }
99 }
100
101 template <class MsgT> // MsgT = MessageRef for ceph-osd and MessageURef for crimson-osd
102 void send_osd_message(int target, MsgT&& m) {
103 message_map[target].emplace_back(std::forward<MsgT>(m));
104 }
105 void send_notify(int to, const pg_notify_t &n);
106 void send_query(int to, spg_t spgid, const pg_query_t &q);
107 void send_info(int to, spg_t to_spgid,
108 epoch_t min_epoch, epoch_t cur_epoch,
109 const pg_info_t &info,
110 std::optional<pg_lease_t> lease = {},
111 std::optional<pg_lease_ack_t> lease_ack = {});
112 };
113
114 struct HeartbeatStamps : public RefCountedObject {
115 mutable ceph::mutex lock = ceph::make_mutex("HeartbeatStamps::lock");
116
117 const int osd;
118
119 // we maintain an upper and lower bound on the delta between our local
120 // mono_clock time (minus the startup_time) to the peer OSD's mono_clock
121 // time (minus its startup_time).
122 //
123 // delta is (remote_clock_time - local_clock_time), so that
124 // local_time + delta -> peer_time, and peer_time - delta -> local_time.
125 //
126 // we have an upper and lower bound value on this delta, meaning the
127 // value of the remote clock is somewhere between [my_time + lb, my_time + ub]
128 //
129 // conversely, if we have a remote timestamp T, then that is
130 // [T - ub, T - lb] in terms of the local clock. i.e., if you are
131 // substracting the delta, then take care that you swap the role of the
132 // lb and ub values.
133
134 /// lower bound on peer clock - local clock
135 std::optional<ceph::signedspan> peer_clock_delta_lb;
136
137 /// upper bound on peer clock - local clock
138 std::optional<ceph::signedspan> peer_clock_delta_ub;
139
140 /// highest up_from we've seen from this rank
141 epoch_t up_from = 0;
142
143 void print(std::ostream& out) const {
144 std::lock_guard l(lock);
145 out << "hbstamp(osd." << osd << " up_from " << up_from
146 << " peer_clock_delta [";
147 if (peer_clock_delta_lb) {
148 out << *peer_clock_delta_lb;
149 }
150 out << ",";
151 if (peer_clock_delta_ub) {
152 out << *peer_clock_delta_ub;
153 }
154 out << "])";
155 }
156
157 void sent_ping(std::optional<ceph::signedspan> *delta_ub) {
158 std::lock_guard l(lock);
159 // the non-primaries need a lower bound on remote clock - local clock. if
160 // we assume the transit for the last ping_reply was
161 // instantaneous, that would be (the negative of) our last
162 // peer_clock_delta_lb value.
163 if (peer_clock_delta_lb) {
164 *delta_ub = - *peer_clock_delta_lb;
165 }
166 }
167
168 void got_ping(epoch_t this_up_from,
169 ceph::signedspan now,
170 ceph::signedspan peer_send_stamp,
171 std::optional<ceph::signedspan> delta_ub,
172 ceph::signedspan *out_delta_ub) {
173 std::lock_guard l(lock);
174 if (this_up_from < up_from) {
175 return;
176 }
177 if (this_up_from > up_from) {
178 up_from = this_up_from;
179 }
180 peer_clock_delta_lb = peer_send_stamp - now;
181 peer_clock_delta_ub = delta_ub;
182 *out_delta_ub = - *peer_clock_delta_lb;
183 }
184
185 void got_ping_reply(ceph::signedspan now,
186 ceph::signedspan peer_send_stamp,
187 std::optional<ceph::signedspan> delta_ub) {
188 std::lock_guard l(lock);
189 peer_clock_delta_lb = peer_send_stamp - now;
190 peer_clock_delta_ub = delta_ub;
191 }
192
193 private:
194 FRIEND_MAKE_REF(HeartbeatStamps);
195 HeartbeatStamps(int o)
196 : RefCountedObject(NULL),
197 osd(o) {}
198 };
199 using HeartbeatStampsRef = ceph::ref_t<HeartbeatStamps>;
200
201 inline std::ostream& operator<<(std::ostream& out, const HeartbeatStamps& hb)
202 {
203 hb.print(out);
204 return out;
205 }
206
207
208 struct PeeringCtx : BufferedRecoveryMessages {
209 ObjectStore::Transaction transaction;
210 HBHandle* handle = nullptr;
211
212 PeeringCtx() = default;
213
214 PeeringCtx(const PeeringCtx &) = delete;
215 PeeringCtx &operator=(const PeeringCtx &) = delete;
216
217 PeeringCtx(PeeringCtx &&) = default;
218 PeeringCtx &operator=(PeeringCtx &&) = default;
219
220 void reset_transaction() {
221 transaction = ObjectStore::Transaction();
222 }
223 };
224
225 /**
226 * Wraps PeeringCtx to hide the difference between buffering messages to
227 * be sent after flush or immediately.
228 */
229 struct PeeringCtxWrapper {
230 utime_t start_time;
231 BufferedRecoveryMessages &msgs;
232 ObjectStore::Transaction &transaction;
233 HBHandle * const handle = nullptr;
234
235 PeeringCtxWrapper(PeeringCtx &wrapped) :
236 msgs(wrapped),
237 transaction(wrapped.transaction),
238 handle(wrapped.handle) {}
239
240 PeeringCtxWrapper(BufferedRecoveryMessages &buf, PeeringCtx &wrapped)
241 : msgs(buf),
242 transaction(wrapped.transaction),
243 handle(wrapped.handle) {}
244
245 PeeringCtxWrapper(PeeringCtxWrapper &&ctx) = default;
246
247 template <class MsgT> // MsgT = MessageRef for ceph-osd and MessageURef for crimson-osd
248 void send_osd_message(int target, MsgT&& m) {
249 msgs.send_osd_message(target, std::forward<MsgT>(m));
250 }
251 void send_notify(int to, const pg_notify_t &n) {
252 msgs.send_notify(to, n);
253 }
254 void send_query(int to, spg_t spgid, const pg_query_t &q) {
255 msgs.send_query(to, spgid, q);
256 }
257 void send_info(int to, spg_t to_spgid,
258 epoch_t min_epoch, epoch_t cur_epoch,
259 const pg_info_t &info,
260 std::optional<pg_lease_t> lease = {},
261 std::optional<pg_lease_ack_t> lease_ack = {}) {
262 msgs.send_info(to, to_spgid, min_epoch, cur_epoch, info,
263 lease, lease_ack);
264 }
265 };
266
267 /* Encapsulates PG recovery process */
268 class PeeringState : public MissingLoc::MappingInfo {
269 public:
270 struct PeeringListener : public EpochSource {
271 /// Prepare t with written information
272 virtual void prepare_write(
273 pg_info_t &info,
274 pg_info_t &last_written_info,
275 PastIntervals &past_intervals,
276 PGLog &pglog,
277 bool dirty_info,
278 bool dirty_big_info,
279 bool need_write_epoch,
280 ObjectStore::Transaction &t) = 0;
281
282 /// Notify that info/history changed (generally to update scrub registration)
283 virtual void on_info_history_change() = 0;
284
285 /// Notify PG that Primary/Replica status has changed (to update scrub registration)
286 virtual void on_primary_status_change(bool was_primary, bool now_primary) = 0;
287
288 /// Need to reschedule next scrub. Assuming no change in role
289 virtual void reschedule_scrub() = 0;
290
291 /// Notify that a scrub has been requested
292 virtual void scrub_requested(scrub_level_t scrub_level, scrub_type_t scrub_type) = 0;
293
294 /// Return current snap_trimq size
295 virtual uint64_t get_snap_trimq_size() const = 0;
296
297 /// Send cluster message to osd
298 #if defined(WITH_SEASTAR)
299 virtual void send_cluster_message(
300 int osd, MessageURef m, epoch_t epoch, bool share_map_update=false) = 0;
301 #else
302 virtual void send_cluster_message(
303 int osd, MessageRef m, epoch_t epoch, bool share_map_update=false) = 0;
304 #endif
305 /// Send pg_created to mon
306 virtual void send_pg_created(pg_t pgid) = 0;
307
308 virtual ceph::signedspan get_mnow() const = 0;
309 virtual HeartbeatStampsRef get_hb_stamps(int peer) = 0;
310 virtual void schedule_renew_lease(epoch_t plr, ceph::timespan delay) = 0;
311 virtual void queue_check_readable(epoch_t lpr, ceph::timespan delay) = 0;
312 virtual void recheck_readable() = 0;
313
314 virtual unsigned get_target_pg_log_entries() const = 0;
315
316 // ============ Flush state ==================
317 /**
318 * try_flush_or_schedule_async()
319 *
320 * If true, caller may assume all past operations on this pg
321 * have been flushed. Else, caller will receive an on_flushed()
322 * call once the flush has completed.
323 */
324 virtual bool try_flush_or_schedule_async() = 0;
325 /// Arranges for a commit on t to call on_flushed() once flushed.
326 virtual void start_flush_on_transaction(
327 ObjectStore::Transaction &t) = 0;
328 /// Notification that all outstanding flushes for interval have completed
329 virtual void on_flushed() = 0;
330
331 //============= Recovery ====================
332 /// Arrange for even to be queued after delay
333 virtual void schedule_event_after(
334 PGPeeringEventRef event,
335 float delay) = 0;
336 /**
337 * request_local_background_io_reservation
338 *
339 * Request reservation at priority with on_grant queued on grant
340 * and on_preempt on preempt
341 */
342 virtual void request_local_background_io_reservation(
343 unsigned priority,
344 PGPeeringEventURef on_grant,
345 PGPeeringEventURef on_preempt) = 0;
346 /// Modify pending local background reservation request priority
347 virtual void update_local_background_io_priority(
348 unsigned priority) = 0;
349 /// Cancel pending local background reservation request
350 virtual void cancel_local_background_io_reservation() = 0;
351
352 /**
353 * request_remote_background_io_reservation
354 *
355 * Request reservation at priority with on_grant queued on grant
356 * and on_preempt on preempt
357 */
358 virtual void request_remote_recovery_reservation(
359 unsigned priority,
360 PGPeeringEventURef on_grant,
361 PGPeeringEventURef on_preempt) = 0;
362 /// Cancel pending remote background reservation request
363 virtual void cancel_remote_recovery_reservation() = 0;
364
365 /// Arrange for on_commit to be queued upon commit of t
366 virtual void schedule_event_on_commit(
367 ObjectStore::Transaction &t,
368 PGPeeringEventRef on_commit) = 0;
369
370 //============================ HB =============================
371 /// Update hb set to peers
372 virtual void update_heartbeat_peers(std::set<int> peers) = 0;
373
374 /// Std::set targets being probed in this interval
375 virtual void set_probe_targets(const std::set<pg_shard_t> &probe_set) = 0;
376 /// Clear targets being probed in this interval
377 virtual void clear_probe_targets() = 0;
378
379 /// Queue for a pg_temp of wanted
380 virtual void queue_want_pg_temp(const std::vector<int> &wanted) = 0;
381 /// Clear queue for a pg_temp of wanted
382 virtual void clear_want_pg_temp() = 0;
383
384 /// Arrange for stats to be shipped to mon to be updated for this pg
385 virtual void publish_stats_to_osd() = 0;
386 /// Clear stats to be shipped to mon for this pg
387 virtual void clear_publish_stats() = 0;
388
389 /// Notification to check outstanding operation targets
390 virtual void check_recovery_sources(const OSDMapRef& newmap) = 0;
391 /// Notification to check outstanding blocklist
392 virtual void check_blocklisted_watchers() = 0;
393 /// Notification to clear state associated with primary
394 virtual void clear_primary_state() = 0;
395
396 // =================== Event notification ====================
397 virtual void on_pool_change() = 0;
398 virtual void on_role_change() = 0;
399 virtual void on_change(ObjectStore::Transaction &t) = 0;
400 virtual void on_activate(interval_set<snapid_t> to_trim) = 0;
401 virtual void on_activate_complete() = 0;
402 virtual void on_new_interval() = 0;
403 virtual Context *on_clean() = 0;
404 virtual void on_activate_committed() = 0;
405 virtual void on_active_exit() = 0;
406
407 // ====================== PG deletion =======================
408 /// Notification of removal complete, t must be populated to complete removal
409 virtual void on_removal(ObjectStore::Transaction &t) = 0;
410 /// Perform incremental removal work
411 virtual std::pair<ghobject_t, bool> do_delete_work(
412 ObjectStore::Transaction &t, ghobject_t _next) = 0;
413
414 // ======================= PG Merge =========================
415 virtual void clear_ready_to_merge() = 0;
416 virtual void set_not_ready_to_merge_target(pg_t pgid, pg_t src) = 0;
417 virtual void set_not_ready_to_merge_source(pg_t pgid) = 0;
418 virtual void set_ready_to_merge_target(eversion_t lu, epoch_t les, epoch_t lec) = 0;
419 virtual void set_ready_to_merge_source(eversion_t lu) = 0;
420
421 // ==================== Std::map notifications ===================
422 virtual void on_active_actmap() = 0;
423 virtual void on_active_advmap(const OSDMapRef &osdmap) = 0;
424 virtual epoch_t cluster_osdmap_trim_lower_bound() = 0;
425
426 // ============ recovery reservation notifications ==========
427 virtual void on_backfill_reserved() = 0;
428 virtual void on_backfill_canceled() = 0;
429 virtual void on_recovery_reserved() = 0;
430
431 // ================recovery space accounting ================
432 virtual bool try_reserve_recovery_space(
433 int64_t primary_num_bytes, int64_t local_num_bytes) = 0;
434 virtual void unreserve_recovery_space() = 0;
435
436 // ================== Peering log events ====================
437 /// Get handler for rolling forward/back log entries
438 virtual PGLog::LogEntryHandlerRef get_log_handler(
439 ObjectStore::Transaction &t) = 0;
440
441 // ============ On disk representation changes ==============
442 virtual void rebuild_missing_set_with_deletes(PGLog &pglog) = 0;
443
444 // ======================= Logging ==========================
445 virtual PerfCounters &get_peering_perf() = 0;
446 virtual PerfCounters &get_perf_logger() = 0;
447 virtual void log_state_enter(const char *state) = 0;
448 virtual void log_state_exit(
449 const char *state_name, utime_t enter_time,
450 uint64_t events, utime_t event_dur) = 0;
451 virtual void dump_recovery_info(ceph::Formatter *f) const = 0;
452
453 virtual OstreamTemp get_clog_info() = 0;
454 virtual OstreamTemp get_clog_error() = 0;
455 virtual OstreamTemp get_clog_debug() = 0;
456
457 virtual ~PeeringListener() {}
458 };
459
460 struct QueryState : boost::statechart::event< QueryState > {
461 ceph::Formatter *f;
462 explicit QueryState(ceph::Formatter *f) : f(f) {}
463 void print(std::ostream *out) const {
464 *out << "Query";
465 }
466 };
467
468 struct QueryUnfound : boost::statechart::event< QueryUnfound > {
469 ceph::Formatter *f;
470 explicit QueryUnfound(ceph::Formatter *f) : f(f) {}
471 void print(std::ostream *out) const {
472 *out << "QueryUnfound";
473 }
474 };
475
476 struct AdvMap : boost::statechart::event< AdvMap > {
477 OSDMapRef osdmap;
478 OSDMapRef lastmap;
479 std::vector<int> newup, newacting;
480 int up_primary, acting_primary;
481 AdvMap(
482 OSDMapRef osdmap, OSDMapRef lastmap,
483 std::vector<int>& newup, int up_primary,
484 std::vector<int>& newacting, int acting_primary):
485 osdmap(osdmap), lastmap(lastmap),
486 newup(newup),
487 newacting(newacting),
488 up_primary(up_primary),
489 acting_primary(acting_primary) {}
490 void print(std::ostream *out) const {
491 *out << "AdvMap";
492 }
493 };
494
495 struct ActMap : boost::statechart::event< ActMap > {
496 ActMap() : boost::statechart::event< ActMap >() {}
497 void print(std::ostream *out) const {
498 *out << "ActMap";
499 }
500 };
501 struct Activate : boost::statechart::event< Activate > {
502 epoch_t activation_epoch;
503 explicit Activate(epoch_t q) : boost::statechart::event< Activate >(),
504 activation_epoch(q) {}
505 void print(std::ostream *out) const {
506 *out << "Activate from " << activation_epoch;
507 }
508 };
509 struct ActivateCommitted : boost::statechart::event< ActivateCommitted > {
510 epoch_t epoch;
511 epoch_t activation_epoch;
512 explicit ActivateCommitted(epoch_t e, epoch_t ae)
513 : boost::statechart::event< ActivateCommitted >(),
514 epoch(e),
515 activation_epoch(ae) {}
516 void print(std::ostream *out) const {
517 *out << "ActivateCommitted from " << activation_epoch
518 << " processed at " << epoch;
519 }
520 };
521 public:
522 struct UnfoundBackfill : boost::statechart::event<UnfoundBackfill> {
523 explicit UnfoundBackfill() {}
524 void print(std::ostream *out) const {
525 *out << "UnfoundBackfill";
526 }
527 };
528 struct UnfoundRecovery : boost::statechart::event<UnfoundRecovery> {
529 explicit UnfoundRecovery() {}
530 void print(std::ostream *out) const {
531 *out << "UnfoundRecovery";
532 }
533 };
534
535 struct RequestScrub : boost::statechart::event<RequestScrub> {
536 scrub_level_t deep;
537 scrub_type_t repair;
538 explicit RequestScrub(bool d, bool r) : deep(scrub_level_t(d)), repair(scrub_type_t(r)) {}
539 void print(std::ostream *out) const {
540 *out << "RequestScrub(" << ((deep==scrub_level_t::deep) ? "deep" : "shallow")
541 << ((repair==scrub_type_t::do_repair) ? " repair)" : ")");
542 }
543 };
544
545 TrivialEvent(Initialize)
546 TrivialEvent(GotInfo)
547 TrivialEvent(NeedUpThru)
548 TrivialEvent(Backfilled)
549 TrivialEvent(LocalBackfillReserved)
550 TrivialEvent(RejectTooFullRemoteReservation)
551 TrivialEvent(RequestBackfill)
552 TrivialEvent(RemoteRecoveryPreempted)
553 TrivialEvent(RemoteBackfillPreempted)
554 TrivialEvent(BackfillTooFull)
555 TrivialEvent(RecoveryTooFull)
556
557 TrivialEvent(MakePrimary)
558 TrivialEvent(MakeStray)
559 TrivialEvent(NeedActingChange)
560 TrivialEvent(IsIncomplete)
561 TrivialEvent(IsDown)
562
563 TrivialEvent(AllReplicasRecovered)
564 TrivialEvent(DoRecovery)
565 TrivialEvent(LocalRecoveryReserved)
566 TrivialEvent(AllRemotesReserved)
567 TrivialEvent(AllBackfillsReserved)
568 TrivialEvent(GoClean)
569
570 TrivialEvent(AllReplicasActivated)
571
572 TrivialEvent(IntervalFlush)
573
574 TrivialEvent(DeleteStart)
575 TrivialEvent(DeleteSome)
576
577 TrivialEvent(SetForceRecovery)
578 TrivialEvent(UnsetForceRecovery)
579 TrivialEvent(SetForceBackfill)
580 TrivialEvent(UnsetForceBackfill)
581
582 TrivialEvent(DeleteReserved)
583 TrivialEvent(DeleteInterrupted)
584
585 TrivialEvent(CheckReadable)
586
587 void start_handle(PeeringCtx *new_ctx);
588 void end_handle();
589 void begin_block_outgoing();
590 void end_block_outgoing();
591 void clear_blocked_outgoing();
592 private:
593
594 /* States */
595 struct Initial;
596 class PeeringMachine : public boost::statechart::state_machine< PeeringMachine, Initial > {
597 public:
598 PeeringState *state;
599 PGStateHistory *state_history;
600 CephContext *cct;
601 spg_t spgid;
602 DoutPrefixProvider *dpp;
603 PeeringListener *pl;
604
605 utime_t event_time;
606 uint64_t event_count;
607
608 void clear_event_counters() {
609 event_time = utime_t();
610 event_count = 0;
611 }
612
613 void log_enter(const char *state_name);
614 void log_exit(const char *state_name, utime_t duration);
615
616 PeeringMachine(
617 PeeringState *state, CephContext *cct,
618 spg_t spgid,
619 DoutPrefixProvider *dpp,
620 PeeringListener *pl,
621 PGStateHistory *state_history) :
622 state(state),
623 state_history(state_history),
624 cct(cct), spgid(spgid),
625 dpp(dpp), pl(pl),
626 event_count(0) {}
627
628 /* Accessor functions for state methods */
629 ObjectStore::Transaction& get_cur_transaction() {
630 ceph_assert(state->rctx);
631 return state->rctx->transaction;
632 }
633
634 PeeringCtxWrapper &get_recovery_ctx() {
635 assert(state->rctx);
636 return *(state->rctx);
637 }
638
639 void send_notify(int to, const pg_notify_t &n) {
640 ceph_assert(state->rctx);
641 state->rctx->send_notify(to, n);
642 }
643 void send_query(int to, const pg_query_t &query) {
644 state->rctx->send_query(
645 to,
646 spg_t(spgid.pgid, query.to),
647 query);
648 }
649 };
650 friend class PeeringMachine;
651
652 /* States */
653 // Initial
654 // Reset
655 // Start
656 // Started
657 // Primary
658 // WaitActingChange
659 // Peering
660 // GetInfo
661 // GetLog
662 // GetMissing
663 // WaitUpThru
664 // Incomplete
665 // Active
666 // Activating
667 // Clean
668 // Recovered
669 // Backfilling
670 // WaitRemoteBackfillReserved
671 // WaitLocalBackfillReserved
672 // NotBackfilling
673 // NotRecovering
674 // Recovering
675 // WaitRemoteRecoveryReserved
676 // WaitLocalRecoveryReserved
677 // ReplicaActive
678 // RepNotRecovering
679 // RepRecovering
680 // RepWaitBackfillReserved
681 // RepWaitRecoveryReserved
682 // Stray
683 // ToDelete
684 // WaitDeleteReserved
685 // Deleting
686 // Crashed
687
688 struct Crashed : boost::statechart::state< Crashed, PeeringMachine >, NamedState {
689 explicit Crashed(my_context ctx);
690 };
691
692 struct Reset;
693
694 struct Initial : boost::statechart::state< Initial, PeeringMachine >, NamedState {
695 explicit Initial(my_context ctx);
696 void exit();
697
698 typedef boost::mpl::list <
699 boost::statechart::transition< Initialize, Reset >,
700 boost::statechart::custom_reaction< NullEvt >,
701 boost::statechart::transition< boost::statechart::event_base, Crashed >
702 > reactions;
703
704 boost::statechart::result react(const MNotifyRec&);
705 boost::statechart::result react(const MInfoRec&);
706 boost::statechart::result react(const MLogRec&);
707 boost::statechart::result react(const boost::statechart::event_base&) {
708 return discard_event();
709 }
710 };
711
712 struct Reset : boost::statechart::state< Reset, PeeringMachine >, NamedState {
713 explicit Reset(my_context ctx);
714 void exit();
715
716 typedef boost::mpl::list <
717 boost::statechart::custom_reaction< QueryState >,
718 boost::statechart::custom_reaction< QueryUnfound >,
719 boost::statechart::custom_reaction< AdvMap >,
720 boost::statechart::custom_reaction< ActMap >,
721 boost::statechart::custom_reaction< NullEvt >,
722 boost::statechart::custom_reaction< IntervalFlush >,
723 boost::statechart::transition< boost::statechart::event_base, Crashed >
724 > reactions;
725 boost::statechart::result react(const QueryState& q);
726 boost::statechart::result react(const QueryUnfound& q);
727 boost::statechart::result react(const AdvMap&);
728 boost::statechart::result react(const ActMap&);
729 boost::statechart::result react(const IntervalFlush&);
730 boost::statechart::result react(const boost::statechart::event_base&) {
731 return discard_event();
732 }
733 };
734
735 struct Start;
736
737 struct Started : boost::statechart::state< Started, PeeringMachine, Start >, NamedState {
738 explicit Started(my_context ctx);
739 void exit();
740
741 typedef boost::mpl::list <
742 boost::statechart::custom_reaction< QueryState >,
743 boost::statechart::custom_reaction< QueryUnfound >,
744 boost::statechart::custom_reaction< AdvMap >,
745 boost::statechart::custom_reaction< IntervalFlush >,
746 // ignored
747 boost::statechart::custom_reaction< NullEvt >,
748 boost::statechart::custom_reaction<SetForceRecovery>,
749 boost::statechart::custom_reaction<UnsetForceRecovery>,
750 boost::statechart::custom_reaction<SetForceBackfill>,
751 boost::statechart::custom_reaction<UnsetForceBackfill>,
752 boost::statechart::custom_reaction<RequestScrub>,
753 boost::statechart::custom_reaction<CheckReadable>,
754 // crash
755 boost::statechart::transition< boost::statechart::event_base, Crashed >
756 > reactions;
757 boost::statechart::result react(const QueryState& q);
758 boost::statechart::result react(const QueryUnfound& q);
759 boost::statechart::result react(const AdvMap&);
760 boost::statechart::result react(const IntervalFlush&);
761 boost::statechart::result react(const boost::statechart::event_base&) {
762 return discard_event();
763 }
764 };
765
766 struct Primary;
767 struct Stray;
768
769 struct Start : boost::statechart::state< Start, Started >, NamedState {
770 explicit Start(my_context ctx);
771 void exit();
772
773 typedef boost::mpl::list <
774 boost::statechart::transition< MakePrimary, Primary >,
775 boost::statechart::transition< MakeStray, Stray >
776 > reactions;
777 };
778
779 struct Peering;
780 struct WaitActingChange;
781 struct Incomplete;
782 struct Down;
783
784 struct Primary : boost::statechart::state< Primary, Started, Peering >, NamedState {
785 explicit Primary(my_context ctx);
786 void exit();
787
788 typedef boost::mpl::list <
789 boost::statechart::custom_reaction< ActMap >,
790 boost::statechart::custom_reaction< MNotifyRec >,
791 boost::statechart::custom_reaction<SetForceRecovery>,
792 boost::statechart::custom_reaction<UnsetForceRecovery>,
793 boost::statechart::custom_reaction<SetForceBackfill>,
794 boost::statechart::custom_reaction<UnsetForceBackfill>,
795 boost::statechart::custom_reaction<RequestScrub>
796 > reactions;
797 boost::statechart::result react(const ActMap&);
798 boost::statechart::result react(const MNotifyRec&);
799 boost::statechart::result react(const SetForceRecovery&);
800 boost::statechart::result react(const UnsetForceRecovery&);
801 boost::statechart::result react(const SetForceBackfill&);
802 boost::statechart::result react(const UnsetForceBackfill&);
803 boost::statechart::result react(const RequestScrub&);
804 };
805
806 struct WaitActingChange : boost::statechart::state< WaitActingChange, Primary>,
807 NamedState {
808 typedef boost::mpl::list <
809 boost::statechart::custom_reaction< QueryState >,
810 boost::statechart::custom_reaction< QueryUnfound >,
811 boost::statechart::custom_reaction< AdvMap >,
812 boost::statechart::custom_reaction< MLogRec >,
813 boost::statechart::custom_reaction< MInfoRec >,
814 boost::statechart::custom_reaction< MNotifyRec >
815 > reactions;
816 explicit WaitActingChange(my_context ctx);
817 boost::statechart::result react(const QueryState& q);
818 boost::statechart::result react(const QueryUnfound& q);
819 boost::statechart::result react(const AdvMap&);
820 boost::statechart::result react(const MLogRec&);
821 boost::statechart::result react(const MInfoRec&);
822 boost::statechart::result react(const MNotifyRec&);
823 void exit();
824 };
825
826 struct GetInfo;
827 struct Active;
828
829 struct Peering : boost::statechart::state< Peering, Primary, GetInfo >, NamedState {
830 PastIntervals::PriorSet prior_set;
831 bool history_les_bound; //< need osd_find_best_info_ignore_history_les
832
833 explicit Peering(my_context ctx);
834 void exit();
835
836 typedef boost::mpl::list <
837 boost::statechart::custom_reaction< QueryState >,
838 boost::statechart::custom_reaction< QueryUnfound >,
839 boost::statechart::transition< Activate, Active >,
840 boost::statechart::custom_reaction< AdvMap >
841 > reactions;
842 boost::statechart::result react(const QueryState& q);
843 boost::statechart::result react(const QueryUnfound& q);
844 boost::statechart::result react(const AdvMap &advmap);
845 };
846
847 struct WaitLocalRecoveryReserved;
848 struct Activating;
849 struct Active : boost::statechart::state< Active, Primary, Activating >, NamedState {
850 explicit Active(my_context ctx);
851 void exit();
852
853 const std::set<pg_shard_t> remote_shards_to_reserve_recovery;
854 const std::set<pg_shard_t> remote_shards_to_reserve_backfill;
855 bool all_replicas_activated;
856
857 typedef boost::mpl::list <
858 boost::statechart::custom_reaction< QueryState >,
859 boost::statechart::custom_reaction< QueryUnfound >,
860 boost::statechart::custom_reaction< ActMap >,
861 boost::statechart::custom_reaction< AdvMap >,
862 boost::statechart::custom_reaction< MInfoRec >,
863 boost::statechart::custom_reaction< MNotifyRec >,
864 boost::statechart::custom_reaction< MLogRec >,
865 boost::statechart::custom_reaction< MTrim >,
866 boost::statechart::custom_reaction< Backfilled >,
867 boost::statechart::custom_reaction< ActivateCommitted >,
868 boost::statechart::custom_reaction< AllReplicasActivated >,
869 boost::statechart::custom_reaction< DeferRecovery >,
870 boost::statechart::custom_reaction< DeferBackfill >,
871 boost::statechart::custom_reaction< UnfoundRecovery >,
872 boost::statechart::custom_reaction< UnfoundBackfill >,
873 boost::statechart::custom_reaction< RemoteReservationRevokedTooFull>,
874 boost::statechart::custom_reaction< RemoteReservationRevoked>,
875 boost::statechart::custom_reaction< DoRecovery>,
876 boost::statechart::custom_reaction< RenewLease>,
877 boost::statechart::custom_reaction< MLeaseAck>,
878 boost::statechart::custom_reaction< CheckReadable>
879 > reactions;
880 boost::statechart::result react(const QueryState& q);
881 boost::statechart::result react(const QueryUnfound& q);
882 boost::statechart::result react(const ActMap&);
883 boost::statechart::result react(const AdvMap&);
884 boost::statechart::result react(const MInfoRec& infoevt);
885 boost::statechart::result react(const MNotifyRec& notevt);
886 boost::statechart::result react(const MLogRec& logevt);
887 boost::statechart::result react(const MTrim& trimevt);
888 boost::statechart::result react(const Backfilled&) {
889 return discard_event();
890 }
891 boost::statechart::result react(const ActivateCommitted&);
892 boost::statechart::result react(const AllReplicasActivated&);
893 boost::statechart::result react(const RenewLease&);
894 boost::statechart::result react(const MLeaseAck&);
895 boost::statechart::result react(const DeferRecovery& evt) {
896 return discard_event();
897 }
898 boost::statechart::result react(const DeferBackfill& evt) {
899 return discard_event();
900 }
901 boost::statechart::result react(const UnfoundRecovery& evt) {
902 return discard_event();
903 }
904 boost::statechart::result react(const UnfoundBackfill& evt) {
905 return discard_event();
906 }
907 boost::statechart::result react(const RemoteReservationRevokedTooFull&) {
908 return discard_event();
909 }
910 boost::statechart::result react(const RemoteReservationRevoked&) {
911 return discard_event();
912 }
913 boost::statechart::result react(const DoRecovery&) {
914 return discard_event();
915 }
916 boost::statechart::result react(const CheckReadable&);
917 void all_activated_and_committed();
918 };
919
920 struct Clean : boost::statechart::state< Clean, Active >, NamedState {
921 typedef boost::mpl::list<
922 boost::statechart::transition< DoRecovery, WaitLocalRecoveryReserved >,
923 boost::statechart::custom_reaction<SetForceRecovery>,
924 boost::statechart::custom_reaction<SetForceBackfill>
925 > reactions;
926 explicit Clean(my_context ctx);
927 void exit();
928 boost::statechart::result react(const boost::statechart::event_base&) {
929 return discard_event();
930 }
931 };
932
933 struct Recovered : boost::statechart::state< Recovered, Active >, NamedState {
934 typedef boost::mpl::list<
935 boost::statechart::transition< GoClean, Clean >,
936 boost::statechart::transition< DoRecovery, WaitLocalRecoveryReserved >,
937 boost::statechart::custom_reaction< AllReplicasActivated >
938 > reactions;
939 explicit Recovered(my_context ctx);
940 void exit();
941 boost::statechart::result react(const AllReplicasActivated&) {
942 post_event(GoClean());
943 return forward_event();
944 }
945 };
946
947 struct Backfilling : boost::statechart::state< Backfilling, Active >, NamedState {
948 typedef boost::mpl::list<
949 boost::statechart::custom_reaction< Backfilled >,
950 boost::statechart::custom_reaction< DeferBackfill >,
951 boost::statechart::custom_reaction< UnfoundBackfill >,
952 boost::statechart::custom_reaction< RemoteReservationRejectedTooFull >,
953 boost::statechart::custom_reaction< RemoteReservationRevokedTooFull>,
954 boost::statechart::custom_reaction< RemoteReservationRevoked>
955 > reactions;
956 explicit Backfilling(my_context ctx);
957 boost::statechart::result react(const RemoteReservationRejectedTooFull& evt) {
958 // for compat with old peers
959 post_event(RemoteReservationRevokedTooFull());
960 return discard_event();
961 }
962 void backfill_release_reservations();
963 boost::statechart::result react(const Backfilled& evt);
964 boost::statechart::result react(const RemoteReservationRevokedTooFull& evt);
965 boost::statechart::result react(const RemoteReservationRevoked& evt);
966 boost::statechart::result react(const DeferBackfill& evt);
967 boost::statechart::result react(const UnfoundBackfill& evt);
968 void cancel_backfill();
969 void exit();
970 };
971
972 struct WaitRemoteBackfillReserved : boost::statechart::state< WaitRemoteBackfillReserved, Active >, NamedState {
973 typedef boost::mpl::list<
974 boost::statechart::custom_reaction< RemoteBackfillReserved >,
975 boost::statechart::custom_reaction< RemoteReservationRejectedTooFull >,
976 boost::statechart::custom_reaction< RemoteReservationRevoked >,
977 boost::statechart::transition< AllBackfillsReserved, Backfilling >
978 > reactions;
979 std::set<pg_shard_t>::const_iterator backfill_osd_it;
980 explicit WaitRemoteBackfillReserved(my_context ctx);
981 void retry();
982 void exit();
983 boost::statechart::result react(const RemoteBackfillReserved& evt);
984 boost::statechart::result react(const RemoteReservationRejectedTooFull& evt);
985 boost::statechart::result react(const RemoteReservationRevoked& evt);
986 };
987
988 struct WaitLocalBackfillReserved : boost::statechart::state< WaitLocalBackfillReserved, Active >, NamedState {
989 typedef boost::mpl::list<
990 boost::statechart::transition< LocalBackfillReserved, WaitRemoteBackfillReserved >,
991 boost::statechart::custom_reaction< RemoteBackfillReserved >
992 > reactions;
993 explicit WaitLocalBackfillReserved(my_context ctx);
994 boost::statechart::result react(const RemoteBackfillReserved& evt) {
995 /* no-op */
996 return discard_event();
997 }
998 void exit();
999 };
1000
1001 struct NotBackfilling : boost::statechart::state< NotBackfilling, Active>, NamedState {
1002 typedef boost::mpl::list<
1003 boost::statechart::custom_reaction< QueryUnfound >,
1004 boost::statechart::transition< RequestBackfill, WaitLocalBackfillReserved>,
1005 boost::statechart::custom_reaction< RemoteBackfillReserved >,
1006 boost::statechart::custom_reaction< RemoteReservationRejectedTooFull >
1007 > reactions;
1008 explicit NotBackfilling(my_context ctx);
1009 void exit();
1010 boost::statechart::result react(const QueryUnfound& q);
1011 boost::statechart::result react(const RemoteBackfillReserved& evt);
1012 boost::statechart::result react(const RemoteReservationRejectedTooFull& evt);
1013 };
1014
1015 struct NotRecovering : boost::statechart::state< NotRecovering, Active>, NamedState {
1016 typedef boost::mpl::list<
1017 boost::statechart::custom_reaction< QueryUnfound >,
1018 boost::statechart::transition< DoRecovery, WaitLocalRecoveryReserved >,
1019 boost::statechart::custom_reaction< DeferRecovery >,
1020 boost::statechart::custom_reaction< UnfoundRecovery >
1021 > reactions;
1022 explicit NotRecovering(my_context ctx);
1023 boost::statechart::result react(const QueryUnfound& q);
1024 boost::statechart::result react(const DeferRecovery& evt) {
1025 /* no-op */
1026 return discard_event();
1027 }
1028 boost::statechart::result react(const UnfoundRecovery& evt) {
1029 /* no-op */
1030 return discard_event();
1031 }
1032 void exit();
1033 };
1034
1035 struct ToDelete;
1036 struct RepNotRecovering;
1037 struct ReplicaActive : boost::statechart::state< ReplicaActive, Started, RepNotRecovering >, NamedState {
1038 explicit ReplicaActive(my_context ctx);
1039 void exit();
1040
1041 typedef boost::mpl::list <
1042 boost::statechart::custom_reaction< QueryState >,
1043 boost::statechart::custom_reaction< QueryUnfound >,
1044 boost::statechart::custom_reaction< ActMap >,
1045 boost::statechart::custom_reaction< MQuery >,
1046 boost::statechart::custom_reaction< MInfoRec >,
1047 boost::statechart::custom_reaction< MLogRec >,
1048 boost::statechart::custom_reaction< MTrim >,
1049 boost::statechart::custom_reaction< Activate >,
1050 boost::statechart::custom_reaction< ActivateCommitted >,
1051 boost::statechart::custom_reaction< DeferRecovery >,
1052 boost::statechart::custom_reaction< DeferBackfill >,
1053 boost::statechart::custom_reaction< UnfoundRecovery >,
1054 boost::statechart::custom_reaction< UnfoundBackfill >,
1055 boost::statechart::custom_reaction< RemoteBackfillPreempted >,
1056 boost::statechart::custom_reaction< RemoteRecoveryPreempted >,
1057 boost::statechart::custom_reaction< RecoveryDone >,
1058 boost::statechart::transition<DeleteStart, ToDelete>,
1059 boost::statechart::custom_reaction< MLease >
1060 > reactions;
1061 boost::statechart::result react(const QueryState& q);
1062 boost::statechart::result react(const QueryUnfound& q);
1063 boost::statechart::result react(const MInfoRec& infoevt);
1064 boost::statechart::result react(const MLogRec& logevt);
1065 boost::statechart::result react(const MTrim& trimevt);
1066 boost::statechart::result react(const ActMap&);
1067 boost::statechart::result react(const MQuery&);
1068 boost::statechart::result react(const Activate&);
1069 boost::statechart::result react(const ActivateCommitted&);
1070 boost::statechart::result react(const MLease&);
1071 boost::statechart::result react(const RecoveryDone&) {
1072 return discard_event();
1073 }
1074 boost::statechart::result react(const DeferRecovery& evt) {
1075 return discard_event();
1076 }
1077 boost::statechart::result react(const DeferBackfill& evt) {
1078 return discard_event();
1079 }
1080 boost::statechart::result react(const UnfoundRecovery& evt) {
1081 return discard_event();
1082 }
1083 boost::statechart::result react(const UnfoundBackfill& evt) {
1084 return discard_event();
1085 }
1086 boost::statechart::result react(const RemoteBackfillPreempted& evt) {
1087 return discard_event();
1088 }
1089 boost::statechart::result react(const RemoteRecoveryPreempted& evt) {
1090 return discard_event();
1091 }
1092 };
1093
1094 struct RepRecovering : boost::statechart::state< RepRecovering, ReplicaActive >, NamedState {
1095 typedef boost::mpl::list<
1096 boost::statechart::transition< RecoveryDone, RepNotRecovering >,
1097 // for compat with old peers
1098 boost::statechart::transition< RemoteReservationRejectedTooFull, RepNotRecovering >,
1099 boost::statechart::transition< RemoteReservationCanceled, RepNotRecovering >,
1100 boost::statechart::custom_reaction< BackfillTooFull >,
1101 boost::statechart::custom_reaction< RemoteRecoveryPreempted >,
1102 boost::statechart::custom_reaction< RemoteBackfillPreempted >
1103 > reactions;
1104 explicit RepRecovering(my_context ctx);
1105 boost::statechart::result react(const RemoteRecoveryPreempted &evt);
1106 boost::statechart::result react(const BackfillTooFull &evt);
1107 boost::statechart::result react(const RemoteBackfillPreempted &evt);
1108 void exit();
1109 };
1110
1111 struct RepWaitBackfillReserved : boost::statechart::state< RepWaitBackfillReserved, ReplicaActive >, NamedState {
1112 typedef boost::mpl::list<
1113 boost::statechart::custom_reaction< RemoteBackfillReserved >,
1114 boost::statechart::custom_reaction< RejectTooFullRemoteReservation >,
1115 boost::statechart::custom_reaction< RemoteReservationRejectedTooFull >,
1116 boost::statechart::custom_reaction< RemoteReservationCanceled >
1117 > reactions;
1118 explicit RepWaitBackfillReserved(my_context ctx);
1119 void exit();
1120 boost::statechart::result react(const RemoteBackfillReserved &evt);
1121 boost::statechart::result react(const RejectTooFullRemoteReservation &evt);
1122 boost::statechart::result react(const RemoteReservationRejectedTooFull &evt);
1123 boost::statechart::result react(const RemoteReservationCanceled &evt);
1124 };
1125
1126 struct RepWaitRecoveryReserved : boost::statechart::state< RepWaitRecoveryReserved, ReplicaActive >, NamedState {
1127 typedef boost::mpl::list<
1128 boost::statechart::custom_reaction< RemoteRecoveryReserved >,
1129 // for compat with old peers
1130 boost::statechart::custom_reaction< RemoteReservationRejectedTooFull >,
1131 boost::statechart::custom_reaction< RemoteReservationCanceled >
1132 > reactions;
1133 explicit RepWaitRecoveryReserved(my_context ctx);
1134 void exit();
1135 boost::statechart::result react(const RemoteRecoveryReserved &evt);
1136 boost::statechart::result react(const RemoteReservationRejectedTooFull &evt) {
1137 // for compat with old peers
1138 post_event(RemoteReservationCanceled());
1139 return discard_event();
1140 }
1141 boost::statechart::result react(const RemoteReservationCanceled &evt);
1142 };
1143
1144 struct RepNotRecovering : boost::statechart::state< RepNotRecovering, ReplicaActive>, NamedState {
1145 typedef boost::mpl::list<
1146 boost::statechart::custom_reaction< RequestRecoveryPrio >,
1147 boost::statechart::custom_reaction< RequestBackfillPrio >,
1148 boost::statechart::custom_reaction< RejectTooFullRemoteReservation >,
1149 boost::statechart::transition< RemoteReservationRejectedTooFull, RepNotRecovering >,
1150 boost::statechart::transition< RemoteReservationCanceled, RepNotRecovering >,
1151 boost::statechart::custom_reaction< RemoteRecoveryReserved >,
1152 boost::statechart::custom_reaction< RemoteBackfillReserved >,
1153 boost::statechart::transition< RecoveryDone, RepNotRecovering > // for compat with pre-reservation peers
1154 > reactions;
1155 explicit RepNotRecovering(my_context ctx);
1156 boost::statechart::result react(const RequestRecoveryPrio &evt);
1157 boost::statechart::result react(const RequestBackfillPrio &evt);
1158 boost::statechart::result react(const RemoteBackfillReserved &evt) {
1159 // my reservation completion raced with a RELEASE from primary
1160 return discard_event();
1161 }
1162 boost::statechart::result react(const RemoteRecoveryReserved &evt) {
1163 // my reservation completion raced with a RELEASE from primary
1164 return discard_event();
1165 }
1166 boost::statechart::result react(const RejectTooFullRemoteReservation &evt);
1167 void exit();
1168 };
1169
1170 struct Recovering : boost::statechart::state< Recovering, Active >, NamedState {
1171 typedef boost::mpl::list <
1172 boost::statechart::custom_reaction< AllReplicasRecovered >,
1173 boost::statechart::custom_reaction< DeferRecovery >,
1174 boost::statechart::custom_reaction< UnfoundRecovery >,
1175 boost::statechart::custom_reaction< RequestBackfill >
1176 > reactions;
1177 explicit Recovering(my_context ctx);
1178 void exit();
1179 void release_reservations(bool cancel = false);
1180 boost::statechart::result react(const AllReplicasRecovered &evt);
1181 boost::statechart::result react(const DeferRecovery& evt);
1182 boost::statechart::result react(const UnfoundRecovery& evt);
1183 boost::statechart::result react(const RequestBackfill &evt);
1184 };
1185
1186 struct WaitRemoteRecoveryReserved : boost::statechart::state< WaitRemoteRecoveryReserved, Active >, NamedState {
1187 typedef boost::mpl::list <
1188 boost::statechart::custom_reaction< RemoteRecoveryReserved >,
1189 boost::statechart::transition< AllRemotesReserved, Recovering >
1190 > reactions;
1191 std::set<pg_shard_t>::const_iterator remote_recovery_reservation_it;
1192 explicit WaitRemoteRecoveryReserved(my_context ctx);
1193 boost::statechart::result react(const RemoteRecoveryReserved &evt);
1194 void exit();
1195 };
1196
1197 struct WaitLocalRecoveryReserved : boost::statechart::state< WaitLocalRecoveryReserved, Active >, NamedState {
1198 typedef boost::mpl::list <
1199 boost::statechart::transition< LocalRecoveryReserved, WaitRemoteRecoveryReserved >,
1200 boost::statechart::custom_reaction< RecoveryTooFull >
1201 > reactions;
1202 explicit WaitLocalRecoveryReserved(my_context ctx);
1203 void exit();
1204 boost::statechart::result react(const RecoveryTooFull &evt);
1205 };
1206
1207 struct Activating : boost::statechart::state< Activating, Active >, NamedState {
1208 typedef boost::mpl::list <
1209 boost::statechart::transition< AllReplicasRecovered, Recovered >,
1210 boost::statechart::transition< DoRecovery, WaitLocalRecoveryReserved >,
1211 boost::statechart::transition< RequestBackfill, WaitLocalBackfillReserved >
1212 > reactions;
1213 explicit Activating(my_context ctx);
1214 void exit();
1215 };
1216
1217 struct Stray : boost::statechart::state< Stray, Started >,
1218 NamedState {
1219 explicit Stray(my_context ctx);
1220 void exit();
1221
1222 typedef boost::mpl::list <
1223 boost::statechart::custom_reaction< MQuery >,
1224 boost::statechart::custom_reaction< MLogRec >,
1225 boost::statechart::custom_reaction< MInfoRec >,
1226 boost::statechart::custom_reaction< ActMap >,
1227 boost::statechart::custom_reaction< RecoveryDone >,
1228 boost::statechart::transition<DeleteStart, ToDelete>
1229 > reactions;
1230 boost::statechart::result react(const MQuery& query);
1231 boost::statechart::result react(const MLogRec& logevt);
1232 boost::statechart::result react(const MInfoRec& infoevt);
1233 boost::statechart::result react(const ActMap&);
1234 boost::statechart::result react(const RecoveryDone&) {
1235 return discard_event();
1236 }
1237 };
1238
1239 struct WaitDeleteReserved;
1240 struct ToDelete : boost::statechart::state<ToDelete, Started, WaitDeleteReserved>, NamedState {
1241 unsigned priority = 0;
1242 typedef boost::mpl::list <
1243 boost::statechart::custom_reaction< ActMap >,
1244 boost::statechart::custom_reaction< ActivateCommitted >,
1245 boost::statechart::custom_reaction< DeleteSome >
1246 > reactions;
1247 explicit ToDelete(my_context ctx);
1248 boost::statechart::result react(const ActMap &evt);
1249 boost::statechart::result react(const DeleteSome &evt) {
1250 // happens if we drop out of Deleting due to reprioritization etc.
1251 return discard_event();
1252 }
1253 boost::statechart::result react(const ActivateCommitted&) {
1254 // Can happens if we were activated as a stray but not actually pulled
1255 // from prior to the pg going clean and sending a delete.
1256 return discard_event();
1257 }
1258 void exit();
1259 };
1260
1261 struct Deleting;
1262 struct WaitDeleteReserved : boost::statechart::state<WaitDeleteReserved,
1263 ToDelete>, NamedState {
1264 typedef boost::mpl::list <
1265 boost::statechart::transition<DeleteReserved, Deleting>
1266 > reactions;
1267 explicit WaitDeleteReserved(my_context ctx);
1268 void exit();
1269 };
1270
1271 struct Deleting : boost::statechart::state<Deleting,
1272 ToDelete>, NamedState {
1273 typedef boost::mpl::list <
1274 boost::statechart::custom_reaction< DeleteSome >,
1275 boost::statechart::transition<DeleteInterrupted, WaitDeleteReserved>
1276 > reactions;
1277 ghobject_t next;
1278 explicit Deleting(my_context ctx);
1279 boost::statechart::result react(const DeleteSome &evt);
1280 void exit();
1281 };
1282
1283 struct GetLog;
1284
1285 struct GetInfo : boost::statechart::state< GetInfo, Peering >, NamedState {
1286 std::set<pg_shard_t> peer_info_requested;
1287
1288 explicit GetInfo(my_context ctx);
1289 void exit();
1290 void get_infos();
1291
1292 typedef boost::mpl::list <
1293 boost::statechart::custom_reaction< QueryState >,
1294 boost::statechart::custom_reaction< QueryUnfound >,
1295 boost::statechart::transition< GotInfo, GetLog >,
1296 boost::statechart::custom_reaction< MNotifyRec >,
1297 boost::statechart::transition< IsDown, Down >
1298 > reactions;
1299 boost::statechart::result react(const QueryState& q);
1300 boost::statechart::result react(const QueryUnfound& q);
1301 boost::statechart::result react(const MNotifyRec& infoevt);
1302 };
1303
1304 struct GotLog : boost::statechart::event< GotLog > {
1305 GotLog() : boost::statechart::event< GotLog >() {}
1306 };
1307
1308 struct GetLog : boost::statechart::state< GetLog, Peering >, NamedState {
1309 pg_shard_t auth_log_shard;
1310 boost::intrusive_ptr<MOSDPGLog> msg;
1311
1312 explicit GetLog(my_context ctx);
1313 void exit();
1314
1315 typedef boost::mpl::list <
1316 boost::statechart::custom_reaction< QueryState >,
1317 boost::statechart::custom_reaction< QueryUnfound >,
1318 boost::statechart::custom_reaction< MLogRec >,
1319 boost::statechart::custom_reaction< GotLog >,
1320 boost::statechart::custom_reaction< AdvMap >,
1321 boost::statechart::transition< NeedActingChange, WaitActingChange >,
1322 boost::statechart::transition< IsIncomplete, Incomplete >
1323 > reactions;
1324 boost::statechart::result react(const AdvMap&);
1325 boost::statechart::result react(const QueryState& q);
1326 boost::statechart::result react(const QueryUnfound& q);
1327 boost::statechart::result react(const MLogRec& logevt);
1328 boost::statechart::result react(const GotLog&);
1329 };
1330
1331 struct WaitUpThru;
1332
1333 struct GetMissing : boost::statechart::state< GetMissing, Peering >, NamedState {
1334 std::set<pg_shard_t> peer_missing_requested;
1335
1336 explicit GetMissing(my_context ctx);
1337 void exit();
1338
1339 typedef boost::mpl::list <
1340 boost::statechart::custom_reaction< QueryState >,
1341 boost::statechart::custom_reaction< QueryUnfound >,
1342 boost::statechart::custom_reaction< MLogRec >,
1343 boost::statechart::transition< NeedUpThru, WaitUpThru >
1344 > reactions;
1345 boost::statechart::result react(const QueryState& q);
1346 boost::statechart::result react(const QueryUnfound& q);
1347 boost::statechart::result react(const MLogRec& logevt);
1348 };
1349
1350 struct WaitUpThru : boost::statechart::state< WaitUpThru, Peering >, NamedState {
1351 explicit WaitUpThru(my_context ctx);
1352 void exit();
1353
1354 typedef boost::mpl::list <
1355 boost::statechart::custom_reaction< QueryState >,
1356 boost::statechart::custom_reaction< QueryUnfound >,
1357 boost::statechart::custom_reaction< ActMap >,
1358 boost::statechart::custom_reaction< MLogRec >
1359 > reactions;
1360 boost::statechart::result react(const QueryState& q);
1361 boost::statechart::result react(const QueryUnfound& q);
1362 boost::statechart::result react(const ActMap& am);
1363 boost::statechart::result react(const MLogRec& logrec);
1364 };
1365
1366 struct Down : boost::statechart::state< Down, Peering>, NamedState {
1367 explicit Down(my_context ctx);
1368 typedef boost::mpl::list <
1369 boost::statechart::custom_reaction< QueryState >,
1370 boost::statechart::custom_reaction< QueryUnfound >,
1371 boost::statechart::custom_reaction< MNotifyRec >
1372 > reactions;
1373 boost::statechart::result react(const QueryState& q);
1374 boost::statechart::result react(const QueryUnfound& q);
1375 boost::statechart::result react(const MNotifyRec& infoevt);
1376 void exit();
1377 };
1378
1379 struct Incomplete : boost::statechart::state< Incomplete, Peering>, NamedState {
1380 typedef boost::mpl::list <
1381 boost::statechart::custom_reaction< AdvMap >,
1382 boost::statechart::custom_reaction< MNotifyRec >,
1383 boost::statechart::custom_reaction< QueryUnfound >,
1384 boost::statechart::custom_reaction< QueryState >
1385 > reactions;
1386 explicit Incomplete(my_context ctx);
1387 boost::statechart::result react(const AdvMap &advmap);
1388 boost::statechart::result react(const MNotifyRec& infoevt);
1389 boost::statechart::result react(const QueryUnfound& q);
1390 boost::statechart::result react(const QueryState& q);
1391 void exit();
1392 };
1393
1394 PGStateHistory state_history;
1395 CephContext* cct;
1396 spg_t spgid;
1397 DoutPrefixProvider *dpp;
1398 PeeringListener *pl;
1399
1400 /// context passed in by state machine caller
1401 PeeringCtx *orig_ctx;
1402
1403 /// populated if we are buffering messages pending a flush
1404 std::optional<BufferedRecoveryMessages> messages_pending_flush;
1405
1406 /**
1407 * populated between start_handle() and end_handle(), points into
1408 * the message lists for messages_pending_flush while blocking messages
1409 * or into orig_ctx otherwise
1410 */
1411 std::optional<PeeringCtxWrapper> rctx;
1412
1413 /**
1414 * OSDMap state
1415 */
1416 OSDMapRef osdmap_ref; ///< Reference to current OSDMap
1417 PGPool pool; ///< Current pool state
1418 epoch_t last_persisted_osdmap = 0; ///< Last osdmap epoch persisted
1419
1420
1421 /**
1422 * Peering state information
1423 */
1424 int role = -1; ///< 0 = primary, 1 = replica, -1=none.
1425 uint64_t state = 0; ///< PG_STATE_*
1426
1427 pg_shard_t primary; ///< id/shard of primary
1428 pg_shard_t pg_whoami; ///< my id/shard
1429 pg_shard_t up_primary; ///< id/shard of primary of up set
1430 std::vector<int> up; ///< crush mapping without temp pgs
1431 std::set<pg_shard_t> upset; ///< up in set form
1432 std::vector<int> acting; ///< actual acting set for the current interval
1433 std::set<pg_shard_t> actingset; ///< acting in set form
1434
1435 /// union of acting, recovery, and backfill targets
1436 std::set<pg_shard_t> acting_recovery_backfill;
1437
1438 std::vector<HeartbeatStampsRef> hb_stamps;
1439
1440 ceph::signedspan readable_interval = ceph::signedspan::zero();
1441
1442 /// how long we can service reads in this interval
1443 ceph::signedspan readable_until = ceph::signedspan::zero();
1444
1445 /// upper bound on any acting OSDs' readable_until in this interval
1446 ceph::signedspan readable_until_ub = ceph::signedspan::zero();
1447
1448 /// upper bound from prior interval(s)
1449 ceph::signedspan prior_readable_until_ub = ceph::signedspan::zero();
1450
1451 /// pg instances from prior interval(s) that may still be readable
1452 std::set<int> prior_readable_down_osds;
1453
1454 /// [replica] upper bound we got from the primary (primary's clock)
1455 ceph::signedspan readable_until_ub_from_primary = ceph::signedspan::zero();
1456
1457 /// [primary] last upper bound shared by primary to replicas
1458 ceph::signedspan readable_until_ub_sent = ceph::signedspan::zero();
1459
1460 /// [primary] readable ub acked by acting set members
1461 std::vector<ceph::signedspan> acting_readable_until_ub;
1462
1463 bool send_notify = false; ///< True if a notify needs to be sent to the primary
1464
1465 bool dirty_info = false; ///< small info structu on disk out of date
1466 bool dirty_big_info = false; ///< big info structure on disk out of date
1467
1468 pg_info_t info; ///< current pg info
1469 pg_info_t last_written_info; ///< last written info
1470 PastIntervals past_intervals; ///< information about prior pg mappings
1471 PGLog pg_log; ///< pg log
1472
1473 epoch_t last_peering_reset = 0; ///< epoch of last peering reset
1474
1475 /// last_update that has committed; ONLY DEFINED WHEN is_active()
1476 eversion_t last_update_ondisk;
1477 eversion_t last_complete_ondisk; ///< last_complete that has committed.
1478 eversion_t last_update_applied; ///< last_update readable
1479 /// last version to which rollback_info trimming has been applied
1480 eversion_t last_rollback_info_trimmed_to_applied;
1481
1482 /// Counter to determine when pending flushes have completed
1483 unsigned flushes_in_progress = 0;
1484
1485 /**
1486 * Primary state
1487 */
1488 std::set<pg_shard_t> stray_set; ///< non-acting osds that have PG data.
1489 std::map<pg_shard_t, pg_info_t> peer_info; ///< info from peers (stray or prior)
1490 std::map<pg_shard_t, int64_t> peer_bytes; ///< Peer's num_bytes from peer_info
1491 std::set<pg_shard_t> peer_purged; ///< peers purged
1492 std::map<pg_shard_t, pg_missing_t> peer_missing; ///< peer missing sets
1493 std::set<pg_shard_t> peer_log_requested; ///< logs i've requested (and start stamps)
1494 std::set<pg_shard_t> peer_missing_requested; ///< missing sets requested
1495
1496 /// features supported by all peers
1497 uint64_t peer_features = CEPH_FEATURES_SUPPORTED_DEFAULT;
1498 /// features supported by acting set
1499 uint64_t acting_features = CEPH_FEATURES_SUPPORTED_DEFAULT;
1500 /// features supported by up and acting
1501 uint64_t upacting_features = CEPH_FEATURES_SUPPORTED_DEFAULT;
1502
1503 /// most recently consumed osdmap's require_osd_version
1504 ceph_release_t last_require_osd_release;
1505
1506 std::vector<int> want_acting; ///< non-empty while peering needs a new acting set
1507
1508 // acting_recovery_backfill contains shards that are acting,
1509 // async recovery targets, or backfill targets.
1510 std::map<pg_shard_t,eversion_t> peer_last_complete_ondisk;
1511
1512 /// up: min over last_complete_ondisk, peer_last_complete_ondisk
1513 eversion_t min_last_complete_ondisk;
1514 /// point to which the log should be trimmed
1515 eversion_t pg_trim_to;
1516
1517 std::set<int> blocked_by; ///< osds we are blocked by (for pg stats)
1518
1519 bool need_up_thru = false; ///< true if osdmap with updated up_thru needed
1520
1521 /// I deleted these strays; ignore racing PGInfo from them
1522 std::set<pg_shard_t> peer_activated;
1523
1524 std::set<pg_shard_t> backfill_targets; ///< osds to be backfilled
1525 std::set<pg_shard_t> async_recovery_targets; ///< osds to be async recovered
1526
1527 /// osds which might have objects on them which are unfound on the primary
1528 std::set<pg_shard_t> might_have_unfound;
1529
1530 bool deleting = false; /// true while in removing or OSD is shutting down
1531 std::atomic<bool> deleted = {false}; /// true once deletion complete
1532
1533 MissingLoc missing_loc; ///< information about missing objects
1534
1535 bool backfill_reserved = false;
1536 bool backfill_reserving = false;
1537
1538 PeeringMachine machine;
1539
1540 void update_osdmap_ref(OSDMapRef newmap) {
1541 osdmap_ref = std::move(newmap);
1542 }
1543
1544 void update_heartbeat_peers();
1545 void query_unfound(Formatter *f, std::string state);
1546 bool proc_replica_info(
1547 pg_shard_t from, const pg_info_t &oinfo, epoch_t send_epoch);
1548 void remove_down_peer_info(const OSDMapRef &osdmap);
1549 void check_recovery_sources(const OSDMapRef& map);
1550 void set_last_peering_reset();
1551 void check_full_transition(OSDMapRef lastmap, OSDMapRef osdmap);
1552 bool should_restart_peering(
1553 int newupprimary,
1554 int newactingprimary,
1555 const std::vector<int>& newup,
1556 const std::vector<int>& newacting,
1557 OSDMapRef lastmap,
1558 OSDMapRef osdmap);
1559 void start_peering_interval(
1560 const OSDMapRef lastmap,
1561 const std::vector<int>& newup, int up_primary,
1562 const std::vector<int>& newacting, int acting_primary,
1563 ObjectStore::Transaction &t);
1564 void on_new_interval();
1565 void clear_recovery_state();
1566 void clear_primary_state();
1567 void check_past_interval_bounds() const;
1568 bool set_force_recovery(bool b);
1569 bool set_force_backfill(bool b);
1570
1571 /// clip calculated priority to reasonable range
1572 int clamp_recovery_priority(int prio, int pool_recovery_prio, int max);
1573 /// get log recovery reservation priority
1574 unsigned get_recovery_priority();
1575 /// get backfill reservation priority
1576 unsigned get_backfill_priority();
1577 /// get priority for pg deletion
1578 unsigned get_delete_priority();
1579
1580 public:
1581 /**
1582 * recovery_msg_priority_t
1583 *
1584 * Defines priority values for use with recovery messages. The values are
1585 * chosen to be reasonable for wpq during an upgrade scenarios, but are
1586 * actually translated into a class in PGRecoveryMsg::get_scheduler_class()
1587 */
1588 enum recovery_msg_priority_t : int {
1589 FORCED = 20,
1590 UNDERSIZED = 15,
1591 DEGRADED = 10,
1592 BEST_EFFORT = 5
1593 };
1594
1595 /// get message priority for recovery messages
1596 int get_recovery_op_priority() const {
1597 if (cct->_conf->osd_op_queue == "mclock_scheduler") {
1598 /* For mclock, we use special priority values which will be
1599 * translated into op classes within PGRecoveryMsg::get_scheduler_class
1600 */
1601 if (is_forced_recovery_or_backfill()) {
1602 return recovery_msg_priority_t::FORCED;
1603 } else if (is_undersized()) {
1604 return recovery_msg_priority_t::UNDERSIZED;
1605 } else if (is_degraded()) {
1606 return recovery_msg_priority_t::DEGRADED;
1607 } else {
1608 return recovery_msg_priority_t::BEST_EFFORT;
1609 }
1610 } else {
1611 /* For WeightedPriorityQueue, we use pool or osd config settings to
1612 * statically set the priority for recovery messages. This special
1613 * handling should probably be removed after Reef */
1614 int64_t pri = 0;
1615 pool.info.opts.get(pool_opts_t::RECOVERY_OP_PRIORITY, &pri);
1616 return pri > 0 ? pri : cct->_conf->osd_recovery_op_priority;
1617 }
1618 }
1619
1620 private:
1621 bool check_prior_readable_down_osds(const OSDMapRef& map);
1622
1623 bool adjust_need_up_thru(const OSDMapRef osdmap);
1624 PastIntervals::PriorSet build_prior();
1625
1626 void reject_reservation();
1627
1628 // acting std::set
1629 std::map<pg_shard_t, pg_info_t>::const_iterator find_best_info(
1630 const std::map<pg_shard_t, pg_info_t> &infos,
1631 bool restrict_to_up_acting,
1632 bool *history_les_bound) const;
1633
1634 static void calc_ec_acting(
1635 std::map<pg_shard_t, pg_info_t>::const_iterator auth_log_shard,
1636 unsigned size,
1637 const std::vector<int> &acting,
1638 const std::vector<int> &up,
1639 const std::map<pg_shard_t, pg_info_t> &all_info,
1640 bool restrict_to_up_acting,
1641 std::vector<int> *want,
1642 std::set<pg_shard_t> *backfill,
1643 std::set<pg_shard_t> *acting_backfill,
1644 std::ostream &ss);
1645
1646 static std::pair<std::map<pg_shard_t, pg_info_t>::const_iterator, eversion_t>
1647 select_replicated_primary(
1648 std::map<pg_shard_t, pg_info_t>::const_iterator auth_log_shard,
1649 uint64_t force_auth_primary_missing_objects,
1650 const std::vector<int> &up,
1651 pg_shard_t up_primary,
1652 const std::map<pg_shard_t, pg_info_t> &all_info,
1653 const OSDMapRef osdmap,
1654 std::ostream &ss);
1655
1656 static void calc_replicated_acting(
1657 std::map<pg_shard_t, pg_info_t>::const_iterator primary_shard,
1658 eversion_t oldest_auth_log_entry,
1659 unsigned size,
1660 const std::vector<int> &acting,
1661 const std::vector<int> &up,
1662 pg_shard_t up_primary,
1663 const std::map<pg_shard_t, pg_info_t> &all_info,
1664 bool restrict_to_up_acting,
1665 std::vector<int> *want,
1666 std::set<pg_shard_t> *backfill,
1667 std::set<pg_shard_t> *acting_backfill,
1668 const OSDMapRef osdmap,
1669 const PGPool& pool,
1670 std::ostream &ss);
1671 static void calc_replicated_acting_stretch(
1672 std::map<pg_shard_t, pg_info_t>::const_iterator primary_shard,
1673 eversion_t oldest_auth_log_entry,
1674 unsigned size,
1675 const std::vector<int> &acting,
1676 const std::vector<int> &up,
1677 pg_shard_t up_primary,
1678 const std::map<pg_shard_t, pg_info_t> &all_info,
1679 bool restrict_to_up_acting,
1680 std::vector<int> *want,
1681 std::set<pg_shard_t> *backfill,
1682 std::set<pg_shard_t> *acting_backfill,
1683 const OSDMapRef osdmap,
1684 const PGPool& pool,
1685 std::ostream &ss);
1686
1687 void choose_async_recovery_ec(
1688 const std::map<pg_shard_t, pg_info_t> &all_info,
1689 const pg_info_t &auth_info,
1690 std::vector<int> *want,
1691 std::set<pg_shard_t> *async_recovery,
1692 const OSDMapRef osdmap) const;
1693 void choose_async_recovery_replicated(
1694 const std::map<pg_shard_t, pg_info_t> &all_info,
1695 const pg_info_t &auth_info,
1696 std::vector<int> *want,
1697 std::set<pg_shard_t> *async_recovery,
1698 const OSDMapRef osdmap) const;
1699
1700 bool recoverable(const std::vector<int> &want) const;
1701 bool choose_acting(pg_shard_t &auth_log_shard,
1702 bool restrict_to_up_acting,
1703 bool *history_les_bound,
1704 bool request_pg_temp_change_only = false);
1705
1706 bool search_for_missing(
1707 const pg_info_t &oinfo, const pg_missing_t &omissing,
1708 pg_shard_t fromosd,
1709 PeeringCtxWrapper &rctx);
1710 void build_might_have_unfound();
1711 void log_weirdness();
1712 void activate(
1713 ObjectStore::Transaction& t,
1714 epoch_t activation_epoch,
1715 PeeringCtxWrapper &ctx);
1716
1717 void rewind_divergent_log(ObjectStore::Transaction& t, eversion_t newhead);
1718 void merge_log(
1719 ObjectStore::Transaction& t, pg_info_t &oinfo,
1720 pg_log_t&& olog, pg_shard_t from);
1721
1722 void proc_primary_info(ObjectStore::Transaction &t, const pg_info_t &info);
1723 void proc_master_log(ObjectStore::Transaction& t, pg_info_t &oinfo,
1724 pg_log_t&& olog, pg_missing_t&& omissing,
1725 pg_shard_t from);
1726 void proc_replica_log(pg_info_t &oinfo, const pg_log_t &olog,
1727 pg_missing_t&& omissing, pg_shard_t from);
1728
1729 void calc_min_last_complete_ondisk() {
1730 eversion_t min = last_complete_ondisk;
1731 ceph_assert(!acting_recovery_backfill.empty());
1732 for (std::set<pg_shard_t>::iterator i = acting_recovery_backfill.begin();
1733 i != acting_recovery_backfill.end();
1734 ++i) {
1735 if (*i == get_primary()) continue;
1736 if (peer_last_complete_ondisk.count(*i) == 0)
1737 return; // we don't have complete info
1738 eversion_t a = peer_last_complete_ondisk[*i];
1739 if (a < min)
1740 min = a;
1741 }
1742 if (min == min_last_complete_ondisk)
1743 return;
1744 min_last_complete_ondisk = min;
1745 return;
1746 }
1747
1748 void fulfill_info(
1749 pg_shard_t from, const pg_query_t &query,
1750 std::pair<pg_shard_t, pg_info_t> &notify_info);
1751 void fulfill_log(
1752 pg_shard_t from, const pg_query_t &query, epoch_t query_epoch);
1753 void fulfill_query(const MQuery& q, PeeringCtxWrapper &rctx);
1754
1755 void try_mark_clean();
1756
1757 void update_blocked_by();
1758 void update_calc_stats();
1759
1760 void add_log_entry(const pg_log_entry_t& e, bool applied);
1761
1762 void calc_trim_to();
1763 void calc_trim_to_aggressive();
1764
1765 public:
1766 PeeringState(
1767 CephContext *cct,
1768 pg_shard_t pg_whoami,
1769 spg_t spgid,
1770 const PGPool &pool,
1771 OSDMapRef curmap,
1772 DoutPrefixProvider *dpp,
1773 PeeringListener *pl);
1774
1775 /// Process evt
1776 void handle_event(const boost::statechart::event_base &evt,
1777 PeeringCtx *rctx) {
1778 start_handle(rctx);
1779 machine.process_event(evt);
1780 end_handle();
1781 }
1782
1783 /// Process evt
1784 void handle_event(PGPeeringEventRef evt,
1785 PeeringCtx *rctx) {
1786 start_handle(rctx);
1787 machine.process_event(evt->get_event());
1788 end_handle();
1789 }
1790
1791 /// Init fresh instance of PG
1792 void init(
1793 int role,
1794 const std::vector<int>& newup, int new_up_primary,
1795 const std::vector<int>& newacting, int new_acting_primary,
1796 const pg_history_t& history,
1797 const PastIntervals& pi,
1798 ObjectStore::Transaction &t);
1799
1800 /// Init pg instance from disk state
1801 template <typename F>
1802 auto init_from_disk_state(
1803 pg_info_t &&info_from_disk,
1804 PastIntervals &&past_intervals_from_disk,
1805 F &&pg_log_init) {
1806 info = std::move(info_from_disk);
1807 last_written_info = info;
1808 past_intervals = std::move(past_intervals_from_disk);
1809 auto ret = pg_log_init(pg_log);
1810 log_weirdness();
1811 return ret;
1812 }
1813
1814 /// Std::set initial primary/acting
1815 void init_primary_up_acting(
1816 const std::vector<int> &newup,
1817 const std::vector<int> &newacting,
1818 int new_up_primary,
1819 int new_acting_primary);
1820 void init_hb_stamps();
1821
1822 /// Std::set initial role
1823 void set_role(int r) {
1824 role = r;
1825 }
1826
1827 /// Std::set predicates used for determining readable and recoverable
1828 void set_backend_predicates(
1829 IsPGReadablePredicate *is_readable,
1830 IsPGRecoverablePredicate *is_recoverable) {
1831 missing_loc.set_backend_predicates(is_readable, is_recoverable);
1832 }
1833
1834 /// Send current pg_info to peers
1835 void share_pg_info();
1836
1837 /// Get stats for child pgs
1838 void start_split_stats(
1839 const std::set<spg_t>& childpgs, std::vector<object_stat_sum_t> *out);
1840
1841 /// Update new child with stats
1842 void finish_split_stats(
1843 const object_stat_sum_t& stats, ObjectStore::Transaction &t);
1844
1845 /// Split state for child_pgid into *child
1846 void split_into(
1847 pg_t child_pgid, PeeringState *child, unsigned split_bits);
1848
1849 /// Merge state from sources
1850 void merge_from(
1851 std::map<spg_t,PeeringState *>& sources,
1852 PeeringCtx &rctx,
1853 unsigned split_bits,
1854 const pg_merge_meta_t& last_pg_merge_meta);
1855
1856 /// Permit stray replicas to purge now unnecessary state
1857 void purge_strays();
1858
1859 /**
1860 * update_stats
1861 *
1862 * Mechanism for updating stats and/or history. Pass t to mark
1863 * dirty and write out. Return true if stats should be published
1864 * to the osd.
1865 */
1866 void update_stats(
1867 std::function<bool(pg_history_t &, pg_stat_t &)> f,
1868 ObjectStore::Transaction *t = nullptr);
1869
1870 void update_stats_wo_resched(
1871 std::function<void(pg_history_t &, pg_stat_t &)> f);
1872
1873 /**
1874 * adjust_purged_snaps
1875 *
1876 * Mechanism for updating purged_snaps. Marks dirty_info, big_dirty_info.
1877 */
1878 void adjust_purged_snaps(
1879 std::function<void(interval_set<snapid_t> &snaps)> f);
1880
1881 /// Updates info.hit_set to hset_history, does not dirty
1882 void update_hset(const pg_hit_set_history_t &hset_history);
1883
1884 /// Get all pg_shards that needs recovery
1885 std::vector<pg_shard_t> get_replica_recovery_order() const;
1886
1887 /**
1888 * update_history
1889 *
1890 * Merges new_history into info.history clearing past_intervals and
1891 * dirtying as needed.
1892 *
1893 * Calls PeeringListener::on_info_history_change()
1894 */
1895 void update_history(const pg_history_t& new_history);
1896
1897 /**
1898 * prepare_stats_for_publish
1899 *
1900 * Returns updated pg_stat_t if stats have changed since
1901 * pg_stats_publish adding in unstable_stats.
1902 *
1903 * @param pg_stats_publish the latest pg_stat possessed by caller
1904 * @param unstable_stats additional stats which should be included in the
1905 * returned stats
1906 * @return the up to date stats if it is different from the specfied
1907 * @c pg_stats_publish
1908 */
1909 std::optional<pg_stat_t> prepare_stats_for_publish(
1910 const std::optional<pg_stat_t> &pg_stats_publish,
1911 const object_stat_collection_t &unstable_stats);
1912
1913 /**
1914 * Merge entries updating missing as necessary on all
1915 * acting_recovery_backfill logs and missings (also missing_loc)
1916 */
1917 bool append_log_entries_update_missing(
1918 const mempool::osd_pglog::list<pg_log_entry_t> &entries,
1919 ObjectStore::Transaction &t,
1920 std::optional<eversion_t> trim_to,
1921 std::optional<eversion_t> roll_forward_to);
1922
1923 void append_log_with_trim_to_updated(
1924 std::vector<pg_log_entry_t>&& log_entries,
1925 eversion_t roll_forward_to,
1926 ObjectStore::Transaction &t,
1927 bool transaction_applied,
1928 bool async) {
1929 update_trim_to();
1930 append_log(std::move(log_entries), pg_trim_to, roll_forward_to,
1931 min_last_complete_ondisk, t, transaction_applied, async);
1932 }
1933
1934 /**
1935 * Updates local log to reflect new write from primary.
1936 */
1937 void append_log(
1938 std::vector<pg_log_entry_t>&& logv,
1939 eversion_t trim_to,
1940 eversion_t roll_forward_to,
1941 eversion_t min_last_complete_ondisk,
1942 ObjectStore::Transaction &t,
1943 bool transaction_applied,
1944 bool async);
1945
1946 /**
1947 * retrieve the min last_backfill among backfill targets
1948 */
1949 hobject_t earliest_backfill() const;
1950
1951
1952 /**
1953 * Updates local log/missing to reflect new oob log update from primary
1954 */
1955 void merge_new_log_entries(
1956 const mempool::osd_pglog::list<pg_log_entry_t> &entries,
1957 ObjectStore::Transaction &t,
1958 std::optional<eversion_t> trim_to,
1959 std::optional<eversion_t> roll_forward_to);
1960
1961 /// Update missing set to reflect e (TODOSAM: not sure why this is needed)
1962 void add_local_next_event(const pg_log_entry_t& e) {
1963 pg_log.missing_add_next_entry(e);
1964 }
1965
1966 /// Update log trim boundary
1967 void update_trim_to() {
1968 bool hard_limit = (get_osdmap()->test_flag(CEPH_OSDMAP_PGLOG_HARDLIMIT));
1969 if (hard_limit)
1970 calc_trim_to_aggressive();
1971 else
1972 calc_trim_to();
1973 }
1974
1975 /// Pre-process pending update on hoid represented by logv
1976 void pre_submit_op(
1977 const hobject_t &hoid,
1978 const std::vector<pg_log_entry_t>& logv,
1979 eversion_t at_version);
1980
1981 /// Signal that oid has been locally recovered to version v
1982 void recover_got(
1983 const hobject_t &oid, eversion_t v,
1984 bool is_delete,
1985 ObjectStore::Transaction &t);
1986
1987 /// Signal that oid has been recovered on peer to version
1988 void on_peer_recover(
1989 pg_shard_t peer,
1990 const hobject_t &soid,
1991 const eversion_t &version);
1992
1993 /// Notify that soid is being recovered on peer
1994 void begin_peer_recover(
1995 pg_shard_t peer,
1996 const hobject_t soid);
1997
1998 /// Pull missing sets from all candidate peers
1999 bool discover_all_missing(
2000 BufferedRecoveryMessages &rctx);
2001
2002 /// Notify that hoid has been fully recocovered
2003 void object_recovered(
2004 const hobject_t &hoid,
2005 const object_stat_sum_t &stat_diff) {
2006 info.stats.stats.sum.add(stat_diff);
2007 missing_loc.recovered(hoid);
2008 }
2009
2010 /// Update info/stats to reflect backfill progress
2011 void update_backfill_progress(
2012 const hobject_t &updated_backfill,
2013 const pg_stat_t &updated_stats,
2014 bool preserve_local_num_bytes,
2015 ObjectStore::Transaction &t);
2016
2017 /// Update info/stats to reflect completed backfill on hoid
2018 void update_complete_backfill_object_stats(
2019 const hobject_t &hoid,
2020 const pg_stat_t &stats);
2021
2022 /// Update last_backfill for peer to new_last_backfill
2023 void update_peer_last_backfill(
2024 pg_shard_t peer,
2025 const hobject_t &new_last_backfill);
2026
2027 /// Update info.stats with delta_stats for operation on soid
2028 void apply_op_stats(
2029 const hobject_t &soid,
2030 const object_stat_sum_t &delta_stats);
2031
2032 /**
2033 * force_object_missing
2034 *
2035 * Force oid on peer to be missing at version. If the object does not
2036 * currently need recovery, either candidates if provided or the remainder
2037 * of the acting std::set will be deemed to have the object.
2038 */
2039 void force_object_missing(
2040 const pg_shard_t &peer,
2041 const hobject_t &oid,
2042 eversion_t version) {
2043 force_object_missing(std::set<pg_shard_t>{peer}, oid, version);
2044 }
2045 void force_object_missing(
2046 const std::set<pg_shard_t> &peer,
2047 const hobject_t &oid,
2048 eversion_t version);
2049
2050 /// Update state prior to backfilling soid on targets
2051 void prepare_backfill_for_missing(
2052 const hobject_t &soid,
2053 const eversion_t &version,
2054 const std::vector<pg_shard_t> &targets);
2055
2056 /// Std::set targets with the right version for revert (see recover_primary)
2057 void set_revert_with_targets(
2058 const hobject_t &soid,
2059 const std::set<pg_shard_t> &good_peers);
2060
2061 /// Update lcod for fromosd
2062 void update_peer_last_complete_ondisk(
2063 pg_shard_t fromosd,
2064 eversion_t lcod) {
2065 peer_last_complete_ondisk[fromosd] = lcod;
2066 }
2067
2068 /// Update lcod
2069 void update_last_complete_ondisk(
2070 eversion_t lcod) {
2071 last_complete_ondisk = lcod;
2072 }
2073
2074 /// Update state to reflect recovery up to version
2075 void recovery_committed_to(eversion_t version);
2076
2077 /// Mark recovery complete
2078 void local_recovery_complete() {
2079 info.last_complete = info.last_update;
2080 }
2081
2082 /// Update last_requested pointer to v
2083 void set_last_requested(version_t v) {
2084 pg_log.set_last_requested(v);
2085 }
2086
2087 /// Write dirty state to t
2088 void write_if_dirty(ObjectStore::Transaction& t);
2089
2090 /// Mark write completed to v with persisted lc
2091 void complete_write(eversion_t v, eversion_t lc);
2092
2093 /// Update local write applied pointer
2094 void local_write_applied(eversion_t v) {
2095 last_update_applied = v;
2096 }
2097
2098 /// Updates peering state with new map
2099 void advance_map(
2100 OSDMapRef osdmap, ///< [in] new osdmap
2101 OSDMapRef lastmap, ///< [in] prev osdmap
2102 std::vector<int>& newup, ///< [in] new up set
2103 int up_primary, ///< [in] new up primary
2104 std::vector<int>& newacting, ///< [in] new acting
2105 int acting_primary, ///< [in] new acting primary
2106 PeeringCtx &rctx ///< [out] recovery context
2107 );
2108
2109 /// Activates most recently updated map
2110 void activate_map(
2111 PeeringCtx &rctx ///< [out] recovery context
2112 );
2113
2114 /// resets last_persisted_osdmap
2115 void reset_last_persisted() {
2116 last_persisted_osdmap = 0;
2117 dirty_info = true;
2118 dirty_big_info = true;
2119 }
2120
2121 /// Signal shutdown beginning
2122 void shutdown() {
2123 deleting = true;
2124 }
2125
2126 /// Signal shutdown complete
2127 void set_delete_complete() {
2128 deleted = true;
2129 }
2130
2131 /// Dirty info and write out
2132 void force_write_state(ObjectStore::Transaction &t) {
2133 dirty_info = true;
2134 dirty_big_info = true;
2135 write_if_dirty(t);
2136 }
2137
2138 /// Get current interval's readable_until
2139 ceph::signedspan get_readable_until() const {
2140 return readable_until;
2141 }
2142
2143 /// Get prior intervals' readable_until upper bound
2144 ceph::signedspan get_prior_readable_until_ub() const {
2145 return prior_readable_until_ub;
2146 }
2147
2148 /// Get prior intervals' readable_until down OSDs of note
2149 const std::set<int>& get_prior_readable_down_osds() const {
2150 return prior_readable_down_osds;
2151 }
2152
2153 /// Reset prior intervals' readable_until upper bound (e.g., bc it passed)
2154 void clear_prior_readable_until_ub() {
2155 prior_readable_until_ub = ceph::signedspan::zero();
2156 prior_readable_down_osds.clear();
2157 info.history.prior_readable_until_ub = ceph::signedspan::zero();
2158 }
2159
2160 void renew_lease(ceph::signedspan now) {
2161 bool was_min = (readable_until_ub == readable_until);
2162 readable_until_ub_sent = now + readable_interval;
2163 if (was_min) {
2164 recalc_readable_until();
2165 }
2166 }
2167
2168 void send_lease();
2169 void schedule_renew_lease();
2170
2171 pg_lease_t get_lease() {
2172 return pg_lease_t(readable_until, readable_until_ub_sent, readable_interval);
2173 }
2174
2175 void proc_lease(const pg_lease_t& l);
2176 void proc_lease_ack(int from, const pg_lease_ack_t& la);
2177 void proc_renew_lease();
2178
2179 pg_lease_ack_t get_lease_ack() {
2180 return pg_lease_ack_t(readable_until_ub_from_primary);
2181 }
2182
2183 /// [primary] recalc readable_until[_ub] for the current interval
2184 void recalc_readable_until();
2185
2186 //============================ const helpers ================================
2187 const char *get_current_state() const {
2188 return state_history.get_current_state();
2189 }
2190 epoch_t get_last_peering_reset() const {
2191 return last_peering_reset;
2192 }
2193 eversion_t get_last_rollback_info_trimmed_to_applied() const {
2194 return last_rollback_info_trimmed_to_applied;
2195 }
2196 /// Returns stable reference to internal pool structure
2197 const PGPool &get_pgpool() const {
2198 return pool;
2199 }
2200 /// Returns reference to current osdmap
2201 const OSDMapRef &get_osdmap() const {
2202 ceph_assert(osdmap_ref);
2203 return osdmap_ref;
2204 }
2205 /// Returns epoch of current osdmap
2206 epoch_t get_osdmap_epoch() const {
2207 return get_osdmap()->get_epoch();
2208 }
2209
2210 bool is_ec_pg() const override {
2211 return pool.info.is_erasure();
2212 }
2213 int get_pg_size() const override {
2214 return pool.info.size;
2215 }
2216 bool is_deleting() const {
2217 return deleting;
2218 }
2219 bool is_deleted() const {
2220 return deleted;
2221 }
2222 const std::set<pg_shard_t> &get_upset() const override {
2223 return upset;
2224 }
2225 bool is_acting_recovery_backfill(pg_shard_t osd) const {
2226 return acting_recovery_backfill.count(osd);
2227 }
2228 bool is_acting(pg_shard_t osd) const {
2229 return has_shard(pool.info.is_erasure(), acting, osd);
2230 }
2231 bool is_up(pg_shard_t osd) const {
2232 return has_shard(pool.info.is_erasure(), up, osd);
2233 }
2234 static bool has_shard(bool ec, const std::vector<int>& v, pg_shard_t osd) {
2235 if (ec) {
2236 return v.size() > (unsigned)osd.shard && v[osd.shard] == osd.osd;
2237 } else {
2238 return std::find(v.begin(), v.end(), osd.osd) != v.end();
2239 }
2240 }
2241 const PastIntervals& get_past_intervals() const {
2242 return past_intervals;
2243 }
2244 /// acting osd that is not the primary
2245 bool is_nonprimary() const {
2246 return role >= 0 && pg_whoami != primary;
2247 }
2248 /// primary osd
2249 bool is_primary() const {
2250 return pg_whoami == primary;
2251 }
2252 bool pg_has_reset_since(epoch_t e) const {
2253 return deleted || e < get_last_peering_reset();
2254 }
2255
2256 int get_role() const {
2257 return role;
2258 }
2259 const std::vector<int> &get_acting() const {
2260 return acting;
2261 }
2262 const std::set<pg_shard_t> &get_actingset() const {
2263 return actingset;
2264 }
2265 int get_acting_primary() const {
2266 return primary.osd;
2267 }
2268 pg_shard_t get_primary() const {
2269 return primary;
2270 }
2271 const std::vector<int> &get_up() const {
2272 return up;
2273 }
2274 int get_up_primary() const {
2275 return up_primary.osd;
2276 }
2277
2278 bool is_backfill_target(pg_shard_t osd) const {
2279 return backfill_targets.count(osd);
2280 }
2281 const std::set<pg_shard_t> &get_backfill_targets() const {
2282 return backfill_targets;
2283 }
2284 bool is_async_recovery_target(pg_shard_t peer) const {
2285 return async_recovery_targets.count(peer);
2286 }
2287 const std::set<pg_shard_t> &get_async_recovery_targets() const {
2288 return async_recovery_targets;
2289 }
2290 const std::set<pg_shard_t> &get_acting_recovery_backfill() const {
2291 return acting_recovery_backfill;
2292 }
2293
2294 const PGLog &get_pg_log() const {
2295 return pg_log;
2296 }
2297
2298 bool state_test(uint64_t m) const { return (state & m) != 0; }
2299 void state_set(uint64_t m) { state |= m; }
2300 void state_clear(uint64_t m) { state &= ~m; }
2301
2302 bool is_complete() const { return info.last_complete == info.last_update; }
2303 bool should_send_notify() const { return send_notify; }
2304
2305 uint64_t get_state() const { return state; }
2306 bool is_active() const { return state_test(PG_STATE_ACTIVE); }
2307 bool is_activating() const { return state_test(PG_STATE_ACTIVATING); }
2308 bool is_peering() const { return state_test(PG_STATE_PEERING); }
2309 bool is_down() const { return state_test(PG_STATE_DOWN); }
2310 bool is_recovery_unfound() const {
2311 return state_test(PG_STATE_RECOVERY_UNFOUND);
2312 }
2313 bool is_backfilling() const {
2314 return state_test(PG_STATE_BACKFILLING);
2315 }
2316 bool is_backfill_unfound() const {
2317 return state_test(PG_STATE_BACKFILL_UNFOUND);
2318 }
2319 bool is_incomplete() const { return state_test(PG_STATE_INCOMPLETE); }
2320 bool is_clean() const { return state_test(PG_STATE_CLEAN); }
2321 bool is_degraded() const { return state_test(PG_STATE_DEGRADED); }
2322 bool is_undersized() const { return state_test(PG_STATE_UNDERSIZED); }
2323 bool is_remapped() const { return state_test(PG_STATE_REMAPPED); }
2324 bool is_peered() const {
2325 return state_test(PG_STATE_ACTIVE) || state_test(PG_STATE_PEERED);
2326 }
2327 bool is_recovering() const { return state_test(PG_STATE_RECOVERING); }
2328 bool is_premerge() const { return state_test(PG_STATE_PREMERGE); }
2329 bool is_repair() const { return state_test(PG_STATE_REPAIR); }
2330 bool is_empty() const { return info.last_update == eversion_t(0,0); }
2331
2332 bool get_need_up_thru() const {
2333 return need_up_thru;
2334 }
2335
2336 bool is_forced_recovery_or_backfill() const {
2337 return get_state() & (PG_STATE_FORCED_RECOVERY | PG_STATE_FORCED_BACKFILL);
2338 }
2339
2340 bool is_backfill_reserved() const {
2341 return backfill_reserved;
2342 }
2343
2344 bool is_backfill_reserving() const {
2345 return backfill_reserving;
2346 }
2347
2348 ceph_release_t get_last_require_osd_release() const {
2349 return last_require_osd_release;
2350 }
2351
2352 const pg_info_t &get_info() const {
2353 return info;
2354 }
2355
2356 const decltype(peer_info) &get_peer_info() const {
2357 return peer_info;
2358 }
2359 const decltype(peer_missing) &get_peer_missing() const {
2360 return peer_missing;
2361 }
2362 const pg_missing_const_i &get_peer_missing(const pg_shard_t &peer) const {
2363 if (peer == pg_whoami) {
2364 return pg_log.get_missing();
2365 } else {
2366 assert(peer_missing.count(peer));
2367 return peer_missing.find(peer)->second;
2368 }
2369 }
2370 const pg_info_t&get_peer_info(pg_shard_t peer) const {
2371 assert(peer_info.count(peer));
2372 return peer_info.find(peer)->second;
2373 }
2374 bool has_peer_info(pg_shard_t peer) const {
2375 return peer_info.count(peer);
2376 }
2377
2378 bool needs_recovery() const;
2379 bool needs_backfill() const;
2380
2381 /**
2382 * Returns whether a particular object can be safely read on this replica
2383 */
2384 bool can_serve_replica_read(const hobject_t &hoid) {
2385 ceph_assert(!is_primary());
2386 return !pg_log.get_log().has_write_since(
2387 hoid, get_min_last_complete_ondisk());
2388 }
2389
2390 /**
2391 * Returns whether the current acting set is able to go active
2392 * and serve writes. It needs to satisfy min_size and any
2393 * applicable stretch cluster constraints.
2394 */
2395 bool acting_set_writeable() {
2396 return (actingset.size() >= pool.info.min_size) &&
2397 (pool.info.stretch_set_can_peer(acting, *get_osdmap(), NULL));
2398 }
2399
2400 /**
2401 * Returns whether all peers which might have unfound objects have been
2402 * queried or marked lost.
2403 */
2404 bool all_unfound_are_queried_or_lost(const OSDMapRef osdmap) const;
2405 bool all_missing_unfound() const {
2406 const auto& missing = pg_log.get_missing();
2407 if (!missing.have_missing())
2408 return false;
2409 for (auto& m : missing.get_items()) {
2410 if (!missing_loc.is_unfound(m.first))
2411 return false;
2412 }
2413 return true;
2414 }
2415
2416 bool perform_deletes_during_peering() const {
2417 return !(get_osdmap()->test_flag(CEPH_OSDMAP_RECOVERY_DELETES));
2418 }
2419
2420
2421 bool have_unfound() const {
2422 return missing_loc.have_unfound();
2423 }
2424 uint64_t get_num_unfound() const {
2425 return missing_loc.num_unfound();
2426 }
2427
2428 bool have_missing() const {
2429 return pg_log.get_missing().num_missing() > 0;
2430 }
2431 unsigned int get_num_missing() const {
2432 return pg_log.get_missing().num_missing();
2433 }
2434
2435 const MissingLoc &get_missing_loc() const {
2436 return missing_loc;
2437 }
2438
2439 const MissingLoc::missing_by_count_t &get_missing_by_count() const {
2440 return missing_loc.get_missing_by_count();
2441 }
2442
2443 eversion_t get_min_last_complete_ondisk() const {
2444 return min_last_complete_ondisk;
2445 }
2446
2447 eversion_t get_pg_trim_to() const {
2448 return pg_trim_to;
2449 }
2450
2451 eversion_t get_last_update_applied() const {
2452 return last_update_applied;
2453 }
2454
2455 eversion_t get_last_update_ondisk() const {
2456 return last_update_ondisk;
2457 }
2458
2459 bool debug_has_dirty_state() const {
2460 return dirty_info || dirty_big_info;
2461 }
2462
2463 std::string get_pg_state_string() const {
2464 return pg_state_string(state);
2465 }
2466
2467 /// Dump representation of past_intervals to out
2468 void print_past_intervals(std::ostream &out) const {
2469 out << "[" << past_intervals.get_bounds()
2470 << ")/" << past_intervals.size();
2471 }
2472
2473 void dump_history(ceph::Formatter *f) const {
2474 state_history.dump(f);
2475 }
2476
2477 /// Dump formatted peering status
2478 void dump_peering_state(ceph::Formatter *f);
2479
2480 private:
2481 /// Mask feature vector with feature set from new peer
2482 void apply_peer_features(uint64_t f) { peer_features &= f; }
2483
2484 /// Reset feature vector to default
2485 void reset_min_peer_features() {
2486 peer_features = CEPH_FEATURES_SUPPORTED_DEFAULT;
2487 }
2488 public:
2489 /// Get feature vector common to all known peers with this pg
2490 uint64_t get_min_peer_features() const { return peer_features; }
2491
2492 /// Get feature vector common to acting set
2493 uint64_t get_min_acting_features() const { return acting_features; }
2494
2495 /// Get feature vector common to up/acting set
2496 uint64_t get_min_upacting_features() const { return upacting_features; }
2497
2498
2499 // Flush control interface
2500 private:
2501 /**
2502 * Start additional flush (blocks needs_flush/activation until
2503 * complete_flush is called once for each start_flush call as
2504 * required by start_flush_on_transaction).
2505 */
2506 void start_flush(ObjectStore::Transaction &t) {
2507 flushes_in_progress++;
2508 pl->start_flush_on_transaction(t);
2509 }
2510 public:
2511 /// True if there are outstanding flushes
2512 bool needs_flush() const {
2513 return flushes_in_progress > 0;
2514 }
2515 /// Must be called once per start_flush
2516 void complete_flush();
2517
2518 friend std::ostream &operator<<(std::ostream &out, const PeeringState &ps);
2519 };
2520
2521 std::ostream &operator<<(std::ostream &out, const PeeringState &ps);