/src/serenity/Userland/Libraries/LibSQL/TreeNode.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2021, Jan de Visser <jan@de-visser.net> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/Debug.h> |
8 | | #include <AK/Format.h> |
9 | | #include <AK/StringBuilder.h> |
10 | | #include <LibSQL/BTree.h> |
11 | | #include <LibSQL/Serializer.h> |
12 | | |
13 | | namespace SQL { |
14 | | |
15 | | DownPointer::DownPointer(TreeNode* owner, Block::Index block_index) |
16 | 0 | : m_owner(owner) |
17 | 0 | , m_block_index(block_index) |
18 | 0 | , m_node(nullptr) |
19 | 0 | { |
20 | 0 | } |
21 | | |
22 | | DownPointer::DownPointer(TreeNode* owner, TreeNode* node) |
23 | 0 | : m_owner(owner) |
24 | 0 | , m_block_index((node) ? node->block_index() : 0) |
25 | 0 | , m_node(adopt_own_if_nonnull(node)) |
26 | 0 | { |
27 | 0 | } |
28 | | |
29 | | DownPointer::DownPointer(TreeNode* owner, DownPointer& down) |
30 | 0 | : m_owner(owner) |
31 | 0 | , m_block_index(down.m_block_index) |
32 | 0 | , m_node(move(down.m_node)) |
33 | 0 | { |
34 | 0 | } |
35 | | |
36 | | DownPointer::DownPointer(DownPointer&& other) |
37 | 0 | : m_owner(other.m_owner) |
38 | 0 | , m_block_index(other.block_index()) |
39 | 0 | , m_node(other.m_node ? move(other.m_node) : nullptr) |
40 | 0 | { |
41 | 0 | } |
42 | | |
43 | | TreeNode* DownPointer::node() |
44 | 0 | { |
45 | 0 | if (!m_node) |
46 | 0 | deserialize(m_owner->tree().serializer()); |
47 | 0 | return m_node; |
48 | 0 | } |
49 | | |
50 | | void DownPointer::deserialize(Serializer& serializer) |
51 | 0 | { |
52 | 0 | if (m_node || !m_block_index) |
53 | 0 | return; |
54 | 0 | serializer.read_storage(m_block_index); |
55 | 0 | m_node = serializer.make_and_deserialize<TreeNode>(m_owner->tree(), m_owner, m_block_index); |
56 | 0 | } |
57 | | |
58 | | TreeNode::TreeNode(BTree& tree, Block::Index block_index) |
59 | 0 | : IndexNode(block_index) |
60 | 0 | , m_tree(tree) |
61 | 0 | , m_up(nullptr) |
62 | 0 | , m_entries() |
63 | 0 | , m_down() |
64 | 0 | { |
65 | 0 | } |
66 | | |
67 | | TreeNode::TreeNode(BTree& tree, TreeNode* up, Block::Index block_index) |
68 | 0 | : IndexNode(block_index) |
69 | 0 | , m_tree(tree) |
70 | 0 | , m_up(up) |
71 | 0 | , m_entries() |
72 | 0 | , m_down() |
73 | 0 | { |
74 | 0 | m_down.append(DownPointer(this, nullptr)); |
75 | 0 | m_is_leaf = true; |
76 | 0 | } |
77 | | |
78 | | TreeNode::TreeNode(BTree& tree, TreeNode* up, DownPointer& left, Block::Index block_index) |
79 | 0 | : IndexNode(block_index) |
80 | 0 | , m_tree(tree) |
81 | 0 | , m_up(up) |
82 | 0 | , m_entries() |
83 | 0 | , m_down() |
84 | 0 | { |
85 | 0 | if (left.m_node != nullptr) |
86 | 0 | left.m_node->m_up = this; |
87 | 0 | m_down.append(DownPointer(this, left)); |
88 | 0 | m_is_leaf = left.block_index() == 0; |
89 | 0 | if (!block_index) |
90 | 0 | set_block_index(m_tree.request_new_block_index()); |
91 | 0 | } |
92 | | |
93 | | TreeNode::TreeNode(BTree& tree, TreeNode* up, TreeNode* left, Block::Index block_index) |
94 | 0 | : IndexNode(block_index) |
95 | 0 | , m_tree(tree) |
96 | 0 | , m_up(up) |
97 | 0 | , m_entries() |
98 | 0 | , m_down() |
99 | 0 | { |
100 | 0 | m_down.append(DownPointer(this, left)); |
101 | 0 | m_is_leaf = left->block_index() == 0; |
102 | 0 | } |
103 | | |
104 | | void TreeNode::deserialize(Serializer& serializer) |
105 | 0 | { |
106 | 0 | auto nodes = serializer.deserialize<u32>(); |
107 | 0 | dbgln_if(SQL_DEBUG, "Deserializing node. Size {}", nodes); |
108 | 0 | if (nodes > 0) { |
109 | 0 | for (u32 i = 0; i < nodes; i++) { |
110 | 0 | auto left = serializer.deserialize<u32>(); |
111 | 0 | dbgln_if(SQL_DEBUG, "Down[{}] {}", i, left); |
112 | 0 | if (!m_down.is_empty()) |
113 | 0 | VERIFY((left == 0) == m_is_leaf); |
114 | 0 | else |
115 | 0 | m_is_leaf = (left == 0); |
116 | 0 | m_entries.append(serializer.deserialize<Key>(m_tree.descriptor())); |
117 | 0 | m_down.empend(this, left); |
118 | 0 | } |
119 | 0 | auto right = serializer.deserialize<u32>(); |
120 | 0 | dbgln_if(SQL_DEBUG, "Right {}", right); |
121 | 0 | VERIFY((right == 0) == m_is_leaf); |
122 | 0 | m_down.empend(this, right); |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | | void TreeNode::serialize(Serializer& serializer) const |
127 | 0 | { |
128 | 0 | u32 sz = size(); |
129 | 0 | serializer.serialize<u32>(sz); |
130 | 0 | if (sz > 0) { |
131 | 0 | for (auto ix = 0u; ix < size(); ix++) { |
132 | 0 | auto& entry = m_entries[ix]; |
133 | 0 | dbgln_if(SQL_DEBUG, "Serializing Left[{}] = {}", ix, m_down[ix].block_index()); |
134 | 0 | serializer.serialize<u32>(is_leaf() ? 0u : m_down[ix].block_index()); |
135 | 0 | serializer.serialize<Key>(entry); |
136 | 0 | } |
137 | 0 | dbgln_if(SQL_DEBUG, "Serializing Right = {}", m_down[size()].block_index()); |
138 | 0 | serializer.serialize<u32>(is_leaf() ? 0u : m_down[size()].block_index()); |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | | size_t TreeNode::length() const |
143 | 0 | { |
144 | 0 | if (!size()) |
145 | 0 | return 0; |
146 | 0 | size_t len = sizeof(u32); |
147 | 0 | for (auto& key : m_entries) |
148 | 0 | len += sizeof(u32) + key.length(); |
149 | 0 | return len; |
150 | 0 | } |
151 | | |
152 | | bool TreeNode::insert(Key const& key) |
153 | 0 | { |
154 | 0 | dbgln_if(SQL_DEBUG, "[#{}] INSERT({})", block_index(), key.to_byte_string()); |
155 | 0 | if (!is_leaf()) |
156 | 0 | return node_for(key)->insert_in_leaf(key); |
157 | 0 | return insert_in_leaf(key); |
158 | 0 | } |
159 | | |
160 | | bool TreeNode::update_key_pointer(Key const& key) |
161 | 0 | { |
162 | 0 | dbgln_if(SQL_DEBUG, "[#{}] UPDATE({}, {})", block_index(), key.to_byte_string(), key.block_index()); |
163 | 0 | if (!is_leaf()) |
164 | 0 | return node_for(key)->update_key_pointer(key); |
165 | | |
166 | 0 | for (auto ix = 0u; ix < size(); ix++) { |
167 | 0 | if (key == m_entries[ix]) { |
168 | 0 | dbgln_if(SQL_DEBUG, "[#{}] {} == {}", |
169 | 0 | block_index(), key.to_byte_string(), m_entries[ix].to_byte_string()); |
170 | 0 | if (m_entries[ix].block_index() != key.block_index()) { |
171 | 0 | m_entries[ix].set_block_index(key.block_index()); |
172 | 0 | dump_if(SQL_DEBUG, "To WAL"); |
173 | 0 | tree().serializer().serialize_and_write<TreeNode>(*this); |
174 | 0 | } |
175 | 0 | return true; |
176 | 0 | } |
177 | 0 | } |
178 | 0 | return false; |
179 | 0 | } |
180 | | |
181 | | bool TreeNode::insert_in_leaf(Key const& key) |
182 | 0 | { |
183 | 0 | VERIFY(is_leaf()); |
184 | 0 | if (!m_tree.duplicates_allowed()) { |
185 | 0 | for (auto& entry : m_entries) { |
186 | 0 | if (key == entry) { |
187 | 0 | dbgln_if(SQL_DEBUG, "[#{}] duplicate key {}", block_index(), key.to_byte_string()); |
188 | 0 | return false; |
189 | 0 | } |
190 | 0 | } |
191 | 0 | } |
192 | | |
193 | 0 | dbgln_if(SQL_DEBUG, "[#{}] insert_in_leaf({})", block_index(), key.to_byte_string()); |
194 | 0 | just_insert(key, nullptr); |
195 | 0 | return true; |
196 | 0 | } |
197 | | |
198 | | Block::Index TreeNode::down_pointer(size_t ix) const |
199 | 0 | { |
200 | 0 | return m_down[ix].block_index(); |
201 | 0 | } |
202 | | |
203 | | TreeNode* TreeNode::down_node(size_t ix) |
204 | 0 | { |
205 | 0 | return m_down[ix].node(); |
206 | 0 | } |
207 | | |
208 | | TreeNode* TreeNode::node_for(Key const& key) |
209 | 0 | { |
210 | 0 | dump_if(SQL_DEBUG, ByteString::formatted("node_for(Key {})", key.to_byte_string())); |
211 | 0 | if (is_leaf()) |
212 | 0 | return this; |
213 | 0 | for (size_t ix = 0; ix < size(); ix++) { |
214 | 0 | if (key < m_entries[ix]) { |
215 | 0 | dbgln_if(SQL_DEBUG, "[{}] {} < {} v{}", |
216 | 0 | block_index(), (ByteString)key, (ByteString)m_entries[ix], m_down[ix].block_index()); |
217 | 0 | return down_node(ix)->node_for(key); |
218 | 0 | } |
219 | 0 | } |
220 | 0 | dbgln_if(SQL_DEBUG, "[#{}] {} >= {} v{}", |
221 | 0 | block_index(), key.to_byte_string(), (ByteString)m_entries[size() - 1], m_down[size()].block_index()); |
222 | 0 | return down_node(size())->node_for(key); |
223 | 0 | } |
224 | | |
225 | | Optional<u32> TreeNode::get(Key& key) |
226 | 0 | { |
227 | 0 | dump_if(SQL_DEBUG, ByteString::formatted("get({})", key.to_byte_string())); |
228 | 0 | for (auto ix = 0u; ix < size(); ix++) { |
229 | 0 | if (key < m_entries[ix]) { |
230 | 0 | if (is_leaf()) { |
231 | 0 | dbgln_if(SQL_DEBUG, "[#{}] {} < {} -> 0", |
232 | 0 | block_index(), key.to_byte_string(), (ByteString)m_entries[ix]); |
233 | 0 | return {}; |
234 | 0 | } else { |
235 | 0 | dbgln_if(SQL_DEBUG, "[{}] {} < {} ({} -> {})", |
236 | 0 | block_index(), key.to_byte_string(), (ByteString)m_entries[ix], |
237 | 0 | ix, m_down[ix].block_index()); |
238 | 0 | return down_node(ix)->get(key); |
239 | 0 | } |
240 | 0 | } |
241 | 0 | if (key == m_entries[ix]) { |
242 | 0 | dbgln_if(SQL_DEBUG, "[#{}] {} == {} -> {}", |
243 | 0 | block_index(), key.to_byte_string(), (ByteString)m_entries[ix], |
244 | 0 | m_entries[ix].block_index()); |
245 | 0 | key.set_block_index(m_entries[ix].block_index()); |
246 | 0 | return m_entries[ix].block_index(); |
247 | 0 | } |
248 | 0 | } |
249 | 0 | if (m_entries.is_empty()) { |
250 | 0 | dbgln_if(SQL_DEBUG, "[#{}] {} Empty node??", block_index(), key.to_byte_string()); |
251 | 0 | VERIFY_NOT_REACHED(); |
252 | 0 | } |
253 | 0 | if (is_leaf()) { |
254 | 0 | dbgln_if(SQL_DEBUG, "[#{}] {} > {} -> 0", |
255 | 0 | block_index(), key.to_byte_string(), (ByteString)m_entries[size() - 1]); |
256 | 0 | return {}; |
257 | 0 | } |
258 | 0 | dbgln_if(SQL_DEBUG, "[#{}] {} > {} ({} -> {})", |
259 | 0 | block_index(), key.to_byte_string(), (ByteString)m_entries[size() - 1], |
260 | 0 | size(), m_down[size()].block_index()); |
261 | 0 | return down_node(size())->get(key); |
262 | 0 | } |
263 | | |
264 | | void TreeNode::just_insert(Key const& key, TreeNode* right) |
265 | 0 | { |
266 | 0 | dbgln_if(SQL_DEBUG, "[#{}] just_insert({}, right = {})", |
267 | 0 | block_index(), (ByteString)key, (right) ? right->block_index() : 0); |
268 | 0 | dump_if(SQL_DEBUG, "Before"); |
269 | 0 | for (auto ix = 0u; ix < size(); ix++) { |
270 | 0 | if (key < m_entries[ix]) { |
271 | 0 | m_entries.insert(ix, key); |
272 | 0 | VERIFY(is_leaf() == (right == nullptr)); |
273 | 0 | m_down.insert(ix + 1, DownPointer(this, right)); |
274 | 0 | if (length() > Block::DATA_SIZE) { |
275 | 0 | split(); |
276 | 0 | } else { |
277 | 0 | dump_if(SQL_DEBUG, "To WAL"); |
278 | 0 | tree().serializer().serialize_and_write(*this); |
279 | 0 | } |
280 | 0 | return; |
281 | 0 | } |
282 | 0 | } |
283 | 0 | m_entries.append(key); |
284 | 0 | m_down.empend(this, right); |
285 | |
|
286 | 0 | if (length() > Block::DATA_SIZE) { |
287 | 0 | split(); |
288 | 0 | } else { |
289 | 0 | dump_if(SQL_DEBUG, "To WAL"); |
290 | 0 | tree().serializer().serialize_and_write(*this); |
291 | 0 | } |
292 | 0 | } |
293 | | |
294 | | void TreeNode::split() |
295 | 0 | { |
296 | 0 | dump_if(SQL_DEBUG, "Splitting node"); |
297 | 0 | if (!m_up) |
298 | | // Make new m_up. This is the new root node. |
299 | 0 | m_up = m_tree.new_root(); |
300 | | |
301 | | // Take the left pointer for the new node: |
302 | 0 | auto median_index = size() / 2; |
303 | 0 | if (!(size() % 2)) |
304 | 0 | ++median_index; |
305 | 0 | DownPointer left = m_down.take(median_index); |
306 | | |
307 | | // Create the new right node: |
308 | 0 | auto* new_node = new TreeNode(tree(), m_up, left); |
309 | | |
310 | | // Move the rightmost keys from this node to the new right node: |
311 | 0 | while (m_entries.size() > median_index) { |
312 | 0 | auto entry = m_entries.take(median_index); |
313 | 0 | auto down = m_down.take(median_index); |
314 | | |
315 | | // Reparent to new right node: |
316 | 0 | if (down.m_node != nullptr) |
317 | 0 | down.m_node->m_up = new_node; |
318 | 0 | new_node->m_entries.append(entry); |
319 | 0 | new_node->m_down.append(move(down)); |
320 | 0 | } |
321 | | |
322 | | // Move the median key in the node one level up. Its right node will |
323 | | // be the new node: |
324 | 0 | auto median = m_entries.take_last(); |
325 | |
|
326 | 0 | dump_if(SQL_DEBUG, "Split Left To WAL"); |
327 | 0 | tree().serializer().serialize_and_write(*this); |
328 | 0 | new_node->dump_if(SQL_DEBUG, "Split Right to WAL"); |
329 | 0 | tree().serializer().serialize_and_write(*new_node); |
330 | |
|
331 | 0 | m_up->just_insert(median, new_node); |
332 | 0 | } |
333 | | |
334 | | void TreeNode::dump_if(int flag, ByteString&& msg) |
335 | 0 | { |
336 | 0 | if (!flag) |
337 | 0 | return; |
338 | 0 | StringBuilder builder; |
339 | 0 | builder.appendff("[#{}] ", block_index()); |
340 | 0 | if (!msg.is_empty()) |
341 | 0 | builder.appendff("{}", msg); |
342 | 0 | builder.append(": "sv); |
343 | 0 | if (m_up) |
344 | 0 | builder.appendff("[^{}] -> ", m_up->block_index()); |
345 | 0 | else |
346 | 0 | builder.append("* -> "sv); |
347 | 0 | for (size_t ix = 0; ix < m_entries.size(); ix++) { |
348 | 0 | if (!is_leaf()) |
349 | 0 | builder.appendff("[v{}] ", m_down[ix].block_index()); |
350 | 0 | else |
351 | 0 | VERIFY(m_down[ix].block_index() == 0); |
352 | 0 | builder.appendff("'{}' ", (ByteString)m_entries[ix]); |
353 | 0 | } |
354 | 0 | if (!is_leaf()) |
355 | 0 | builder.appendff("[v{}]", m_down[size()].block_index()); |
356 | 0 | else |
357 | 0 | VERIFY(m_down[size()].block_index() == 0); |
358 | 0 | builder.appendff(" (size {}", (int)size()); |
359 | 0 | if (is_leaf()) |
360 | 0 | builder.append(", leaf"sv); |
361 | 0 | builder.append(')'); |
362 | 0 | dbgln(builder.to_byte_string()); |
363 | 0 | } |
364 | | |
365 | | void TreeNode::list_node(int indent) |
366 | 0 | { |
367 | 0 | auto do_indent = [&]() { |
368 | 0 | for (int i = 0; i < indent; ++i) |
369 | 0 | warn(" "); |
370 | 0 | }; |
371 | 0 | do_indent(); |
372 | 0 | warnln("--> #{}", block_index()); |
373 | 0 | for (auto ix = 0u; ix < size(); ix++) { |
374 | 0 | if (!is_leaf()) |
375 | 0 | down_node(ix)->list_node(indent + 2); |
376 | 0 | do_indent(); |
377 | 0 | warnln("{}", m_entries[ix].to_byte_string()); |
378 | 0 | } |
379 | 0 | if (!is_leaf()) |
380 | 0 | down_node(size())->list_node(indent + 2); |
381 | 0 | } |
382 | | |
383 | | } |