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.
Files changed (62) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/extension/parquet/parquet_extension.cpp +1 -1
  3. package/src/duckdb/src/common/enum_util.cpp +5 -0
  4. package/src/duckdb/src/common/file_buffer.cpp +1 -1
  5. package/src/duckdb/src/common/types/date.cpp +1 -1
  6. package/src/duckdb/src/common/types/validity_mask.cpp +56 -0
  7. package/src/duckdb/src/execution/index/fixed_size_buffer.cpp +3 -10
  8. package/src/duckdb/src/execution/operator/csv_scanner/parallel_csv_reader.cpp +6 -3
  9. package/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp +1 -1
  10. package/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +1 -1
  11. package/src/duckdb/src/function/table/arrow_conversion.cpp +9 -1
  12. package/src/duckdb/src/function/table/read_csv.cpp +5 -22
  13. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  14. package/src/duckdb/src/include/duckdb/common/constants.hpp +0 -15
  15. package/src/duckdb/src/include/duckdb/common/serializer/memory_stream.hpp +1 -1
  16. package/src/duckdb/src/include/duckdb/common/types/validity_mask.hpp +3 -0
  17. package/src/duckdb/src/include/duckdb/function/table/arrow.hpp +3 -0
  18. package/src/duckdb/src/include/duckdb/main/query_result.hpp +1 -1
  19. package/src/duckdb/src/include/duckdb/storage/block.hpp +3 -3
  20. package/src/duckdb/src/include/duckdb/storage/compression/bitpacking.hpp +1 -8
  21. package/src/duckdb/src/include/duckdb/storage/data_pointer.hpp +2 -2
  22. package/src/duckdb/src/include/duckdb/storage/metadata/metadata_manager.hpp +2 -0
  23. package/src/duckdb/src/include/duckdb/storage/metadata/metadata_reader.hpp +2 -0
  24. package/src/duckdb/src/include/duckdb/storage/metadata/metadata_writer.hpp +6 -2
  25. package/src/duckdb/src/include/duckdb/storage/storage_info.hpp +19 -0
  26. package/src/duckdb/src/include/duckdb/storage/table/chunk_info.hpp +19 -13
  27. package/src/duckdb/src/include/duckdb/storage/table/column_data.hpp +1 -1
  28. package/src/duckdb/src/include/duckdb/storage/table/row_group.hpp +15 -15
  29. package/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp +59 -0
  30. package/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp +1 -1
  31. package/src/duckdb/src/include/duckdb/transaction/commit_state.hpp +1 -6
  32. package/src/duckdb/src/include/duckdb/transaction/delete_info.hpp +3 -2
  33. package/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp +4 -2
  34. package/src/duckdb/src/include/duckdb/transaction/local_storage.hpp +1 -1
  35. package/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp +0 -1
  36. package/src/duckdb/src/main/settings/settings.cpp +5 -10
  37. package/src/duckdb/src/optimizer/statistics/expression/propagate_cast.cpp +14 -0
  38. package/src/duckdb/src/storage/checkpoint/table_data_writer.cpp +0 -1
  39. package/src/duckdb/src/storage/checkpoint_manager.cpp +37 -36
  40. package/src/duckdb/src/storage/compression/bitpacking.cpp +55 -48
  41. package/src/duckdb/src/storage/data_table.cpp +1 -1
  42. package/src/duckdb/src/storage/local_storage.cpp +9 -2
  43. package/src/duckdb/src/storage/metadata/metadata_manager.cpp +41 -2
  44. package/src/duckdb/src/storage/metadata/metadata_reader.cpp +12 -3
  45. package/src/duckdb/src/storage/metadata/metadata_writer.cpp +8 -2
  46. package/src/duckdb/src/storage/single_file_block_manager.cpp +1 -2
  47. package/src/duckdb/src/storage/storage_info.cpp +1 -1
  48. package/src/duckdb/src/storage/table/chunk_info.cpp +39 -33
  49. package/src/duckdb/src/storage/table/column_data.cpp +14 -9
  50. package/src/duckdb/src/storage/table/list_column_data.cpp +2 -2
  51. package/src/duckdb/src/storage/table/row_group.cpp +102 -192
  52. package/src/duckdb/src/storage/table/row_group_collection.cpp +2 -2
  53. package/src/duckdb/src/storage/table/row_version_manager.cpp +228 -0
  54. package/src/duckdb/src/storage/table/update_segment.cpp +2 -2
  55. package/src/duckdb/src/transaction/cleanup_state.cpp +2 -1
  56. package/src/duckdb/src/transaction/commit_state.cpp +5 -4
  57. package/src/duckdb/src/transaction/duck_transaction.cpp +4 -2
  58. package/src/duckdb/src/transaction/rollback_state.cpp +2 -1
  59. package/src/duckdb/src/transaction/undo_buffer.cpp +3 -5
  60. package/src/duckdb/ub_src_storage_table.cpp +2 -0
  61. package/test/prepare.test.ts +10 -1
  62. 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<VersionNode> version_info;
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
- ChunkInfo *GetChunkInfo(idx_t vector_idx);
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
@@ -101,7 +101,7 @@ struct UpdateNodeData {
101
101
  };
102
102
 
103
103
  struct UpdateNode {
104
- unique_ptr<UpdateNodeData> info[RowGroup::ROW_GROUP_VECTOR_COUNT];
104
+ unique_ptr<UpdateNodeData> info[Storage::ROW_GROUP_VECTOR_COUNT];
105
105
  };
106
106
 
107
107
  } // namespace duckdb
@@ -23,7 +23,7 @@ struct UpdateInfo;
23
23
 
24
24
  class CommitState {
25
25
  public:
26
- explicit CommitState(ClientContext &context, transaction_t commit_id, optional_ptr<WriteAheadLog> log = nullptr);
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
- ChunkVectorInfo *vinfo;
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, ChunkVectorInfo *vinfo, row_t rows[], idx_t count, idx_t base_row);
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 = RowGroup::ROW_GROUP_SIZE;
91
+ static constexpr const idx_t MERGE_THRESHOLD = Storage::ROW_GROUP_SIZE;
92
92
 
93
93
  public:
94
94
  struct CommitState {
@@ -48,7 +48,6 @@ public:
48
48
  void Rollback() noexcept;
49
49
 
50
50
  private:
51
- ClientContext &context;
52
51
  ArenaAllocator allocator;
53
52
 
54
53
  private:
@@ -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
- if (mode_str == "none") {
730
- config.options.force_bitpacking_mode = BitpackingMode::AUTO;
731
- } else {
732
- auto mode = BitpackingModeFromString(mode_str);
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
- // Deserialize the index metadata
367
- auto info = deserializer.ReadProperty<unique_ptr<CreateInfo>>(100, "index");
368
- auto &index_info = info->Cast<CreateIndexInfo>();
369
-
370
- // Create the index in the catalog
371
- auto &schema_catalog = catalog.GetSchema(context, info->schema);
372
- auto &table_catalog =
373
- catalog.GetEntry(context, CatalogType::TABLE_ENTRY, info->schema, index_info.table).Cast<DuckTableEntry>();
374
- auto &index_catalog = schema_catalog.CreateIndex(context, index_info, table_catalog)->Cast<DuckIndexEntry>();
375
- index_catalog.info = table_catalog.GetStorage().info;
376
-
377
- // We deserialize the index lazily, i.e., we do not need to load any node information
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 index_block_pointer = deserializer.ReadProperty<BlockPointer>(101, "root_block_pointer");
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 &p_exp : index_info.parsed_expressions) {
385
- parsed_expressions.push_back(p_exp->Copy());
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 : table_catalog.GetColumns().Logical()) {
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, index_info.table, column_names, column_types, column_ids, &table_catalog);
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 (index_info.index_type) {
417
+ switch (info.index_type) {
417
418
  case IndexType::ART: {
418
- auto &storage = table_catalog.GetStorage();
419
- auto art = make_uniq<ART>(index_info.column_ids, TableIOManager::Get(storage), std::move(unbound_expressions),
420
- index_info.constraint_type, storage.db, nullptr, index_block_pointer);
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
- index_catalog.index = art.get();
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::AUTO;
37
+ return BitpackingMode::INVALID;
39
38
  }
40
39
  }
41
40
 
42
41
  string BitpackingModeToString(const BitpackingMode &mode) {
43
42
  switch (mode) {
44
- case (BitpackingMode::AUTO):
43
+ case BitpackingMode::AUTO:
45
44
  return "auto";
46
- case (BitpackingMode::CONSTANT):
45
+ case BitpackingMode::CONSTANT:
47
46
  return "constant";
48
- case (BitpackingMode::CONSTANT_DELTA):
47
+ case BitpackingMode::CONSTANT_DELTA:
49
48
  return "constant_delta";
50
- case (BitpackingMode::DELTA_FOR):
49
+ case BitpackingMode::DELTA_FOR:
51
50
  return "delta_for";
52
- case (BitpackingMode::FOR):
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
- while (skip_count > 0) {
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
- skip_count -= left_in_this_group;
729
- skip_count -= number_of_groups_to_skip * BITPACKING_METADATA_GROUP_SIZE;
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 = RowGroup::ROW_GROUP_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() > RowGroup::ROW_GROUP_SIZE) {
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 the append
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
  }