1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/execution/index/art/art_node.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/execution/index/art/fixed_size_allocator.hpp" |
12 | #include "duckdb/execution/index/art/swizzleable_pointer.hpp" |
13 | |
14 | namespace duckdb { |
15 | |
16 | // classes |
17 | enum class NType : uint8_t { |
18 | PREFIX_SEGMENT = 1, |
19 | LEAF_SEGMENT = 2, |
20 | LEAF = 3, |
21 | NODE_4 = 4, |
22 | NODE_16 = 5, |
23 | NODE_48 = 6, |
24 | NODE_256 = 7 |
25 | }; |
26 | class ART; |
27 | class Node; |
28 | class Prefix; |
29 | class MetaBlockReader; |
30 | class MetaBlockWriter; |
31 | |
32 | // structs |
33 | struct BlockPointer; |
34 | struct ARTFlags; |
35 | |
36 | //! The ARTNode is the swizzleable pointer class of the ART index. |
37 | //! If the ARTNode pointer is not swizzled, then the leftmost byte identifies the NType. |
38 | //! The remaining bytes are the position in the respective ART buffer. |
39 | class Node : public SwizzleablePointer { |
40 | public: |
41 | // constants (this allows testing performance with different ART node sizes) |
42 | |
43 | //! Node prefixes (NOTE: this should always hold: PREFIX_SEGMENT_SIZE >= PREFIX_INLINE_BYTES) |
44 | static constexpr uint32_t PREFIX_INLINE_BYTES = 8; |
45 | static constexpr uint32_t PREFIX_SEGMENT_SIZE = 32; |
46 | //! Node thresholds |
47 | static constexpr uint8_t NODE_48_SHRINK_THRESHOLD = 12; |
48 | static constexpr uint8_t NODE_256_SHRINK_THRESHOLD = 36; |
49 | //! Node sizes |
50 | static constexpr uint8_t NODE_4_CAPACITY = 4; |
51 | static constexpr uint8_t NODE_16_CAPACITY = 16; |
52 | static constexpr uint8_t NODE_48_CAPACITY = 48; |
53 | static constexpr uint16_t NODE_256_CAPACITY = 256; |
54 | //! Other constants |
55 | static constexpr uint8_t EMPTY_MARKER = 48; |
56 | static constexpr uint32_t LEAF_SEGMENT_SIZE = 8; |
57 | |
58 | public: |
59 | //! Constructs an empty ARTNode |
60 | Node(); |
61 | //! Constructs a swizzled pointer from a block ID and an offset |
62 | explicit Node(MetaBlockReader &reader); |
63 | //! Get a new pointer to a node, might cause a new buffer allocation, and initialize it |
64 | static void New(ART &art, Node &node, const NType type); |
65 | //! Free the node (and its subtree) |
66 | static void Free(ART &art, Node &node); |
67 | |
68 | inline bool operator==(const Node &node) const { |
69 | return swizzle_flag == node.swizzle_flag && type == node.type && offset == node.offset && |
70 | buffer_id == node.buffer_id; |
71 | } |
72 | |
73 | //! Retrieve the node type from the leftmost byte |
74 | inline NType DecodeARTNodeType() const { |
75 | D_ASSERT(!IsSwizzled()); |
76 | D_ASSERT(type >= (uint8_t)NType::PREFIX_SEGMENT); |
77 | D_ASSERT(type <= (uint8_t)NType::NODE_256); |
78 | return NType(type); |
79 | } |
80 | |
81 | //! Set the pointer |
82 | inline void SetPtr(const SwizzleablePointer ptr) { |
83 | swizzle_flag = ptr.swizzle_flag; |
84 | type = ptr.type; |
85 | offset = ptr.offset; |
86 | buffer_id = ptr.buffer_id; |
87 | } |
88 | |
89 | //! Replace the child node at the respective byte |
90 | void ReplaceChild(const ART &art, const uint8_t byte, const Node child); |
91 | //! Insert the child node at byte |
92 | static void InsertChild(ART &art, Node &node, const uint8_t byte, const Node child); |
93 | //! Delete the child node at the respective byte |
94 | static void DeleteChild(ART &art, Node &node, const uint8_t byte); |
95 | |
96 | //! Get the child for the respective byte in the node |
97 | optional_ptr<Node> GetChild(ART &art, const uint8_t byte) const; |
98 | //! Get the first child that is greater or equal to the specific byte |
99 | optional_ptr<Node> GetNextChild(ART &art, uint8_t &byte, const bool deserialize = true) const; |
100 | |
101 | //! Serialize the node |
102 | BlockPointer Serialize(ART &art, MetaBlockWriter &writer); |
103 | //! Deserialize the node |
104 | void Deserialize(ART &art); |
105 | |
106 | //! Returns the string representation of the node, or only traverses and verifies the node and its subtree |
107 | string VerifyAndToString(ART &art, const bool only_verify); |
108 | //! Returns the capacity of the node |
109 | idx_t GetCapacity() const; |
110 | //! Returns a pointer to the prefix of the node |
111 | Prefix &GetPrefix(ART &art); |
112 | //! Returns the matching node type for a given count |
113 | static NType GetARTNodeTypeByCount(const idx_t count); |
114 | //! Get references to the different allocators |
115 | static FixedSizeAllocator &GetAllocator(const ART &art, NType type); |
116 | |
117 | //! Initializes a merge by fully deserializing the subtree of the node and incrementing its buffer IDs |
118 | void InitializeMerge(ART &art, const ARTFlags &flags); |
119 | //! Merge another node into this node |
120 | bool Merge(ART &art, Node &other); |
121 | //! Merge two nodes by first resolving their prefixes |
122 | bool ResolvePrefixes(ART &art, Node &other); |
123 | //! Merge two nodes that have no prefix or the same prefix |
124 | bool MergeInternal(ART &art, Node &other); |
125 | |
126 | //! Vacuum all nodes that exceed their respective vacuum thresholds |
127 | static void Vacuum(ART &art, Node &node, const ARTFlags &flags); |
128 | }; |
129 | |
130 | } // namespace duckdb |
131 | |