duckdb 0.7.2-dev2552.0 → 0.7.2-dev2699.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.gyp +7 -7
- package/package.json +2 -2
- package/src/duckdb/extension/parquet/parquet_statistics.cpp +3 -0
- package/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp +2 -2
- package/src/duckdb/src/common/adbc/adbc.cpp +5 -2
- package/src/duckdb/src/common/radix_partitioning.cpp +1 -1
- package/src/duckdb/src/execution/index/art/art.cpp +286 -269
- package/src/duckdb/src/execution/index/art/art_key.cpp +22 -32
- package/src/duckdb/src/execution/index/art/fixed_size_allocator.cpp +224 -0
- package/src/duckdb/src/execution/index/art/iterator.cpp +142 -123
- package/src/duckdb/src/execution/index/art/leaf.cpp +319 -170
- package/src/duckdb/src/execution/index/art/leaf_segment.cpp +42 -0
- package/src/duckdb/src/execution/index/art/node.cpp +444 -379
- package/src/duckdb/src/execution/index/art/node16.cpp +178 -114
- package/src/duckdb/src/execution/index/art/node256.cpp +117 -79
- package/src/duckdb/src/execution/index/art/node4.cpp +169 -114
- package/src/duckdb/src/execution/index/art/node48.cpp +175 -105
- package/src/duckdb/src/execution/index/art/prefix.cpp +405 -127
- package/src/duckdb/src/execution/index/art/prefix_segment.cpp +42 -0
- package/src/duckdb/src/execution/index/art/swizzleable_pointer.cpp +10 -85
- package/src/duckdb/src/execution/operator/join/physical_index_join.cpp +2 -1
- package/src/duckdb/src/execution/operator/persistent/base_csv_reader.cpp +2 -2
- package/src/duckdb/src/execution/operator/persistent/csv_reader_options.cpp +2 -0
- package/src/duckdb/src/execution/operator/persistent/parallel_csv_reader.cpp +4 -0
- package/src/duckdb/src/execution/operator/schema/physical_create_index.cpp +11 -12
- package/src/duckdb/src/function/table/read_csv.cpp +5 -1
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/common/queue.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +53 -45
- package/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp +29 -24
- package/src/duckdb/src/include/duckdb/execution/index/art/fixed_size_allocator.hpp +114 -0
- package/src/duckdb/src/include/duckdb/execution/index/art/iterator.hpp +26 -20
- package/src/duckdb/src/include/duckdb/execution/index/art/leaf.hpp +63 -39
- package/src/duckdb/src/include/duckdb/execution/index/art/leaf_segment.hpp +36 -0
- package/src/duckdb/src/include/duckdb/execution/index/art/node.hpp +98 -116
- package/src/duckdb/src/include/duckdb/execution/index/art/node16.hpp +48 -36
- package/src/duckdb/src/include/duckdb/execution/index/art/node256.hpp +52 -35
- package/src/duckdb/src/include/duckdb/execution/index/art/node4.hpp +46 -36
- package/src/duckdb/src/include/duckdb/execution/index/art/node48.hpp +57 -35
- package/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +57 -50
- package/src/duckdb/src/include/duckdb/execution/index/art/prefix_segment.hpp +40 -0
- package/src/duckdb/src/include/duckdb/execution/index/art/swizzleable_pointer.hpp +38 -31
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/csv_file_handle.hpp +2 -1
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/csv_reader_options.hpp +2 -0
- package/src/duckdb/src/include/duckdb/main/query_result.hpp +1 -1
- package/src/duckdb/src/include/duckdb/parser/statement/insert_statement.hpp +4 -1
- package/src/duckdb/src/include/duckdb/parser/transformer.hpp +2 -1
- package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +0 -5
- package/src/duckdb/src/include/duckdb/storage/index.hpp +13 -28
- package/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp +0 -2
- package/src/duckdb/src/include/duckdb/transaction/cleanup_state.hpp +5 -0
- package/src/duckdb/src/include/duckdb.h +26 -0
- package/src/duckdb/src/main/capi/helper-c.cpp +7 -0
- package/src/duckdb/src/main/client_context.cpp +1 -1
- package/src/duckdb/src/main/query_result.cpp +1 -1
- package/src/duckdb/src/parser/statement/insert_statement.cpp +15 -6
- package/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp +1 -1
- package/src/duckdb/src/parser/transform/expression/transform_function.cpp +18 -5
- package/src/duckdb/src/parser/transform/statement/transform_insert.cpp +5 -7
- package/src/duckdb/src/planner/binder/statement/bind_create.cpp +20 -7
- package/src/duckdb/src/planner/binder/statement/bind_insert.cpp +14 -9
- package/src/duckdb/src/storage/checkpoint_manager.cpp +11 -9
- package/src/duckdb/src/storage/data_table.cpp +6 -3
- package/src/duckdb/src/storage/index.cpp +18 -6
- package/src/duckdb/src/storage/local_storage.cpp +8 -2
- package/src/duckdb/src/storage/standard_buffer_manager.cpp +0 -9
- package/src/duckdb/src/storage/wal_replay.cpp +1 -1
- package/src/duckdb/src/transaction/cleanup_state.cpp +6 -0
- package/src/duckdb/src/transaction/undo_buffer.cpp +8 -0
- package/src/duckdb/ub_extension_icu_third_party_icu_i18n.cpp +4 -4
- package/src/duckdb/ub_src_execution_index_art.cpp +7 -1
@@ -1,191 +1,469 @@
|
|
1
1
|
#include "duckdb/execution/index/art/prefix.hpp"
|
2
2
|
|
3
3
|
#include "duckdb/execution/index/art/art.hpp"
|
4
|
+
#include "duckdb/execution/index/art/art_key.hpp"
|
5
|
+
#include "duckdb/execution/index/art/node.hpp"
|
6
|
+
#include "duckdb/execution/index/art/prefix_segment.hpp"
|
7
|
+
#include "duckdb/storage/meta_block_reader.hpp"
|
8
|
+
#include "duckdb/storage/meta_block_writer.hpp"
|
4
9
|
|
5
10
|
namespace duckdb {
|
6
11
|
|
7
|
-
|
8
|
-
|
12
|
+
void Prefix::Free(ART &art) {
|
13
|
+
|
14
|
+
if (IsInlined()) {
|
15
|
+
return Initialize();
|
16
|
+
}
|
17
|
+
|
18
|
+
// delete all prefix segments
|
19
|
+
auto ptr = data.ptr;
|
20
|
+
while (ptr.IsSet()) {
|
21
|
+
auto next_ptr = PrefixSegment::Get(art, ptr).next;
|
22
|
+
Node::Free(art, ptr);
|
23
|
+
ptr = next_ptr;
|
24
|
+
}
|
25
|
+
|
26
|
+
Initialize();
|
9
27
|
}
|
10
28
|
|
11
|
-
|
12
|
-
|
29
|
+
void Prefix::Initialize(ART &art, const ARTKey &key, const uint32_t depth, const uint32_t count_p) {
|
30
|
+
|
31
|
+
// prefix can be inlined
|
32
|
+
if (count_p <= Node::PREFIX_INLINE_BYTES) {
|
33
|
+
memcpy(data.inlined, key.data + depth, count_p);
|
34
|
+
count = count_p;
|
35
|
+
return;
|
36
|
+
}
|
37
|
+
|
38
|
+
// prefix cannot be inlined, copy to segment(s)
|
39
|
+
count = 0;
|
40
|
+
reference<PrefixSegment> segment(PrefixSegment::New(art, data.ptr));
|
41
|
+
for (idx_t i = 0; i < count_p; i++) {
|
42
|
+
segment = segment.get().Append(art, count, key.data[depth + i]);
|
43
|
+
}
|
44
|
+
D_ASSERT(count == count_p);
|
13
45
|
}
|
14
46
|
|
15
|
-
|
16
|
-
|
47
|
+
void Prefix::Initialize(ART &art, const Prefix &other, const uint32_t count_p) {
|
48
|
+
|
49
|
+
D_ASSERT(count_p <= other.count);
|
50
|
+
|
51
|
+
// copy inlined data
|
52
|
+
if (other.IsInlined()) {
|
53
|
+
memcpy(data.inlined, other.data.inlined, count_p);
|
54
|
+
count = count_p;
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
|
58
|
+
// initialize the count and get the first segment
|
59
|
+
count = 0;
|
60
|
+
reference<PrefixSegment> segment(PrefixSegment::New(art, data.ptr));
|
61
|
+
|
62
|
+
// iterate the segments of the other prefix and copy their data
|
63
|
+
auto other_ptr = other.data.ptr;
|
64
|
+
auto remaining = count_p;
|
65
|
+
|
66
|
+
while (remaining != 0) {
|
67
|
+
D_ASSERT(other_ptr.IsSet());
|
68
|
+
auto &other_segment = PrefixSegment::Get(art, other_ptr);
|
69
|
+
auto copy_count = MinValue(Node::PREFIX_SEGMENT_SIZE, remaining);
|
70
|
+
|
71
|
+
// copy the data
|
72
|
+
for (idx_t i = 0; i < copy_count; i++) {
|
73
|
+
segment = segment.get().Append(art, count, other_segment.bytes[i]);
|
74
|
+
}
|
75
|
+
|
76
|
+
// adjust the loop variables
|
77
|
+
other_ptr = other_segment.next;
|
78
|
+
remaining -= copy_count;
|
79
|
+
}
|
80
|
+
D_ASSERT(count == count_p);
|
17
81
|
}
|
18
82
|
|
19
|
-
|
20
|
-
Destroy();
|
83
|
+
void Prefix::InitializeMerge(ART &art, const idx_t buffer_count) {
|
21
84
|
|
22
|
-
this->size = size;
|
23
|
-
uint8_t *prefix;
|
24
85
|
if (IsInlined()) {
|
25
|
-
|
26
|
-
} else {
|
27
|
-
// allocate new prefix
|
28
|
-
value.ptr = AllocateArray<uint8_t>(size);
|
29
|
-
prefix = value.ptr;
|
86
|
+
return;
|
30
87
|
}
|
31
|
-
return prefix;
|
32
|
-
}
|
33
88
|
|
34
|
-
|
89
|
+
reference<PrefixSegment> segment(PrefixSegment::Get(art, data.ptr));
|
90
|
+
data.ptr.buffer_id += buffer_count;
|
91
|
+
|
92
|
+
auto ptr = segment.get().next;
|
93
|
+
while (ptr.IsSet()) {
|
94
|
+
segment.get().next.buffer_id += buffer_count;
|
95
|
+
segment = PrefixSegment::Get(art, ptr);
|
96
|
+
ptr = segment.get().next;
|
97
|
+
}
|
35
98
|
}
|
36
99
|
|
37
|
-
Prefix::
|
38
|
-
auto prefix = AllocatePrefix(size);
|
100
|
+
void Prefix::Append(ART &art, const Prefix &other) {
|
39
101
|
|
40
|
-
//
|
41
|
-
|
42
|
-
|
43
|
-
|
102
|
+
// result fits into inlined data, i.e., both prefixes are also inlined
|
103
|
+
if (count + other.count <= Node::PREFIX_INLINE_BYTES) {
|
104
|
+
memcpy(data.inlined + count, other.data.inlined, other.count);
|
105
|
+
count += other.count;
|
106
|
+
return;
|
44
107
|
}
|
45
|
-
}
|
46
108
|
|
47
|
-
|
48
|
-
|
109
|
+
// this prefix is inlined, but will no longer be after appending the other prefix,
|
110
|
+
// move the inlined bytes to the first prefix segment
|
111
|
+
if (IsInlined()) {
|
112
|
+
MoveInlinedToSegment(art);
|
113
|
+
}
|
49
114
|
|
50
|
-
//
|
51
|
-
|
52
|
-
|
53
|
-
|
115
|
+
// get the tail of the segments of this prefix
|
116
|
+
reference<PrefixSegment> segment(PrefixSegment::Get(art, data.ptr).GetTail(art));
|
117
|
+
|
118
|
+
// the other prefix is inlined
|
119
|
+
if (other.IsInlined()) {
|
120
|
+
for (idx_t i = 0; i < other.count; i++) {
|
121
|
+
segment = segment.get().Append(art, count, other.data.inlined[i]);
|
122
|
+
}
|
123
|
+
return;
|
54
124
|
}
|
55
|
-
}
|
56
125
|
|
57
|
-
|
58
|
-
|
59
|
-
|
126
|
+
// iterate all segments of the other prefix and copy their data
|
127
|
+
auto other_ptr = other.data.ptr;
|
128
|
+
auto remaining = other.count;
|
60
129
|
|
61
|
-
|
62
|
-
|
63
|
-
|
130
|
+
while (other_ptr.IsSet()) {
|
131
|
+
auto &other_segment = PrefixSegment::Get(art, other_ptr);
|
132
|
+
auto copy_count = MinValue(Node::PREFIX_SEGMENT_SIZE, remaining);
|
133
|
+
|
134
|
+
// copy the data
|
135
|
+
for (idx_t i = 0; i < copy_count; i++) {
|
136
|
+
segment = segment.get().Append(art, count, other_segment.bytes[i]);
|
137
|
+
}
|
64
138
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
size = 0;
|
139
|
+
// adjust the loop variables
|
140
|
+
other_ptr = other_segment.next;
|
141
|
+
remaining -= copy_count;
|
69
142
|
}
|
143
|
+
D_ASSERT(remaining == 0);
|
70
144
|
}
|
71
145
|
|
72
|
-
|
73
|
-
|
74
|
-
|
146
|
+
void Prefix::Concatenate(ART &art, const uint8_t byte, const Prefix &other) {
|
147
|
+
|
148
|
+
auto new_size = count + 1 + other.count;
|
149
|
+
|
150
|
+
// overwrite into this prefix (both are inlined)
|
151
|
+
if (new_size <= Node::PREFIX_INLINE_BYTES) {
|
152
|
+
// move this prefix backwards
|
153
|
+
memmove(data.inlined + other.count + 1, data.inlined, count);
|
154
|
+
// copy byte
|
155
|
+
data.inlined[other.count] = byte;
|
156
|
+
// copy the other prefix into this prefix
|
157
|
+
memcpy(data.inlined, other.data.inlined, other.count);
|
158
|
+
count = new_size;
|
159
|
+
return;
|
160
|
+
}
|
161
|
+
|
162
|
+
auto this_count = count;
|
163
|
+
auto this_data = data;
|
164
|
+
Initialize();
|
165
|
+
|
166
|
+
// append the other prefix
|
167
|
+
Append(art, other);
|
168
|
+
|
169
|
+
if (IsInlined()) {
|
170
|
+
// move to a segment
|
171
|
+
reference<PrefixSegment> segment(MoveInlinedToSegment(art));
|
172
|
+
// append the byte
|
173
|
+
segment = segment.get().Append(art, count, byte);
|
174
|
+
// append this prefix
|
175
|
+
for (idx_t i = 0; i < this_count; i++) {
|
176
|
+
segment = segment.get().Append(art, count, this_data.inlined[i]);
|
177
|
+
}
|
178
|
+
return;
|
179
|
+
}
|
180
|
+
|
181
|
+
// get the tail
|
182
|
+
reference<PrefixSegment> segment(PrefixSegment::Get(art, data.ptr).GetTail(art));
|
183
|
+
// append the byte
|
184
|
+
segment = segment.get().Append(art, count, byte);
|
185
|
+
|
186
|
+
// iterate all segments of this prefix, copy their data, and free them
|
187
|
+
auto this_ptr = this_data.ptr;
|
188
|
+
auto remaining = this_count;
|
189
|
+
|
190
|
+
while (this_ptr.IsSet()) {
|
191
|
+
auto &this_segment = PrefixSegment::Get(art, this_ptr);
|
192
|
+
auto copy_count = MinValue(Node::PREFIX_SEGMENT_SIZE, remaining);
|
193
|
+
|
194
|
+
// copy the data
|
195
|
+
for (idx_t i = 0; i < copy_count; i++) {
|
196
|
+
segment = segment.get().Append(art, count, this_segment.bytes[i]);
|
197
|
+
}
|
198
|
+
|
199
|
+
// adjust the loop variables
|
200
|
+
Node::Free(art, this_ptr);
|
201
|
+
this_ptr = this_segment.next;
|
202
|
+
remaining -= copy_count;
|
203
|
+
}
|
204
|
+
D_ASSERT(remaining == 0);
|
75
205
|
}
|
76
206
|
|
77
|
-
|
78
|
-
|
207
|
+
uint8_t Prefix::Reduce(ART &art, const idx_t reduce_count) {
|
208
|
+
|
209
|
+
auto new_count = count - reduce_count - 1;
|
210
|
+
auto new_first_byte = GetByte(art, reduce_count);
|
211
|
+
|
212
|
+
// prefix is now empty
|
213
|
+
if (new_count == 0) {
|
214
|
+
Free(art);
|
215
|
+
return new_first_byte;
|
216
|
+
}
|
217
|
+
|
218
|
+
// was inlined, just move bytes
|
219
|
+
if (IsInlined()) {
|
220
|
+
memmove(data.inlined, data.inlined + reduce_count + 1, new_count);
|
221
|
+
count = new_count;
|
222
|
+
return new_first_byte;
|
223
|
+
}
|
224
|
+
|
225
|
+
count = 0;
|
226
|
+
auto start = reduce_count + 1;
|
227
|
+
auto offset = start % Node::PREFIX_SEGMENT_SIZE;
|
228
|
+
auto remaining = new_count;
|
229
|
+
|
230
|
+
// get the source segment, i.e., the segment that contains the byte at start
|
231
|
+
reference<PrefixSegment> src_segment(PrefixSegment::Get(art, data.ptr));
|
232
|
+
for (idx_t i = 0; i < start / Node::PREFIX_SEGMENT_SIZE; i++) {
|
233
|
+
D_ASSERT(src_segment.get().next.IsSet());
|
234
|
+
src_segment = PrefixSegment::Get(art, src_segment.get().next);
|
235
|
+
}
|
236
|
+
|
237
|
+
// iterate all segments starting at the source segment and shift their data
|
238
|
+
reference<PrefixSegment> dst_segment(PrefixSegment::Get(art, data.ptr));
|
239
|
+
while (true) {
|
240
|
+
auto copy_count = MinValue(Node::PREFIX_SEGMENT_SIZE - offset, remaining);
|
241
|
+
|
242
|
+
// copy the data
|
243
|
+
for (idx_t i = offset; i < offset + copy_count; i++) {
|
244
|
+
dst_segment = dst_segment.get().Append(art, count, src_segment.get().bytes[i]);
|
245
|
+
}
|
79
246
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
247
|
+
// adjust the loop variables
|
248
|
+
offset = 0;
|
249
|
+
remaining -= copy_count;
|
250
|
+
if (remaining == 0) {
|
251
|
+
break;
|
252
|
+
}
|
253
|
+
D_ASSERT(src_segment.get().next.IsSet());
|
254
|
+
src_segment = PrefixSegment::Get(art, src_segment.get().next);
|
255
|
+
}
|
256
|
+
|
257
|
+
// possibly inline the data
|
258
|
+
if (IsInlined()) {
|
259
|
+
MoveSegmentToInlined(art);
|
84
260
|
}
|
85
|
-
|
86
|
-
return
|
261
|
+
|
262
|
+
return new_first_byte;
|
87
263
|
}
|
88
264
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
265
|
+
uint8_t Prefix::GetByte(const ART &art, const idx_t position) const {
|
266
|
+
|
267
|
+
D_ASSERT(position < count);
|
268
|
+
if (IsInlined()) {
|
269
|
+
return data.inlined[position];
|
270
|
+
}
|
271
|
+
|
272
|
+
// get the correct segment
|
273
|
+
reference<PrefixSegment> segment(PrefixSegment::Get(art, data.ptr));
|
274
|
+
for (idx_t i = 0; i < position / Node::PREFIX_SEGMENT_SIZE; i++) {
|
275
|
+
D_ASSERT(segment.get().next.IsSet());
|
276
|
+
segment = PrefixSegment::Get(art, segment.get().next);
|
277
|
+
}
|
278
|
+
|
279
|
+
return segment.get().bytes[position % Node::PREFIX_SEGMENT_SIZE];
|
93
280
|
}
|
94
281
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
282
|
+
uint32_t Prefix::KeyMismatchPosition(const ART &art, const ARTKey &key, const uint32_t depth) const {
|
283
|
+
|
284
|
+
if (IsInlined()) {
|
285
|
+
for (idx_t mismatch_position = 0; mismatch_position < count; mismatch_position++) {
|
286
|
+
D_ASSERT(depth + mismatch_position < key.len);
|
287
|
+
if (key[depth + mismatch_position] != data.inlined[mismatch_position]) {
|
288
|
+
return mismatch_position;
|
289
|
+
}
|
290
|
+
}
|
291
|
+
return count;
|
292
|
+
}
|
293
|
+
|
294
|
+
uint32_t mismatch_position = 0;
|
295
|
+
auto ptr = data.ptr;
|
296
|
+
|
297
|
+
while (mismatch_position != count) {
|
298
|
+
D_ASSERT(depth + mismatch_position < key.len);
|
299
|
+
D_ASSERT(ptr.IsSet());
|
300
|
+
|
301
|
+
auto &segment = PrefixSegment::Get(art, ptr);
|
302
|
+
auto compare_count = MinValue(Node::PREFIX_SEGMENT_SIZE, count - mismatch_position);
|
303
|
+
|
304
|
+
// compare bytes
|
305
|
+
for (uint32_t i = 0; i < compare_count; i++) {
|
306
|
+
if (key[depth + mismatch_position] != segment.bytes[i]) {
|
307
|
+
return mismatch_position;
|
308
|
+
}
|
309
|
+
mismatch_position++;
|
102
310
|
}
|
103
|
-
DeleteArray<uint8_t>(data, new_size);
|
104
311
|
|
105
|
-
|
106
|
-
|
107
|
-
// take over the data directly
|
108
|
-
Destroy();
|
109
|
-
size = new_size;
|
110
|
-
value.ptr = data;
|
312
|
+
// adjust loop variables
|
313
|
+
ptr = segment.next;
|
111
314
|
}
|
315
|
+
return count;
|
112
316
|
}
|
113
317
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
// have to allocate space in our prefix array
|
118
|
-
auto new_prefix = AllocateArray<uint8_t>(new_size);
|
119
|
-
idx_t new_prefix_idx = 0;
|
318
|
+
uint32_t Prefix::MismatchPosition(const ART &art, const Prefix &other) const {
|
319
|
+
|
320
|
+
D_ASSERT(count <= other.count);
|
120
321
|
|
121
|
-
// 1
|
122
|
-
|
123
|
-
|
322
|
+
// case 1: both prefixes are inlined
|
323
|
+
if (IsInlined() && other.IsInlined()) {
|
324
|
+
for (uint32_t i = 0; i < count; i++) {
|
325
|
+
if (data.inlined[i] != other.data.inlined[i]) {
|
326
|
+
return i;
|
327
|
+
}
|
328
|
+
}
|
329
|
+
return count;
|
124
330
|
}
|
125
331
|
|
126
|
-
// 2
|
127
|
-
|
332
|
+
// case 2: only this prefix is inlined
|
333
|
+
if (IsInlined()) {
|
334
|
+
// we only need the first segment of the other prefix
|
335
|
+
auto &segment = PrefixSegment::Get(art, other.data.ptr);
|
336
|
+
for (uint32_t i = 0; i < count; i++) {
|
337
|
+
if (data.inlined[i] != segment.bytes[i]) {
|
338
|
+
return i;
|
339
|
+
}
|
340
|
+
}
|
341
|
+
return count;
|
342
|
+
}
|
128
343
|
|
129
|
-
// 3
|
130
|
-
auto
|
131
|
-
|
132
|
-
|
344
|
+
// case 3: both prefixes are not inlined
|
345
|
+
auto ptr = data.ptr;
|
346
|
+
auto other_ptr = other.data.ptr;
|
347
|
+
|
348
|
+
// iterate segments and compare bytes
|
349
|
+
uint32_t mismatch_position = 0;
|
350
|
+
while (ptr.IsSet()) {
|
351
|
+
D_ASSERT(other_ptr.IsSet());
|
352
|
+
auto &segment = PrefixSegment::Get(art, ptr);
|
353
|
+
auto &other_segment = PrefixSegment::Get(art, other_ptr);
|
354
|
+
|
355
|
+
// compare bytes
|
356
|
+
auto compare_count = MinValue(Node::PREFIX_SEGMENT_SIZE, count - mismatch_position);
|
357
|
+
for (uint32_t i = 0; i < compare_count; i++) {
|
358
|
+
if (segment.bytes[i] != other_segment.bytes[i]) {
|
359
|
+
return mismatch_position;
|
360
|
+
}
|
361
|
+
mismatch_position++;
|
362
|
+
}
|
363
|
+
|
364
|
+
// adjust loop variables
|
365
|
+
ptr = segment.next;
|
366
|
+
other_ptr = other_segment.next;
|
133
367
|
}
|
134
|
-
|
368
|
+
return count;
|
135
369
|
}
|
136
370
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
auto prefix = GetPrefixData();
|
141
|
-
auto partial_key = prefix[n];
|
371
|
+
void Prefix::Serialize(const ART &art, MetaBlockWriter &writer) const {
|
372
|
+
|
373
|
+
writer.Write(count);
|
142
374
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
return
|
375
|
+
// write inlined data
|
376
|
+
if (IsInlined()) {
|
377
|
+
writer.WriteData(data.inlined, count);
|
378
|
+
return;
|
147
379
|
}
|
148
|
-
|
149
|
-
|
150
|
-
|
380
|
+
|
381
|
+
D_ASSERT(data.ptr.IsSet());
|
382
|
+
auto ptr = data.ptr;
|
383
|
+
auto remaining = count;
|
384
|
+
|
385
|
+
// iterate all prefix segments and write their bytes
|
386
|
+
while (ptr.IsSet()) {
|
387
|
+
auto &segment = PrefixSegment::Get(art, ptr);
|
388
|
+
auto copy_count = MinValue(Node::PREFIX_SEGMENT_SIZE, remaining);
|
389
|
+
|
390
|
+
// write the bytes
|
391
|
+
writer.WriteData(segment.bytes, copy_count);
|
392
|
+
|
393
|
+
// adjust loop variables
|
394
|
+
remaining -= copy_count;
|
395
|
+
ptr = segment.next;
|
151
396
|
}
|
152
|
-
|
153
|
-
return partial_key;
|
397
|
+
D_ASSERT(remaining == 0);
|
154
398
|
}
|
155
399
|
|
156
|
-
void Prefix::
|
157
|
-
writer.Write(size);
|
158
|
-
auto prefix = GetPrefixData();
|
159
|
-
writer.WriteData(prefix, size);
|
160
|
-
}
|
400
|
+
void Prefix::Deserialize(ART &art, MetaBlockReader &reader) {
|
161
401
|
|
162
|
-
|
163
|
-
auto prefix_size = reader.Read<uint32_t>();
|
164
|
-
auto prefix = AllocatePrefix(prefix_size);
|
165
|
-
this->size = prefix_size;
|
166
|
-
reader.ReadData(prefix, size);
|
167
|
-
}
|
402
|
+
auto count_p = reader.Read<uint32_t>();
|
168
403
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
return pos;
|
175
|
-
}
|
404
|
+
// copy into inlined data
|
405
|
+
if (count_p <= Node::PREFIX_INLINE_BYTES) {
|
406
|
+
reader.ReadData(data.inlined, count_p);
|
407
|
+
count = count_p;
|
408
|
+
return;
|
176
409
|
}
|
177
|
-
|
410
|
+
|
411
|
+
// copy into segments
|
412
|
+
count = 0;
|
413
|
+
reference<PrefixSegment> segment(PrefixSegment::New(art, data.ptr));
|
414
|
+
for (idx_t i = 0; i < count_p; i++) {
|
415
|
+
segment = segment.get().Append(art, count, reader.Read<uint8_t>());
|
416
|
+
}
|
417
|
+
D_ASSERT(count_p == count);
|
178
418
|
}
|
179
419
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
420
|
+
void Prefix::Vacuum(ART &art) {
|
421
|
+
|
422
|
+
if (IsInlined()) {
|
423
|
+
return;
|
424
|
+
}
|
425
|
+
|
426
|
+
// first pointer has special treatment because we don't obtain it from a prefix segment
|
427
|
+
auto &allocator = Node::GetAllocator(art, NType::PREFIX_SEGMENT);
|
428
|
+
if (allocator.NeedsVacuum(data.ptr)) {
|
429
|
+
data.ptr.SetPtr(allocator.VacuumPointer(data.ptr));
|
430
|
+
}
|
431
|
+
|
432
|
+
auto ptr = data.ptr;
|
433
|
+
while (ptr.IsSet()) {
|
434
|
+
auto &segment = PrefixSegment::Get(art, ptr);
|
435
|
+
ptr = segment.next;
|
436
|
+
if (ptr.IsSet() && allocator.NeedsVacuum(ptr)) {
|
437
|
+
segment.next.SetPtr(allocator.VacuumPointer(ptr));
|
438
|
+
ptr = segment.next;
|
186
439
|
}
|
187
440
|
}
|
188
|
-
|
441
|
+
}
|
442
|
+
|
443
|
+
PrefixSegment &Prefix::MoveInlinedToSegment(ART &art) {
|
444
|
+
|
445
|
+
D_ASSERT(IsInlined());
|
446
|
+
|
447
|
+
Node ptr;
|
448
|
+
auto &segment = PrefixSegment::New(art, ptr);
|
449
|
+
|
450
|
+
// move data
|
451
|
+
D_ASSERT(Node::PREFIX_SEGMENT_SIZE >= Node::PREFIX_INLINE_BYTES);
|
452
|
+
memcpy(segment.bytes, data.inlined, count);
|
453
|
+
data.ptr = ptr;
|
454
|
+
return segment;
|
455
|
+
}
|
456
|
+
|
457
|
+
void Prefix::MoveSegmentToInlined(ART &art) {
|
458
|
+
|
459
|
+
D_ASSERT(IsInlined());
|
460
|
+
D_ASSERT(data.ptr.IsSet());
|
461
|
+
|
462
|
+
auto ptr = data.ptr;
|
463
|
+
auto &segment = PrefixSegment::Get(art, data.ptr);
|
464
|
+
|
465
|
+
memcpy(data.inlined, segment.bytes, count);
|
466
|
+
Node::Free(art, ptr);
|
189
467
|
}
|
190
468
|
|
191
469
|
} // namespace duckdb
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#include "duckdb/execution/index/art/prefix_segment.hpp"
|
2
|
+
|
3
|
+
#include "duckdb/execution/index/art/art.hpp"
|
4
|
+
#include "duckdb/execution/index/art/node.hpp"
|
5
|
+
|
6
|
+
namespace duckdb {
|
7
|
+
|
8
|
+
PrefixSegment &PrefixSegment::New(ART &art, Node &node) {
|
9
|
+
|
10
|
+
node.SetPtr(Node::GetAllocator(art, NType::PREFIX_SEGMENT).New());
|
11
|
+
node.type = (uint8_t)NType::PREFIX_SEGMENT;
|
12
|
+
|
13
|
+
auto &segment = PrefixSegment::Get(art, node);
|
14
|
+
segment.next.Reset();
|
15
|
+
return segment;
|
16
|
+
}
|
17
|
+
|
18
|
+
PrefixSegment &PrefixSegment::Append(ART &art, uint32_t &count, const uint8_t byte) {
|
19
|
+
|
20
|
+
reference<PrefixSegment> segment(*this);
|
21
|
+
auto position = count % Node::PREFIX_SEGMENT_SIZE;
|
22
|
+
|
23
|
+
// we need a new segment
|
24
|
+
if (position == 0 && count != 0) {
|
25
|
+
segment = PrefixSegment::New(art, next);
|
26
|
+
}
|
27
|
+
|
28
|
+
segment.get().bytes[position] = byte;
|
29
|
+
count++;
|
30
|
+
return segment.get();
|
31
|
+
}
|
32
|
+
|
33
|
+
PrefixSegment &PrefixSegment::GetTail(const ART &art) {
|
34
|
+
|
35
|
+
reference<PrefixSegment> segment(*this);
|
36
|
+
while (segment.get().next.IsSet()) {
|
37
|
+
segment = PrefixSegment::Get(art, segment.get().next);
|
38
|
+
}
|
39
|
+
return segment.get();
|
40
|
+
}
|
41
|
+
|
42
|
+
} // namespace duckdb
|