1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
2 // vim: ts=8 sw=2 smarttab
6 #include "key_layout.h"
7 #include "crimson/os/seastore/onode_manager/staged-fltree/node_types.h"
9 namespace crimson::os::seastore::onode
{
11 class NodeExtentMutable
;
13 struct node_header_t
{
14 static constexpr unsigned FIELD_TYPE_BITS
= 6u;
15 static_assert(static_cast<uint8_t>(field_type_t::_MAX
) <= 1u << FIELD_TYPE_BITS
);
16 static constexpr unsigned NODE_TYPE_BITS
= 1u;
17 static constexpr unsigned B_LEVEL_TAIL_BITS
= 1u;
18 using bits_t
= uint8_t;
21 std::optional
<field_type_t
> get_field_type() const {
22 if (field_type
>= FIELD_TYPE_MAGIC
&&
23 field_type
< static_cast<uint8_t>(field_type_t::_MAX
)) {
24 return static_cast<field_type_t
>(field_type
);
29 node_type_t
get_node_type() const {
30 return static_cast<node_type_t
>(node_type
);
32 bool get_is_level_tail() const {
36 static void bootstrap_extent(
37 NodeExtentMutable
&, field_type_t
, node_type_t
, bool, level_t
);
39 static void update_is_level_tail(NodeExtentMutable
&, const node_header_t
&, bool);
41 bits_t field_type
: FIELD_TYPE_BITS
;
42 bits_t node_type
: NODE_TYPE_BITS
;
43 bits_t is_level_tail
: B_LEVEL_TAIL_BITS
;
44 static_assert(sizeof(bits_t
) * 8 ==
45 FIELD_TYPE_BITS
+ NODE_TYPE_BITS
+ B_LEVEL_TAIL_BITS
);
49 void set_field_type(field_type_t type
) {
50 field_type
= static_cast<uint8_t>(type
);
52 void set_node_type(node_type_t type
) {
53 node_type
= static_cast<uint8_t>(type
);
55 void set_is_level_tail(bool value
) {
56 is_level_tail
= static_cast<uint8_t>(value
);
58 } __attribute__((packed
));
60 template <typename FixedKeyType
, field_type_t _FIELD_TYPE
>
62 using key_t
= FixedKeyType
;
63 static constexpr field_type_t FIELD_TYPE
= _FIELD_TYPE
;
64 static constexpr node_offset_t OVERHEAD
= sizeof(_slot_t
) - sizeof(key_t
);
67 node_offset_t right_offset
;
68 } __attribute__((packed
));
69 using slot_0_t
= _slot_t
<shard_pool_crush_t
, field_type_t::N0
>;
70 using slot_1_t
= _slot_t
<crush_t
, field_type_t::N1
>;
71 using slot_3_t
= _slot_t
<snap_gen_t
, field_type_t::N3
>;
78 template <typename FieldType
>
79 const char* fields_start(const FieldType
& node
) {
80 return reinterpret_cast<const char*>(&node
);
83 template <node_type_t NODE_TYPE
, typename FieldType
>
84 node_range_t
fields_free_range_before(
85 const FieldType
& node
, index_t index
) {
86 assert(index
<= node
.num_keys
);
87 node_offset_t offset_start
= node
.get_key_start_offset(index
);
88 node_offset_t offset_end
=
89 (index
== 0 ? FieldType::SIZE
90 : node
.get_item_start_offset(index
- 1));
91 if constexpr (NODE_TYPE
== node_type_t::INTERNAL
) {
92 if (node
.is_level_tail() && index
== node
.num_keys
) {
93 offset_end
-= sizeof(laddr_t
);
96 assert(offset_start
<= offset_end
);
97 assert(offset_end
- offset_start
< FieldType::SIZE
);
98 return {offset_start
, offset_end
};
102 * _node_fields_013_t (node_fields_0_t, node_fields_1_t, leaf_fields_3_t
104 * The STAGE_LEFT layout implementation for node N0/N1, or the STAGE_RIGHT
105 * layout implementation for leaf node N3.
107 * The node layout storing n slots:
109 * # <----------------------------- node range --------------------------------------> #
110 * # #<~># free space #
111 * # <----- left part -----------------------------> # <~# <----- right slots -------> #
112 * # # <---- left slots -------------> #~> # #
113 * # # slots [2, n) |<~># #<~>| right slots [2, n) #
114 * # # <- slot 0 -> | <- slot 1 -> | # # | <-- s1 --> | <-- s0 --> #
116 * # | num_ # | right | | right | # # | next-stage | next-stage #
117 * # header | keys # key | offset | key | offset | # # | container | container #
118 * # | # 0 | 0 | 1 | 1 |...#...#...| or onode 1 | or onode 0 #
121 * | +----------------+ |
122 * +--------------------------------------------+
124 template <typename SlotType
>
125 struct _node_fields_013_t
{
126 // TODO: decide by NODE_BLOCK_SIZE, sizeof(SlotType), sizeof(laddr_t)
127 // and the minimal size of variable_key.
128 using num_keys_t
= uint8_t;
129 using key_t
= typename
SlotType::key_t
;
130 using key_get_type
= const key_t
&;
131 using me_t
= _node_fields_013_t
<SlotType
>;
132 static constexpr field_type_t FIELD_TYPE
= SlotType::FIELD_TYPE
;
133 static constexpr node_offset_t SIZE
= NODE_BLOCK_SIZE
;
134 static constexpr node_offset_t HEADER_SIZE
=
135 sizeof(node_header_t
) + sizeof(num_keys_t
);
136 static constexpr node_offset_t ITEM_OVERHEAD
= SlotType::OVERHEAD
;
138 bool is_level_tail() const { return header
.get_is_level_tail(); }
139 node_offset_t
total_size() const { return SIZE
; }
140 key_get_type
get_key(index_t index
) const {
141 assert(index
< num_keys
);
142 return slots
[index
].key
;
144 node_offset_t
get_key_start_offset(index_t index
) const {
145 assert(index
<= num_keys
);
146 auto offset
= HEADER_SIZE
+ sizeof(SlotType
) * index
;
147 assert(offset
< SIZE
);
150 node_offset_t
get_item_start_offset(index_t index
) const {
151 assert(index
< num_keys
);
152 auto offset
= slots
[index
].right_offset
;
153 assert(offset
<= SIZE
);
156 const void* p_offset(index_t index
) const {
157 assert(index
< num_keys
);
158 return &slots
[index
].right_offset
;
160 node_offset_t
get_item_end_offset(index_t index
) const {
161 return index
== 0 ? SIZE
: get_item_start_offset(index
- 1);
163 template <node_type_t NODE_TYPE
>
164 node_offset_t
free_size_before(index_t index
) const {
165 auto range
= fields_free_range_before
<NODE_TYPE
>(*this, index
);
166 return range
.end
- range
.start
;
169 static node_offset_t
estimate_insert_one() { return sizeof(SlotType
); }
171 static void insert_at(
172 NodeExtentMutable
&, const full_key_t
<KT
>& key
,
173 const me_t
& node
, index_t index
, node_offset_t size_right
);
174 static void update_size_at(
175 NodeExtentMutable
&, const me_t
& node
, index_t index
, int change
);
176 static void append_key(
177 NodeExtentMutable
&, const key_t
& key
, char*& p_append
);
179 static void append_key(
180 NodeExtentMutable
& mut
, const full_key_t
<KT
>& key
, char*& p_append
) {
181 append_key(mut
, key_t::template from_key
<KT
>(key
), p_append
);
183 static void append_offset(
184 NodeExtentMutable
& mut
, node_offset_t offset_to_right
, char*& p_append
);
186 node_header_t header
;
187 num_keys_t num_keys
= 0u;
189 } __attribute__((packed
));
190 using node_fields_0_t
= _node_fields_013_t
<slot_0_t
>;
191 using node_fields_1_t
= _node_fields_013_t
<slot_1_t
>;
196 * The STAGE_STRING layout implementation for node N2.
198 * The node layout storing n slots:
200 * # <--------------------------------- node range ----------------------------------------> #
201 * # #<~># free space #
202 * # <------- left part ---------------> # <~# <--------- right slots ---------------------> #
203 * # # <---- offsets ----> #~> #<~>| slots [2, n) #
204 * # # offsets [2, n) |<~># # | <----- slot 1 ----> | <----- slot 0 ----> #
206 * # | num_ # offset | offset | # # | next-stage | ns-oid | next-stage | ns-oid #
207 * # header | keys # 0 | 1 |...#...#...| container1 | 1 | container0 | 0 #
210 * | +----------------+ |
211 * +-----------------------------------------------+
213 struct node_fields_2_t
{
214 // TODO: decide by NODE_BLOCK_SIZE, sizeof(node_off_t), sizeof(laddr_t)
215 // and the minimal size of variable_key.
216 using num_keys_t
= uint8_t;
217 using key_t
= ns_oid_view_t
;
218 using key_get_type
= key_t
;
219 static constexpr field_type_t FIELD_TYPE
= field_type_t::N2
;
220 static constexpr node_offset_t SIZE
= NODE_BLOCK_SIZE
;
221 static constexpr node_offset_t HEADER_SIZE
=
222 sizeof(node_header_t
) + sizeof(num_keys_t
);
223 static constexpr node_offset_t ITEM_OVERHEAD
= sizeof(node_offset_t
);
225 bool is_level_tail() const { return header
.get_is_level_tail(); }
226 node_offset_t
total_size() const { return SIZE
; }
227 key_get_type
get_key(index_t index
) const {
228 assert(index
< num_keys
);
229 node_offset_t item_end_offset
=
230 (index
== 0 ? SIZE
: offsets
[index
- 1]);
231 assert(item_end_offset
<= SIZE
);
232 const char* p_start
= fields_start(*this);
233 return key_t(p_start
+ item_end_offset
);
235 node_offset_t
get_key_start_offset(index_t index
) const {
236 assert(index
<= num_keys
);
237 auto offset
= HEADER_SIZE
+ sizeof(node_offset_t
) * num_keys
;
238 assert(offset
<= SIZE
);
241 node_offset_t
get_item_start_offset(index_t index
) const {
242 assert(index
< num_keys
);
243 auto offset
= offsets
[index
];
244 assert(offset
<= SIZE
);
247 const void* p_offset(index_t index
) const {
248 assert(index
< num_keys
);
249 return &offsets
[index
];
251 node_offset_t
get_item_end_offset(index_t index
) const {
252 return index
== 0 ? SIZE
: get_item_start_offset(index
- 1);
254 template <node_type_t NODE_TYPE
>
255 node_offset_t
free_size_before(index_t index
) const {
256 auto range
= fields_free_range_before
<NODE_TYPE
>(*this, index
);
257 return range
.end
- range
.start
;
260 static node_offset_t
estimate_insert_one() { return sizeof(node_offset_t
); }
262 static void insert_at(
263 NodeExtentMutable
& mut
, const full_key_t
<KT
>& key
,
264 const node_fields_2_t
& node
, index_t index
, node_offset_t size_right
) {
265 ceph_abort("not implemented");
267 static void update_size_at(
268 NodeExtentMutable
& mut
, const node_fields_2_t
& node
, index_t index
, int change
) {
269 ceph_abort("not implemented");
271 static void append_key(
272 NodeExtentMutable
& mut
, const key_t
& key
, char*& p_append
) {
273 ns_oid_view_t::append(mut
, key
, p_append
);
276 static void append_key(
277 NodeExtentMutable
& mut
, const full_key_t
<KT
>& key
, char*& p_append
) {
278 ns_oid_view_t::append
<KT
>(mut
, key
, p_append
);
280 static void append_offset(
281 NodeExtentMutable
& mut
, node_offset_t offset_to_right
, char*& p_append
);
283 node_header_t header
;
284 num_keys_t num_keys
= 0u;
285 node_offset_t offsets
[];
286 } __attribute__((packed
));
289 * internal_fields_3_t
291 * The STAGE_RIGHT layout implementation for N2.
293 * The node layout storing 3 children:
295 * # <---------------- node range ---------------------------> #
296 * # # <-- keys ---> # <---- laddrs -----------> #
297 * # free space: # |<~># |<~>#
299 * # | num_ # key | key | # laddr | laddr | laddr | #
300 * # header | keys # 0 | 1 |...# 0 | 1 | 2 |...#
302 // TODO: decide by NODE_BLOCK_SIZE, sizeof(snap_gen_t), sizeof(laddr_t)
303 static constexpr unsigned MAX_NUM_KEYS_I3
= 170u;
304 template <unsigned MAX_NUM_KEYS
>
305 struct _internal_fields_3_t
{
306 using key_get_type
= const snap_gen_t
&;
307 using me_t
= _internal_fields_3_t
<MAX_NUM_KEYS
>;
308 // TODO: decide by NODE_BLOCK_SIZE, sizeof(snap_gen_t), sizeof(laddr_t)
309 using num_keys_t
= uint8_t;
310 static constexpr field_type_t FIELD_TYPE
= field_type_t::N3
;
311 static constexpr node_offset_t SIZE
= sizeof(me_t
);
312 static constexpr node_offset_t HEADER_SIZE
=
313 sizeof(node_header_t
) + sizeof(num_keys_t
);
314 static constexpr node_offset_t ITEM_OVERHEAD
= 0u;
316 bool is_level_tail() const { return header
.get_is_level_tail(); }
317 node_offset_t
total_size() const {
318 if (is_level_tail()) {
319 return SIZE
- sizeof(snap_gen_t
);
324 key_get_type
get_key(index_t index
) const {
325 assert(index
< num_keys
);
328 template <node_type_t NODE_TYPE
>
329 std::enable_if_t
<NODE_TYPE
== node_type_t::INTERNAL
, node_offset_t
>
330 free_size_before(index_t index
) const {
331 assert(index
<= num_keys
);
332 assert(num_keys
<= (is_level_tail() ? MAX_NUM_KEYS
- 1 : MAX_NUM_KEYS
));
333 auto free
= (MAX_NUM_KEYS
- index
) * (sizeof(snap_gen_t
) + sizeof(laddr_t
));
334 if (is_level_tail() && index
== num_keys
) {
335 free
-= (sizeof(snap_gen_t
) + sizeof(laddr_t
));
341 static node_offset_t
estimate_insert_one() {
342 return sizeof(snap_gen_t
) + sizeof(laddr_t
);
345 static void insert_at(
346 NodeExtentMutable
& mut
, const full_key_t
<KT
>& key
,
347 const me_t
& node
, index_t index
, node_offset_t size_right
) {
348 ceph_abort("not implemented");
350 static void update_size_at(
351 NodeExtentMutable
& mut
, const me_t
& node
, index_t index
, int change
) {
352 ceph_abort("not implemented");
355 node_header_t header
;
356 num_keys_t num_keys
= 0u;
357 snap_gen_t keys
[MAX_NUM_KEYS
];
358 laddr_packed_t child_addrs
[MAX_NUM_KEYS
];
359 } __attribute__((packed
));
360 static_assert(_internal_fields_3_t
<MAX_NUM_KEYS_I3
>::SIZE
<= NODE_BLOCK_SIZE
&&
361 _internal_fields_3_t
<MAX_NUM_KEYS_I3
+ 1>::SIZE
> NODE_BLOCK_SIZE
);
362 using internal_fields_3_t
= _internal_fields_3_t
<MAX_NUM_KEYS_I3
>;
364 using leaf_fields_3_t
= _node_fields_013_t
<slot_3_t
>;