]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/crimson/seastore/onode_tree/test_value.h
import ceph quincy 17.2.4
[ceph.git] / ceph / src / test / crimson / seastore / onode_tree / test_value.h
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 <fmt/format.h>
7
8 #include "crimson/common/log.h"
9 #include "crimson/os/seastore/onode_manager/staged-fltree/value.h"
10
11 namespace crimson::os::seastore::onode {
12
13 struct test_item_t {
14 using id_t = uint16_t;
15 using magic_t = uint32_t;
16
17 value_size_t size;
18 id_t id;
19 magic_t magic;
20
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));
24 }
25
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;
30
31 ceph_assert(_id <= std::numeric_limits<id_t>::max());
32 id_t id = _id;
33
34 return {size, id, (magic_t)id * 137};
35 }
36 };
37 inline std::ostream& operator<<(std::ostream& os, const test_item_t& item) {
38 return os << "TestItem(#" << item.id << ", " << item.size << "B)";
39 }
40
41 enum class delta_op_t : uint8_t {
42 UPDATE_ID,
43 UPDATE_TAIL_MAGIC,
44 };
45
46 inline std::ostream& operator<<(std::ostream& os, const delta_op_t op) {
47 switch (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";
52 default:
53 return os << "unknown";
54 }
55 }
56
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,
63 bool DO_SPLIT_CHECK>
64 class TestValue final : public Value {
65 public:
66 static constexpr tree_conf_t TREE_CONF = {
67 MAGIC,
68 MAX_NS_SIZE,
69 MAX_OID_SIZE,
70 MAX_VALUE_PAYLOAD_SIZE,
71 INTERNAL_NODE_SIZE,
72 LEAF_NODE_SIZE,
73 DO_SPLIT_CHECK
74 };
75
76 using id_t = test_item_t::id_t;
77 using magic_t = test_item_t::magic_t;
78 struct magic_packed_t {
79 magic_t value;
80 } __attribute__((packed));
81
82 private:
83 struct payload_t {
84 id_t id;
85 } __attribute__((packed));
86
87 struct Replayable {
88 static void set_id(NodeExtentMutable& payload_mut, id_t id) {
89 auto p_payload = get_write(payload_mut);
90 p_payload->id = id;
91 }
92
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);
97 }
98
99 private:
100 static payload_t* get_write(NodeExtentMutable& payload_mut) {
101 return reinterpret_cast<payload_t*>(payload_mut.get_write());
102 }
103 };
104
105 public:
106 class Recorder final : public ValueDeltaRecorder {
107
108 public:
109 Recorder(ceph::bufferlist& encoded)
110 : ValueDeltaRecorder(encoded) {}
111 ~Recorder() override = default;
112
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);
117 }
118
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);
123 }
124
125 protected:
126 value_magic_t get_header_magic() const override {
127 return TREE_CONF.value_magic;
128 }
129
130 void apply_value_delta(ceph::bufferlist::const_iterator& delta,
131 NodeExtentMutable& payload_mut,
132 laddr_t value_addr) override {
133 delta_op_t op;
134 try {
135 ceph::decode(op, delta);
136 switch (op) {
137 case delta_op_t::UPDATE_ID: {
138 logger().debug("OTree::TestValue::Replay: decoding UPDATE_ID ...");
139 id_t id;
140 ceph::decode(id, delta);
141 logger().debug("OTree::TestValue::Replay: apply id={} ...", id);
142 Replayable::set_id(payload_mut, id);
143 break;
144 }
145 case delta_op_t::UPDATE_TAIL_MAGIC: {
146 logger().debug("OTree::TestValue::Replay: decoding UPDATE_TAIL_MAGIC ...");
147 magic_t magic;
148 ceph::decode(magic, delta);
149 logger().debug("OTree::TestValue::Replay: apply magic={} ...", magic);
150 Replayable::set_tail_magic(payload_mut, magic);
151 break;
152 }
153 default:
154 logger().error("OTree::TestValue::Replay: got unknown op {} when replay {:#x}+{:#x}",
155 op, value_addr, payload_mut.get_length());
156 ceph_abort();
157 }
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());
161 ceph_abort();
162 }
163 }
164
165 private:
166 seastar::logger& logger() {
167 return crimson::get_logger(ceph_subsys_test);
168 }
169 };
170
171 TestValue(NodeExtentManager& nm, const ValueBuilder& vb, Ref<tree_cursor_t>& p_cursor)
172 : Value(nm, vb, p_cursor) {}
173 ~TestValue() override = default;
174
175 id_t get_id() const {
176 return read_payload<payload_t>()->id;
177 }
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);
182 }
183 Replayable::set_id(value_mutable.first, id);
184 }
185
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;
191 }
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);
196 }
197 Replayable::set_tail_magic(value_mutable.first, magic);
198 }
199
200 /*
201 * tree_util.h related interfaces
202 */
203
204 using item_t = test_item_t;
205
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);
210 }
211
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);
216 }
217 };
218
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>;
226
227 }