duckdb 0.7.2-dev2552.0 → 0.7.2-dev2675.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/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/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/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/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
@@ -5,12 +5,20 @@
|
|
5
5
|
#include "duckdb/execution/expression_executor.hpp"
|
6
6
|
#include "duckdb/storage/arena_allocator.hpp"
|
7
7
|
#include "duckdb/execution/index/art/art_key.hpp"
|
8
|
+
#include "duckdb/execution/index/art/prefix_segment.hpp"
|
9
|
+
#include "duckdb/execution/index/art/leaf_segment.hpp"
|
10
|
+
#include "duckdb/execution/index/art/prefix.hpp"
|
11
|
+
#include "duckdb/execution/index/art/leaf.hpp"
|
12
|
+
#include "duckdb/execution/index/art/node4.hpp"
|
13
|
+
#include "duckdb/execution/index/art/node16.hpp"
|
14
|
+
#include "duckdb/execution/index/art/node48.hpp"
|
15
|
+
#include "duckdb/execution/index/art/node256.hpp"
|
16
|
+
#include "duckdb/execution/index/art/iterator.hpp"
|
8
17
|
#include "duckdb/common/types/conflict_manager.hpp"
|
9
18
|
#include "duckdb/storage/table/scan_state.hpp"
|
10
19
|
|
11
20
|
#include <algorithm>
|
12
21
|
#include <cstring>
|
13
|
-
#include <ctgmath>
|
14
22
|
|
15
23
|
namespace duckdb {
|
16
24
|
|
@@ -27,23 +35,30 @@ struct ARTIndexScanState : public IndexScanState {
|
|
27
35
|
};
|
28
36
|
|
29
37
|
ART::ART(const vector<column_t> &column_ids, TableIOManager &table_io_manager,
|
30
|
-
const vector<unique_ptr<Expression>> &unbound_expressions, IndexConstraintType constraint_type,
|
31
|
-
AttachedDatabase &db,
|
38
|
+
const vector<unique_ptr<Expression>> &unbound_expressions, const IndexConstraintType constraint_type,
|
39
|
+
AttachedDatabase &db, const idx_t block_id, const idx_t block_offset)
|
32
40
|
|
33
|
-
: Index(db, IndexType::ART, table_io_manager, column_ids, unbound_expressions, constraint_type
|
41
|
+
: Index(db, IndexType::ART, table_io_manager, column_ids, unbound_expressions, constraint_type) {
|
34
42
|
|
35
43
|
if (!Radix::IsLittleEndian()) {
|
36
44
|
throw NotImplementedException("ART indexes are not supported on big endian architectures");
|
37
45
|
}
|
38
46
|
|
47
|
+
// initialize all allocators
|
48
|
+
allocators.emplace_back(make_uniq<FixedSizeAllocator>(sizeof(PrefixSegment), buffer_manager.GetBufferAllocator()));
|
49
|
+
allocators.emplace_back(make_uniq<FixedSizeAllocator>(sizeof(LeafSegment), buffer_manager.GetBufferAllocator()));
|
50
|
+
allocators.emplace_back(make_uniq<FixedSizeAllocator>(sizeof(Leaf), buffer_manager.GetBufferAllocator()));
|
51
|
+
allocators.emplace_back(make_uniq<FixedSizeAllocator>(sizeof(Node4), buffer_manager.GetBufferAllocator()));
|
52
|
+
allocators.emplace_back(make_uniq<FixedSizeAllocator>(sizeof(Node16), buffer_manager.GetBufferAllocator()));
|
53
|
+
allocators.emplace_back(make_uniq<FixedSizeAllocator>(sizeof(Node48), buffer_manager.GetBufferAllocator()));
|
54
|
+
allocators.emplace_back(make_uniq<FixedSizeAllocator>(sizeof(Node256), buffer_manager.GetBufferAllocator()));
|
55
|
+
|
39
56
|
// set the root node of the tree
|
40
|
-
tree =
|
57
|
+
tree = make_uniq<Node>();
|
41
58
|
if (block_id != DConstants::INVALID_INDEX) {
|
42
|
-
tree =
|
43
|
-
|
44
|
-
|
45
|
-
buffer_manager.IncreaseUsedMemory(memory_size);
|
46
|
-
}
|
59
|
+
tree->buffer_id = block_id;
|
60
|
+
tree->offset = block_offset;
|
61
|
+
tree->Deserialize(*this);
|
47
62
|
}
|
48
63
|
serialized_data_pointer = BlockPointer(block_id, block_offset);
|
49
64
|
|
@@ -71,15 +86,7 @@ ART::ART(const vector<column_t> &column_ids, TableIOManager &table_io_manager,
|
|
71
86
|
}
|
72
87
|
|
73
88
|
ART::~ART() {
|
74
|
-
|
75
|
-
return;
|
76
|
-
}
|
77
|
-
Verify();
|
78
|
-
if (track_memory) {
|
79
|
-
buffer_manager.DecreaseUsedMemory(memory_size);
|
80
|
-
}
|
81
|
-
Node::Delete(tree);
|
82
|
-
tree = nullptr;
|
89
|
+
tree->Reset();
|
83
90
|
}
|
84
91
|
|
85
92
|
//===--------------------------------------------------------------------===//
|
@@ -87,7 +94,7 @@ ART::~ART() {
|
|
87
94
|
//===--------------------------------------------------------------------===//
|
88
95
|
|
89
96
|
unique_ptr<IndexScanState> ART::InitializeScanSinglePredicate(const Transaction &transaction, const Value &value,
|
90
|
-
ExpressionType expression_type) {
|
97
|
+
const ExpressionType expression_type) {
|
91
98
|
// initialize point lookup
|
92
99
|
auto result = make_uniq<ARTIndexScanState>();
|
93
100
|
result->values[0] = value;
|
@@ -95,9 +102,10 @@ unique_ptr<IndexScanState> ART::InitializeScanSinglePredicate(const Transaction
|
|
95
102
|
return std::move(result);
|
96
103
|
}
|
97
104
|
|
98
|
-
unique_ptr<IndexScanState> ART::InitializeScanTwoPredicates(Transaction &transaction, const Value &low_value,
|
99
|
-
ExpressionType low_expression_type,
|
100
|
-
|
105
|
+
unique_ptr<IndexScanState> ART::InitializeScanTwoPredicates(const Transaction &transaction, const Value &low_value,
|
106
|
+
const ExpressionType low_expression_type,
|
107
|
+
const Value &high_value,
|
108
|
+
const ExpressionType high_expression_type) {
|
101
109
|
// initialize range lookup
|
102
110
|
auto result = make_uniq<ARTIndexScanState>();
|
103
111
|
result->values[0] = low_value;
|
@@ -112,7 +120,7 @@ unique_ptr<IndexScanState> ART::InitializeScanTwoPredicates(Transaction &transac
|
|
112
120
|
//===--------------------------------------------------------------------===//
|
113
121
|
|
114
122
|
template <class T>
|
115
|
-
static void TemplatedGenerateKeys(ArenaAllocator &allocator, Vector &input, idx_t count, vector<
|
123
|
+
static void TemplatedGenerateKeys(ArenaAllocator &allocator, Vector &input, idx_t count, vector<ARTKey> &keys) {
|
116
124
|
UnifiedVectorFormat idata;
|
117
125
|
input.ToUnifiedFormat(count, idata);
|
118
126
|
|
@@ -121,13 +129,13 @@ static void TemplatedGenerateKeys(ArenaAllocator &allocator, Vector &input, idx_
|
|
121
129
|
for (idx_t i = 0; i < count; i++) {
|
122
130
|
auto idx = idata.sel->get_index(i);
|
123
131
|
if (idata.validity.RowIsValid(idx)) {
|
124
|
-
|
132
|
+
ARTKey::CreateARTKey<T>(allocator, input.GetType(), keys[i], input_data[idx]);
|
125
133
|
}
|
126
134
|
}
|
127
135
|
}
|
128
136
|
|
129
137
|
template <class T>
|
130
|
-
static void ConcatenateKeys(ArenaAllocator &allocator, Vector &input, idx_t count, vector<
|
138
|
+
static void ConcatenateKeys(ArenaAllocator &allocator, Vector &input, idx_t count, vector<ARTKey> &keys) {
|
131
139
|
UnifiedVectorFormat idata;
|
132
140
|
input.ToUnifiedFormat(count, idata);
|
133
141
|
|
@@ -139,16 +147,16 @@ static void ConcatenateKeys(ArenaAllocator &allocator, Vector &input, idx_t coun
|
|
139
147
|
if (!keys[i].Empty()) {
|
140
148
|
if (!idata.validity.RowIsValid(idx)) {
|
141
149
|
// this column entry is NULL, set whole key to NULL
|
142
|
-
keys[i] =
|
150
|
+
keys[i] = ARTKey();
|
143
151
|
} else {
|
144
|
-
auto other_key =
|
145
|
-
keys[i].
|
152
|
+
auto other_key = ARTKey::CreateARTKey<T>(allocator, input.GetType(), input_data[idx]);
|
153
|
+
keys[i].ConcatenateARTKey(allocator, other_key);
|
146
154
|
}
|
147
155
|
}
|
148
156
|
}
|
149
157
|
}
|
150
158
|
|
151
|
-
void ART::GenerateKeys(ArenaAllocator &allocator, DataChunk &input, vector<
|
159
|
+
void ART::GenerateKeys(ArenaAllocator &allocator, DataChunk &input, vector<ARTKey> &keys) {
|
152
160
|
// generate keys for the first input column
|
153
161
|
switch (input.data[0].GetType().InternalType()) {
|
154
162
|
case PhysicalType::BOOL:
|
@@ -249,7 +257,7 @@ void ART::GenerateKeys(ArenaAllocator &allocator, DataChunk &input, vector<Key>
|
|
249
257
|
struct KeySection {
|
250
258
|
KeySection(idx_t start_p, idx_t end_p, idx_t depth_p, data_t key_byte_p)
|
251
259
|
: start(start_p), end(end_p), depth(depth_p), key_byte(key_byte_p) {};
|
252
|
-
KeySection(idx_t start_p, idx_t end_p, vector<
|
260
|
+
KeySection(idx_t start_p, idx_t end_p, vector<ARTKey> &keys, KeySection &key_section)
|
253
261
|
: start(start_p), end(end_p), depth(key_section.depth + 1), key_byte(keys[end_p].data[key_section.depth]) {};
|
254
262
|
idx_t start;
|
255
263
|
idx_t end;
|
@@ -257,7 +265,7 @@ struct KeySection {
|
|
257
265
|
data_t key_byte;
|
258
266
|
};
|
259
267
|
|
260
|
-
void GetChildSections(vector<KeySection> &child_sections, vector<
|
268
|
+
void GetChildSections(vector<KeySection> &child_sections, vector<ARTKey> &keys, KeySection &key_section) {
|
261
269
|
|
262
270
|
idx_t child_start_idx = key_section.start;
|
263
271
|
for (idx_t i = key_section.start + 1; i <= key_section.end; i++) {
|
@@ -269,7 +277,7 @@ void GetChildSections(vector<KeySection> &child_sections, vector<Key> &keys, Key
|
|
269
277
|
child_sections.emplace_back(child_start_idx, key_section.end, keys, key_section);
|
270
278
|
}
|
271
279
|
|
272
|
-
bool Construct(ART &art, vector<
|
280
|
+
bool Construct(ART &art, vector<ARTKey> &keys, row_t *row_ids, Node &node, KeySection &key_section,
|
273
281
|
bool &has_constraint) {
|
274
282
|
|
275
283
|
D_ASSERT(key_section.start < keys.size());
|
@@ -297,29 +305,28 @@ bool Construct(ART &art, vector<Key> &keys, row_t *row_ids, Node *&node, KeySect
|
|
297
305
|
}
|
298
306
|
|
299
307
|
if (single_row_id) {
|
300
|
-
|
308
|
+
Leaf::New(art, node, start_key, prefix_start, row_ids[key_section.start]);
|
301
309
|
} else {
|
302
|
-
|
310
|
+
Leaf::New(art, node, start_key, prefix_start, row_ids + key_section.start, num_row_ids);
|
303
311
|
}
|
304
|
-
art.IncreaseMemorySize(node->MemorySize(art, false));
|
305
312
|
return true;
|
306
313
|
}
|
314
|
+
|
307
315
|
// create a new node and recurse
|
308
316
|
|
309
317
|
// we will find at least two child entries of this node, otherwise we'd have reached a leaf
|
310
318
|
vector<KeySection> child_sections;
|
311
319
|
GetChildSections(child_sections, keys, key_section);
|
312
320
|
|
313
|
-
auto node_type = Node::
|
314
|
-
Node::New(
|
321
|
+
auto node_type = Node::GetARTNodeTypeByCount(child_sections.size());
|
322
|
+
Node::New(art, node, node_type);
|
315
323
|
|
316
324
|
auto prefix_length = key_section.depth - prefix_start;
|
317
|
-
node
|
318
|
-
art.IncreaseMemorySize(node->MemorySize(art, false));
|
325
|
+
node.GetPrefix(art).Initialize(art, start_key, prefix_start, prefix_length);
|
319
326
|
|
320
327
|
// recurse on each child section
|
321
328
|
for (auto &child_section : child_sections) {
|
322
|
-
Node
|
329
|
+
Node new_child;
|
323
330
|
auto no_violation = Construct(art, keys, row_ids, new_child, child_section, has_constraint);
|
324
331
|
Node::InsertChild(art, node, child_section.key_byte, new_child);
|
325
332
|
if (!no_violation) {
|
@@ -329,7 +336,7 @@ bool Construct(ART &art, vector<Key> &keys, row_t *row_ids, Node *&node, KeySect
|
|
329
336
|
return true;
|
330
337
|
}
|
331
338
|
|
332
|
-
bool ART::ConstructFromSorted(idx_t count, vector<
|
339
|
+
bool ART::ConstructFromSorted(idx_t count, vector<ARTKey> &keys, Vector &row_identifiers) {
|
333
340
|
|
334
341
|
// prepare the row_identifiers
|
335
342
|
row_identifiers.Flatten(count);
|
@@ -337,7 +344,7 @@ bool ART::ConstructFromSorted(idx_t count, vector<Key> &keys, Vector &row_identi
|
|
337
344
|
|
338
345
|
auto key_section = KeySection(0, count - 1, 0, 0);
|
339
346
|
auto has_constraint = IsUnique();
|
340
|
-
return Construct(*this, keys, row_ids, this->tree, key_section, has_constraint);
|
347
|
+
return Construct(*this, keys, row_ids, *this->tree, key_section, has_constraint);
|
341
348
|
}
|
342
349
|
|
343
350
|
//===--------------------------------------------------------------------===//
|
@@ -348,11 +355,9 @@ PreservedError ART::Insert(IndexLock &lock, DataChunk &input, Vector &row_ids) {
|
|
348
355
|
D_ASSERT(row_ids.GetType().InternalType() == ROW_TYPE);
|
349
356
|
D_ASSERT(logical_types[0] == input.data[0].GetType());
|
350
357
|
|
351
|
-
auto old_memory_size = memory_size;
|
352
|
-
|
353
358
|
// generate the keys for the given input
|
354
359
|
ArenaAllocator arena_allocator(BufferAllocator::Get(db));
|
355
|
-
vector<
|
360
|
+
vector<ARTKey> keys(input.size());
|
356
361
|
GenerateKeys(arena_allocator, input, keys);
|
357
362
|
|
358
363
|
// get the corresponding row IDs
|
@@ -367,7 +372,7 @@ PreservedError ART::Insert(IndexLock &lock, DataChunk &input, Vector &row_ids) {
|
|
367
372
|
}
|
368
373
|
|
369
374
|
row_t row_id = row_identifiers[i];
|
370
|
-
if (!Insert(tree, keys[i], 0, row_id)) {
|
375
|
+
if (!Insert(*tree, keys[i], 0, row_id)) {
|
371
376
|
// failed to insert because of constraint violation
|
372
377
|
failed_index = i;
|
373
378
|
break;
|
@@ -381,11 +386,10 @@ PreservedError ART::Insert(IndexLock &lock, DataChunk &input, Vector &row_ids) {
|
|
381
386
|
continue;
|
382
387
|
}
|
383
388
|
row_t row_id = row_identifiers[i];
|
384
|
-
Erase(tree, keys[i], 0, row_id);
|
389
|
+
Erase(*tree, keys[i], 0, row_id);
|
385
390
|
}
|
386
391
|
}
|
387
392
|
|
388
|
-
IncreaseAndVerifyMemorySize(old_memory_size);
|
389
393
|
if (failed_index != DConstants::INVALID_INDEX) {
|
390
394
|
return PreservedError(ConstraintException("PRIMARY KEY or UNIQUE constraint violated: duplicate key \"%s\"",
|
391
395
|
AppendRowError(input, failed_index)));
|
@@ -414,10 +418,13 @@ void ART::VerifyAppend(DataChunk &chunk, ConflictManager &conflict_manager) {
|
|
414
418
|
CheckConstraintsForChunk(chunk, conflict_manager);
|
415
419
|
}
|
416
420
|
|
417
|
-
bool ART::InsertToLeaf(
|
421
|
+
bool ART::InsertToLeaf(Node &leaf_node, const row_t &row_id) {
|
422
|
+
|
423
|
+
auto &leaf = Leaf::Get(*this, leaf_node);
|
424
|
+
|
418
425
|
#ifdef DEBUG
|
419
426
|
for (idx_t k = 0; k < leaf.count; k++) {
|
420
|
-
D_ASSERT(leaf.GetRowId(k) != row_id);
|
427
|
+
D_ASSERT(leaf.GetRowId(*this, k) != row_id);
|
421
428
|
}
|
422
429
|
#endif
|
423
430
|
if (IsUnique() && leaf.count != 0) {
|
@@ -427,86 +434,75 @@ bool ART::InsertToLeaf(Leaf &leaf, row_t row_id) {
|
|
427
434
|
return true;
|
428
435
|
}
|
429
436
|
|
430
|
-
bool ART::Insert(Node
|
437
|
+
bool ART::Insert(Node &node, const ARTKey &key, idx_t depth, const row_t &row_id) {
|
431
438
|
|
432
|
-
if (!node) {
|
439
|
+
if (!node.IsSet()) {
|
433
440
|
// node is currently empty, create a leaf here with the key
|
434
|
-
|
435
|
-
IncreaseMemorySize(node->MemorySize(*this, false));
|
441
|
+
Leaf::New(*this, node, key, depth, row_id);
|
436
442
|
return true;
|
437
443
|
}
|
438
444
|
|
439
|
-
if (node
|
440
|
-
|
441
|
-
//
|
442
|
-
auto leaf = (
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
// leaf node is already there (its key matches the current key), update row_id vector
|
447
|
-
if (new_prefix_length == leaf->prefix.Size() && depth + leaf->prefix.Size() == key.len) {
|
448
|
-
return InsertToLeaf(*leaf, row_id);
|
449
|
-
}
|
450
|
-
while (leaf->prefix[new_prefix_length] == key[depth + new_prefix_length]) {
|
451
|
-
new_prefix_length++;
|
452
|
-
// leaf node is already there (its key matches the current key), update row_id vector
|
453
|
-
if (new_prefix_length == leaf->prefix.Size() && depth + leaf->prefix.Size() == key.len) {
|
454
|
-
return InsertToLeaf(*leaf, row_id);
|
455
|
-
}
|
445
|
+
if (node.DecodeARTNodeType() == NType::LEAF) {
|
446
|
+
|
447
|
+
// add a row ID to a leaf, if they have the same key
|
448
|
+
auto &leaf = Leaf::Get(*this, node);
|
449
|
+
auto mismatch_position = leaf.prefix.KeyMismatchPosition(*this, key, depth);
|
450
|
+
if (mismatch_position == leaf.prefix.count && depth + leaf.prefix.count == key.len) {
|
451
|
+
return InsertToLeaf(node, row_id);
|
456
452
|
}
|
457
453
|
|
458
|
-
|
459
|
-
|
460
|
-
|
454
|
+
// replace leaf with Node4 and store both leaves in it
|
455
|
+
auto old_node = node;
|
456
|
+
auto &new_n4 = Node4::New(*this, node);
|
457
|
+
new_n4.prefix.Initialize(*this, key, depth, mismatch_position);
|
461
458
|
|
462
|
-
auto key_byte =
|
463
|
-
Node4::InsertChild(*this,
|
459
|
+
auto key_byte = old_node.GetPrefix(*this).Reduce(*this, mismatch_position);
|
460
|
+
Node4::InsertChild(*this, node, key_byte, old_node);
|
464
461
|
|
465
|
-
Node
|
466
|
-
|
467
|
-
|
462
|
+
Node leaf_node;
|
463
|
+
Leaf::New(*this, leaf_node, key, depth + mismatch_position + 1, row_id);
|
464
|
+
Node4::InsertChild(*this, node, key[depth + mismatch_position], leaf_node);
|
468
465
|
|
469
|
-
node = new_node;
|
470
466
|
return true;
|
471
467
|
}
|
472
468
|
|
473
469
|
// handle prefix of inner node
|
474
|
-
|
470
|
+
auto &old_node_prefix = node.GetPrefix(*this);
|
471
|
+
if (old_node_prefix.count) {
|
472
|
+
|
473
|
+
auto mismatch_position = old_node_prefix.KeyMismatchPosition(*this, key, depth);
|
474
|
+
if (mismatch_position != old_node_prefix.count) {
|
475
475
|
|
476
|
-
uint32_t mismatch_pos = node->prefix.KeyMismatchPosition(key, depth);
|
477
|
-
if (mismatch_pos != node->prefix.Size()) {
|
478
476
|
// prefix differs, create new node
|
479
|
-
|
480
|
-
|
481
|
-
|
477
|
+
auto old_node = node;
|
478
|
+
auto &new_n4 = Node4::New(*this, node);
|
479
|
+
new_n4.prefix.Initialize(*this, key, depth, mismatch_position);
|
482
480
|
|
483
|
-
|
484
|
-
|
485
|
-
Node4::InsertChild(*this, new_node, key_byte, node);
|
481
|
+
auto key_byte = old_node_prefix.Reduce(*this, mismatch_position);
|
482
|
+
Node4::InsertChild(*this, node, key_byte, old_node);
|
486
483
|
|
487
|
-
Node
|
488
|
-
|
489
|
-
|
484
|
+
Node leaf_node;
|
485
|
+
Leaf::New(*this, leaf_node, key, depth + mismatch_position + 1, row_id);
|
486
|
+
Node4::InsertChild(*this, node, key[depth + mismatch_position], leaf_node);
|
490
487
|
|
491
|
-
node = new_node;
|
492
488
|
return true;
|
493
489
|
}
|
494
|
-
depth += node
|
490
|
+
depth += node.GetPrefix(*this).count;
|
495
491
|
}
|
496
492
|
|
497
493
|
// recurse
|
498
494
|
D_ASSERT(depth < key.len);
|
499
|
-
|
500
|
-
if (
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
return insertion_result;
|
495
|
+
auto child = node.GetChild(*this, key[depth]);
|
496
|
+
if (child) {
|
497
|
+
bool success = Insert(*child, key, depth + 1, row_id);
|
498
|
+
node.ReplaceChild(*this, key[depth], *child);
|
499
|
+
return success;
|
505
500
|
}
|
506
501
|
|
507
|
-
|
502
|
+
// insert at position
|
503
|
+
Node leaf_node;
|
504
|
+
Leaf::New(*this, leaf_node, key, depth + 1, row_id);
|
508
505
|
Node::InsertChild(*this, node, key[depth], leaf_node);
|
509
|
-
IncreaseMemorySize(leaf_node->MemorySize(*this, false));
|
510
506
|
return true;
|
511
507
|
}
|
512
508
|
|
@@ -524,11 +520,9 @@ void ART::Delete(IndexLock &state, DataChunk &input, Vector &row_ids) {
|
|
524
520
|
|
525
521
|
// then generate the keys for the given input
|
526
522
|
ArenaAllocator arena_allocator(BufferAllocator::Get(db));
|
527
|
-
vector<
|
523
|
+
vector<ARTKey> keys(expression.size());
|
528
524
|
GenerateKeys(arena_allocator, expression, keys);
|
529
525
|
|
530
|
-
auto old_memory_size = memory_size;
|
531
|
-
|
532
526
|
// now erase the elements from the database
|
533
527
|
row_ids.Flatten(input.size());
|
534
528
|
auto row_identifiers = FlatVector::GetData<row_t>(row_ids);
|
@@ -537,75 +531,65 @@ void ART::Delete(IndexLock &state, DataChunk &input, Vector &row_ids) {
|
|
537
531
|
if (keys[i].Empty()) {
|
538
532
|
continue;
|
539
533
|
}
|
540
|
-
Erase(tree, keys[i], 0, row_identifiers[i]);
|
534
|
+
Erase(*tree, keys[i], 0, row_identifiers[i]);
|
541
535
|
#ifdef DEBUG
|
542
|
-
auto node = Lookup(tree, keys[i], 0);
|
543
|
-
if (node) {
|
544
|
-
auto leaf = (
|
545
|
-
for (idx_t k = 0; k < leaf
|
546
|
-
D_ASSERT(leaf
|
536
|
+
auto node = Lookup(*tree, keys[i], 0);
|
537
|
+
if (node.IsSet()) {
|
538
|
+
auto &leaf = Leaf::Get(*this, node);
|
539
|
+
for (idx_t k = 0; k < leaf.count; k++) {
|
540
|
+
D_ASSERT(leaf.GetRowId(*this, k) != row_identifiers[i]);
|
547
541
|
}
|
548
542
|
}
|
549
543
|
#endif
|
550
544
|
}
|
551
|
-
|
552
|
-
// if we deserialize nodes while erasing, then we might end up with more
|
553
|
-
// memory afterwards, so we have to either increase or decrease the used memory
|
554
|
-
Verify();
|
555
|
-
if (track_memory && old_memory_size >= memory_size) {
|
556
|
-
buffer_manager.DecreaseUsedMemory(old_memory_size - memory_size);
|
557
|
-
} else if (track_memory) {
|
558
|
-
buffer_manager.IncreaseUsedMemory(memory_size - old_memory_size);
|
559
|
-
}
|
560
545
|
}
|
561
546
|
|
562
|
-
void ART::Erase(Node
|
547
|
+
void ART::Erase(Node &node, const ARTKey &key, idx_t depth, const row_t &row_id) {
|
563
548
|
|
564
|
-
if (!node) {
|
549
|
+
if (!node.IsSet()) {
|
565
550
|
return;
|
566
551
|
}
|
567
552
|
|
568
|
-
// delete a
|
569
|
-
if (node
|
570
|
-
auto leaf = (
|
571
|
-
leaf
|
553
|
+
// delete a row ID from a leaf
|
554
|
+
if (node.DecodeARTNodeType() == NType::LEAF) {
|
555
|
+
auto &leaf = Leaf::Get(*this, node);
|
556
|
+
leaf.Remove(*this, row_id);
|
572
557
|
|
573
|
-
if (leaf
|
574
|
-
|
575
|
-
|
576
|
-
node = nullptr;
|
558
|
+
if (leaf.count == 0) {
|
559
|
+
Node::Free(*this, node);
|
560
|
+
node.Reset();
|
577
561
|
}
|
578
562
|
return;
|
579
563
|
}
|
580
564
|
|
581
565
|
// handle prefix
|
582
|
-
|
583
|
-
|
566
|
+
auto &node_prefix = node.GetPrefix(*this);
|
567
|
+
if (node_prefix.count) {
|
568
|
+
if (node_prefix.KeyMismatchPosition(*this, key, depth) != node_prefix.count) {
|
584
569
|
return;
|
585
570
|
}
|
586
|
-
depth +=
|
571
|
+
depth += node_prefix.count;
|
587
572
|
}
|
588
573
|
|
589
|
-
|
590
|
-
if (
|
591
|
-
|
592
|
-
D_ASSERT(child);
|
574
|
+
auto child = node.GetChild(*this, key[depth]);
|
575
|
+
if (child) {
|
576
|
+
D_ASSERT(child->IsSet());
|
593
577
|
|
594
|
-
if (child->
|
578
|
+
if (child->DecodeARTNodeType() == NType::LEAF) {
|
595
579
|
// leaf found, remove entry
|
596
|
-
auto leaf = (
|
597
|
-
leaf
|
580
|
+
auto &leaf = Leaf::Get(*this, *child);
|
581
|
+
leaf.Remove(*this, row_id);
|
598
582
|
|
599
|
-
if (leaf
|
583
|
+
if (leaf.count == 0) {
|
600
584
|
// leaf is empty, delete leaf, decrement node counter and maybe shrink node
|
601
|
-
Node::
|
585
|
+
Node::DeleteChild(*this, node, key[depth]);
|
602
586
|
}
|
603
|
-
|
604
|
-
} else {
|
605
|
-
// recurse
|
606
|
-
Erase(child, key, depth + 1, row_id);
|
607
|
-
node->ReplaceChildPointer(pos, child);
|
587
|
+
return;
|
608
588
|
}
|
589
|
+
|
590
|
+
// recurse
|
591
|
+
Erase(*child, key, depth + 1, row_id);
|
592
|
+
node.ReplaceChild(*this, key[depth], *child);
|
609
593
|
}
|
610
594
|
}
|
611
595
|
|
@@ -613,116 +597,114 @@ void ART::Erase(Node *&node, Key &key, idx_t depth, row_t row_id) {
|
|
613
597
|
// Point Query (Equal)
|
614
598
|
//===--------------------------------------------------------------------===//
|
615
599
|
|
616
|
-
static
|
600
|
+
static ARTKey CreateKey(ArenaAllocator &allocator, PhysicalType type, Value &value) {
|
617
601
|
D_ASSERT(type == value.type().InternalType());
|
618
602
|
switch (type) {
|
619
603
|
case PhysicalType::BOOL:
|
620
|
-
return
|
604
|
+
return ARTKey::CreateARTKey<bool>(allocator, value.type(), value);
|
621
605
|
case PhysicalType::INT8:
|
622
|
-
return
|
606
|
+
return ARTKey::CreateARTKey<int8_t>(allocator, value.type(), value);
|
623
607
|
case PhysicalType::INT16:
|
624
|
-
return
|
608
|
+
return ARTKey::CreateARTKey<int16_t>(allocator, value.type(), value);
|
625
609
|
case PhysicalType::INT32:
|
626
|
-
return
|
610
|
+
return ARTKey::CreateARTKey<int32_t>(allocator, value.type(), value);
|
627
611
|
case PhysicalType::INT64:
|
628
|
-
return
|
612
|
+
return ARTKey::CreateARTKey<int64_t>(allocator, value.type(), value);
|
629
613
|
case PhysicalType::UINT8:
|
630
|
-
return
|
614
|
+
return ARTKey::CreateARTKey<uint8_t>(allocator, value.type(), value);
|
631
615
|
case PhysicalType::UINT16:
|
632
|
-
return
|
616
|
+
return ARTKey::CreateARTKey<uint16_t>(allocator, value.type(), value);
|
633
617
|
case PhysicalType::UINT32:
|
634
|
-
return
|
618
|
+
return ARTKey::CreateARTKey<uint32_t>(allocator, value.type(), value);
|
635
619
|
case PhysicalType::UINT64:
|
636
|
-
return
|
620
|
+
return ARTKey::CreateARTKey<uint64_t>(allocator, value.type(), value);
|
637
621
|
case PhysicalType::INT128:
|
638
|
-
return
|
622
|
+
return ARTKey::CreateARTKey<hugeint_t>(allocator, value.type(), value);
|
639
623
|
case PhysicalType::FLOAT:
|
640
|
-
return
|
624
|
+
return ARTKey::CreateARTKey<float>(allocator, value.type(), value);
|
641
625
|
case PhysicalType::DOUBLE:
|
642
|
-
return
|
626
|
+
return ARTKey::CreateARTKey<double>(allocator, value.type(), value);
|
643
627
|
case PhysicalType::VARCHAR:
|
644
|
-
return
|
628
|
+
return ARTKey::CreateARTKey<string_t>(allocator, value.type(), value);
|
645
629
|
default:
|
646
|
-
throw InternalException("Invalid type for
|
630
|
+
throw InternalException("Invalid type for the ART key");
|
647
631
|
}
|
648
632
|
}
|
649
633
|
|
650
|
-
bool ART::SearchEqual(
|
651
|
-
|
652
|
-
auto old_memory_size = memory_size;
|
653
|
-
auto leaf = (Leaf *)(Lookup(tree, key, 0));
|
654
|
-
IncreaseAndVerifyMemorySize(old_memory_size);
|
634
|
+
bool ART::SearchEqual(ARTKey &key, idx_t max_count, vector<row_t> &result_ids) {
|
655
635
|
|
656
|
-
|
636
|
+
auto leaf_node = Lookup(*tree, key, 0);
|
637
|
+
if (!leaf_node.IsSet()) {
|
657
638
|
return true;
|
658
639
|
}
|
659
|
-
|
640
|
+
|
641
|
+
auto &leaf = Leaf::Get(*this, leaf_node);
|
642
|
+
if (leaf.count > max_count) {
|
660
643
|
return false;
|
661
644
|
}
|
662
|
-
for (idx_t i = 0; i < leaf
|
663
|
-
row_t row_id = leaf
|
645
|
+
for (idx_t i = 0; i < leaf.count; i++) {
|
646
|
+
row_t row_id = leaf.GetRowId(*this, i);
|
664
647
|
result_ids.push_back(row_id);
|
665
648
|
}
|
666
649
|
return true;
|
667
650
|
}
|
668
651
|
|
669
|
-
void ART::SearchEqualJoinNoFetch(
|
670
|
-
result_size = 0;
|
652
|
+
void ART::SearchEqualJoinNoFetch(ARTKey &key, idx_t &result_size) {
|
671
653
|
|
672
654
|
// we need to look for a leaf
|
673
|
-
auto
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
if (!leaf) {
|
655
|
+
auto leaf_node = Lookup(*tree, key, 0);
|
656
|
+
if (!leaf_node.IsSet()) {
|
657
|
+
result_size = 0;
|
678
658
|
return;
|
679
659
|
}
|
680
|
-
|
660
|
+
|
661
|
+
auto &leaf = Leaf::Get(*this, leaf_node);
|
662
|
+
result_size = leaf.count;
|
681
663
|
}
|
682
664
|
|
683
665
|
//===--------------------------------------------------------------------===//
|
684
666
|
// Lookup
|
685
667
|
//===--------------------------------------------------------------------===//
|
686
668
|
|
687
|
-
|
669
|
+
Node ART::Lookup(Node node, const ARTKey &key, idx_t depth) {
|
688
670
|
|
689
|
-
while (node) {
|
690
|
-
if (node
|
691
|
-
auto leaf = (
|
692
|
-
auto &leaf_prefix = leaf->prefix;
|
671
|
+
while (node.IsSet()) {
|
672
|
+
if (node.DecodeARTNodeType() == NType::LEAF) {
|
673
|
+
auto &leaf = Leaf::Get(*this, node);
|
693
674
|
|
694
675
|
// check if leaf contains key
|
695
|
-
for (idx_t i = 0; i < leaf
|
696
|
-
if (
|
697
|
-
return
|
676
|
+
for (idx_t i = 0; i < leaf.prefix.count; i++) {
|
677
|
+
if (leaf.prefix.GetByte(*this, i) != key[i + depth]) {
|
678
|
+
return Node();
|
698
679
|
}
|
699
680
|
}
|
700
|
-
return
|
681
|
+
return node;
|
701
682
|
}
|
702
683
|
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
684
|
+
auto &node_prefix = node.GetPrefix(*this);
|
685
|
+
if (node_prefix.count) {
|
686
|
+
for (idx_t pos = 0; pos < node_prefix.count; pos++) {
|
687
|
+
if (key[depth + pos] != node_prefix.GetByte(*this, pos)) {
|
688
|
+
// prefix mismatch, subtree of node does not contain key
|
689
|
+
return Node();
|
708
690
|
}
|
709
691
|
}
|
710
|
-
depth +=
|
692
|
+
depth += node_prefix.count;
|
711
693
|
}
|
712
694
|
|
713
695
|
// prefix matches key, but no child at byte, does not contain key
|
714
|
-
|
715
|
-
if (
|
716
|
-
return
|
696
|
+
auto child = node.GetChild(*this, key[depth]);
|
697
|
+
if (!child) {
|
698
|
+
return Node();
|
717
699
|
}
|
718
700
|
|
719
701
|
// recurse into child
|
720
|
-
node =
|
721
|
-
D_ASSERT(node);
|
702
|
+
node = *child;
|
703
|
+
D_ASSERT(node.IsSet());
|
722
704
|
depth++;
|
723
705
|
}
|
724
706
|
|
725
|
-
return
|
707
|
+
return Node();
|
726
708
|
}
|
727
709
|
|
728
710
|
//===--------------------------------------------------------------------===//
|
@@ -731,42 +713,37 @@ Leaf *ART::Lookup(Node *node, Key &key, idx_t depth) {
|
|
731
713
|
// False (Otherwise)
|
732
714
|
//===--------------------------------------------------------------------===//
|
733
715
|
|
734
|
-
bool ART::SearchGreater(ARTIndexScanState *state,
|
716
|
+
bool ART::SearchGreater(ARTIndexScanState *state, ARTKey &key, bool inclusive, idx_t max_count,
|
735
717
|
vector<row_t> &result_ids) {
|
736
718
|
|
737
|
-
auto old_memory_size = memory_size;
|
738
719
|
Iterator *it = &state->iterator;
|
739
720
|
|
740
721
|
// greater than scan: first set the iterator to the node at which we will start our scan by finding the lowest node
|
741
722
|
// that satisfies our requirement
|
742
723
|
if (!it->art) {
|
743
724
|
it->art = this;
|
744
|
-
|
745
|
-
if (!found) {
|
746
|
-
IncreaseAndVerifyMemorySize(old_memory_size);
|
725
|
+
if (!it->LowerBound(*tree, key, inclusive)) {
|
747
726
|
return true;
|
748
727
|
}
|
749
728
|
}
|
729
|
+
|
750
730
|
// after that we continue the scan; we don't need to check the bounds as any value following this value is
|
751
731
|
// automatically bigger and hence satisfies our predicate
|
752
|
-
|
753
|
-
|
754
|
-
IncreaseAndVerifyMemorySize(old_memory_size);
|
755
|
-
return success;
|
732
|
+
ARTKey empty_key = ARTKey();
|
733
|
+
return it->Scan(empty_key, max_count, result_ids, false);
|
756
734
|
}
|
757
735
|
|
758
736
|
//===--------------------------------------------------------------------===//
|
759
737
|
// Less Than
|
760
738
|
//===--------------------------------------------------------------------===//
|
761
739
|
|
762
|
-
bool ART::SearchLess(ARTIndexScanState *state,
|
740
|
+
bool ART::SearchLess(ARTIndexScanState *state, ARTKey &upper_bound, bool inclusive, idx_t max_count,
|
763
741
|
vector<row_t> &result_ids) {
|
764
742
|
|
765
|
-
if (!tree) {
|
743
|
+
if (!tree->IsSet()) {
|
766
744
|
return true;
|
767
745
|
}
|
768
746
|
|
769
|
-
auto old_memory_size = memory_size;
|
770
747
|
Iterator *it = &state->iterator;
|
771
748
|
|
772
749
|
if (!it->art) {
|
@@ -775,43 +752,37 @@ bool ART::SearchLess(ARTIndexScanState *state, Key &upper_bound, bool inclusive,
|
|
775
752
|
it->FindMinimum(*tree);
|
776
753
|
// early out min value higher than upper bound query
|
777
754
|
if (it->cur_key > upper_bound) {
|
778
|
-
IncreaseAndVerifyMemorySize(old_memory_size);
|
779
755
|
return true;
|
780
756
|
}
|
781
757
|
}
|
758
|
+
|
782
759
|
// now continue the scan until we reach the upper bound
|
783
|
-
|
784
|
-
IncreaseAndVerifyMemorySize(old_memory_size);
|
785
|
-
return success;
|
760
|
+
return it->Scan(upper_bound, max_count, result_ids, inclusive);
|
786
761
|
}
|
787
762
|
|
788
763
|
//===--------------------------------------------------------------------===//
|
789
764
|
// Closed Range Query
|
790
765
|
//===--------------------------------------------------------------------===//
|
791
766
|
|
792
|
-
bool ART::SearchCloseRange(ARTIndexScanState *state,
|
767
|
+
bool ART::SearchCloseRange(ARTIndexScanState *state, ARTKey &lower_bound, ARTKey &upper_bound, bool left_inclusive,
|
793
768
|
bool right_inclusive, idx_t max_count, vector<row_t> &result_ids) {
|
794
769
|
|
795
|
-
auto old_memory_size = memory_size;
|
796
770
|
Iterator *it = &state->iterator;
|
797
771
|
|
798
772
|
// first find the first node that satisfies the left predicate
|
799
773
|
if (!it->art) {
|
800
774
|
it->art = this;
|
801
|
-
|
802
|
-
if (!found) {
|
803
|
-
IncreaseAndVerifyMemorySize(old_memory_size);
|
775
|
+
if (!it->LowerBound(*tree, lower_bound, left_inclusive)) {
|
804
776
|
return true;
|
805
777
|
}
|
806
778
|
}
|
779
|
+
|
807
780
|
// now continue the scan until we reach the upper bound
|
808
|
-
|
809
|
-
IncreaseAndVerifyMemorySize(old_memory_size);
|
810
|
-
return success;
|
781
|
+
return it->Scan(upper_bound, max_count, result_ids, right_inclusive);
|
811
782
|
}
|
812
783
|
|
813
|
-
bool ART::Scan(Transaction &transaction, DataTable &table, IndexScanState &table_state,
|
814
|
-
vector<row_t> &result_ids) {
|
784
|
+
bool ART::Scan(const Transaction &transaction, const DataTable &table, IndexScanState &table_state,
|
785
|
+
const idx_t max_count, vector<row_t> &result_ids) {
|
815
786
|
|
816
787
|
auto state = (ARTIndexScanState *)&table_state;
|
817
788
|
vector<row_t> row_ids;
|
@@ -931,8 +902,6 @@ void ART::CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_m
|
|
931
902
|
// don't alter the index during constraint checking
|
932
903
|
lock_guard<mutex> l(lock);
|
933
904
|
|
934
|
-
auto old_memory_size = memory_size;
|
935
|
-
|
936
905
|
// first resolve the expressions for the index
|
937
906
|
DataChunk expression_chunk;
|
938
907
|
expression_chunk.Initialize(Allocator::DefaultAllocator(), logical_types);
|
@@ -940,7 +909,7 @@ void ART::CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_m
|
|
940
909
|
|
941
910
|
// generate the keys for the given input
|
942
911
|
ArenaAllocator arena_allocator(BufferAllocator::Get(db));
|
943
|
-
vector<
|
912
|
+
vector<ARTKey> keys(expression_chunk.size());
|
944
913
|
GenerateKeys(arena_allocator, expression_chunk, keys);
|
945
914
|
|
946
915
|
idx_t found_conflict = DConstants::INVALID_INDEX;
|
@@ -953,8 +922,8 @@ void ART::CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_m
|
|
953
922
|
continue;
|
954
923
|
}
|
955
924
|
|
956
|
-
|
957
|
-
if (
|
925
|
+
auto leaf_node = Lookup(*tree, keys[i], 0);
|
926
|
+
if (!leaf_node.IsSet()) {
|
958
927
|
if (conflict_manager.AddMiss(i)) {
|
959
928
|
found_conflict = i;
|
960
929
|
}
|
@@ -963,18 +932,17 @@ void ART::CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_m
|
|
963
932
|
|
964
933
|
// When we find a node, we need to update the 'matches' and 'row_ids'
|
965
934
|
// NOTE: Leafs can have more than one row_id, but for UNIQUE/PRIMARY KEY they will only have one
|
966
|
-
|
967
|
-
|
935
|
+
Leaf &leaf = Leaf::Get(*this, leaf_node);
|
936
|
+
D_ASSERT(leaf.count == 1);
|
937
|
+
auto row_id = leaf.GetRowId(*this, 0);
|
968
938
|
if (conflict_manager.AddHit(i, row_id)) {
|
969
939
|
found_conflict = i;
|
970
940
|
}
|
971
941
|
}
|
972
942
|
|
973
943
|
conflict_manager.FinishLookup();
|
974
|
-
IncreaseAndVerifyMemorySize(old_memory_size);
|
975
944
|
|
976
945
|
if (found_conflict == DConstants::INVALID_INDEX) {
|
977
|
-
// No conflicts detected
|
978
946
|
return;
|
979
947
|
}
|
980
948
|
|
@@ -988,65 +956,114 @@ void ART::CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_m
|
|
988
956
|
//===--------------------------------------------------------------------===//
|
989
957
|
|
990
958
|
BlockPointer ART::Serialize(MetaBlockWriter &writer) {
|
959
|
+
|
991
960
|
lock_guard<mutex> l(lock);
|
992
|
-
|
993
|
-
if (tree) {
|
961
|
+
if (tree->IsSet()) {
|
994
962
|
serialized_data_pointer = tree->Serialize(*this, writer);
|
995
963
|
} else {
|
996
964
|
serialized_data_pointer = {(block_id_t)DConstants::INVALID_INDEX, (uint32_t)DConstants::INVALID_INDEX};
|
997
965
|
}
|
998
|
-
|
966
|
+
|
999
967
|
return serialized_data_pointer;
|
1000
968
|
}
|
1001
969
|
|
1002
970
|
//===--------------------------------------------------------------------===//
|
1003
|
-
//
|
971
|
+
// Vacuum
|
1004
972
|
//===--------------------------------------------------------------------===//
|
1005
|
-
bool ART::MergeIndexes(IndexLock &state, Index &other_index) {
|
1006
|
-
auto &other_art = other_index.Cast<ART>();
|
1007
973
|
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
974
|
+
void ART::InitializeVacuum(ARTFlags &flags) {
|
975
|
+
|
976
|
+
flags.vacuum_flags.reserve(allocators.size());
|
977
|
+
for (auto &allocator : allocators) {
|
978
|
+
flags.vacuum_flags.push_back(allocator->InitializeVacuum());
|
1013
979
|
}
|
980
|
+
}
|
1014
981
|
|
1015
|
-
|
982
|
+
void ART::FinalizeVacuum(const ARTFlags &flags) {
|
983
|
+
|
984
|
+
for (idx_t i = 0; i < allocators.size(); i++) {
|
985
|
+
if (flags.vacuum_flags[i]) {
|
986
|
+
allocators[i]->FinalizeVacuum();
|
987
|
+
}
|
988
|
+
}
|
989
|
+
}
|
990
|
+
|
991
|
+
void ART::Vacuum(IndexLock &state) {
|
992
|
+
|
993
|
+
if (!tree->IsSet()) {
|
994
|
+
for (auto &allocator : allocators) {
|
995
|
+
allocator->Reset();
|
996
|
+
}
|
997
|
+
return;
|
998
|
+
}
|
999
|
+
|
1000
|
+
// holds true, if an allocator needs a vacuum, and false otherwise
|
1001
|
+
ARTFlags flags;
|
1002
|
+
InitializeVacuum(flags);
|
1003
|
+
|
1004
|
+
// skip vacuum if no allocators require it
|
1005
|
+
auto perform_vacuum = false;
|
1006
|
+
for (const auto &vacuum_flag : flags.vacuum_flags) {
|
1007
|
+
if (vacuum_flag) {
|
1008
|
+
perform_vacuum = true;
|
1009
|
+
break;
|
1010
|
+
}
|
1011
|
+
}
|
1012
|
+
if (!perform_vacuum) {
|
1013
|
+
return;
|
1014
|
+
}
|
1015
|
+
|
1016
|
+
// traverse the allocated memory of the tree to perform a vacuum
|
1017
|
+
Node::Vacuum(*this, *tree, flags);
|
1018
|
+
|
1019
|
+
// finalize the vacuum operation
|
1020
|
+
FinalizeVacuum(flags);
|
1016
1021
|
}
|
1017
1022
|
|
1018
1023
|
//===--------------------------------------------------------------------===//
|
1019
|
-
//
|
1024
|
+
// Merging
|
1020
1025
|
//===--------------------------------------------------------------------===//
|
1021
1026
|
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1027
|
+
void ART::InitializeMerge(ARTFlags &flags) {
|
1028
|
+
|
1029
|
+
flags.merge_buffer_counts.reserve(allocators.size());
|
1030
|
+
for (auto &allocator : allocators) {
|
1031
|
+
flags.merge_buffer_counts.emplace_back(allocator->buffers.size());
|
1025
1032
|
}
|
1026
|
-
return "[empty]";
|
1027
1033
|
}
|
1028
1034
|
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1035
|
+
bool ART::MergeIndexes(IndexLock &state, Index &other_index) {
|
1036
|
+
|
1037
|
+
auto &other_art = other_index.Cast<ART>();
|
1038
|
+
|
1039
|
+
if (tree->IsSet()) {
|
1040
|
+
// fully deserialize other_index, and traverse it to increment its buffer IDs
|
1041
|
+
ARTFlags flags;
|
1042
|
+
InitializeMerge(flags);
|
1043
|
+
other_art.tree->InitializeMerge(other_art, flags);
|
1034
1044
|
}
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1045
|
+
|
1046
|
+
// merge the node storage
|
1047
|
+
for (idx_t i = 0; i < allocators.size(); i++) {
|
1048
|
+
allocators[i]->Merge(*other_art.allocators[i]);
|
1038
1049
|
}
|
1039
|
-
|
1050
|
+
|
1051
|
+
// merge the ARTs
|
1052
|
+
if (!tree->Merge(*this, *other_art.tree)) {
|
1053
|
+
return false;
|
1054
|
+
}
|
1055
|
+
return true;
|
1040
1056
|
}
|
1041
1057
|
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
if (
|
1048
|
-
|
1058
|
+
//===--------------------------------------------------------------------===//
|
1059
|
+
// Utility
|
1060
|
+
//===--------------------------------------------------------------------===//
|
1061
|
+
|
1062
|
+
string ART::ToString() {
|
1063
|
+
if (tree->IsSet()) {
|
1064
|
+
return tree->ToString(*this);
|
1049
1065
|
}
|
1066
|
+
return "[empty]";
|
1050
1067
|
}
|
1051
1068
|
|
1052
1069
|
} // namespace duckdb
|