1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
2 // vim: ts=8 sw=2 smarttab
6 #include <fmt/format.h>
8 #include "crimson/common/log.h"
9 #include "crimson/os/seastore/onode_manager/staged-fltree/value.h"
11 namespace crimson::os::seastore::onode
{
14 using id_t
= uint16_t;
15 using magic_t
= uint32_t;
21 value_size_t
get_payload_size() const {
22 assert(size
> sizeof(value_header_t
));
23 return static_cast<value_size_t
>(size
- sizeof(value_header_t
));
26 static test_item_t
create(std::size_t _size
, std::size_t _id
) {
27 ceph_assert(_size
<= std::numeric_limits
<value_size_t
>::max());
28 ceph_assert(_size
> sizeof(value_header_t
));
29 value_size_t size
= _size
;
31 ceph_assert(_id
<= std::numeric_limits
<id_t
>::max());
34 return {size
, id
, (magic_t
)id
* 137};
37 inline std::ostream
& operator<<(std::ostream
& os
, const test_item_t
& item
) {
38 return os
<< "TestItem(#" << item
.id
<< ", " << item
.size
<< "B)";
41 enum class delta_op_t
: uint8_t {
46 inline std::ostream
& operator<<(std::ostream
& os
, const delta_op_t op
) {
48 case delta_op_t::UPDATE_ID
:
49 return os
<< "update_id";
50 case delta_op_t::UPDATE_TAIL_MAGIC
:
51 return os
<< "update_tail_magic";
53 return os
<< "unknown";
57 template <value_magic_t MAGIC
,
58 string_size_t MAX_NS_SIZE
,
59 string_size_t MAX_OID_SIZE
,
60 value_size_t MAX_VALUE_PAYLOAD_SIZE
,
61 extent_len_t INTERNAL_NODE_SIZE
,
62 extent_len_t LEAF_NODE_SIZE
,
64 class TestValue final
: public Value
{
66 static constexpr tree_conf_t TREE_CONF
= {
70 MAX_VALUE_PAYLOAD_SIZE
,
76 using id_t
= test_item_t::id_t
;
77 using magic_t
= test_item_t::magic_t
;
78 struct magic_packed_t
{
80 } __attribute__((packed
));
85 } __attribute__((packed
));
88 static void set_id(NodeExtentMutable
& payload_mut
, id_t id
) {
89 auto p_payload
= get_write(payload_mut
);
93 static void set_tail_magic(NodeExtentMutable
& payload_mut
, magic_t magic
) {
94 auto length
= payload_mut
.get_length();
95 auto offset_magic
= length
- sizeof(magic_t
);
96 payload_mut
.copy_in_relative(offset_magic
, magic
);
100 static payload_t
* get_write(NodeExtentMutable
& payload_mut
) {
101 return reinterpret_cast<payload_t
*>(payload_mut
.get_write());
106 class Recorder final
: public ValueDeltaRecorder
{
109 Recorder(ceph::bufferlist
& encoded
)
110 : ValueDeltaRecorder(encoded
) {}
111 ~Recorder() override
= default;
113 void encode_set_id(NodeExtentMutable
& payload_mut
, id_t id
) {
114 auto& encoded
= get_encoded(payload_mut
);
115 ceph::encode(delta_op_t::UPDATE_ID
, encoded
);
116 ceph::encode(id
, encoded
);
119 void encode_set_tail_magic(NodeExtentMutable
& payload_mut
, magic_t magic
) {
120 auto& encoded
= get_encoded(payload_mut
);
121 ceph::encode(delta_op_t::UPDATE_TAIL_MAGIC
, encoded
);
122 ceph::encode(magic
, encoded
);
126 value_magic_t
get_header_magic() const override
{
127 return TREE_CONF
.value_magic
;
130 void apply_value_delta(ceph::bufferlist::const_iterator
& delta
,
131 NodeExtentMutable
& payload_mut
,
132 laddr_t value_addr
) override
{
135 ceph::decode(op
, delta
);
137 case delta_op_t::UPDATE_ID
: {
138 logger().debug("OTree::TestValue::Replay: decoding UPDATE_ID ...");
140 ceph::decode(id
, delta
);
141 logger().debug("OTree::TestValue::Replay: apply id={} ...", id
);
142 Replayable::set_id(payload_mut
, id
);
145 case delta_op_t::UPDATE_TAIL_MAGIC
: {
146 logger().debug("OTree::TestValue::Replay: decoding UPDATE_TAIL_MAGIC ...");
148 ceph::decode(magic
, delta
);
149 logger().debug("OTree::TestValue::Replay: apply magic={} ...", magic
);
150 Replayable::set_tail_magic(payload_mut
, magic
);
154 logger().error("OTree::TestValue::Replay: got unknown op {} when replay {:#x}+{:#x}",
155 op
, value_addr
, payload_mut
.get_length());
158 } catch (buffer::error
& e
) {
159 logger().error("OTree::TestValue::Replay: got decode error {} when replay {:#x}+{:#x}",
160 e
, value_addr
, payload_mut
.get_length());
166 seastar::logger
& logger() {
167 return crimson::get_logger(ceph_subsys_test
);
171 TestValue(NodeExtentManager
& nm
, const ValueBuilder
& vb
, Ref
<tree_cursor_t
>& p_cursor
)
172 : Value(nm
, vb
, p_cursor
) {}
173 ~TestValue() override
= default;
175 id_t
get_id() const {
176 return read_payload
<payload_t
>()->id
;
178 void set_id_replayable(Transaction
& t
, id_t id
) {
179 auto value_mutable
= prepare_mutate_payload
<payload_t
, Recorder
>(t
);
180 if (value_mutable
.second
) {
181 value_mutable
.second
->encode_set_id(value_mutable
.first
, id
);
183 Replayable::set_id(value_mutable
.first
, id
);
186 magic_t
get_tail_magic() const {
187 auto p_payload
= read_payload
<payload_t
>();
188 auto offset_magic
= get_payload_size() - sizeof(magic_t
);
189 auto p_magic
= reinterpret_cast<const char*>(p_payload
) + offset_magic
;
190 return reinterpret_cast<const magic_packed_t
*>(p_magic
)->value
;
192 void set_tail_magic_replayable(Transaction
& t
, magic_t magic
) {
193 auto value_mutable
= prepare_mutate_payload
<payload_t
, Recorder
>(t
);
194 if (value_mutable
.second
) {
195 value_mutable
.second
->encode_set_tail_magic(value_mutable
.first
, magic
);
197 Replayable::set_tail_magic(value_mutable
.first
, magic
);
201 * tree_util.h related interfaces
204 using item_t
= test_item_t
;
206 void initialize(Transaction
& t
, const item_t
& item
) {
207 ceph_assert(get_payload_size() + sizeof(value_header_t
) == item
.size
);
208 set_id_replayable(t
, item
.id
);
209 set_tail_magic_replayable(t
, item
.magic
);
212 void validate(const item_t
& item
) const {
213 ceph_assert(get_payload_size() + sizeof(value_header_t
) == item
.size
);
214 ceph_assert(get_id() == item
.id
);
215 ceph_assert(get_tail_magic() == item
.magic
);
219 using UnboundedValue
= TestValue
<
220 value_magic_t::TEST_UNBOUND
, 4096, 4096, 4096, 4096, 4096, false>;
221 using BoundedValue
= TestValue
<
222 value_magic_t::TEST_BOUNDED
, 320, 320, 640, 4096, 4096, true>;
223 // should be the same configuration with FLTreeOnode
224 using ExtendedValue
= TestValue
<
225 value_magic_t::TEST_EXTENDED
, 256, 2048, 1200, 8192, 16384, true>;