]> git.proxmox.com Git - ceph.git/blob - ceph/src/osd/scheduler/OpScheduler.h
dc524314f251017468504db28e99e6cd973555bd
[ceph.git] / ceph / src / osd / scheduler / OpScheduler.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2019 Red Hat Inc.
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #pragma once
16
17 #include <ostream>
18 #include <variant>
19
20 #include "common/ceph_context.h"
21 #include "osd/scheduler/OpSchedulerItem.h"
22
23 namespace ceph::osd::scheduler {
24
25 using client = uint64_t;
26 using WorkItem = std::variant<std::monostate, OpSchedulerItem, double>;
27
28 /**
29 * Base interface for classes responsible for choosing
30 * op processing order in the OSD.
31 */
32 class OpScheduler {
33 public:
34 // Enqueue op for scheduling
35 virtual void enqueue(OpSchedulerItem &&item) = 0;
36
37 // Enqueue op for processing as though it were enqueued prior
38 // to other items already scheduled.
39 virtual void enqueue_front(OpSchedulerItem &&item) = 0;
40
41 // Returns true iff there are no ops scheduled
42 virtual bool empty() const = 0;
43
44 // Return next op to be processed
45 virtual WorkItem dequeue() = 0;
46
47 // Dump formatted representation for the queue
48 virtual void dump(ceph::Formatter &f) const = 0;
49
50 // Print human readable brief description with relevant parameters
51 virtual void print(std::ostream &out) const = 0;
52
53 // Apply config changes to the scheduler (if any)
54 virtual void update_configuration() = 0;
55
56 // Destructor
57 virtual ~OpScheduler() {};
58 };
59
60 std::ostream &operator<<(std::ostream &lhs, const OpScheduler &);
61 using OpSchedulerRef = std::unique_ptr<OpScheduler>;
62
63 OpSchedulerRef make_scheduler(
64 CephContext *cct, uint32_t num_shards, bool is_rotational,
65 std::string_view osd_objectstore);
66
67 /**
68 * Implements OpScheduler in terms of OpQueue
69 *
70 * Templated on queue type to avoid dynamic dispatch, T should implement
71 * OpQueue<OpSchedulerItem, client>. This adapter is mainly responsible for
72 * the boilerplate priority cutoff/strict concept which is needed for
73 * OpQueue based implementations.
74 */
75 template <typename T>
76 class ClassedOpQueueScheduler final : public OpScheduler {
77 unsigned cutoff;
78 T queue;
79
80 static unsigned int get_io_prio_cut(CephContext *cct) {
81 if (cct->_conf->osd_op_queue_cut_off == "debug_random") {
82 srand(time(NULL));
83 return (rand() % 2 < 1) ? CEPH_MSG_PRIO_HIGH : CEPH_MSG_PRIO_LOW;
84 } else if (cct->_conf->osd_op_queue_cut_off == "high") {
85 return CEPH_MSG_PRIO_HIGH;
86 } else {
87 // default / catch-all is 'low'
88 return CEPH_MSG_PRIO_LOW;
89 }
90 }
91 public:
92 template <typename... Args>
93 ClassedOpQueueScheduler(CephContext *cct, Args&&... args) :
94 cutoff(get_io_prio_cut(cct)),
95 queue(std::forward<Args>(args)...)
96 {}
97
98 void enqueue(OpSchedulerItem &&item) final {
99 unsigned priority = item.get_priority();
100 unsigned cost = item.get_cost();
101
102 if (priority >= cutoff)
103 queue.enqueue_strict(
104 item.get_owner(), priority, std::move(item));
105 else
106 queue.enqueue(
107 item.get_owner(), priority, cost, std::move(item));
108 }
109
110 void enqueue_front(OpSchedulerItem &&item) final {
111 unsigned priority = item.get_priority();
112 unsigned cost = item.get_cost();
113 if (priority >= cutoff)
114 queue.enqueue_strict_front(
115 item.get_owner(),
116 priority, std::move(item));
117 else
118 queue.enqueue_front(
119 item.get_owner(),
120 priority, cost, std::move(item));
121 }
122
123 bool empty() const final {
124 return queue.empty();
125 }
126
127 WorkItem dequeue() final {
128 return queue.dequeue();
129 }
130
131 void dump(ceph::Formatter &f) const final {
132 return queue.dump(&f);
133 }
134
135 void print(std::ostream &out) const final {
136 out << "ClassedOpQueueScheduler(queue=";
137 queue.print(out);
138 out << ", cutoff=" << cutoff << ")";
139 }
140
141 void update_configuration() final {
142 // no-op
143 }
144
145 ~ClassedOpQueueScheduler() final {};
146 };
147
148 }