duckdb 0.8.2-dev4314.0 → 0.8.2-dev4424.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/package.json +1 -1
- package/src/duckdb/extension/parquet/parquet_extension.cpp +1 -1
- package/src/duckdb/src/common/enum_util.cpp +5 -0
- package/src/duckdb/src/common/file_buffer.cpp +1 -1
- package/src/duckdb/src/common/types/date.cpp +1 -1
- package/src/duckdb/src/common/types/validity_mask.cpp +56 -0
- package/src/duckdb/src/execution/index/fixed_size_buffer.cpp +3 -10
- package/src/duckdb/src/execution/operator/csv_scanner/parallel_csv_reader.cpp +6 -3
- package/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp +1 -1
- package/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +1 -1
- package/src/duckdb/src/function/table/arrow_conversion.cpp +9 -1
- package/src/duckdb/src/function/table/read_csv.cpp +5 -22
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/common/constants.hpp +0 -15
- package/src/duckdb/src/include/duckdb/common/serializer/memory_stream.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/types/validity_mask.hpp +3 -0
- package/src/duckdb/src/include/duckdb/function/table/arrow.hpp +3 -0
- package/src/duckdb/src/include/duckdb/main/query_result.hpp +1 -1
- package/src/duckdb/src/include/duckdb/storage/block.hpp +3 -3
- package/src/duckdb/src/include/duckdb/storage/compression/bitpacking.hpp +1 -8
- package/src/duckdb/src/include/duckdb/storage/data_pointer.hpp +2 -2
- package/src/duckdb/src/include/duckdb/storage/metadata/metadata_manager.hpp +2 -0
- package/src/duckdb/src/include/duckdb/storage/metadata/metadata_reader.hpp +2 -0
- package/src/duckdb/src/include/duckdb/storage/metadata/metadata_writer.hpp +6 -2
- package/src/duckdb/src/include/duckdb/storage/storage_info.hpp +19 -0
- package/src/duckdb/src/include/duckdb/storage/table/chunk_info.hpp +19 -13
- package/src/duckdb/src/include/duckdb/storage/table/column_data.hpp +1 -1
- package/src/duckdb/src/include/duckdb/storage/table/row_group.hpp +15 -15
- package/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp +59 -0
- package/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp +1 -1
- package/src/duckdb/src/include/duckdb/transaction/commit_state.hpp +1 -6
- package/src/duckdb/src/include/duckdb/transaction/delete_info.hpp +3 -2
- package/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp +4 -2
- package/src/duckdb/src/include/duckdb/transaction/local_storage.hpp +1 -1
- package/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp +0 -1
- package/src/duckdb/src/main/settings/settings.cpp +5 -10
- package/src/duckdb/src/optimizer/statistics/expression/propagate_cast.cpp +14 -0
- package/src/duckdb/src/storage/checkpoint/table_data_writer.cpp +0 -1
- package/src/duckdb/src/storage/checkpoint_manager.cpp +37 -36
- package/src/duckdb/src/storage/compression/bitpacking.cpp +55 -48
- package/src/duckdb/src/storage/data_table.cpp +1 -1
- package/src/duckdb/src/storage/local_storage.cpp +9 -2
- package/src/duckdb/src/storage/metadata/metadata_manager.cpp +41 -2
- package/src/duckdb/src/storage/metadata/metadata_reader.cpp +12 -3
- package/src/duckdb/src/storage/metadata/metadata_writer.cpp +8 -2
- package/src/duckdb/src/storage/single_file_block_manager.cpp +1 -2
- package/src/duckdb/src/storage/storage_info.cpp +1 -1
- package/src/duckdb/src/storage/table/chunk_info.cpp +39 -33
- package/src/duckdb/src/storage/table/column_data.cpp +14 -9
- package/src/duckdb/src/storage/table/list_column_data.cpp +2 -2
- package/src/duckdb/src/storage/table/row_group.cpp +102 -192
- package/src/duckdb/src/storage/table/row_group_collection.cpp +2 -2
- package/src/duckdb/src/storage/table/row_version_manager.cpp +228 -0
- package/src/duckdb/src/storage/table/update_segment.cpp +2 -2
- package/src/duckdb/src/transaction/cleanup_state.cpp +2 -1
- package/src/duckdb/src/transaction/commit_state.cpp +5 -4
- package/src/duckdb/src/transaction/duck_transaction.cpp +4 -2
- package/src/duckdb/src/transaction/rollback_state.cpp +2 -1
- package/src/duckdb/src/transaction/undo_buffer.cpp +3 -5
- package/src/duckdb/ub_src_storage_table.cpp +2 -0
- package/test/prepare.test.ts +10 -1
- package/test/test_all_types.test.ts +4 -4
@@ -36,11 +36,12 @@ class Vector;
|
|
36
36
|
struct ColumnCheckpointState;
|
37
37
|
struct RowGroupPointer;
|
38
38
|
struct TransactionData;
|
39
|
-
struct VersionNode;
|
40
39
|
class CollectionScanState;
|
41
40
|
class TableFilterSet;
|
42
41
|
struct ColumnFetchState;
|
43
42
|
struct RowGroupAppendState;
|
43
|
+
class MetadataManager;
|
44
|
+
class RowVersionManager;
|
44
45
|
|
45
46
|
struct RowGroupWriteData {
|
46
47
|
vector<unique_ptr<ColumnCheckpointState>> states;
|
@@ -50,11 +51,6 @@ struct RowGroupWriteData {
|
|
50
51
|
class RowGroup : public SegmentBase<RowGroup> {
|
51
52
|
public:
|
52
53
|
friend class ColumnData;
|
53
|
-
friend class VersionDeleteState;
|
54
|
-
|
55
|
-
public:
|
56
|
-
static constexpr const idx_t ROW_GROUP_SIZE = STANDARD_ROW_GROUPS_SIZE;
|
57
|
-
static constexpr const idx_t ROW_GROUP_VECTOR_COUNT = ROW_GROUP_SIZE / STANDARD_VECTOR_SIZE;
|
58
54
|
|
59
55
|
public:
|
60
56
|
RowGroup(RowGroupCollection &collection, idx_t start, idx_t count);
|
@@ -65,7 +61,7 @@ private:
|
|
65
61
|
//! The RowGroupCollection this row-group is a part of
|
66
62
|
reference<RowGroupCollection> collection;
|
67
63
|
//! The version info of the row_group (inserted and deleted tuple info)
|
68
|
-
shared_ptr<
|
64
|
+
shared_ptr<RowVersionManager> version_info;
|
69
65
|
//! The column data of the row_group
|
70
66
|
vector<shared_ptr<ColumnData>> columns;
|
71
67
|
|
@@ -145,12 +141,17 @@ public:
|
|
145
141
|
|
146
142
|
void NextVector(CollectionScanState &state);
|
147
143
|
|
144
|
+
idx_t DeleteRows(idx_t vector_idx, transaction_t transaction_id, row_t rows[], idx_t count);
|
145
|
+
RowVersionManager &GetOrCreateVersionInfo();
|
146
|
+
|
148
147
|
// Serialization
|
149
148
|
static void Serialize(RowGroupPointer &pointer, Serializer &serializer);
|
150
149
|
static RowGroupPointer Deserialize(Deserializer &deserializer);
|
151
150
|
|
152
151
|
private:
|
153
|
-
|
152
|
+
shared_ptr<RowVersionManager> &GetVersionInfo();
|
153
|
+
shared_ptr<RowVersionManager> &GetOrCreateVersionInfoPtr();
|
154
|
+
|
154
155
|
ColumnData &GetColumn(storage_t c);
|
155
156
|
idx_t GetColumnCount() const;
|
156
157
|
vector<shared_ptr<ColumnData>> &GetColumns();
|
@@ -158,18 +159,17 @@ private:
|
|
158
159
|
template <TableScanType TYPE>
|
159
160
|
void TemplatedScan(TransactionData transaction, CollectionScanState &state, DataChunk &result);
|
160
161
|
|
162
|
+
vector<MetaBlockPointer> CheckpointDeletes(MetadataManager &manager);
|
163
|
+
|
164
|
+
bool HasUnloadedDeletes() const;
|
165
|
+
|
161
166
|
private:
|
162
167
|
mutex row_group_lock;
|
163
168
|
mutex stats_lock;
|
164
169
|
vector<MetaBlockPointer> column_pointers;
|
165
170
|
unique_ptr<atomic<bool>[]> is_loaded;
|
166
|
-
|
167
|
-
|
168
|
-
struct VersionNode {
|
169
|
-
unique_ptr<ChunkInfo> info[RowGroup::ROW_GROUP_VECTOR_COUNT];
|
170
|
-
|
171
|
-
void SetStart(idx_t start);
|
172
|
-
idx_t GetCommittedDeletedCount(idx_t count);
|
171
|
+
vector<MetaBlockPointer> deletes_pointers;
|
172
|
+
atomic<bool> deletes_is_loaded;
|
173
173
|
};
|
174
174
|
|
175
175
|
} // namespace duckdb
|
@@ -0,0 +1,59 @@
|
|
1
|
+
//===----------------------------------------------------------------------===//
|
2
|
+
// DuckDB
|
3
|
+
//
|
4
|
+
// duckdb/storage/table/row_version_manager.hpp
|
5
|
+
//
|
6
|
+
//
|
7
|
+
//===----------------------------------------------------------------------===//
|
8
|
+
|
9
|
+
#pragma once
|
10
|
+
|
11
|
+
#include "duckdb/common/vector_size.hpp"
|
12
|
+
#include "duckdb/storage/table/chunk_info.hpp"
|
13
|
+
#include "duckdb/storage/storage_info.hpp"
|
14
|
+
#include "duckdb/common/mutex.hpp"
|
15
|
+
|
16
|
+
namespace duckdb {
|
17
|
+
|
18
|
+
class MetadataManager;
|
19
|
+
struct MetaBlockPointer;
|
20
|
+
|
21
|
+
class RowVersionManager {
|
22
|
+
public:
|
23
|
+
explicit RowVersionManager(idx_t start);
|
24
|
+
|
25
|
+
idx_t GetStart() {
|
26
|
+
return start;
|
27
|
+
}
|
28
|
+
void SetStart(idx_t start);
|
29
|
+
idx_t GetCommittedDeletedCount(idx_t count);
|
30
|
+
|
31
|
+
idx_t GetSelVector(TransactionData transaction, idx_t vector_idx, SelectionVector &sel_vector, idx_t max_count);
|
32
|
+
idx_t GetCommittedSelVector(transaction_t start_time, transaction_t transaction_id, idx_t vector_idx,
|
33
|
+
SelectionVector &sel_vector, idx_t max_count);
|
34
|
+
bool Fetch(TransactionData transaction, idx_t row);
|
35
|
+
|
36
|
+
void AppendVersionInfo(TransactionData transaction, idx_t count, idx_t row_group_start, idx_t row_group_end);
|
37
|
+
void CommitAppend(transaction_t commit_id, idx_t row_group_start, idx_t count);
|
38
|
+
void RevertAppend(idx_t start_row);
|
39
|
+
|
40
|
+
idx_t DeleteRows(idx_t vector_idx, transaction_t transaction_id, row_t rows[], idx_t count);
|
41
|
+
void CommitDelete(idx_t vector_idx, transaction_t commit_id, row_t rows[], idx_t count);
|
42
|
+
|
43
|
+
vector<MetaBlockPointer> Checkpoint(MetadataManager &manager);
|
44
|
+
static shared_ptr<RowVersionManager> Deserialize(MetaBlockPointer delete_pointer, MetadataManager &manager,
|
45
|
+
idx_t start);
|
46
|
+
|
47
|
+
private:
|
48
|
+
mutex version_lock;
|
49
|
+
idx_t start;
|
50
|
+
unique_ptr<ChunkInfo> vector_info[Storage::ROW_GROUP_VECTOR_COUNT];
|
51
|
+
bool has_changes;
|
52
|
+
vector<MetaBlockPointer> storage_pointers;
|
53
|
+
|
54
|
+
private:
|
55
|
+
optional_ptr<ChunkInfo> GetChunkInfo(idx_t vector_idx);
|
56
|
+
ChunkVectorInfo &GetVectorInfo(idx_t vector_idx);
|
57
|
+
};
|
58
|
+
|
59
|
+
} // namespace duckdb
|
@@ -23,7 +23,7 @@ struct UpdateInfo;
|
|
23
23
|
|
24
24
|
class CommitState {
|
25
25
|
public:
|
26
|
-
explicit CommitState(
|
26
|
+
explicit CommitState(transaction_t commit_id, optional_ptr<WriteAheadLog> log = nullptr);
|
27
27
|
|
28
28
|
optional_ptr<WriteAheadLog> log;
|
29
29
|
transaction_t commit_id;
|
@@ -35,9 +35,6 @@ public:
|
|
35
35
|
unique_ptr<DataChunk> delete_chunk;
|
36
36
|
unique_ptr<DataChunk> update_chunk;
|
37
37
|
|
38
|
-
private:
|
39
|
-
ClientContext &context;
|
40
|
-
|
41
38
|
public:
|
42
39
|
template <bool HAS_LOG>
|
43
40
|
void CommitEntry(UndoFlags type, data_ptr_t data);
|
@@ -49,8 +46,6 @@ private:
|
|
49
46
|
void WriteCatalogEntry(CatalogEntry &entry, data_ptr_t extra_data);
|
50
47
|
void WriteDelete(DeleteInfo &info);
|
51
48
|
void WriteUpdate(UpdateInfo &info);
|
52
|
-
|
53
|
-
void AppendRowId(row_t rowid);
|
54
49
|
};
|
55
50
|
|
56
51
|
} // namespace duckdb
|
@@ -11,12 +11,13 @@
|
|
11
11
|
#include "duckdb/common/constants.hpp"
|
12
12
|
|
13
13
|
namespace duckdb {
|
14
|
-
class ChunkVectorInfo;
|
15
14
|
class DataTable;
|
15
|
+
class RowVersionManager;
|
16
16
|
|
17
17
|
struct DeleteInfo {
|
18
18
|
DataTable *table;
|
19
|
-
|
19
|
+
RowVersionManager *version_info;
|
20
|
+
idx_t vector_idx;
|
20
21
|
idx_t count;
|
21
22
|
idx_t base_row;
|
22
23
|
row_t rows[1];
|
@@ -11,12 +11,13 @@
|
|
11
11
|
#include "duckdb/transaction/transaction.hpp"
|
12
12
|
|
13
13
|
namespace duckdb {
|
14
|
+
class RowVersionManager;
|
14
15
|
|
15
16
|
class DuckTransaction : public Transaction {
|
16
17
|
public:
|
17
18
|
DuckTransaction(TransactionManager &manager, ClientContext &context, transaction_t start_time,
|
18
19
|
transaction_t transaction_id);
|
19
|
-
~DuckTransaction();
|
20
|
+
~DuckTransaction() override;
|
20
21
|
|
21
22
|
//! The start timestamp of this transaction
|
22
23
|
transaction_t start_time;
|
@@ -49,7 +50,8 @@ public:
|
|
49
50
|
|
50
51
|
bool ChangesMade();
|
51
52
|
|
52
|
-
void PushDelete(DataTable &table,
|
53
|
+
void PushDelete(DataTable &table, RowVersionManager &info, idx_t vector_idx, row_t rows[], idx_t count,
|
54
|
+
idx_t base_row);
|
53
55
|
void PushAppend(DataTable &table, idx_t row_start, idx_t row_count);
|
54
56
|
UpdateInfo *CreateUpdateInfo(idx_t type_size, idx_t entries);
|
55
57
|
|
@@ -88,7 +88,7 @@ private:
|
|
88
88
|
class LocalStorage {
|
89
89
|
public:
|
90
90
|
// Threshold to merge row groups instead of appending
|
91
|
-
static constexpr const idx_t MERGE_THRESHOLD =
|
91
|
+
static constexpr const idx_t MERGE_THRESHOLD = Storage::ROW_GROUP_SIZE;
|
92
92
|
|
93
93
|
public:
|
94
94
|
struct CommitState {
|
@@ -726,17 +726,12 @@ Value ForceCompressionSetting::GetSetting(ClientContext &context) {
|
|
726
726
|
//===--------------------------------------------------------------------===//
|
727
727
|
void ForceBitpackingModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) {
|
728
728
|
auto mode_str = StringUtil::Lower(input.ToString());
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
if (mode == BitpackingMode::AUTO) {
|
734
|
-
throw ParserException(
|
735
|
-
"Unrecognized option for force_bitpacking_mode, expected none, constant, constant_delta, "
|
736
|
-
"delta_for, or for");
|
737
|
-
}
|
738
|
-
config.options.force_bitpacking_mode = mode;
|
729
|
+
auto mode = BitpackingModeFromString(mode_str);
|
730
|
+
if (mode == BitpackingMode::INVALID) {
|
731
|
+
throw ParserException("Unrecognized option for force_bitpacking_mode, expected none, constant, constant_delta, "
|
732
|
+
"delta_for, or for");
|
739
733
|
}
|
734
|
+
config.options.force_bitpacking_mode = mode;
|
740
735
|
}
|
741
736
|
|
742
737
|
void ForceBitpackingModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) {
|
@@ -22,6 +22,20 @@ static unique_ptr<BaseStatistics> StatisticsOperationsNumericNumericCast(const B
|
|
22
22
|
}
|
23
23
|
|
24
24
|
static unique_ptr<BaseStatistics> StatisticsNumericCastSwitch(const BaseStatistics &input, const LogicalType &target) {
|
25
|
+
// Downcasting timestamps to times is not a truncation operation
|
26
|
+
switch (target.id()) {
|
27
|
+
case LogicalTypeId::TIME:
|
28
|
+
switch (input.GetType().id()) {
|
29
|
+
case LogicalTypeId::TIMESTAMP:
|
30
|
+
case LogicalTypeId::TIMESTAMP_TZ:
|
31
|
+
return nullptr;
|
32
|
+
default:
|
33
|
+
break;
|
34
|
+
}
|
35
|
+
default:
|
36
|
+
break;
|
37
|
+
}
|
38
|
+
|
25
39
|
switch (target.InternalType()) {
|
26
40
|
case PhysicalType::INT8:
|
27
41
|
case PhysicalType::INT16:
|
@@ -66,7 +66,6 @@ void SingleFileTableDataWriter::FinalizeTable(TableStatistics &&global_stats, Da
|
|
66
66
|
row_group_serializer.End();
|
67
67
|
}
|
68
68
|
|
69
|
-
// TODO: Serialize this:
|
70
69
|
auto index_pointers = info->indexes.SerializeIndexes(table_data_writer);
|
71
70
|
|
72
71
|
// Now begin the metadata as a unit
|
@@ -363,63 +363,64 @@ void CheckpointWriter::WriteIndex(IndexCatalogEntry &index_catalog, Serializer &
|
|
363
363
|
|
364
364
|
void CheckpointReader::ReadIndex(ClientContext &context, Deserializer &deserializer) {
|
365
365
|
|
366
|
-
//
|
367
|
-
auto
|
368
|
-
auto &
|
369
|
-
|
370
|
-
//
|
371
|
-
auto &
|
372
|
-
auto &
|
373
|
-
catalog.GetEntry(context, CatalogType::TABLE_ENTRY,
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
366
|
+
// deserialize the index create info
|
367
|
+
auto create_info = deserializer.ReadProperty<unique_ptr<CreateInfo>>(100, "index");
|
368
|
+
auto &info = create_info->Cast<CreateIndexInfo>();
|
369
|
+
|
370
|
+
// create the index in the catalog
|
371
|
+
auto &schema = catalog.GetSchema(context, create_info->schema);
|
372
|
+
auto &table =
|
373
|
+
catalog.GetEntry(context, CatalogType::TABLE_ENTRY, create_info->schema, info.table).Cast<DuckTableEntry>();
|
374
|
+
|
375
|
+
auto &index = schema.CreateIndex(context, info, table)->Cast<DuckIndexEntry>();
|
376
|
+
|
377
|
+
index.info = table.GetStorage().info;
|
378
|
+
// insert the parsed expressions into the stored index so that we correctly (de)serialize it during consecutive
|
379
|
+
// checkpoints
|
380
|
+
for (auto &parsed_expr : info.parsed_expressions) {
|
381
|
+
index.parsed_expressions.push_back(parsed_expr->Copy());
|
382
|
+
}
|
383
|
+
|
384
|
+
// we deserialize the index lazily, i.e., we do not need to load any node information
|
378
385
|
// except the root block pointer
|
379
|
-
auto
|
386
|
+
auto root_block_pointer = deserializer.ReadProperty<BlockPointer>(101, "root_block_pointer");
|
380
387
|
|
381
|
-
// obtain the expressions of the ART from the index metadata
|
382
|
-
vector<unique_ptr<Expression>> unbound_expressions;
|
388
|
+
// obtain the parsed expressions of the ART from the index metadata
|
383
389
|
vector<unique_ptr<ParsedExpression>> parsed_expressions;
|
384
|
-
for (auto &
|
385
|
-
parsed_expressions.push_back(
|
390
|
+
for (auto &parsed_expr : info.parsed_expressions) {
|
391
|
+
parsed_expressions.push_back(parsed_expr->Copy());
|
386
392
|
}
|
393
|
+
D_ASSERT(!parsed_expressions.empty());
|
387
394
|
|
388
|
-
// bind the parsed expressions
|
389
|
-
// add the table to the bind context
|
395
|
+
// add the table to the bind context to bind the parsed expressions
|
390
396
|
auto binder = Binder::CreateBinder(context);
|
391
397
|
vector<LogicalType> column_types;
|
392
398
|
vector<string> column_names;
|
393
|
-
for (auto &col :
|
399
|
+
for (auto &col : table.GetColumns().Logical()) {
|
394
400
|
column_types.push_back(col.Type());
|
395
401
|
column_names.push_back(col.Name());
|
396
402
|
}
|
403
|
+
|
404
|
+
// create a binder to bind the parsed expressions
|
397
405
|
vector<column_t> column_ids;
|
398
|
-
binder->bind_context.AddBaseTable(0,
|
406
|
+
binder->bind_context.AddBaseTable(0, info.table, column_names, column_types, column_ids, &table);
|
399
407
|
IndexBinder idx_binder(*binder, context);
|
408
|
+
|
409
|
+
// bind the parsed expressions to create unbound expressions
|
410
|
+
vector<unique_ptr<Expression>> unbound_expressions;
|
400
411
|
unbound_expressions.reserve(parsed_expressions.size());
|
401
412
|
for (auto &expr : parsed_expressions) {
|
402
413
|
unbound_expressions.push_back(idx_binder.Bind(expr));
|
403
414
|
}
|
404
415
|
|
405
|
-
if (parsed_expressions.empty()) {
|
406
|
-
// this is a PK/FK index: we create the necessary bound column ref expressions
|
407
|
-
unbound_expressions.reserve(index_info.column_ids.size());
|
408
|
-
for (idx_t key_nr = 0; key_nr < index_info.column_ids.size(); key_nr++) {
|
409
|
-
auto &col = table_catalog.GetColumn(LogicalIndex(index_info.column_ids[key_nr]));
|
410
|
-
unbound_expressions.push_back(
|
411
|
-
make_uniq<BoundColumnRefExpression>(col.GetName(), col.GetType(), ColumnBinding(0, key_nr)));
|
412
|
-
}
|
413
|
-
}
|
414
|
-
|
415
416
|
// create the index and add it to the storage
|
416
|
-
switch (
|
417
|
+
switch (info.index_type) {
|
417
418
|
case IndexType::ART: {
|
418
|
-
auto &storage =
|
419
|
-
auto art = make_uniq<ART>(
|
420
|
-
|
419
|
+
auto &storage = table.GetStorage();
|
420
|
+
auto art = make_uniq<ART>(info.column_ids, TableIOManager::Get(storage), std::move(unbound_expressions),
|
421
|
+
info.constraint_type, storage.db, nullptr, root_block_pointer);
|
421
422
|
|
422
|
-
|
423
|
+
index.index = art.get();
|
423
424
|
storage.info->indexes.AddIndex(std::move(art));
|
424
425
|
} break;
|
425
426
|
default:
|
@@ -23,8 +23,7 @@ static constexpr const idx_t BITPACKING_METADATA_GROUP_SIZE = STANDARD_VECTOR_SI
|
|
23
23
|
|
24
24
|
BitpackingMode BitpackingModeFromString(const string &str) {
|
25
25
|
auto mode = StringUtil::Lower(str);
|
26
|
-
|
27
|
-
if (mode == "auto") {
|
26
|
+
if (mode == "auto" || mode == "none") {
|
28
27
|
return BitpackingMode::AUTO;
|
29
28
|
} else if (mode == "constant") {
|
30
29
|
return BitpackingMode::CONSTANT;
|
@@ -35,21 +34,21 @@ BitpackingMode BitpackingModeFromString(const string &str) {
|
|
35
34
|
} else if (mode == "for") {
|
36
35
|
return BitpackingMode::FOR;
|
37
36
|
} else {
|
38
|
-
return BitpackingMode::
|
37
|
+
return BitpackingMode::INVALID;
|
39
38
|
}
|
40
39
|
}
|
41
40
|
|
42
41
|
string BitpackingModeToString(const BitpackingMode &mode) {
|
43
42
|
switch (mode) {
|
44
|
-
case
|
43
|
+
case BitpackingMode::AUTO:
|
45
44
|
return "auto";
|
46
|
-
case
|
45
|
+
case BitpackingMode::CONSTANT:
|
47
46
|
return "constant";
|
48
|
-
case
|
47
|
+
case BitpackingMode::CONSTANT_DELTA:
|
49
48
|
return "constant_delta";
|
50
|
-
case
|
49
|
+
case BitpackingMode::DELTA_FOR:
|
51
50
|
return "delta_for";
|
52
|
-
case
|
51
|
+
case BitpackingMode::FOR:
|
53
52
|
return "for";
|
54
53
|
default:
|
55
54
|
throw NotImplementedException("Unknown bitpacking mode: " + to_string((uint8_t)mode) + "\n");
|
@@ -161,7 +160,7 @@ public:
|
|
161
160
|
// Don't delta encoding 1 value makes no sense
|
162
161
|
if (compression_buffer_idx < 2) {
|
163
162
|
return;
|
164
|
-
}
|
163
|
+
}
|
165
164
|
|
166
165
|
// TODO: handle NULLS here?
|
167
166
|
// Currently we cannot handle nulls because we would need an additional step of patching for this.
|
@@ -686,48 +685,57 @@ public:
|
|
686
685
|
}
|
687
686
|
|
688
687
|
void Skip(ColumnSegment &segment, idx_t skip_count) {
|
689
|
-
|
690
|
-
if (current_group_offset + skip_count < BITPACKING_METADATA_GROUP_SIZE) {
|
691
|
-
// Skipping Delta FOR requires a bit of decoding to figure out the new delta
|
692
|
-
if (current_group.mode == BitpackingMode::DELTA_FOR) {
|
693
|
-
// if current_group_offset points into the middle of a
|
694
|
-
// BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE, we need to scan a few
|
695
|
-
// values before current_group_offset to align with the algorithm groups
|
696
|
-
idx_t extra_count = current_group_offset % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE;
|
697
|
-
|
698
|
-
// Calculate total offset and count to bitunpack
|
699
|
-
idx_t base_decompress_count = BitpackingPrimitives::RoundUpToAlgorithmGroupSize(skip_count);
|
700
|
-
idx_t decompress_count = base_decompress_count + extra_count;
|
701
|
-
idx_t decompress_offset = current_group_offset - extra_count;
|
702
|
-
bool skip_sign_extension = true;
|
703
|
-
|
704
|
-
BitpackingPrimitives::UnPackBuffer<T>(data_ptr_cast(decompression_buffer),
|
705
|
-
current_group_ptr + decompress_offset, decompress_count,
|
706
|
-
current_width, skip_sign_extension);
|
707
|
-
|
708
|
-
ApplyFrameOfReference<T_S>(reinterpret_cast<T_S *>(decompression_buffer + extra_count),
|
709
|
-
current_frame_of_reference, skip_count);
|
710
|
-
DeltaDecode<T_S>(reinterpret_cast<T_S *>(decompression_buffer + extra_count),
|
711
|
-
static_cast<T_S>(current_delta_offset), skip_count);
|
712
|
-
current_delta_offset = decompression_buffer[extra_count + skip_count - 1];
|
713
|
-
|
714
|
-
current_group_offset += skip_count;
|
715
|
-
} else {
|
716
|
-
current_group_offset += skip_count;
|
717
|
-
}
|
718
|
-
break;
|
719
|
-
} else {
|
720
|
-
auto left_in_this_group = BITPACKING_METADATA_GROUP_SIZE - current_group_offset;
|
721
|
-
auto number_of_groups_to_skip = (skip_count - left_in_this_group) / BITPACKING_METADATA_GROUP_SIZE;
|
722
|
-
|
723
|
-
current_group_offset = 0;
|
724
|
-
bitpacking_metadata_ptr -= number_of_groups_to_skip * sizeof(bitpacking_metadata_encoded_t);
|
688
|
+
bool skip_sign_extend = true;
|
725
689
|
|
690
|
+
idx_t skipped = 0;
|
691
|
+
while (skipped < skip_count) {
|
692
|
+
// Exhausted this metadata group, move pointers to next group and load metadata for next group.
|
693
|
+
if (current_group_offset >= BITPACKING_METADATA_GROUP_SIZE) {
|
726
694
|
LoadNextGroup();
|
695
|
+
}
|
727
696
|
|
728
|
-
|
729
|
-
|
697
|
+
idx_t offset_in_compression_group =
|
698
|
+
current_group_offset % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE;
|
699
|
+
|
700
|
+
if (current_group.mode == BitpackingMode::CONSTANT) {
|
701
|
+
idx_t remaining = skip_count - skipped;
|
702
|
+
idx_t to_skip = MinValue(remaining, BITPACKING_METADATA_GROUP_SIZE - current_group_offset);
|
703
|
+
skipped += to_skip;
|
704
|
+
current_group_offset += to_skip;
|
705
|
+
continue;
|
706
|
+
}
|
707
|
+
if (current_group.mode == BitpackingMode::CONSTANT_DELTA) {
|
708
|
+
idx_t remaining = skip_count - skipped;
|
709
|
+
idx_t to_skip = MinValue(remaining, BITPACKING_METADATA_GROUP_SIZE - current_group_offset);
|
710
|
+
skipped += to_skip;
|
711
|
+
current_group_offset += to_skip;
|
712
|
+
continue;
|
713
|
+
}
|
714
|
+
D_ASSERT(current_group.mode == BitpackingMode::FOR || current_group.mode == BitpackingMode::DELTA_FOR);
|
715
|
+
|
716
|
+
idx_t to_skip =
|
717
|
+
MinValue<idx_t>(skip_count - skipped,
|
718
|
+
BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE - offset_in_compression_group);
|
719
|
+
// Calculate start of compression algorithm group
|
720
|
+
if (current_group.mode == BitpackingMode::DELTA_FOR) {
|
721
|
+
data_ptr_t current_position_ptr = current_group_ptr + current_group_offset * current_width / 8;
|
722
|
+
data_ptr_t decompression_group_start_pointer =
|
723
|
+
current_position_ptr - offset_in_compression_group * current_width / 8;
|
724
|
+
|
725
|
+
BitpackingPrimitives::UnPackBlock<T>(data_ptr_cast(decompression_buffer),
|
726
|
+
decompression_group_start_pointer, current_width,
|
727
|
+
skip_sign_extend);
|
728
|
+
|
729
|
+
T *decompression_ptr = decompression_buffer + offset_in_compression_group;
|
730
|
+
ApplyFrameOfReference<T_S>(reinterpret_cast<T_S *>(decompression_ptr),
|
731
|
+
static_cast<T_S>(current_frame_of_reference), to_skip);
|
732
|
+
DeltaDecode<T_S>(reinterpret_cast<T_S *>(decompression_ptr), static_cast<T_S>(current_delta_offset),
|
733
|
+
to_skip);
|
734
|
+
current_delta_offset = decompression_ptr[to_skip - 1];
|
730
735
|
}
|
736
|
+
|
737
|
+
skipped += to_skip;
|
738
|
+
current_group_offset += to_skip;
|
731
739
|
}
|
732
740
|
}
|
733
741
|
|
@@ -757,7 +765,6 @@ void BitpackingScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t
|
|
757
765
|
bool skip_sign_extend = true;
|
758
766
|
|
759
767
|
idx_t scanned = 0;
|
760
|
-
|
761
768
|
while (scanned < scan_count) {
|
762
769
|
// Exhausted this metadata group, move pointers to next group and load metadata for next group.
|
763
770
|
if (scan_state.current_group_offset >= BITPACKING_METADATA_GROUP_SIZE) {
|
@@ -208,7 +208,7 @@ void DataTable::InitializeScanWithOffset(TableScanState &state, const vector<col
|
|
208
208
|
}
|
209
209
|
|
210
210
|
idx_t DataTable::MaxThreads(ClientContext &context) {
|
211
|
-
idx_t parallel_scan_vector_count =
|
211
|
+
idx_t parallel_scan_vector_count = Storage::ROW_GROUP_VECTOR_COUNT;
|
212
212
|
if (ClientConfig::GetConfig(context).verify_parallelism) {
|
213
213
|
parallel_scan_vector_count = 1;
|
214
214
|
}
|
@@ -102,7 +102,7 @@ void LocalTableStorage::WriteNewRowGroup() {
|
|
102
102
|
}
|
103
103
|
|
104
104
|
void LocalTableStorage::FlushBlocks() {
|
105
|
-
if (!merged_storage && row_groups->GetTotalRows() >
|
105
|
+
if (!merged_storage && row_groups->GetTotalRows() > Storage::ROW_GROUP_SIZE) {
|
106
106
|
optimistic_writer.WriteLastRowGroup(*row_groups);
|
107
107
|
}
|
108
108
|
optimistic_writer.FinalFlush();
|
@@ -159,7 +159,7 @@ void LocalTableStorage::AppendToIndexes(DuckTransaction &transaction, TableAppen
|
|
159
159
|
AppendToIndexes(transaction, *row_groups, table.info->indexes, table.GetTypes(), append_state.current_row);
|
160
160
|
}
|
161
161
|
if (error) {
|
162
|
-
// need to revert
|
162
|
+
// need to revert all appended row ids
|
163
163
|
row_t current_row = append_state.row_start;
|
164
164
|
// remove the data from the indexes, if there are any indexes
|
165
165
|
row_groups->Scan(transaction, [&](DataChunk &chunk) -> bool {
|
@@ -184,6 +184,13 @@ void LocalTableStorage::AppendToIndexes(DuckTransaction &transaction, TableAppen
|
|
184
184
|
if (append_to_table) {
|
185
185
|
table.RevertAppendInternal(append_state.row_start, append_count);
|
186
186
|
}
|
187
|
+
|
188
|
+
// we need to vacuum the indexes to remove any buffers that are now empty
|
189
|
+
// due to reverting the appends
|
190
|
+
table.info->indexes.Scan([&](Index &index) {
|
191
|
+
index.Vacuum();
|
192
|
+
return false;
|
193
|
+
});
|
187
194
|
error.Throw();
|
188
195
|
}
|
189
196
|
}
|
@@ -34,6 +34,12 @@ MetadataHandle MetadataManager::AllocateHandle() {
|
|
34
34
|
MetadataPointer pointer;
|
35
35
|
pointer.block_index = free_block;
|
36
36
|
auto &block = blocks[free_block];
|
37
|
+
if (block.block->BlockId() < MAXIMUM_BLOCK) {
|
38
|
+
// this block is a disk-backed block, yet we are planning to write to it
|
39
|
+
// we need to convert it into a transient block before we can write to it
|
40
|
+
ConvertToTransient(block);
|
41
|
+
D_ASSERT(block.block->BlockId() >= MAXIMUM_BLOCK);
|
42
|
+
}
|
37
43
|
D_ASSERT(!block.free_blocks.empty());
|
38
44
|
pointer.index = block.free_blocks.back();
|
39
45
|
// mark the block as used
|
@@ -54,6 +60,23 @@ MetadataHandle MetadataManager::Pin(MetadataPointer pointer) {
|
|
54
60
|
return handle;
|
55
61
|
}
|
56
62
|
|
63
|
+
void MetadataManager::ConvertToTransient(MetadataBlock &block) {
|
64
|
+
// pin the old block
|
65
|
+
auto old_buffer = buffer_manager.Pin(block.block);
|
66
|
+
|
67
|
+
// allocate a new transient block to replace it
|
68
|
+
shared_ptr<BlockHandle> new_block;
|
69
|
+
auto new_buffer = buffer_manager.Allocate(Storage::BLOCK_SIZE, false, &new_block);
|
70
|
+
|
71
|
+
// copy the data to the transient block
|
72
|
+
memcpy(new_buffer.Ptr(), old_buffer.Ptr(), Storage::BLOCK_SIZE);
|
73
|
+
|
74
|
+
block.block = std::move(new_block);
|
75
|
+
|
76
|
+
// unregister the old block
|
77
|
+
block_manager.UnregisterBlock(block.block_id, false);
|
78
|
+
}
|
79
|
+
|
57
80
|
block_id_t MetadataManager::AllocateNewBlock() {
|
58
81
|
auto new_block_id = GetNextBlockId();
|
59
82
|
|
@@ -91,11 +114,11 @@ MetaBlockPointer MetadataManager::GetDiskPointer(MetadataPointer pointer, uint32
|
|
91
114
|
return MetaBlockPointer(block_pointer, offset);
|
92
115
|
}
|
93
116
|
|
94
|
-
block_id_t MetaBlockPointer::GetBlockId() {
|
117
|
+
block_id_t MetaBlockPointer::GetBlockId() const {
|
95
118
|
return block_id_t(block_pointer & ~(idx_t(0xFF) << 56ULL));
|
96
119
|
}
|
97
120
|
|
98
|
-
uint32_t MetaBlockPointer::GetBlockIndex() {
|
121
|
+
uint32_t MetaBlockPointer::GetBlockIndex() const {
|
99
122
|
return block_pointer >> 56ULL;
|
100
123
|
}
|
101
124
|
|
@@ -262,6 +285,22 @@ void MetadataManager::MarkBlocksAsModified() {
|
|
262
285
|
}
|
263
286
|
}
|
264
287
|
|
288
|
+
void MetadataManager::ClearModifiedBlocks(const vector<MetaBlockPointer> &pointers) {
|
289
|
+
for (auto &pointer : pointers) {
|
290
|
+
auto block_id = pointer.GetBlockId();
|
291
|
+
auto block_index = pointer.GetBlockIndex();
|
292
|
+
auto entry = modified_blocks.find(block_id);
|
293
|
+
if (entry == modified_blocks.end()) {
|
294
|
+
throw InternalException("ClearModifiedBlocks - Block id %llu not found in modified_blocks", block_id);
|
295
|
+
}
|
296
|
+
auto &modified_list = entry->second;
|
297
|
+
// verify the block has been modified
|
298
|
+
D_ASSERT(modified_list && (1ULL << block_index));
|
299
|
+
// unset the bit
|
300
|
+
modified_list &= ~(1ULL << block_index);
|
301
|
+
}
|
302
|
+
}
|
303
|
+
|
265
304
|
block_id_t MetadataManager::GetNextBlockId() {
|
266
305
|
return block_manager.GetFreeBlockId();
|
267
306
|
}
|