]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
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 | ||
f67539c2 TL |
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 | ||
20effc67 | 62 | segment_state_t get(device_segment_id_t offset) const { |
f67539c2 TL |
63 | assert(offset < get_capacity()); |
64 | return static_cast<segment_state_t>( | |
65 | layout.template Pointer<0>( | |
66 | bptr.c_str())[offset]); | |
67 | } | |
68 | ||
20effc67 | 69 | void set(device_segment_id_t offset, segment_state_t state) { |
f67539c2 TL |
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( | |
20effc67 | 76 | device_id_t device_id, |
f67539c2 TL |
77 | seastar::file &device, |
78 | uint64_t offset); | |
79 | ||
80 | read_ertr::future<> read_in( | |
20effc67 | 81 | device_id_t device_id, |
f67539c2 TL |
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 | ||
101 | ~BlockSegment() {} | |
102 | }; | |
103 | ||
104 | /** | |
105 | * BlockSegmentManager | |
106 | * | |
107 | * Implements SegmentManager on a conventional block device. | |
108 | * SegmentStateTracker uses space at the start of the device to store | |
109 | * state analagous to that of the segments of a zns device. | |
110 | */ | |
111 | class BlockSegmentManager final : public SegmentManager { | |
112 | public: | |
20effc67 | 113 | mount_ret mount() final; |
f67539c2 | 114 | |
20effc67 | 115 | mkfs_ret mkfs(segment_manager_config_t) final; |
f67539c2 | 116 | |
f67539c2 TL |
117 | close_ertr::future<> close(); |
118 | ||
20effc67 TL |
119 | BlockSegmentManager( |
120 | const std::string &path) | |
121 | : device_path(path) {} | |
122 | ||
f67539c2 TL |
123 | ~BlockSegmentManager(); |
124 | ||
125 | open_ertr::future<SegmentRef> open(segment_id_t id) final; | |
126 | ||
127 | release_ertr::future<> release(segment_id_t id) final; | |
128 | ||
129 | read_ertr::future<> read( | |
130 | paddr_t addr, | |
131 | size_t len, | |
132 | ceph::bufferptr &out) final; | |
133 | ||
134 | size_t get_size() const final { | |
135 | return superblock.size; | |
136 | } | |
137 | segment_off_t get_block_size() const { | |
138 | return superblock.block_size; | |
139 | } | |
140 | segment_off_t get_segment_size() const { | |
141 | return superblock.segment_size; | |
142 | } | |
143 | ||
20effc67 TL |
144 | device_id_t get_device_id() const final { |
145 | assert(device_id <= DEVICE_ID_MAX_VALID); | |
146 | return device_id; | |
147 | } | |
148 | secondary_device_set_t& get_secondary_devices() final { | |
149 | return superblock.secondary_devices; | |
150 | } | |
f67539c2 TL |
151 | // public so tests can bypass segment interface when simpler |
152 | Segment::write_ertr::future<> segment_write( | |
153 | paddr_t addr, | |
154 | ceph::bufferlist bl, | |
155 | bool ignore_check=false); | |
156 | ||
20effc67 TL |
157 | device_spec_t get_device_spec() const final { |
158 | return {superblock.magic, | |
159 | superblock.dtype, | |
160 | get_device_id()}; | |
161 | } | |
162 | ||
163 | magic_t get_magic() const final { | |
164 | return superblock.magic; | |
165 | } | |
166 | ||
f67539c2 TL |
167 | private: |
168 | friend class BlockSegment; | |
169 | using segment_state_t = Segment::segment_state_t; | |
170 | ||
20effc67 TL |
171 | struct effort_t { |
172 | uint64_t num = 0; | |
173 | uint64_t bytes = 0; | |
174 | ||
175 | void increment(uint64_t read_bytes) { | |
176 | ++num; | |
177 | bytes += read_bytes; | |
178 | } | |
179 | }; | |
180 | ||
181 | struct { | |
182 | effort_t data_read; | |
183 | effort_t data_write; | |
184 | effort_t metadata_write; | |
185 | uint64_t opened_segments; | |
186 | uint64_t closed_segments; | |
187 | uint64_t closed_segments_unused_bytes; | |
188 | uint64_t released_segments; | |
189 | ||
190 | void reset() { | |
191 | data_read = {}; | |
192 | data_write = {}; | |
193 | metadata_write = {}; | |
194 | opened_segments = 0; | |
195 | closed_segments = 0; | |
196 | closed_segments_unused_bytes = 0; | |
197 | released_segments = 0; | |
198 | } | |
199 | } stats; | |
200 | ||
201 | void register_metrics(); | |
202 | seastar::metrics::metric_group metrics; | |
203 | ||
204 | std::string device_path; | |
f67539c2 TL |
205 | std::unique_ptr<SegmentStateTracker> tracker; |
206 | block_sm_superblock_t superblock; | |
207 | seastar::file device; | |
208 | ||
20effc67 TL |
209 | void set_device_id(device_id_t id) { |
210 | assert(id <= DEVICE_ID_MAX_VALID); | |
211 | assert(device_id == DEVICE_ID_NULL || | |
212 | device_id == id); | |
213 | device_id = id; | |
214 | } | |
215 | device_id_t device_id = DEVICE_ID_NULL; | |
216 | ||
f67539c2 | 217 | size_t get_offset(paddr_t addr) { |
20effc67 | 218 | auto& seg_addr = addr.as_seg_paddr(); |
f67539c2 | 219 | return superblock.first_segment_offset + |
20effc67 TL |
220 | (seg_addr.get_segment_id().device_segment_id() * superblock.segment_size) + |
221 | seg_addr.get_segment_off(); | |
f67539c2 TL |
222 | } |
223 | ||
224 | const seastore_meta_t &get_meta() const { | |
225 | return superblock.meta; | |
226 | } | |
227 | ||
228 | std::vector<segment_state_t> segment_state; | |
229 | ||
230 | char *buffer = nullptr; | |
231 | ||
20effc67 TL |
232 | Segment::close_ertr::future<> segment_close( |
233 | segment_id_t id, segment_off_t write_pointer); | |
f67539c2 TL |
234 | }; |
235 | ||
236 | } |