]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #pragma once | |
5 | ||
6 | #include "crimson/os/seastore/onode_manager/staged-fltree/node_types.h" | |
7 | #include "key_layout.h" | |
8 | #include "stage_types.h" | |
9 | ||
10 | namespace crimson::os::seastore::onode { | |
11 | ||
12 | class NodeExtentMutable; | |
13 | ||
14 | /** | |
15 | * node_extent_t | |
16 | * | |
17 | * The top indexing stage implementation for node N0/N1/N2/N3, implements | |
18 | * staged contract as an indexable container, and provides access to node | |
19 | * header. | |
20 | * | |
21 | * The specific field layout are defined by FieldType which are | |
22 | * node_fields_0_t, node_fields_1_t, node_fields_2_t, internal_fields_3_t and | |
23 | * leaf_fields_3_t. Diagrams see node_stage_layout.h. | |
24 | */ | |
25 | template <typename FieldType, node_type_t _NODE_TYPE> | |
26 | class node_extent_t { | |
27 | public: | |
20effc67 | 28 | using value_input_t = value_input_type_t<_NODE_TYPE>; |
f67539c2 TL |
29 | using value_t = value_type_t<_NODE_TYPE>; |
30 | using num_keys_t = typename FieldType::num_keys_t; | |
31 | static constexpr node_type_t NODE_TYPE = _NODE_TYPE; | |
32 | static constexpr field_type_t FIELD_TYPE = FieldType::FIELD_TYPE; | |
f67539c2 TL |
33 | |
34 | // TODO: remove | |
35 | node_extent_t() = default; | |
36 | ||
20effc67 TL |
37 | node_extent_t(const FieldType* p_fields, extent_len_t node_size) |
38 | : p_fields{p_fields}, node_size{node_size} { | |
39 | assert(is_valid_node_size(node_size)); | |
f67539c2 TL |
40 | validate(*p_fields); |
41 | } | |
42 | ||
43 | const char* p_start() const { return fields_start(*p_fields); } | |
44 | ||
f67539c2 TL |
45 | bool is_level_tail() const { return p_fields->is_level_tail(); } |
46 | level_t level() const { return p_fields->header.level; } | |
47 | node_offset_t free_size() const { | |
20effc67 TL |
48 | return p_fields->template free_size_before<NODE_TYPE>( |
49 | keys(), node_size); | |
50 | } | |
51 | extent_len_t total_size() const { | |
52 | return p_fields->total_size(node_size); | |
f67539c2 | 53 | } |
f67539c2 TL |
54 | const char* p_left_bound() const; |
55 | template <node_type_t T = NODE_TYPE> | |
56 | std::enable_if_t<T == node_type_t::INTERNAL, const laddr_packed_t*> | |
57 | get_end_p_laddr() const { | |
58 | assert(is_level_tail()); | |
59 | if constexpr (FIELD_TYPE == field_type_t::N3) { | |
20effc67 | 60 | return p_fields->get_p_child_addr(keys(), node_size); |
f67539c2 | 61 | } else { |
20effc67 TL |
62 | auto offset_start = p_fields->get_item_end_offset( |
63 | keys(), node_size); | |
64 | assert(offset_start <= node_size); | |
f67539c2 TL |
65 | offset_start -= sizeof(laddr_packed_t); |
66 | auto p_addr = p_start() + offset_start; | |
67 | return reinterpret_cast<const laddr_packed_t*>(p_addr); | |
68 | } | |
69 | } | |
70 | ||
71 | // container type system | |
72 | using key_get_type = typename FieldType::key_get_type; | |
73 | static constexpr auto CONTAINER_TYPE = ContainerType::INDEXABLE; | |
74 | index_t keys() const { return p_fields->num_keys; } | |
20effc67 TL |
75 | key_get_type operator[] (index_t index) const { |
76 | return p_fields->get_key(index, node_size); | |
77 | } | |
78 | extent_len_t size_before(index_t index) const { | |
79 | auto free_size = p_fields->template free_size_before<NODE_TYPE>( | |
80 | index, node_size); | |
f67539c2 TL |
81 | assert(total_size() >= free_size); |
82 | return total_size() - free_size; | |
83 | } | |
84 | node_offset_t size_to_nxt_at(index_t index) const; | |
85 | node_offset_t size_overhead_at(index_t index) const { | |
86 | return FieldType::ITEM_OVERHEAD; } | |
20effc67 | 87 | container_range_t get_nxt_container(index_t index) const; |
f67539c2 TL |
88 | |
89 | template <typename T = FieldType> | |
90 | std::enable_if_t<T::FIELD_TYPE == field_type_t::N3, const value_t*> | |
91 | get_p_value(index_t index) const { | |
92 | assert(index < keys()); | |
93 | if constexpr (NODE_TYPE == node_type_t::INTERNAL) { | |
20effc67 | 94 | return p_fields->get_p_child_addr(index, node_size); |
f67539c2 | 95 | } else { |
20effc67 TL |
96 | auto range = get_nxt_container(index).range; |
97 | auto ret = reinterpret_cast<const value_header_t*>(range.p_start); | |
98 | assert(range.p_start + ret->allocation_size() == range.p_end); | |
f67539c2 TL |
99 | return ret; |
100 | } | |
101 | } | |
102 | ||
103 | void encode(const char* p_node_start, ceph::bufferlist& encoded) const { | |
104 | assert(p_node_start == p_start()); | |
105 | // nothing to encode as the container range is the entire extent | |
106 | } | |
107 | ||
108 | static node_extent_t decode(const char* p_node_start, | |
20effc67 | 109 | extent_len_t node_size, |
f67539c2 TL |
110 | ceph::bufferlist::const_iterator& delta) { |
111 | // nothing to decode | |
20effc67 TL |
112 | return node_extent_t( |
113 | reinterpret_cast<const FieldType*>(p_node_start), | |
114 | node_size); | |
f67539c2 TL |
115 | } |
116 | ||
117 | static void validate(const FieldType& fields) { | |
118 | #ifndef NDEBUG | |
119 | assert(fields.header.get_node_type() == NODE_TYPE); | |
120 | assert(fields.header.get_field_type() == FieldType::FIELD_TYPE); | |
121 | if constexpr (NODE_TYPE == node_type_t::INTERNAL) { | |
122 | assert(fields.header.level > 0u); | |
123 | } else { | |
124 | assert(fields.header.level == 0u); | |
125 | } | |
126 | #endif | |
127 | } | |
128 | ||
129 | static void bootstrap_extent( | |
130 | NodeExtentMutable&, field_type_t, node_type_t, bool, level_t); | |
131 | ||
132 | static void update_is_level_tail(NodeExtentMutable&, const node_extent_t&, bool); | |
133 | ||
134 | static node_offset_t header_size() { return FieldType::HEADER_SIZE; } | |
135 | ||
1e59de90 | 136 | template <IsFullKey Key> |
f67539c2 | 137 | static node_offset_t estimate_insert( |
1e59de90 | 138 | const Key& key, const value_input_t& value) { |
f67539c2 TL |
139 | auto size = FieldType::estimate_insert_one(); |
140 | if constexpr (FIELD_TYPE == field_type_t::N2) { | |
1e59de90 | 141 | size += ns_oid_view_t::estimate_size(key); |
f67539c2 TL |
142 | } else if constexpr (FIELD_TYPE == field_type_t::N3 && |
143 | NODE_TYPE == node_type_t::LEAF) { | |
20effc67 | 144 | size += value.allocation_size(); |
f67539c2 TL |
145 | } |
146 | return size; | |
147 | } | |
148 | ||
1e59de90 | 149 | template <IsFullKey Key> |
f67539c2 TL |
150 | static const value_t* insert_at( |
151 | NodeExtentMutable& mut, const node_extent_t&, | |
1e59de90 | 152 | const Key& key, const value_input_t& value, |
f67539c2 TL |
153 | index_t index, node_offset_t size, const char* p_left_bound) { |
154 | if constexpr (FIELD_TYPE == field_type_t::N3) { | |
155 | ceph_abort("not implemented"); | |
156 | } else { | |
157 | ceph_abort("impossible"); | |
158 | } | |
159 | } | |
160 | ||
1e59de90 | 161 | template <IsFullKey Key> |
f67539c2 TL |
162 | static memory_range_t insert_prefix_at( |
163 | NodeExtentMutable&, const node_extent_t&, | |
1e59de90 | 164 | const Key& key, |
f67539c2 TL |
165 | index_t index, node_offset_t size, const char* p_left_bound); |
166 | ||
167 | static void update_size_at( | |
168 | NodeExtentMutable&, const node_extent_t&, index_t index, int change); | |
169 | ||
170 | static node_offset_t trim_until( | |
171 | NodeExtentMutable&, const node_extent_t&, index_t index); | |
172 | static node_offset_t trim_at(NodeExtentMutable&, const node_extent_t&, | |
173 | index_t index, node_offset_t trimmed); | |
174 | ||
20effc67 TL |
175 | static node_offset_t erase_at(NodeExtentMutable&, const node_extent_t&, |
176 | index_t index, const char* p_left_bound); | |
177 | ||
f67539c2 TL |
178 | template <KeyT KT> |
179 | class Appender; | |
180 | ||
181 | private: | |
182 | const FieldType& fields() const { return *p_fields; } | |
183 | const FieldType* p_fields; | |
20effc67 | 184 | extent_len_t node_size; |
f67539c2 TL |
185 | }; |
186 | ||
187 | template <typename FieldType, node_type_t NODE_TYPE> | |
188 | template <KeyT KT> | |
189 | class node_extent_t<FieldType, NODE_TYPE>::Appender { | |
190 | public: | |
191 | Appender(NodeExtentMutable* p_mut, char* p_append) | |
192 | : p_mut{p_mut}, p_start{p_append} { | |
193 | #ifndef NDEBUG | |
194 | auto p_fields = reinterpret_cast<const FieldType*>(p_append); | |
195 | assert(*(p_fields->header.get_field_type()) == FIELD_TYPE); | |
196 | assert(p_fields->header.get_node_type() == NODE_TYPE); | |
197 | assert(p_fields->num_keys == 0); | |
198 | #endif | |
199 | p_append_left = p_start + FieldType::HEADER_SIZE; | |
20effc67 | 200 | p_append_right = p_start + p_mut->get_length(); |
f67539c2 | 201 | } |
20effc67 | 202 | Appender(NodeExtentMutable*, const node_extent_t&, bool open = false); |
f67539c2 | 203 | void append(const node_extent_t& src, index_t from, index_t items); |
20effc67 | 204 | void append(const full_key_t<KT>&, const value_input_t&, const value_t*&); |
f67539c2 TL |
205 | char* wrap(); |
206 | std::tuple<NodeExtentMutable*, char*> open_nxt(const key_get_type&); | |
207 | std::tuple<NodeExtentMutable*, char*> open_nxt(const full_key_t<KT>&); | |
208 | void wrap_nxt(char* p_append) { | |
209 | if constexpr (FIELD_TYPE != field_type_t::N3) { | |
210 | assert(p_append < p_append_right); | |
211 | assert(p_append_left < p_append); | |
212 | p_append_right = p_append; | |
20effc67 TL |
213 | auto new_offset = p_append - p_start; |
214 | assert(new_offset > 0); | |
215 | assert(new_offset < p_mut->get_length()); | |
216 | FieldType::append_offset(*p_mut, new_offset, p_append_left); | |
f67539c2 TL |
217 | ++num_keys; |
218 | } else { | |
219 | ceph_abort("not implemented"); | |
220 | } | |
221 | } | |
222 | ||
223 | private: | |
224 | const node_extent_t* p_src = nullptr; | |
225 | NodeExtentMutable* p_mut; | |
226 | char* p_start; | |
227 | char* p_append_left; | |
228 | char* p_append_right; | |
229 | num_keys_t num_keys = 0; | |
230 | }; | |
231 | ||
232 | } |