]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/crimson/seastore/onode_tree/test_value.h
import quincy beta 17.1.0
[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 "crimson/common/log.h"
7 #include "crimson/os/seastore/onode_manager/staged-fltree/value.h"
8
9 namespace crimson::os::seastore::onode {
10
11 struct test_item_t {
12 using id_t = uint16_t;
13 using magic_t = uint32_t;
14
15 value_size_t size;
16 id_t id;
17 magic_t magic;
18
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));
22 }
23
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;
28
29 ceph_assert(_id <= std::numeric_limits<id_t>::max());
30 id_t id = _id;
31
32 return {size, id, (magic_t)id * 137};
33 }
34 };
35 inline std::ostream& operator<<(std::ostream& os, const test_item_t& item) {
36 return os << "TestItem(#" << item.id << ", " << item.size << "B)";
37 }
38
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,
45 bool DO_SPLIT_CHECK>
46 class TestValue final : public Value {
47 public:
48 static constexpr tree_conf_t TREE_CONF = {
49 MAGIC,
50 MAX_NS_SIZE,
51 MAX_OID_SIZE,
52 MAX_VALUE_PAYLOAD_SIZE,
53 INTERNAL_NODE_SIZE,
54 LEAF_NODE_SIZE,
55 DO_SPLIT_CHECK
56 };
57
58 using id_t = test_item_t::id_t;
59 using magic_t = test_item_t::magic_t;
60 struct magic_packed_t {
61 magic_t value;
62 } __attribute__((packed));
63
64 private:
65 struct payload_t {
66 id_t id;
67 } __attribute__((packed));
68
69 struct Replayable {
70 static void set_id(NodeExtentMutable& payload_mut, id_t id) {
71 auto p_payload = get_write(payload_mut);
72 p_payload->id = id;
73 }
74
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);
79 }
80
81 private:
82 static payload_t* get_write(NodeExtentMutable& payload_mut) {
83 return reinterpret_cast<payload_t*>(payload_mut.get_write());
84 }
85 };
86
87 public:
88 class Recorder final : public ValueDeltaRecorder {
89 enum class delta_op_t : uint8_t {
90 UPDATE_ID,
91 UPDATE_TAIL_MAGIC,
92 };
93
94 public:
95 Recorder(ceph::bufferlist& encoded)
96 : ValueDeltaRecorder(encoded) {}
97 ~Recorder() override = default;
98
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);
103 }
104
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);
109 }
110
111 protected:
112 value_magic_t get_header_magic() const override {
113 return TREE_CONF.value_magic;
114 }
115
116 void apply_value_delta(ceph::bufferlist::const_iterator& delta,
117 NodeExtentMutable& payload_mut,
118 laddr_t value_addr) override {
119 delta_op_t op;
120 try {
121 ceph::decode(op, delta);
122 switch (op) {
123 case delta_op_t::UPDATE_ID: {
124 logger().debug("OTree::TestValue::Replay: decoding UPDATE_ID ...");
125 id_t id;
126 ceph::decode(id, delta);
127 logger().debug("OTree::TestValue::Replay: apply id={} ...", id);
128 Replayable::set_id(payload_mut, id);
129 break;
130 }
131 case delta_op_t::UPDATE_TAIL_MAGIC: {
132 logger().debug("OTree::TestValue::Replay: decoding UPDATE_TAIL_MAGIC ...");
133 magic_t magic;
134 ceph::decode(magic, delta);
135 logger().debug("OTree::TestValue::Replay: apply magic={} ...", magic);
136 Replayable::set_tail_magic(payload_mut, magic);
137 break;
138 }
139 default:
140 logger().error("OTree::TestValue::Replay: got unknown op {} when replay {:#x}+{:#x}",
141 op, value_addr, payload_mut.get_length());
142 ceph_abort();
143 }
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());
147 ceph_abort();
148 }
149 }
150
151 private:
152 seastar::logger& logger() {
153 return crimson::get_logger(ceph_subsys_test);
154 }
155 };
156
157 TestValue(NodeExtentManager& nm, const ValueBuilder& vb, Ref<tree_cursor_t>& p_cursor)
158 : Value(nm, vb, p_cursor) {}
159 ~TestValue() override = default;
160
161 id_t get_id() const {
162 return read_payload<payload_t>()->id;
163 }
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);
168 }
169 Replayable::set_id(value_mutable.first, id);
170 }
171
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;
177 }
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);
182 }
183 Replayable::set_tail_magic(value_mutable.first, magic);
184 }
185
186 /*
187 * tree_util.h related interfaces
188 */
189
190 using item_t = test_item_t;
191
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);
196 }
197
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);
202 }
203 };
204
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>;
212
213 }