]> git.proxmox.com Git - ceph.git/blob - ceph/src/crimson/os/seastore/journal/circular_journal_space.h
c88b65ad5e6b3ada736574222438a5b48a9c6384
[ceph.git] / ceph / src / crimson / os / seastore / journal / circular_journal_space.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
2 // vim: ts=8 sw=2 smarttab expandtab
3
4 #pragma once
5
6 #include <optional>
7 #include <seastar/core/circular_buffer.hh>
8 #include <seastar/core/metrics.hh>
9 #include <seastar/core/shared_future.hh>
10
11 #include "include/buffer.h"
12
13 #include "crimson/common/errorator.h"
14 #include "crimson/os/seastore/journal.h"
15 #include "crimson/os/seastore/random_block_manager.h"
16 #include "crimson/os/seastore/random_block_manager/rbm_device.h"
17 #include "crimson/os/seastore/journal/record_submitter.h"
18 #include "crimson/os/seastore/async_cleaner.h"
19
20 namespace crimson::os::seastore {
21 class SegmentProvider;
22 class JournalTrimmer;
23 }
24
25 namespace crimson::os::seastore::journal {
26
27 class CircularBoundedJournal;
28 class CircularJournalSpace : public JournalAllocator {
29
30 public:
31 const std::string& get_name() const final {
32 return print_name;
33 }
34
35 extent_len_t get_block_size() const final;
36
37 bool can_write() const final {
38 return (device != nullptr);
39 }
40
41 segment_nonce_t get_nonce() const final {
42 return header.magic;
43 }
44
45 bool needs_roll(std::size_t length) const final;
46
47 roll_ertr::future<> roll() final;
48
49 write_ret write(ceph::bufferlist&& to_write) final;
50
51 void update_modify_time(record_t& record) final {}
52
53 close_ertr::future<> close() final {
54 return write_header(
55 ).safe_then([this]() -> close_ertr::future<> {
56 initialized = false;
57 return close_ertr::now();
58 }).handle_error(
59 Journal::open_for_mount_ertr::pass_further{},
60 crimson::ct_error::assert_all{
61 "Invalid error write_header"
62 }
63 );
64 }
65
66 open_ret open(bool is_mkfs) final;
67
68 public:
69 CircularJournalSpace(RBMDevice * device);
70
71 struct cbj_header_t;
72 using write_ertr = Journal::submit_record_ertr;
73 /*
74 * device_write_bl
75 *
76 * @param device address to write
77 * @param bufferlist to write
78 *
79 */
80 write_ertr::future<> device_write_bl(rbm_abs_addr offset, ceph::bufferlist &bl);
81
82 using read_ertr = crimson::errorator<
83 crimson::ct_error::input_output_error,
84 crimson::ct_error::invarg,
85 crimson::ct_error::enoent,
86 crimson::ct_error::erange>;
87 using read_header_ertr = read_ertr;
88 using read_header_ret = read_header_ertr::future<
89 std::optional<std::pair<cbj_header_t, bufferlist>>
90 >;
91 /*
92 * read_header
93 *
94 * read header block from given absolute address
95 *
96 * @param absolute address
97 *
98 */
99 read_header_ret read_header();
100
101 ceph::bufferlist encode_header();
102
103 write_ertr::future<> write_header();
104
105
106 /**
107 * CircularBoundedJournal structure
108 *
109 * +-------------------------------------------------------+
110 * | header | record | record | record | record | ... |
111 * +-------------------------------------------------------+
112 * ^-----------block aligned-----------------^
113 * <----fixed---->
114 */
115
116 struct cbj_header_t {
117 // start offset of CircularBoundedJournal in the device
118 journal_seq_t dirty_tail;
119 journal_seq_t alloc_tail;
120 segment_nonce_t magic;
121
122 DENC(cbj_header_t, v, p) {
123 DENC_START(1, 1, p);
124 denc(v.dirty_tail, p);
125 denc(v.alloc_tail, p);
126 denc(v.magic, p);
127 DENC_FINISH(p);
128 }
129 };
130
131 /**
132 *
133 * Write position for CircularBoundedJournal
134 *
135 * | written to rbm | written length to CircularBoundedJournal | new write |
136 * ----------------->------------------------------------------------>
137 * ^ ^
138 * applied_to written_to
139 *
140 */
141
142 journal_seq_t get_written_to() const {
143 return written_to;
144 }
145 rbm_abs_addr get_rbm_addr(journal_seq_t seq) const {
146 return convert_paddr_to_abs_addr(seq.offset);
147 }
148 void set_written_to(journal_seq_t seq) {
149 rbm_abs_addr addr = convert_paddr_to_abs_addr(seq.offset);
150 assert(addr >= get_records_start());
151 assert(addr < get_journal_end());
152 written_to = seq;
153 }
154 device_id_t get_device_id() const {
155 return device->get_device_id();
156 }
157
158 journal_seq_t get_dirty_tail() const {
159 return header.dirty_tail;
160 }
161 journal_seq_t get_alloc_tail() const {
162 return header.alloc_tail;
163 }
164
165 /*
166 Size-related interfaces
167 +---------------------------------------------------------+
168 | header | record | record | record | record | ... |
169 +---------------------------------------------------------+
170 ^ ^ ^
171 | | |
172 get_journal_start | get_journal_end
173 get_records_start
174 <-- get_records_total_size + block_size -->
175 <--------------- get_journal_size ------------------------>
176 */
177
178 size_t get_records_used_size() const {
179 auto rbm_written_to = get_rbm_addr(get_written_to());
180 auto rbm_tail = get_rbm_addr(get_dirty_tail());
181 return rbm_written_to >= rbm_tail ?
182 rbm_written_to - rbm_tail :
183 rbm_written_to + get_records_total_size() + get_block_size()
184 - rbm_tail;
185 }
186 size_t get_records_total_size() const {
187 assert(device);
188 // a block is for header and a block is reserved to denote the end
189 return device->get_journal_size() - (2 * get_block_size());
190 }
191 rbm_abs_addr get_records_start() const {
192 assert(device);
193 return device->get_shard_journal_start() + get_block_size();
194 }
195 size_t get_records_available_size() const {
196 return get_records_total_size() - get_records_used_size();
197 }
198 bool is_available_size(uint64_t size) {
199 auto rbm_written_to = get_rbm_addr(get_written_to());
200 auto rbm_tail = get_rbm_addr(get_dirty_tail());
201 if (rbm_written_to > rbm_tail &&
202 (get_journal_end() - rbm_written_to) < size &&
203 size > (get_records_used_size() -
204 (get_journal_end() - rbm_written_to))) {
205 return false;
206 }
207 return get_records_available_size() >= size;
208 }
209 rbm_abs_addr get_journal_end() const {
210 assert(device);
211 return device->get_shard_journal_start() + device->get_journal_size();
212 }
213
214 read_ertr::future<> read(
215 uint64_t offset,
216 bufferptr &bptr) {
217 assert(device);
218 return device->read(offset, bptr);
219 }
220
221 seastar::future<> update_journal_tail(
222 journal_seq_t dirty,
223 journal_seq_t alloc) {
224 header.dirty_tail = dirty;
225 header.alloc_tail = alloc;
226 return write_header(
227 ).handle_error(
228 crimson::ct_error::assert_all{
229 "encountered invalid error in update_journal_tail"
230 });
231 }
232
233 void set_initialized(bool init) {
234 initialized = init;
235 }
236
237 void set_cbj_header(cbj_header_t& head) {
238 header = head;
239 }
240
241 cbj_header_t get_cbj_header() {
242 return header;
243 }
244
245 private:
246 std::string print_name;
247 cbj_header_t header;
248 RBMDevice* device;
249 journal_seq_t written_to;
250 bool initialized = false;
251 };
252
253 std::ostream &operator<<(std::ostream &out, const CircularJournalSpace::cbj_header_t &header);
254
255 }
256
257 WRITE_CLASS_DENC_BOUNDED(crimson::os::seastore::journal::CircularJournalSpace::cbj_header_t)
258
259 #if FMT_VERSION >= 90000
260 template <> struct fmt::formatter<crimson::os::seastore::journal::CircularJournalSpace::cbj_header_t> : fmt::ostream_formatter {};
261 #endif