1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
2 // vim: ts=8 sw=2 smarttab
6 #include "crimson/common/log.h"
7 #include "crimson/os/seastore/onode_manager/staged-fltree/value.h"
9 namespace crimson::os::seastore::onode
{
12 using id_t
= uint16_t;
13 using magic_t
= uint32_t;
19 value_size_t
get_payload_size() const {
20 assert(size
> sizeof(value_header_t
));
21 return static_cast<value_size_t
>(size
- sizeof(value_header_t
));
24 static test_item_t
create(std::size_t _size
, std::size_t _id
) {
25 ceph_assert(_size
<= std::numeric_limits
<value_size_t
>::max());
26 ceph_assert(_size
> sizeof(value_header_t
));
27 value_size_t size
= _size
;
29 ceph_assert(_id
<= std::numeric_limits
<id_t
>::max());
32 return {size
, id
, (magic_t
)id
* 137};
35 inline std::ostream
& operator<<(std::ostream
& os
, const test_item_t
& item
) {
36 return os
<< "TestItem(#" << item
.id
<< ", " << item
.size
<< "B)";
39 template <value_magic_t MAGIC
,
40 string_size_t MAX_NS_SIZE
,
41 string_size_t MAX_OID_SIZE
,
42 value_size_t MAX_VALUE_PAYLOAD_SIZE
,
43 extent_len_t INTERNAL_NODE_SIZE
,
44 extent_len_t LEAF_NODE_SIZE
,
46 class TestValue final
: public Value
{
48 static constexpr tree_conf_t TREE_CONF
= {
52 MAX_VALUE_PAYLOAD_SIZE
,
58 using id_t
= test_item_t::id_t
;
59 using magic_t
= test_item_t::magic_t
;
60 struct magic_packed_t
{
62 } __attribute__((packed
));
67 } __attribute__((packed
));
70 static void set_id(NodeExtentMutable
& payload_mut
, id_t id
) {
71 auto p_payload
= get_write(payload_mut
);
75 static void set_tail_magic(NodeExtentMutable
& payload_mut
, magic_t magic
) {
76 auto length
= payload_mut
.get_length();
77 auto offset_magic
= length
- sizeof(magic_t
);
78 payload_mut
.copy_in_relative(offset_magic
, magic
);
82 static payload_t
* get_write(NodeExtentMutable
& payload_mut
) {
83 return reinterpret_cast<payload_t
*>(payload_mut
.get_write());
88 class Recorder final
: public ValueDeltaRecorder
{
89 enum class delta_op_t
: uint8_t {
95 Recorder(ceph::bufferlist
& encoded
)
96 : ValueDeltaRecorder(encoded
) {}
97 ~Recorder() override
= default;
99 void encode_set_id(NodeExtentMutable
& payload_mut
, id_t id
) {
100 auto& encoded
= get_encoded(payload_mut
);
101 ceph::encode(delta_op_t::UPDATE_ID
, encoded
);
102 ceph::encode(id
, encoded
);
105 void encode_set_tail_magic(NodeExtentMutable
& payload_mut
, magic_t magic
) {
106 auto& encoded
= get_encoded(payload_mut
);
107 ceph::encode(delta_op_t::UPDATE_TAIL_MAGIC
, encoded
);
108 ceph::encode(magic
, encoded
);
112 value_magic_t
get_header_magic() const override
{
113 return TREE_CONF
.value_magic
;
116 void apply_value_delta(ceph::bufferlist::const_iterator
& delta
,
117 NodeExtentMutable
& payload_mut
,
118 laddr_t value_addr
) override
{
121 ceph::decode(op
, delta
);
123 case delta_op_t::UPDATE_ID
: {
124 logger().debug("OTree::TestValue::Replay: decoding UPDATE_ID ...");
126 ceph::decode(id
, delta
);
127 logger().debug("OTree::TestValue::Replay: apply id={} ...", id
);
128 Replayable::set_id(payload_mut
, id
);
131 case delta_op_t::UPDATE_TAIL_MAGIC
: {
132 logger().debug("OTree::TestValue::Replay: decoding UPDATE_TAIL_MAGIC ...");
134 ceph::decode(magic
, delta
);
135 logger().debug("OTree::TestValue::Replay: apply magic={} ...", magic
);
136 Replayable::set_tail_magic(payload_mut
, magic
);
140 logger().error("OTree::TestValue::Replay: got unknown op {} when replay {:#x}+{:#x}",
141 op
, value_addr
, payload_mut
.get_length());
144 } catch (buffer::error
& e
) {
145 logger().error("OTree::TestValue::Replay: got decode error {} when replay {:#x}+{:#x}",
146 e
, value_addr
, payload_mut
.get_length());
152 seastar::logger
& logger() {
153 return crimson::get_logger(ceph_subsys_test
);
157 TestValue(NodeExtentManager
& nm
, const ValueBuilder
& vb
, Ref
<tree_cursor_t
>& p_cursor
)
158 : Value(nm
, vb
, p_cursor
) {}
159 ~TestValue() override
= default;
161 id_t
get_id() const {
162 return read_payload
<payload_t
>()->id
;
164 void set_id_replayable(Transaction
& t
, id_t id
) {
165 auto value_mutable
= prepare_mutate_payload
<payload_t
, Recorder
>(t
);
166 if (value_mutable
.second
) {
167 value_mutable
.second
->encode_set_id(value_mutable
.first
, id
);
169 Replayable::set_id(value_mutable
.first
, id
);
172 magic_t
get_tail_magic() const {
173 auto p_payload
= read_payload
<payload_t
>();
174 auto offset_magic
= get_payload_size() - sizeof(magic_t
);
175 auto p_magic
= reinterpret_cast<const char*>(p_payload
) + offset_magic
;
176 return reinterpret_cast<const magic_packed_t
*>(p_magic
)->value
;
178 void set_tail_magic_replayable(Transaction
& t
, magic_t magic
) {
179 auto value_mutable
= prepare_mutate_payload
<payload_t
, Recorder
>(t
);
180 if (value_mutable
.second
) {
181 value_mutable
.second
->encode_set_tail_magic(value_mutable
.first
, magic
);
183 Replayable::set_tail_magic(value_mutable
.first
, magic
);
187 * tree_util.h related interfaces
190 using item_t
= test_item_t
;
192 void initialize(Transaction
& t
, const item_t
& item
) {
193 ceph_assert(get_payload_size() + sizeof(value_header_t
) == item
.size
);
194 set_id_replayable(t
, item
.id
);
195 set_tail_magic_replayable(t
, item
.magic
);
198 void validate(const item_t
& item
) const {
199 ceph_assert(get_payload_size() + sizeof(value_header_t
) == item
.size
);
200 ceph_assert(get_id() == item
.id
);
201 ceph_assert(get_tail_magic() == item
.magic
);
205 using UnboundedValue
= TestValue
<
206 value_magic_t::TEST_UNBOUND
, 4096, 4096, 4096, 4096, 4096, false>;
207 using BoundedValue
= TestValue
<
208 value_magic_t::TEST_BOUNDED
, 320, 320, 640, 4096, 4096, true>;
209 // should be the same configuration with FLTreeOnode
210 using ExtendedValue
= TestValue
<
211 value_magic_t::TEST_EXTENDED
, 256, 2048, 1200, 8192, 16384, true>;