]> git.proxmox.com Git - ceph.git/blob - ceph/src/crimson/os/seastore/segment_manager/block.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / crimson / os / seastore / segment_manager / block.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/intrusive_ptr.hpp>
7 #include <boost/smart_ptr/intrusive_ref_counter.hpp>
8
9 #include <seastar/core/file.hh>
10 #include <seastar/core/future.hh>
11 #include <seastar/core/reactor.hh>
12
13 #include "crimson/common/layout.h"
14
15 #include "crimson/os/seastore/segment_manager.h"
16
17 namespace crimson::os::seastore::segment_manager::block {
18
19 using write_ertr = crimson::errorator<
20 crimson::ct_error::input_output_error>;
21 using read_ertr = crimson::errorator<
22 crimson::ct_error::input_output_error>;
23
24 /**
25 * SegmentStateTracker
26 *
27 * Tracks lifecycle state of each segment using space at the beginning
28 * of the drive.
29 */
30 class SegmentStateTracker {
31 using segment_state_t = Segment::segment_state_t;
32
33 bufferptr bptr;
34
35 using L = absl::container_internal::Layout<uint8_t>;
36 const L layout;
37
38 public:
39 static size_t get_raw_size(size_t segments, size_t block_size) {
40 return p2roundup(segments, block_size);
41 }
42
43 SegmentStateTracker(size_t segments, size_t block_size)
44 : bptr(ceph::buffer::create_page_aligned(
45 get_raw_size(segments, block_size))),
46 layout(bptr.length())
47 {
48 ::memset(
49 bptr.c_str(),
50 static_cast<char>(segment_state_t::EMPTY),
51 bptr.length());
52 }
53
54 size_t get_size() const {
55 return bptr.length();
56 }
57
58 size_t get_capacity() const {
59 return bptr.length();
60 }
61
62 segment_state_t get(device_segment_id_t offset) const {
63 assert(offset < get_capacity());
64 return static_cast<segment_state_t>(
65 layout.template Pointer<0>(
66 bptr.c_str())[offset]);
67 }
68
69 void set(device_segment_id_t offset, segment_state_t state) {
70 assert(offset < get_capacity());
71 layout.template Pointer<0>(bptr.c_str())[offset] =
72 static_cast<uint8_t>(state);
73 }
74
75 write_ertr::future<> write_out(
76 device_id_t device_id,
77 seastar::file &device,
78 uint64_t offset);
79
80 read_ertr::future<> read_in(
81 device_id_t device_id,
82 seastar::file &device,
83 uint64_t offset);
84 };
85
86 class BlockSegmentManager;
87 class BlockSegment final : public Segment {
88 friend class BlockSegmentManager;
89 BlockSegmentManager &manager;
90 const segment_id_t id;
91 segment_off_t write_pointer = 0;
92 public:
93 BlockSegment(BlockSegmentManager &manager, segment_id_t id);
94
95 segment_id_t get_segment_id() const final { return id; }
96 segment_off_t get_write_capacity() const final;
97 segment_off_t get_write_ptr() const final { return write_pointer; }
98 close_ertr::future<> close() final;
99 write_ertr::future<> write(segment_off_t offset, ceph::bufferlist bl) final;
100 write_ertr::future<> advance_wp(segment_off_t offset) final;
101
102 ~BlockSegment() {}
103 };
104
105 /**
106 * BlockSegmentManager
107 *
108 * Implements SegmentManager on a conventional block device.
109 * SegmentStateTracker uses space at the start of the device to store
110 * state analagous to that of the segments of a zns device.
111 */
112 class BlockSegmentManager final : public SegmentManager {
113 // interfaces used by Device
114 public:
115 seastar::future<> start() {
116 return shard_devices.start(device_path, superblock.config.spec.dtype);
117 }
118
119 seastar::future<> stop() {
120 return shard_devices.stop();
121 }
122
123 Device& get_sharded_device() final {
124 return shard_devices.local();
125 }
126 mount_ret mount() final;
127
128 mkfs_ret mkfs(device_config_t) final;
129 // interfaces used by each shard device
130 public:
131 close_ertr::future<> close();
132
133 BlockSegmentManager(
134 const std::string &path,
135 device_type_t dtype)
136 : device_path(path) {
137 ceph_assert(get_device_type() == device_type_t::NONE);
138 superblock.config.spec.dtype = dtype;
139 }
140
141 ~BlockSegmentManager();
142
143 open_ertr::future<SegmentRef> open(segment_id_t id) final;
144
145 release_ertr::future<> release(segment_id_t id) final;
146
147 read_ertr::future<> read(
148 paddr_t addr,
149 size_t len,
150 ceph::bufferptr &out) final;
151
152 device_type_t get_device_type() const final {
153 return superblock.config.spec.dtype;
154 }
155 size_t get_available_size() const final {
156 return shard_info.size;
157 }
158 extent_len_t get_block_size() const {
159 return superblock.block_size;
160 }
161 segment_off_t get_segment_size() const {
162 return superblock.segment_size;
163 }
164
165 device_id_t get_device_id() const final {
166 assert(device_id <= DEVICE_ID_MAX_VALID);
167 return device_id;
168 }
169 secondary_device_set_t& get_secondary_devices() final {
170 return superblock.config.secondary_devices;
171 }
172 // public so tests can bypass segment interface when simpler
173 Segment::write_ertr::future<> segment_write(
174 paddr_t addr,
175 ceph::bufferlist bl,
176 bool ignore_check=false);
177
178 magic_t get_magic() const final {
179 return superblock.config.spec.magic;
180 }
181
182 private:
183 friend class BlockSegment;
184 using segment_state_t = Segment::segment_state_t;
185
186 struct effort_t {
187 uint64_t num = 0;
188 uint64_t bytes = 0;
189
190 void increment(uint64_t read_bytes) {
191 ++num;
192 bytes += read_bytes;
193 }
194 };
195
196 struct {
197 effort_t data_read;
198 effort_t data_write;
199 effort_t metadata_write;
200 uint64_t opened_segments;
201 uint64_t closed_segments;
202 uint64_t closed_segments_unused_bytes;
203 uint64_t released_segments;
204
205 void reset() {
206 data_read = {};
207 data_write = {};
208 metadata_write = {};
209 opened_segments = 0;
210 closed_segments = 0;
211 closed_segments_unused_bytes = 0;
212 released_segments = 0;
213 }
214 } stats;
215
216 void register_metrics();
217 seastar::metrics::metric_group metrics;
218
219 std::string device_path;
220 std::unique_ptr<SegmentStateTracker> tracker;
221 block_shard_info_t shard_info;
222 block_sm_superblock_t superblock;
223 seastar::file device;
224
225 void set_device_id(device_id_t id) {
226 assert(id <= DEVICE_ID_MAX_VALID);
227 assert(device_id == DEVICE_ID_NULL ||
228 device_id == id);
229 device_id = id;
230 }
231 device_id_t device_id = DEVICE_ID_NULL;
232
233 size_t get_offset(paddr_t addr) {
234 auto& seg_addr = addr.as_seg_paddr();
235 return shard_info.first_segment_offset +
236 (seg_addr.get_segment_id().device_segment_id() * superblock.segment_size) +
237 seg_addr.get_segment_off();
238 }
239
240 const seastore_meta_t &get_meta() const {
241 return superblock.config.meta;
242 }
243
244 std::vector<segment_state_t> segment_state;
245
246 char *buffer = nullptr;
247
248 Segment::close_ertr::future<> segment_close(
249 segment_id_t id, segment_off_t write_pointer);
250
251 private:
252 // shard 0 mkfs
253 mkfs_ret primary_mkfs(device_config_t);
254 // all shards mkfs
255 mkfs_ret shard_mkfs();
256 // all shards mount
257 mount_ret shard_mount();
258
259 seastar::sharded<BlockSegmentManager> shard_devices;
260 };
261
262 }