duckdb 0.8.2-dev4314.0 → 0.8.2-dev4376.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/validity_mask.cpp +56 -0
- 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/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/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/compression/bitpacking.cpp +55 -48
- package/src/duckdb/src/storage/data_table.cpp +1 -1
- package/src/duckdb/src/storage/local_storage.cpp +1 -1
- 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
@@ -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
|
@@ -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();
|
@@ -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
|
}
|
@@ -2,9 +2,14 @@
|
|
2
2
|
|
3
3
|
namespace duckdb {
|
4
4
|
|
5
|
-
MetadataReader::MetadataReader(MetadataManager &manager, MetaBlockPointer pointer,
|
6
|
-
|
7
|
-
|
5
|
+
MetadataReader::MetadataReader(MetadataManager &manager, MetaBlockPointer pointer,
|
6
|
+
optional_ptr<vector<MetaBlockPointer>> read_pointers_p, BlockReaderType type)
|
7
|
+
: manager(manager), type(type), next_pointer(FromDiskPointer(pointer)), has_next_block(true),
|
8
|
+
read_pointers(read_pointers_p), index(0), offset(0), next_offset(pointer.offset), capacity(0) {
|
9
|
+
if (read_pointers) {
|
10
|
+
D_ASSERT(read_pointers->empty());
|
11
|
+
read_pointers->push_back(pointer);
|
12
|
+
}
|
8
13
|
}
|
9
14
|
|
10
15
|
MetadataReader::MetadataReader(MetadataManager &manager, BlockPointer pointer)
|
@@ -57,6 +62,10 @@ void MetadataReader::ReadNextBlock() {
|
|
57
62
|
has_next_block = false;
|
58
63
|
} else {
|
59
64
|
next_pointer = FromDiskPointer(MetaBlockPointer(next_block, 0));
|
65
|
+
MetaBlockPointer next_block_pointer(next_block, 0);
|
66
|
+
if (read_pointers) {
|
67
|
+
read_pointers->push_back(next_block_pointer);
|
68
|
+
}
|
60
69
|
}
|
61
70
|
if (next_offset < sizeof(block_id_t)) {
|
62
71
|
next_offset = sizeof(block_id_t);
|
@@ -3,7 +3,9 @@
|
|
3
3
|
|
4
4
|
namespace duckdb {
|
5
5
|
|
6
|
-
MetadataWriter::MetadataWriter(MetadataManager &manager
|
6
|
+
MetadataWriter::MetadataWriter(MetadataManager &manager, optional_ptr<vector<MetaBlockPointer>> written_pointers_p)
|
7
|
+
: manager(manager), written_pointers(written_pointers_p), capacity(0), offset(0) {
|
8
|
+
D_ASSERT(!written_pointers || written_pointers->empty());
|
7
9
|
}
|
8
10
|
|
9
11
|
MetadataWriter::~MetadataWriter() {
|
@@ -38,7 +40,8 @@ void MetadataWriter::NextBlock() {
|
|
38
40
|
|
39
41
|
// write the block id of the new block to the start of the current block
|
40
42
|
if (capacity > 0) {
|
41
|
-
|
43
|
+
auto disk_block = manager.GetDiskPointer(new_handle.pointer);
|
44
|
+
Store<idx_t>(disk_block.block_pointer, BasePtr());
|
42
45
|
}
|
43
46
|
// now update the block id of the block
|
44
47
|
block = std::move(new_handle);
|
@@ -46,6 +49,9 @@ void MetadataWriter::NextBlock() {
|
|
46
49
|
offset = sizeof(idx_t);
|
47
50
|
capacity = MetadataManager::METADATA_BLOCK_SIZE;
|
48
51
|
Store<idx_t>(-1, BasePtr());
|
52
|
+
if (written_pointers) {
|
53
|
+
written_pointers->push_back(manager.GetDiskPointer(current_pointer));
|
54
|
+
}
|
49
55
|
}
|
50
56
|
|
51
57
|
void MetadataWriter::WriteData(const_data_ptr_t buffer, idx_t write_size) {
|
@@ -240,8 +240,7 @@ void SingleFileBlockManager::LoadFreeList() {
|
|
240
240
|
// no free list
|
241
241
|
return;
|
242
242
|
}
|
243
|
-
|
244
|
-
MetadataReader reader(GetMetadataManager(), free_pointer, BlockReaderType::REGISTER_BLOCKS);
|
243
|
+
MetadataReader reader(GetMetadataManager(), free_pointer, nullptr, BlockReaderType::REGISTER_BLOCKS);
|
245
244
|
auto free_list_count = reader.Read<uint64_t>();
|
246
245
|
free_list.clear();
|
247
246
|
for (idx_t i = 0; i < free_list_count; i++) {
|
@@ -2,6 +2,7 @@
|
|
2
2
|
#include "duckdb/transaction/transaction.hpp"
|
3
3
|
#include "duckdb/common/serializer/serializer.hpp"
|
4
4
|
#include "duckdb/common/serializer/deserializer.hpp"
|
5
|
+
#include "duckdb/common/serializer/memory_stream.hpp"
|
5
6
|
|
6
7
|
namespace duckdb {
|
7
8
|
|
@@ -29,15 +30,19 @@ static bool UseVersion(TransactionData transaction, transaction_t id) {
|
|
29
30
|
return TransactionVersionOperator::UseInsertedVersion(transaction.start_time, transaction.transaction_id, id);
|
30
31
|
}
|
31
32
|
|
32
|
-
|
33
|
-
|
33
|
+
void ChunkInfo::Write(WriteStream &writer) const {
|
34
|
+
writer.Write<ChunkInfoType>(type);
|
35
|
+
}
|
36
|
+
|
37
|
+
unique_ptr<ChunkInfo> ChunkInfo::Read(ReadStream &reader) {
|
38
|
+
auto type = reader.Read<ChunkInfoType>();
|
34
39
|
switch (type) {
|
35
40
|
case ChunkInfoType::EMPTY_INFO:
|
36
41
|
return nullptr;
|
37
42
|
case ChunkInfoType::CONSTANT_INFO:
|
38
|
-
return ChunkConstantInfo::
|
43
|
+
return ChunkConstantInfo::Read(reader);
|
39
44
|
case ChunkInfoType::VECTOR_INFO:
|
40
|
-
return ChunkVectorInfo::
|
45
|
+
return ChunkVectorInfo::Read(reader);
|
41
46
|
default:
|
42
47
|
throw SerializationException("Could not deserialize Chunk Info Type: unrecognized type");
|
43
48
|
}
|
@@ -79,22 +84,23 @@ void ChunkConstantInfo::CommitAppend(transaction_t commit_id, idx_t start, idx_t
|
|
79
84
|
insert_id = commit_id;
|
80
85
|
}
|
81
86
|
|
87
|
+
bool ChunkConstantInfo::HasDeletes() const {
|
88
|
+
bool is_deleted = insert_id >= TRANSACTION_ID_START || delete_id < TRANSACTION_ID_START;
|
89
|
+
return is_deleted;
|
90
|
+
}
|
91
|
+
|
82
92
|
idx_t ChunkConstantInfo::GetCommittedDeletedCount(idx_t max_count) {
|
83
93
|
return delete_id < TRANSACTION_ID_START ? max_count : 0;
|
84
94
|
}
|
85
95
|
|
86
|
-
void ChunkConstantInfo::
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
return;
|
91
|
-
}
|
92
|
-
serializer.WriteProperty(100, "type", type);
|
93
|
-
serializer.WriteProperty(200, "start", start);
|
96
|
+
void ChunkConstantInfo::Write(WriteStream &writer) const {
|
97
|
+
D_ASSERT(HasDeletes());
|
98
|
+
ChunkInfo::Write(writer);
|
99
|
+
writer.Write<idx_t>(start);
|
94
100
|
}
|
95
101
|
|
96
|
-
unique_ptr<ChunkInfo> ChunkConstantInfo::
|
97
|
-
auto start =
|
102
|
+
unique_ptr<ChunkInfo> ChunkConstantInfo::Read(ReadStream &reader) {
|
103
|
+
auto start = reader.Read<idx_t>();
|
98
104
|
auto info = make_uniq<ChunkConstantInfo>(start);
|
99
105
|
info->insert_id = 0;
|
100
106
|
info->delete_id = 0;
|
@@ -218,6 +224,10 @@ void ChunkVectorInfo::CommitAppend(transaction_t commit_id, idx_t start, idx_t e
|
|
218
224
|
}
|
219
225
|
}
|
220
226
|
|
227
|
+
bool ChunkVectorInfo::HasDeletes() const {
|
228
|
+
return any_deleted;
|
229
|
+
}
|
230
|
+
|
221
231
|
idx_t ChunkVectorInfo::GetCommittedDeletedCount(idx_t max_count) {
|
222
232
|
if (!any_deleted) {
|
223
233
|
return 0;
|
@@ -231,45 +241,41 @@ idx_t ChunkVectorInfo::GetCommittedDeletedCount(idx_t max_count) {
|
|
231
241
|
return delete_count;
|
232
242
|
}
|
233
243
|
|
234
|
-
void ChunkVectorInfo::
|
244
|
+
void ChunkVectorInfo::Write(WriteStream &writer) const {
|
235
245
|
SelectionVector sel(STANDARD_VECTOR_SIZE);
|
236
246
|
transaction_t start_time = TRANSACTION_ID_START - 1;
|
237
247
|
transaction_t transaction_id = DConstants::INVALID_INDEX;
|
238
248
|
idx_t count = GetSelVector(start_time, transaction_id, sel, STANDARD_VECTOR_SIZE);
|
239
249
|
if (count == STANDARD_VECTOR_SIZE) {
|
240
250
|
// nothing is deleted: skip writing anything
|
241
|
-
|
251
|
+
writer.Write<ChunkInfoType>(ChunkInfoType::EMPTY_INFO);
|
242
252
|
return;
|
243
253
|
}
|
244
254
|
if (count == 0) {
|
245
255
|
// everything is deleted: write a constant vector
|
246
|
-
|
247
|
-
|
256
|
+
writer.Write<ChunkInfoType>(ChunkInfoType::CONSTANT_INFO);
|
257
|
+
writer.Write<idx_t>(start);
|
248
258
|
return;
|
249
259
|
}
|
250
260
|
// write a boolean vector
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
deleted_tuples[i] = true;
|
256
|
-
}
|
261
|
+
ChunkInfo::Write(writer);
|
262
|
+
writer.Write<idx_t>(start);
|
263
|
+
ValidityMask mask(STANDARD_VECTOR_SIZE);
|
264
|
+
mask.Initialize(STANDARD_VECTOR_SIZE);
|
257
265
|
for (idx_t i = 0; i < count; i++) {
|
258
|
-
|
266
|
+
mask.SetInvalid(sel.get_index(i));
|
259
267
|
}
|
260
|
-
|
268
|
+
mask.Write(writer, STANDARD_VECTOR_SIZE);
|
261
269
|
}
|
262
270
|
|
263
|
-
unique_ptr<ChunkInfo> ChunkVectorInfo::
|
264
|
-
auto start =
|
265
|
-
|
271
|
+
unique_ptr<ChunkInfo> ChunkVectorInfo::Read(ReadStream &reader) {
|
272
|
+
auto start = reader.Read<idx_t>();
|
266
273
|
auto result = make_uniq<ChunkVectorInfo>(start);
|
267
274
|
result->any_deleted = true;
|
268
|
-
|
269
|
-
|
270
|
-
sizeof(bool) * STANDARD_VECTOR_SIZE);
|
275
|
+
ValidityMask mask;
|
276
|
+
mask.Read(reader, STANDARD_VECTOR_SIZE);
|
271
277
|
for (idx_t i = 0; i < STANDARD_VECTOR_SIZE; i++) {
|
272
|
-
if (
|
278
|
+
if (mask.RowIsValid(i)) {
|
273
279
|
result->deleted[i] = 0;
|
274
280
|
}
|
275
281
|
}
|
@@ -87,7 +87,7 @@ void ColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx)
|
|
87
87
|
state.last_offset = 0;
|
88
88
|
}
|
89
89
|
|
90
|
-
idx_t ColumnData::ScanVector(ColumnScanState &state, Vector &result, idx_t remaining) {
|
90
|
+
idx_t ColumnData::ScanVector(ColumnScanState &state, Vector &result, idx_t remaining, bool has_updates) {
|
91
91
|
state.previous_states.clear();
|
92
92
|
if (state.version != version) {
|
93
93
|
InitializeScanWithOffset(state, state.row_index);
|
@@ -113,7 +113,8 @@ idx_t ColumnData::ScanVector(ColumnScanState &state, Vector &result, idx_t remai
|
|
113
113
|
idx_t scan_count = MinValue<idx_t>(remaining, state.current->start + state.current->count - state.row_index);
|
114
114
|
idx_t result_offset = initial_remaining - remaining;
|
115
115
|
if (scan_count > 0) {
|
116
|
-
state.current->Scan(state, scan_count, result, result_offset,
|
116
|
+
state.current->Scan(state, scan_count, result, result_offset,
|
117
|
+
!has_updates && scan_count == initial_remaining);
|
117
118
|
|
118
119
|
state.row_index += scan_count;
|
119
120
|
remaining -= scan_count;
|
@@ -138,10 +139,14 @@ idx_t ColumnData::ScanVector(ColumnScanState &state, Vector &result, idx_t remai
|
|
138
139
|
|
139
140
|
template <bool SCAN_COMMITTED, bool ALLOW_UPDATES>
|
140
141
|
idx_t ColumnData::ScanVector(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result) {
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
142
|
+
bool has_updates;
|
143
|
+
{
|
144
|
+
lock_guard<mutex> update_guard(update_lock);
|
145
|
+
has_updates = updates ? true : false;
|
146
|
+
}
|
147
|
+
auto scan_count = ScanVector(state, result, STANDARD_VECTOR_SIZE, has_updates);
|
148
|
+
if (has_updates) {
|
149
|
+
lock_guard<mutex> update_guard(update_lock);
|
145
150
|
if (!ALLOW_UPDATES && updates->HasUncommittedUpdates(vector_index)) {
|
146
151
|
throw TransactionException("Cannot create index with outstanding updates");
|
147
152
|
}
|
@@ -179,7 +184,7 @@ idx_t ColumnData::ScanCommitted(idx_t vector_index, ColumnScanState &state, Vect
|
|
179
184
|
void ColumnData::ScanCommittedRange(idx_t row_group_start, idx_t offset_in_row_group, idx_t count, Vector &result) {
|
180
185
|
ColumnScanState child_state;
|
181
186
|
InitializeScanWithOffset(child_state, row_group_start + offset_in_row_group);
|
182
|
-
auto scan_count = ScanVector(child_state, result, count);
|
187
|
+
auto scan_count = ScanVector(child_state, result, count, updates ? true : false);
|
183
188
|
if (updates) {
|
184
189
|
result.Flatten(scan_count);
|
185
190
|
updates->FetchCommittedRange(offset_in_row_group, count, result);
|
@@ -192,7 +197,7 @@ idx_t ColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t count)
|
|
192
197
|
}
|
193
198
|
// ScanCount can only be used if there are no updates
|
194
199
|
D_ASSERT(!updates);
|
195
|
-
return ScanVector(state, result, count);
|
200
|
+
return ScanVector(state, result, count, false);
|
196
201
|
}
|
197
202
|
|
198
203
|
void ColumnData::Select(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result,
|
@@ -339,7 +344,7 @@ idx_t ColumnData::Fetch(ColumnScanState &state, row_t row_id, Vector &result) {
|
|
339
344
|
state.row_index = start + ((row_id - start) / STANDARD_VECTOR_SIZE * STANDARD_VECTOR_SIZE);
|
340
345
|
state.current = data.GetSegment(state.row_index);
|
341
346
|
state.internal_index = state.current->start;
|
342
|
-
return ScanVector(state, result, STANDARD_VECTOR_SIZE);
|
347
|
+
return ScanVector(state, result, STANDARD_VECTOR_SIZE, false);
|
343
348
|
}
|
344
349
|
|
345
350
|
void ColumnData::FetchRow(TransactionData transaction, ColumnFetchState &state, row_t row_id, Vector &result,
|
@@ -86,7 +86,7 @@ idx_t ListColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t co
|
|
86
86
|
D_ASSERT(!updates);
|
87
87
|
|
88
88
|
Vector offset_vector(LogicalType::UBIGINT, count);
|
89
|
-
idx_t scan_count = ScanVector(state, offset_vector, count);
|
89
|
+
idx_t scan_count = ScanVector(state, offset_vector, count, false);
|
90
90
|
D_ASSERT(scan_count > 0);
|
91
91
|
validity.ScanCount(state.child_states[0], result, count);
|
92
92
|
|
@@ -132,7 +132,7 @@ void ListColumnData::Skip(ColumnScanState &state, idx_t count) {
|
|
132
132
|
// note that we only need to read the first and last entry
|
133
133
|
// however, let's just read all "count" entries for now
|
134
134
|
Vector result(LogicalType::UBIGINT, count);
|
135
|
-
idx_t scan_count = ScanVector(state, result, count);
|
135
|
+
idx_t scan_count = ScanVector(state, result, count, false);
|
136
136
|
if (scan_count == 0) {
|
137
137
|
return;
|
138
138
|
}
|