duckdb 0.5.2-dev764.0 → 0.5.2-dev802.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/src/duckdb.cpp CHANGED
@@ -63958,8 +63958,9 @@ OperatorResultType PhysicalStreamingWindow::Execute(ExecutionContext &context, D
63958
63958
  if (wexpr.children.empty()) {
63959
63959
  D_ASSERT(GetTypeIdSize(result.GetType().InternalType()) == sizeof(int64_t));
63960
63960
  auto data = FlatVector::GetData<int64_t>(result);
63961
+ int64_t start_row = gstate.row_number;
63961
63962
  for (idx_t i = 0; i < input.size(); ++i) {
63962
- data[i] = gstate.row_number + i;
63963
+ data[i] = start_row + i;
63963
63964
  }
63964
63965
  break;
63965
63966
  }
@@ -64006,9 +64007,10 @@ OperatorResultType PhysicalStreamingWindow::Execute(ExecutionContext &context, D
64006
64007
  }
64007
64008
  case ExpressionType::WINDOW_ROW_NUMBER: {
64008
64009
  // Set row numbers
64010
+ int64_t start_row = gstate.row_number;
64009
64011
  auto rdata = FlatVector::GetData<int64_t>(chunk.data[col_idx]);
64010
64012
  for (idx_t i = 0; i < count; i++) {
64011
- rdata[i] = gstate.row_number + i;
64013
+ rdata[i] = start_row + i;
64012
64014
  }
64013
64015
  break;
64014
64016
  }
@@ -64114,6 +64116,7 @@ private:
64114
64116
 
64115
64117
 
64116
64118
 
64119
+
64117
64120
  #include <functional>
64118
64121
 
64119
64122
 
@@ -64580,6 +64583,10 @@ public:
64580
64583
  void Schedule() override {
64581
64584
  auto &distinct_data = *gstate.distinct_data;
64582
64585
 
64586
+ //! Now that all tables are combined, it's time to do the distinct aggregations
64587
+ auto new_event = make_shared<DistinctAggregateFinalizeEvent>(op, gstate, *pipeline, client);
64588
+ this->InsertEvent(move(new_event));
64589
+
64583
64590
  vector<unique_ptr<Task>> tasks;
64584
64591
  for (idx_t table_idx = 0; table_idx < distinct_data.radix_tables.size(); table_idx++) {
64585
64592
  distinct_data.radix_tables[table_idx]->ScheduleTasks(pipeline->executor, shared_from_this(),
@@ -64587,10 +64594,6 @@ public:
64587
64594
  }
64588
64595
  D_ASSERT(!tasks.empty());
64589
64596
  SetTasks(move(tasks));
64590
-
64591
- //! Now that all tables are combined, it's time to do the distinct aggregations
64592
- auto new_event = make_shared<DistinctAggregateFinalizeEvent>(op, gstate, *pipeline, client);
64593
- this->InsertEvent(move(new_event));
64594
64597
  }
64595
64598
  };
64596
64599
 
@@ -71671,6 +71674,7 @@ private:
71671
71674
 
71672
71675
 
71673
71676
 
71677
+
71674
71678
  #include <thread>
71675
71679
 
71676
71680
  namespace duckdb {
@@ -82285,7 +82289,8 @@ static bool CanPlanIndexJoin(Transaction &transaction, TableScanBindData *bind_d
82285
82289
  return false;
82286
82290
  }
82287
82291
  auto table = bind_data->table;
82288
- if (transaction.storage.Find(table->storage.get())) {
82292
+ auto &local_storage = LocalStorage::Get(transaction);
82293
+ if (local_storage.Find(table->storage.get())) {
82289
82294
  // transaction local appends: skip index join
82290
82295
  return false;
82291
82296
  }
@@ -105300,6 +105305,7 @@ void ListFlattenFun::RegisterFunction(BuiltinFunctions &set) {
105300
105305
 
105301
105306
 
105302
105307
 
105308
+
105303
105309
  namespace duckdb {
105304
105310
 
105305
105311
  // FIXME: use a local state for each thread to increase performance?
@@ -116691,6 +116697,8 @@ void StructPackFun::RegisterFunction(BuiltinFunctions &set) {
116691
116697
 
116692
116698
 
116693
116699
 
116700
+
116701
+
116694
116702
  namespace duckdb {
116695
116703
 
116696
116704
  // aggregate state export
@@ -124159,8 +124167,8 @@ unique_ptr<GlobalTableFunctionState> TableScanInitGlobal(ClientContext &context,
124159
124167
  static unique_ptr<BaseStatistics> TableScanStatistics(ClientContext &context, const FunctionData *bind_data_p,
124160
124168
  column_t column_id) {
124161
124169
  auto &bind_data = (const TableScanBindData &)*bind_data_p;
124162
- auto &transaction = Transaction::GetTransaction(context);
124163
- if (transaction.storage.Find(bind_data.table->storage.get())) {
124170
+ auto &local_storage = LocalStorage::Get(context);
124171
+ if (local_storage.Find(bind_data.table->storage.get())) {
124164
124172
  // we don't emit any statistics for tables that have outstanding transaction-local data
124165
124173
  return nullptr;
124166
124174
  }
@@ -124238,9 +124246,9 @@ void TableScanDependency(unordered_set<CatalogEntry *> &entries, const FunctionD
124238
124246
 
124239
124247
  unique_ptr<NodeStatistics> TableScanCardinality(ClientContext &context, const FunctionData *bind_data_p) {
124240
124248
  auto &bind_data = (const TableScanBindData &)*bind_data_p;
124241
- auto &transaction = Transaction::GetTransaction(context);
124249
+ auto &local_storage = LocalStorage::Get(context);
124242
124250
  idx_t estimated_cardinality =
124243
- bind_data.table->storage->info->cardinality + transaction.storage.AddedRows(bind_data.table->storage.get());
124251
+ bind_data.table->storage->info->cardinality + local_storage.AddedRows(bind_data.table->storage.get());
124244
124252
  return make_unique<NodeStatistics>(bind_data.table->storage->info->cardinality, estimated_cardinality);
124245
124253
  }
124246
124254
 
@@ -124265,11 +124273,11 @@ static unique_ptr<GlobalTableFunctionState> IndexScanInitGlobal(ClientContext &c
124265
124273
  row_id_data = (data_ptr_t)&bind_data.result_ids[0];
124266
124274
  }
124267
124275
  auto result = make_unique<IndexScanGlobalState>(row_id_data);
124268
- auto &transaction = Transaction::GetTransaction(context);
124276
+ auto &local_storage = LocalStorage::Get(context);
124269
124277
  result->column_ids = input.column_ids;
124270
124278
  result->local_storage_state.Initialize(input.column_ids, input.filters);
124271
- transaction.storage.InitializeScan(bind_data.table->storage.get(), result->local_storage_state.local_state,
124272
- input.filters);
124279
+ local_storage.InitializeScan(bind_data.table->storage.get(), result->local_storage_state.local_state,
124280
+ input.filters);
124273
124281
 
124274
124282
  result->finished = false;
124275
124283
  return move(result);
@@ -124279,13 +124287,15 @@ static void IndexScanFunction(ClientContext &context, TableFunctionInput &data_p
124279
124287
  auto &bind_data = (const TableScanBindData &)*data_p.bind_data;
124280
124288
  auto &state = (IndexScanGlobalState &)*data_p.global_state;
124281
124289
  auto &transaction = Transaction::GetTransaction(context);
124290
+ auto &local_storage = LocalStorage::Get(transaction);
124291
+
124282
124292
  if (!state.finished) {
124283
124293
  bind_data.table->storage->Fetch(transaction, output, state.column_ids, state.row_ids,
124284
124294
  bind_data.result_ids.size(), state.fetch_state);
124285
124295
  state.finished = true;
124286
124296
  }
124287
124297
  if (output.size() == 0) {
124288
- transaction.storage.Scan(state.local_storage_state.local_state, state.column_ids, output);
124298
+ local_storage.Scan(state.local_storage_state.local_state, state.column_ids, output);
124289
124299
  }
124290
124300
  }
124291
124301
 
@@ -178018,6 +178028,7 @@ void BindContext::AddContext(BindContext other) {
178018
178028
 
178019
178029
 
178020
178030
 
178031
+
178021
178032
  //===----------------------------------------------------------------------===//
178022
178033
  // DuckDB
178023
178034
  //
@@ -178215,6 +178226,7 @@ public:
178215
178226
 
178216
178227
 
178217
178228
 
178229
+
178218
178230
  namespace duckdb {
178219
178231
 
178220
178232
  static void InvertPercentileFractions(unique_ptr<ParsedExpression> &fractions) {
@@ -179094,6 +179106,7 @@ BindResult ExpressionBinder::BindExpression(ConstantExpression &expr, idx_t dept
179094
179106
 
179095
179107
 
179096
179108
 
179109
+
179097
179110
  namespace duckdb {
179098
179111
 
179099
179112
  BindResult ExpressionBinder::BindExpression(FunctionExpression &function, idx_t depth,
@@ -186562,6 +186575,7 @@ BoundLimitPercentModifier::BoundLimitPercentModifier()
186562
186575
 
186563
186576
 
186564
186577
 
186578
+
186565
186579
  namespace duckdb {
186566
186580
 
186567
186581
  class FunctionSerializer {
@@ -194519,6 +194533,8 @@ struct PartialBlock {
194519
194533
 
194520
194534
  public:
194521
194535
  virtual void Flush() = 0;
194536
+ virtual void Clear() {
194537
+ }
194522
194538
  };
194523
194539
 
194524
194540
  struct PartialBlockAllocation {
@@ -194547,9 +194563,8 @@ public:
194547
194563
 
194548
194564
  public:
194549
194565
  PartialBlockManager(BlockManager &block_manager, uint32_t max_partial_block_size = DEFAULT_MAX_PARTIAL_BLOCK_SIZE,
194550
- uint32_t max_use_count = DEFAULT_MAX_USE_COUNT)
194551
- : block_manager(block_manager), max_partial_block_size(max_partial_block_size), max_use_count(max_use_count) {
194552
- }
194566
+ uint32_t max_use_count = DEFAULT_MAX_USE_COUNT);
194567
+ virtual ~PartialBlockManager();
194553
194568
 
194554
194569
  public:
194555
194570
  //! Flush any remaining partial blocks to disk
@@ -194562,6 +194577,9 @@ public:
194562
194577
  //! Register a partially filled block that is filled with "segment_size" entries
194563
194578
  void RegisterPartialBlock(PartialBlockAllocation &&allocation);
194564
194579
 
194580
+ //! Clears all blocks
194581
+ void Clear();
194582
+
194565
194583
  protected:
194566
194584
  BlockManager &block_manager;
194567
194585
  //! A map of (available space -> PartialBlock) for partially filled blocks
@@ -194711,6 +194729,10 @@ public:
194711
194729
  void RegisterPartialBlock(PartialBlockAllocation &&allocation);
194712
194730
  PartialBlockAllocation GetBlockAllocation(uint32_t segment_size);
194713
194731
 
194732
+ PartialBlockManager &GetPartialBlockManager() {
194733
+ return partial_block_manager;
194734
+ }
194735
+
194714
194736
  protected:
194715
194737
  TableCatalogEntry &table;
194716
194738
  PartialBlockManager &partial_block_manager;
@@ -194806,28 +194828,33 @@ private:
194806
194828
 
194807
194829
 
194808
194830
 
194831
+
194809
194832
  namespace duckdb {
194810
194833
  class ColumnData;
194811
194834
  class DatabaseInstance;
194812
194835
  class RowGroup;
194836
+ class PartialBlockManager;
194813
194837
  class TableDataWriter;
194814
194838
 
194815
194839
  struct ColumnCheckpointState {
194816
- ColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, RowGroupWriter &writer);
194840
+ ColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, PartialBlockManager &partial_block_manager);
194817
194841
  virtual ~ColumnCheckpointState();
194818
194842
 
194819
194843
  RowGroup &row_group;
194820
194844
  ColumnData &column_data;
194821
- RowGroupWriter &writer;
194822
194845
  SegmentTree new_tree;
194823
194846
  vector<DataPointer> data_pointers;
194824
194847
  unique_ptr<BaseStatistics> global_stats;
194825
194848
 
194849
+ protected:
194850
+ PartialBlockManager &partial_block_manager;
194851
+
194826
194852
  public:
194827
194853
  virtual unique_ptr<BaseStatistics> GetStatistics();
194828
194854
 
194829
194855
  virtual void FlushSegment(unique_ptr<ColumnSegment> segment, idx_t segment_size);
194830
- virtual void WriteDataPointers();
194856
+ virtual void WriteDataPointers(RowGroupWriter &writer);
194857
+ virtual void GetBlockIds(unordered_set<block_id_t> &result);
194831
194858
  };
194832
194859
 
194833
194860
  } // namespace duckdb
@@ -197104,6 +197131,8 @@ public:
197104
197131
  DataTableInfo &GetTableInfo() const;
197105
197132
  virtual idx_t GetMaxEntry();
197106
197133
 
197134
+ void IncrementVersion();
197135
+
197107
197136
  //! The root type of the column
197108
197137
  const LogicalType &RootType() const;
197109
197138
 
@@ -197149,9 +197178,10 @@ public:
197149
197178
 
197150
197179
  virtual void CommitDropColumn();
197151
197180
 
197152
- virtual unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, RowGroupWriter &writer);
197153
- virtual unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, RowGroupWriter &writer,
197154
- ColumnCheckpointInfo &checkpoint_info);
197181
+ virtual unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group,
197182
+ PartialBlockManager &partial_block_manager);
197183
+ virtual unique_ptr<ColumnCheckpointState>
197184
+ Checkpoint(RowGroup &row_group, PartialBlockManager &partial_block_manager, ColumnCheckpointInfo &checkpoint_info);
197155
197185
 
197156
197186
  virtual void CheckpointScan(ColumnSegment *segment, ColumnScanState &state, idx_t row_group_start, idx_t count,
197157
197187
  Vector &scan_vector);
@@ -197190,6 +197220,8 @@ protected:
197190
197220
  mutex update_lock;
197191
197221
  //! The updates for this column segment
197192
197222
  unique_ptr<UpdateSegment> updates;
197223
+ //! The internal version of the column data
197224
+ idx_t version;
197193
197225
  };
197194
197226
 
197195
197227
  } // namespace duckdb
@@ -200657,12 +200689,14 @@ idx_t ValidityFinalAnalyze(AnalyzeState &state_p) {
200657
200689
  //===--------------------------------------------------------------------===//
200658
200690
  struct ValidityScanState : public SegmentScanState {
200659
200691
  BufferHandle handle;
200692
+ block_id_t block_id;
200660
200693
  };
200661
200694
 
200662
200695
  unique_ptr<SegmentScanState> ValidityInitScan(ColumnSegment &segment) {
200663
200696
  auto result = make_unique<ValidityScanState>();
200664
200697
  auto &buffer_manager = BufferManager::GetBufferManager(segment.db);
200665
200698
  result->handle = buffer_manager.Pin(segment.block);
200699
+ result->block_id = segment.block->BlockId();
200666
200700
  return move(result);
200667
200701
  }
200668
200702
 
@@ -200678,6 +200712,7 @@ void ValidityScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t s
200678
200712
 
200679
200713
  auto &result_mask = FlatVector::Validity(result);
200680
200714
  auto buffer_ptr = scan_state.handle.Ptr() + segment.GetBlockOffset();
200715
+ D_ASSERT(scan_state.block_id == segment.block->BlockId());
200681
200716
  auto input_data = (validity_t *)buffer_ptr;
200682
200717
 
200683
200718
  #ifdef DEBUG
@@ -200803,6 +200838,7 @@ void ValidityScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_cou
200803
200838
  // it is not required for correctness
200804
200839
  auto &result_mask = FlatVector::Validity(result);
200805
200840
  auto buffer_ptr = scan_state.handle.Ptr() + segment.GetBlockOffset();
200841
+ D_ASSERT(scan_state.block_id == segment.block->BlockId());
200806
200842
  auto input_data = (validity_t *)buffer_ptr;
200807
200843
  auto result_data = (validity_t *)result_mask.GetData();
200808
200844
  idx_t start_offset = start / ValidityMask::BITS_PER_VALUE;
@@ -201019,8 +201055,9 @@ public:
201019
201055
 
201020
201056
  void CommitDropColumn() override;
201021
201057
 
201022
- unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, RowGroupWriter &writer) override;
201023
- unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, RowGroupWriter &writer,
201058
+ unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group,
201059
+ PartialBlockManager &partial_block_manager) override;
201060
+ unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, PartialBlockManager &partial_block_manager,
201024
201061
  ColumnCheckpointInfo &checkpoint_info) override;
201025
201062
  void CheckpointScan(ColumnSegment *segment, ColumnScanState &state, idx_t row_group_start, idx_t count,
201026
201063
  Vector &scan_vector) override;
@@ -201080,11 +201117,11 @@ DataTable::DataTable(ClientContext &context, DataTable &parent, ColumnDefinition
201080
201117
  // add the column definitions from this DataTable
201081
201118
  column_definitions.emplace_back(new_column.Copy());
201082
201119
 
201083
- auto &transaction = Transaction::GetTransaction(context);
201084
201120
  this->row_groups = parent.row_groups->AddColumn(new_column, default_value, stats.GetStats(new_column_idx));
201085
201121
 
201086
201122
  // also add this column to client local storage
201087
- transaction.storage.AddColumn(&parent, this, new_column, default_value);
201123
+ auto &local_storage = LocalStorage::Get(context);
201124
+ local_storage.AddColumn(&parent, this, new_column, default_value);
201088
201125
 
201089
201126
  // this table replaces the previous table, hence the parent is no longer the root DataTable
201090
201127
  parent.is_root = false;
@@ -201131,8 +201168,8 @@ DataTable::DataTable(ClientContext &context, DataTable &parent, idx_t removed_co
201131
201168
  this->row_groups = parent.row_groups->RemoveColumn(removed_column);
201132
201169
 
201133
201170
  // scan the original table, and fill the new column with the transformed value
201134
- auto &transaction = Transaction::GetTransaction(context);
201135
- transaction.storage.DropColumn(&parent, this, removed_column);
201171
+ auto &local_storage = LocalStorage::Get(context);
201172
+ local_storage.DropColumn(&parent, this, removed_column);
201136
201173
 
201137
201174
  // this table replaces the previous table, hence the parent is no longer the root DataTable
201138
201175
  parent.is_root = false;
@@ -201152,8 +201189,8 @@ DataTable::DataTable(ClientContext &context, DataTable &parent, unique_ptr<Bound
201152
201189
  VerifyNewConstraint(context, parent, constraint.get());
201153
201190
 
201154
201191
  // Get the local data ownership from old dt
201155
- auto &transaction = Transaction::GetTransaction(context);
201156
- transaction.storage.MoveStorage(&parent, this);
201192
+ auto &local_storage = LocalStorage::Get(context);
201193
+ local_storage.MoveStorage(&parent, this);
201157
201194
  // this table replaces the previous table, hence the parent is no longer the root DataTable
201158
201195
  parent.is_root = false;
201159
201196
  }
@@ -201186,8 +201223,8 @@ DataTable::DataTable(ClientContext &context, DataTable &parent, idx_t changed_id
201186
201223
  parent.row_groups->AlterType(changed_idx, target_type, bound_columns, cast_expr, stats.GetStats(changed_idx));
201187
201224
 
201188
201225
  // scan the original table, and fill the new column with the transformed value
201189
- auto &transaction = Transaction::GetTransaction(context);
201190
- transaction.storage.ChangeType(&parent, this, changed_idx, target_type, bound_columns, cast_expr);
201226
+ auto &local_storage = LocalStorage::Get(context);
201227
+ local_storage.ChangeType(&parent, this, changed_idx, target_type, bound_columns, cast_expr);
201191
201228
 
201192
201229
  // this table replaces the previous table, hence the parent is no longer the root DataTable
201193
201230
  parent.is_root = false;
@@ -201217,7 +201254,8 @@ void DataTable::InitializeScan(TableScanState &state, const vector<column_t> &co
201217
201254
  void DataTable::InitializeScan(Transaction &transaction, TableScanState &state, const vector<column_t> &column_ids,
201218
201255
  TableFilterSet *table_filters) {
201219
201256
  InitializeScan(state, column_ids, table_filters);
201220
- transaction.storage.InitializeScan(this, state.local_state, table_filters);
201257
+ auto &local_storage = LocalStorage::Get(transaction);
201258
+ local_storage.InitializeScan(this, state.local_state, table_filters);
201221
201259
  }
201222
201260
 
201223
201261
  void DataTable::InitializeScanWithOffset(TableScanState &state, const vector<column_t> &column_ids, idx_t start_row,
@@ -201237,16 +201275,17 @@ idx_t DataTable::MaxThreads(ClientContext &context) {
201237
201275
 
201238
201276
  void DataTable::InitializeParallelScan(ClientContext &context, ParallelTableScanState &state) {
201239
201277
  row_groups->InitializeParallelScan(state.scan_state);
201240
- auto &transaction = Transaction::GetTransaction(context);
201241
- transaction.storage.InitializeParallelScan(this, state.local_state);
201278
+
201279
+ auto &local_storage = LocalStorage::Get(context);
201280
+ local_storage.InitializeParallelScan(this, state.local_state);
201242
201281
  }
201243
201282
 
201244
201283
  bool DataTable::NextParallelScan(ClientContext &context, ParallelTableScanState &state, TableScanState &scan_state) {
201245
201284
  if (row_groups->NextParallelScan(context, state.scan_state, scan_state.table_state)) {
201246
201285
  return true;
201247
201286
  }
201248
- auto &transaction = Transaction::GetTransaction(context);
201249
- if (transaction.storage.NextParallelScan(context, this, state.local_state, scan_state.local_state)) {
201287
+ auto &local_storage = LocalStorage::Get(context);
201288
+ if (local_storage.NextParallelScan(context, this, state.local_state, scan_state.local_state)) {
201250
201289
  return true;
201251
201290
  } else {
201252
201291
  // finished all scans: no more scans remaining
@@ -201262,7 +201301,8 @@ void DataTable::Scan(Transaction &transaction, DataChunk &result, TableScanState
201262
201301
  }
201263
201302
 
201264
201303
  // scan the transaction-local segments
201265
- transaction.storage.Scan(state.local_state, state.GetColumnIds(), result);
201304
+ auto &local_storage = LocalStorage::Get(transaction);
201305
+ local_storage.Scan(state.local_state, state.GetColumnIds(), result);
201266
201306
  }
201267
201307
 
201268
201308
  bool DataTable::CreateIndexScan(TableScanState &state, DataChunk &result, TableScanType type) {
@@ -201384,10 +201424,10 @@ static void VerifyForeignKeyConstraint(const BoundForeignKeyConstraint &bfk, Cli
201384
201424
 
201385
201425
  data_table->info->indexes.VerifyForeignKey(*dst_keys_ptr, is_append, dst_chunk, err_msgs);
201386
201426
  // check whether or not the chunk can be inserted or deleted into the referenced table' transaction local storage
201387
- auto &transaction = Transaction::GetTransaction(context);
201388
- bool transaction_check = transaction.storage.Find(data_table);
201427
+ auto &local_storage = LocalStorage::Get(context);
201428
+ bool transaction_check = local_storage.Find(data_table);
201389
201429
  if (transaction_check) {
201390
- auto &transact_index = transaction.storage.GetIndexes(data_table);
201430
+ auto &transact_index = local_storage.GetIndexes(data_table);
201391
201431
  transact_index.VerifyForeignKey(*dst_keys_ptr, is_append, dst_chunk, tran_err_msgs);
201392
201432
  }
201393
201433
 
@@ -201439,8 +201479,8 @@ void DataTable::VerifyNewConstraint(ClientContext &context, DataTable &parent, c
201439
201479
  }
201440
201480
 
201441
201481
  parent.row_groups->VerifyNewConstraint(parent, *constraint);
201442
- auto &transaction = Transaction::GetTransaction(context);
201443
- transaction.storage.VerifyNewConstraint(parent, *constraint);
201482
+ auto &local_storage = LocalStorage::Get(context);
201483
+ local_storage.VerifyNewConstraint(parent, *constraint);
201444
201484
  }
201445
201485
 
201446
201486
  void DataTable::VerifyAppendConstraints(TableCatalogEntry &table, ClientContext &context, DataChunk &chunk) {
@@ -201500,8 +201540,8 @@ void DataTable::InitializeLocalAppend(LocalAppendState &state, ClientContext &co
201500
201540
  if (!is_root) {
201501
201541
  throw TransactionException("Transaction conflict: adding entries to a table that has been altered!");
201502
201542
  }
201503
- auto &transaction = Transaction::GetTransaction(context);
201504
- transaction.storage.InitializeAppend(state, this);
201543
+ auto &local_storage = LocalStorage::Get(context);
201544
+ local_storage.InitializeAppend(state, this);
201505
201545
  }
201506
201546
 
201507
201547
  void DataTable::LocalAppend(LocalAppendState &state, TableCatalogEntry &table, ClientContext &context,
@@ -201761,6 +201801,7 @@ idx_t DataTable::Delete(TableCatalogEntry &table, ClientContext &context, Vector
201761
201801
  }
201762
201802
 
201763
201803
  auto &transaction = Transaction::GetTransaction(context);
201804
+ auto &local_storage = LocalStorage::Get(context);
201764
201805
 
201765
201806
  row_identifiers.Flatten(count);
201766
201807
  auto ids = FlatVector::GetData<row_t>(row_identifiers);
@@ -201771,7 +201812,7 @@ idx_t DataTable::Delete(TableCatalogEntry &table, ClientContext &context, Vector
201771
201812
  // and we only need to fetch columns that are part of this constraint
201772
201813
  DataChunk verify_chunk;
201773
201814
  if (first_id >= MAX_ROW_ID) {
201774
- transaction.storage.FetchChunk(this, row_identifiers, count, verify_chunk);
201815
+ local_storage.FetchChunk(this, row_identifiers, count, verify_chunk);
201775
201816
  } else {
201776
201817
  ColumnFetchState fetch_state;
201777
201818
  vector<column_t> col_ids;
@@ -201787,7 +201828,7 @@ idx_t DataTable::Delete(TableCatalogEntry &table, ClientContext &context, Vector
201787
201828
 
201788
201829
  if (first_id >= MAX_ROW_ID) {
201789
201830
  // deletion is in transaction-local storage: push delete into local chunk collection
201790
- return transaction.storage.Delete(this, row_identifiers, count);
201831
+ return local_storage.Delete(this, row_identifiers, count);
201791
201832
  } else {
201792
201833
  return row_groups->Delete(transaction, this, ids, count);
201793
201834
  }
@@ -201902,7 +201943,8 @@ void DataTable::Update(TableCatalogEntry &table, ClientContext &context, Vector
201902
201943
  auto first_id = FlatVector::GetValue<row_t>(row_ids, 0);
201903
201944
  if (first_id >= MAX_ROW_ID) {
201904
201945
  // update is in transaction-local storage: push update into local storage
201905
- transaction.storage.Update(this, row_ids, column_ids, updates);
201946
+ auto &local_storage = LocalStorage::Get(context);
201947
+ local_storage.Update(this, row_ids, column_ids, updates);
201906
201948
  return;
201907
201949
  }
201908
201950
 
@@ -202099,8 +202141,13 @@ BlockPointer Index::Serialize(duckdb::MetaBlockWriter &writer) {
202099
202141
 
202100
202142
 
202101
202143
 
202144
+
202145
+
202102
202146
  namespace duckdb {
202103
202147
 
202148
+ //===--------------------------------------------------------------------===//
202149
+ // Local Table Storage
202150
+ //===--------------------------------------------------------------------===//
202104
202151
  LocalTableStorage::LocalTableStorage(DataTable &table)
202105
202152
  : table(table), allocator(Allocator::Get(table.db)), deleted_rows(0) {
202106
202153
  auto types = table.GetTypes();
@@ -202127,7 +202174,11 @@ LocalTableStorage::LocalTableStorage(DataTable &table)
202127
202174
  LocalTableStorage::LocalTableStorage(DataTable &new_dt, LocalTableStorage &parent, idx_t changed_idx,
202128
202175
  const LogicalType &target_type, const vector<column_t> &bound_columns,
202129
202176
  Expression &cast_expr)
202130
- : table(new_dt), allocator(Allocator::Get(table.db)), deleted_rows(parent.deleted_rows) {
202177
+ : table(new_dt), allocator(Allocator::Get(table.db)), deleted_rows(parent.deleted_rows),
202178
+ partial_manager(move(parent.partial_manager)), written_blocks(move(parent.written_blocks)) {
202179
+ if (partial_manager) {
202180
+ partial_manager->FlushPartialBlocks();
202181
+ }
202131
202182
  stats.InitializeAlterType(parent.stats, changed_idx, target_type);
202132
202183
  row_groups =
202133
202184
  parent.row_groups->AlterType(changed_idx, target_type, bound_columns, cast_expr, stats.GetStats(changed_idx));
@@ -202136,7 +202187,11 @@ LocalTableStorage::LocalTableStorage(DataTable &new_dt, LocalTableStorage &paren
202136
202187
  }
202137
202188
 
202138
202189
  LocalTableStorage::LocalTableStorage(DataTable &new_dt, LocalTableStorage &parent, idx_t drop_idx)
202139
- : table(new_dt), allocator(Allocator::Get(table.db)), deleted_rows(parent.deleted_rows) {
202190
+ : table(new_dt), allocator(Allocator::Get(table.db)), deleted_rows(parent.deleted_rows),
202191
+ partial_manager(move(parent.partial_manager)), written_blocks(move(parent.written_blocks)) {
202192
+ if (partial_manager) {
202193
+ partial_manager->FlushPartialBlocks();
202194
+ }
202140
202195
  stats.InitializeRemoveColumn(parent.stats, drop_idx);
202141
202196
  row_groups = parent.row_groups->RemoveColumn(drop_idx);
202142
202197
  parent.row_groups.reset();
@@ -202145,7 +202200,8 @@ LocalTableStorage::LocalTableStorage(DataTable &new_dt, LocalTableStorage &paren
202145
202200
 
202146
202201
  LocalTableStorage::LocalTableStorage(DataTable &new_dt, LocalTableStorage &parent, ColumnDefinition &new_column,
202147
202202
  Expression *default_value)
202148
- : table(new_dt), allocator(Allocator::Get(table.db)), deleted_rows(parent.deleted_rows) {
202203
+ : table(new_dt), allocator(Allocator::Get(table.db)), deleted_rows(parent.deleted_rows),
202204
+ partial_manager(move(parent.partial_manager)), written_blocks(move(parent.written_blocks)) {
202149
202205
  idx_t new_column_idx = parent.table.column_definitions.size();
202150
202206
  stats.InitializeAddColumn(parent.stats, new_column.GetType());
202151
202207
  row_groups = parent.row_groups->AddColumn(new_column, default_value, stats.GetStats(new_column_idx));
@@ -202177,6 +202233,20 @@ idx_t LocalTableStorage::EstimatedSize() {
202177
202233
  return appended_rows * row_size;
202178
202234
  }
202179
202235
 
202236
+ //===--------------------------------------------------------------------===//
202237
+ // LocalStorage
202238
+ //===--------------------------------------------------------------------===//
202239
+ LocalStorage::LocalStorage(Transaction &transaction) : transaction(transaction) {
202240
+ }
202241
+
202242
+ LocalStorage &LocalStorage::Get(Transaction &transaction) {
202243
+ return transaction.GetLocalStorage();
202244
+ }
202245
+
202246
+ LocalStorage &LocalStorage::Get(ClientContext &context) {
202247
+ return Transaction::GetTransaction(context).GetLocalStorage();
202248
+ }
202249
+
202180
202250
  void LocalStorage::InitializeScan(DataTable *table, CollectionScanState &state, TableFilterSet *table_filters) {
202181
202251
  auto entry = table_storage.find(table);
202182
202252
  if (entry == table_storage.end()) {
@@ -202230,8 +202300,68 @@ void LocalStorage::Append(LocalAppendState &state, DataChunk &chunk) {
202230
202300
  throw ConstraintException("PRIMARY KEY or UNIQUE constraint violated: duplicated key");
202231
202301
  }
202232
202302
 
202233
- //! Append to the chunk
202234
- storage->row_groups->Append(chunk, state.append_state, storage->stats);
202303
+ //! Append the chunk to the local storage
202304
+ auto new_row_group = storage->row_groups->Append(chunk, state.append_state, storage->stats);
202305
+
202306
+ //! Check if we should pre-emptively flush blocks to disk
202307
+ if (new_row_group) {
202308
+ storage->CheckFlushToDisk();
202309
+ }
202310
+ }
202311
+
202312
+ void LocalTableStorage::CheckFlushToDisk() {
202313
+ // we finished writing a complete row group
202314
+ // check if we should pre-emptively write it to disk
202315
+ if (table.info->IsTemporary() || StorageManager::GetStorageManager(table.db).InMemory()) {
202316
+ return;
202317
+ }
202318
+ if (!table.info->indexes.Empty()) {
202319
+ // we have indexes - we cannot merge
202320
+ return;
202321
+ }
202322
+ if (deleted_rows != 0) {
202323
+ // we have deletes - we cannot merge
202324
+ return;
202325
+ }
202326
+ // we should! write the second-to-last row group to disk
202327
+ // allocate the partial block-manager if none is allocated yet
202328
+ if (!partial_manager) {
202329
+ auto &block_manager = table.info->table_io_manager->GetBlockManagerForRowData();
202330
+ partial_manager = make_unique<PartialBlockManager>(block_manager);
202331
+ }
202332
+ // flush second-to-last row group
202333
+ auto row_group = row_groups->GetRowGroup(-2);
202334
+ FlushToDisk(row_group);
202335
+ }
202336
+
202337
+ void LocalTableStorage::FlushToDisk(RowGroup *row_group) {
202338
+ // flush the specified row group
202339
+ D_ASSERT(row_group);
202340
+ D_ASSERT(deleted_rows == 0);
202341
+ D_ASSERT(table.info->indexes.Empty());
202342
+ D_ASSERT(partial_manager);
202343
+ //! The set of column compression types (if any)
202344
+ vector<CompressionType> compression_types;
202345
+ D_ASSERT(compression_types.empty());
202346
+ for (auto &column : table.column_definitions) {
202347
+ compression_types.push_back(column.CompressionType());
202348
+ }
202349
+ auto row_group_pointer = row_group->WriteToDisk(*partial_manager, compression_types);
202350
+ for (idx_t col_idx = 0; col_idx < row_group_pointer.statistics.size(); col_idx++) {
202351
+ row_group_pointer.states[col_idx]->GetBlockIds(written_blocks);
202352
+ stats.MergeStats(col_idx, *row_group_pointer.statistics[col_idx]);
202353
+ }
202354
+ }
202355
+ void LocalTableStorage::FlushToDisk() {
202356
+ // no partial manager - nothing to flush
202357
+ if (!partial_manager) {
202358
+ return;
202359
+ }
202360
+ // flush the last row group
202361
+ FlushToDisk(row_groups->GetRowGroup(-1));
202362
+ // then flush the partial manager
202363
+ partial_manager->FlushPartialBlocks();
202364
+ partial_manager.reset();
202235
202365
  }
202236
202366
 
202237
202367
  void LocalStorage::FinalizeAppend(LocalAppendState &state) {
@@ -202252,6 +202382,10 @@ idx_t LocalStorage::EstimatedSize() {
202252
202382
  return estimated_size;
202253
202383
  }
202254
202384
 
202385
+ bool LocalTableStorage::HasWrittenBlocks() {
202386
+ return partial_manager || !written_blocks.empty();
202387
+ }
202388
+
202255
202389
  idx_t LocalStorage::Delete(DataTable *table, Vector &row_ids, idx_t count) {
202256
202390
  auto storage = GetStorage(table);
202257
202391
  D_ASSERT(storage);
@@ -202319,10 +202453,16 @@ void LocalStorage::Flush(DataTable &table, LocalTableStorage &storage) {
202319
202453
  table.AppendLock(append_state);
202320
202454
  if ((append_state.row_start == 0 || storage.row_groups->GetTotalRows() >= MERGE_THRESHOLD) &&
202321
202455
  storage.table.info->indexes.Empty() && storage.deleted_rows == 0) {
202322
- // table is currently empty OR we are bulk appending to a table with existing storage: move over the storage
202323
- // directly
202456
+ // table is currently empty OR we are bulk appending: move over the storage directly
202457
+ // first flush any out-standing storage nodes
202458
+ storage.FlushToDisk();
202324
202459
  table.MergeStorage(*storage.row_groups, storage.indexes, storage.stats);
202325
202460
  } else {
202461
+ if (storage.partial_manager || !storage.written_blocks.empty()) {
202462
+ // we have written data but cannot merge to disk after all
202463
+ // revert the data we have already written
202464
+ storage.Rollback();
202465
+ }
202326
202466
  bool constraint_violated = false;
202327
202467
  table.InitializeAppend(transaction, append_state, append_count);
202328
202468
  ScanTableStorage(table, storage, [&](DataChunk &chunk) -> bool {
@@ -202368,6 +202508,27 @@ void LocalStorage::Commit(LocalStorage::CommitState &commit_state, Transaction &
202368
202508
  table_storage.clear();
202369
202509
  }
202370
202510
 
202511
+ void LocalStorage::Rollback() {
202512
+ for (auto &entry : table_storage) {
202513
+ auto storage = entry.second.get();
202514
+ if (!storage) {
202515
+ continue;
202516
+ }
202517
+ storage->Rollback();
202518
+ }
202519
+ }
202520
+
202521
+ void LocalTableStorage::Rollback() {
202522
+ if (partial_manager) {
202523
+ partial_manager->Clear();
202524
+ partial_manager.reset();
202525
+ }
202526
+ auto &block_manager = table.info->table_io_manager->GetBlockManagerForRowData();
202527
+ for (auto block_id : written_blocks) {
202528
+ block_manager.MarkBlockAsModified(block_id);
202529
+ }
202530
+ }
202531
+
202371
202532
  idx_t LocalStorage::AddedRows(DataTable *table) {
202372
202533
  auto entry = table_storage.find(table);
202373
202534
  if (entry == table_storage.end()) {
@@ -202593,6 +202754,12 @@ void MetaBlockWriter::WriteData(const_data_ptr_t buffer, idx_t write_size) {
202593
202754
 
202594
202755
  namespace duckdb {
202595
202756
 
202757
+ PartialBlockManager::PartialBlockManager(BlockManager &block_manager, uint32_t max_partial_block_size,
202758
+ uint32_t max_use_count)
202759
+ : block_manager(block_manager), max_partial_block_size(max_partial_block_size), max_use_count(max_use_count) {
202760
+ }
202761
+ PartialBlockManager::~PartialBlockManager() {
202762
+ }
202596
202763
  //===--------------------------------------------------------------------===//
202597
202764
  // Partial Blocks
202598
202765
  //===--------------------------------------------------------------------===//
@@ -202667,6 +202834,14 @@ void PartialBlockManager::FlushPartialBlocks() {
202667
202834
  for (auto &e : partially_filled_blocks) {
202668
202835
  e.second->Flush();
202669
202836
  }
202837
+ partially_filled_blocks.clear();
202838
+ }
202839
+
202840
+ void PartialBlockManager::Clear() {
202841
+ for (auto &e : partially_filled_blocks) {
202842
+ e.second->Clear();
202843
+ }
202844
+ partially_filled_blocks.clear();
202670
202845
  }
202671
202846
 
202672
202847
  } // namespace duckdb
@@ -202719,13 +202894,9 @@ public:
202719
202894
  void WriteHeader(DatabaseHeader header) override;
202720
202895
 
202721
202896
  //! Returns the number of total blocks
202722
- idx_t TotalBlocks() override {
202723
- return max_block;
202724
- }
202897
+ idx_t TotalBlocks() override;
202725
202898
  //! Returns the number of free blocks
202726
- idx_t FreeBlocks() override {
202727
- return free_list.size();
202728
- }
202899
+ idx_t FreeBlocks() override;
202729
202900
 
202730
202901
  private:
202731
202902
  //! Load the free list from the file
@@ -202766,6 +202937,8 @@ private:
202766
202937
  bool read_only;
202767
202938
  //! Whether or not to use Direct IO to read the blocks
202768
202939
  bool use_direct_io;
202940
+ //! Lock for performing various operations in the single file block manager
202941
+ mutex block_lock;
202769
202942
  };
202770
202943
  } // namespace duckdb
202771
202944
 
@@ -202990,6 +203163,7 @@ bool SingleFileBlockManager::IsRootBlock(block_id_t root) {
202990
203163
  }
202991
203164
 
202992
203165
  block_id_t SingleFileBlockManager::GetFreeBlockId() {
203166
+ lock_guard<mutex> lock(block_lock);
202993
203167
  block_id_t block;
202994
203168
  if (!free_list.empty()) {
202995
203169
  // free list is non empty
@@ -203004,6 +203178,7 @@ block_id_t SingleFileBlockManager::GetFreeBlockId() {
203004
203178
  }
203005
203179
 
203006
203180
  void SingleFileBlockManager::MarkBlockAsModified(block_id_t block_id) {
203181
+ lock_guard<mutex> lock(block_lock);
203007
203182
  D_ASSERT(block_id >= 0);
203008
203183
 
203009
203184
  // check if the block is a multi-use block
@@ -203026,6 +203201,7 @@ void SingleFileBlockManager::MarkBlockAsModified(block_id_t block_id) {
203026
203201
  }
203027
203202
 
203028
203203
  void SingleFileBlockManager::IncreaseBlockReferenceCount(block_id_t block_id) {
203204
+ lock_guard<mutex> lock(block_lock);
203029
203205
  D_ASSERT(free_list.find(block_id) == free_list.end());
203030
203206
  auto entry = multi_use_blocks.find(block_id);
203031
203207
  if (entry != multi_use_blocks.end()) {
@@ -203039,6 +203215,16 @@ block_id_t SingleFileBlockManager::GetMetaBlock() {
203039
203215
  return meta_block;
203040
203216
  }
203041
203217
 
203218
+ idx_t SingleFileBlockManager::TotalBlocks() {
203219
+ lock_guard<mutex> lock(block_lock);
203220
+ return max_block;
203221
+ }
203222
+
203223
+ idx_t SingleFileBlockManager::FreeBlocks() {
203224
+ lock_guard<mutex> lock(block_lock);
203225
+ return free_list.size();
203226
+ }
203227
+
203042
203228
  unique_ptr<Block> SingleFileBlockManager::CreateBlock(block_id_t block_id, FileBuffer *source_buffer) {
203043
203229
  if (source_buffer) {
203044
203230
  D_ASSERT(source_buffer->AllocSize() == Storage::BLOCK_ALLOC_SIZE);
@@ -204894,8 +205080,9 @@ public:
204894
205080
 
204895
205081
  void CommitDropColumn() override;
204896
205082
 
204897
- unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, RowGroupWriter &writer) override;
204898
- unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, RowGroupWriter &writer,
205083
+ unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group,
205084
+ PartialBlockManager &partial_block_manager) override;
205085
+ unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, PartialBlockManager &partial_block_manager,
204899
205086
  ColumnCheckpointInfo &checkpoint_info) override;
204900
205087
 
204901
205088
  void DeserializeColumn(Deserializer &source) override;
@@ -204916,8 +205103,9 @@ private:
204916
205103
 
204917
205104
  namespace duckdb {
204918
205105
 
204919
- ColumnCheckpointState::ColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, RowGroupWriter &writer)
204920
- : row_group(row_group), column_data(column_data), writer(writer) {
205106
+ ColumnCheckpointState::ColumnCheckpointState(RowGroup &row_group, ColumnData &column_data,
205107
+ PartialBlockManager &partial_block_manager)
205108
+ : row_group(row_group), column_data(column_data), partial_block_manager(partial_block_manager) {
204921
205109
  }
204922
205110
 
204923
205111
  ColumnCheckpointState::~ColumnCheckpointState() {
@@ -204930,13 +205118,15 @@ unique_ptr<BaseStatistics> ColumnCheckpointState::GetStatistics() {
204930
205118
 
204931
205119
  struct PartialBlockForCheckpoint : PartialBlock {
204932
205120
  struct PartialColumnSegment {
205121
+ ColumnData *data;
204933
205122
  ColumnSegment *segment;
204934
205123
  uint32_t offset_in_block;
204935
205124
  };
204936
205125
 
204937
205126
  public:
204938
- PartialBlockForCheckpoint(ColumnSegment *first_segment, BlockManager &block_manager, PartialBlockState state)
204939
- : PartialBlock(state), first_segment(first_segment), block_manager(block_manager) {
205127
+ PartialBlockForCheckpoint(ColumnData *first_data, ColumnSegment *first_segment, BlockManager &block_manager,
205128
+ PartialBlockState state)
205129
+ : PartialBlock(state), first_data(first_data), first_segment(first_segment), block_manager(block_manager) {
204940
205130
  }
204941
205131
 
204942
205132
  ~PartialBlockForCheckpoint() override {
@@ -204949,6 +205139,7 @@ public:
204949
205139
  // the block to get written to storage (via BlockManger::ConvertToPersistent),
204950
205140
  // and all segments to have their references updated
204951
205141
  // (via ColumnSegment::ConvertToPersistent)
205142
+ ColumnData *first_data;
204952
205143
  ColumnSegment *first_segment;
204953
205144
  BlockManager &block_manager;
204954
205145
  vector<PartialColumnSegment> tail_segments;
@@ -204963,18 +205154,26 @@ public:
204963
205154
  // At this point, we've already copied all data from tail_segments
204964
205155
  // into the page owned by first_segment. We flush all segment data to
204965
205156
  // disk with the following call.
205157
+ first_data->IncrementVersion();
204966
205158
  first_segment->ConvertToPersistent(&block_manager, state.block_id);
204967
205159
  // Now that the page is persistent, update tail_segments to point to the
204968
205160
  // newly persistent block.
204969
205161
  for (auto e : tail_segments) {
205162
+ e.data->IncrementVersion();
204970
205163
  e.segment->MarkAsPersistent(first_segment->block, e.offset_in_block);
204971
205164
  }
204972
205165
  first_segment = nullptr;
204973
205166
  tail_segments.clear();
204974
205167
  }
204975
205168
 
204976
- void AddSegmentToTail(ColumnSegment *segment, uint32_t offset_in_block) {
204977
- tail_segments.push_back({segment, offset_in_block});
205169
+ void Clear() override {
205170
+ first_data = nullptr;
205171
+ first_segment = nullptr;
205172
+ tail_segments.clear();
205173
+ }
205174
+
205175
+ void AddSegmentToTail(ColumnData *data, ColumnSegment *segment, uint32_t offset_in_block) {
205176
+ tail_segments.push_back({data, segment, offset_in_block});
204978
205177
  }
204979
205178
  };
204980
205179
 
@@ -204996,7 +205195,7 @@ void ColumnCheckpointState::FlushSegment(unique_ptr<ColumnSegment> segment, idx_
204996
205195
 
204997
205196
  if (!segment->stats.statistics->IsConstant()) {
204998
205197
  // non-constant block
204999
- PartialBlockAllocation allocation = writer.GetBlockAllocation(segment_size);
205198
+ PartialBlockAllocation allocation = partial_block_manager.GetBlockAllocation(segment_size);
205000
205199
  block_id = allocation.state.block_id;
205001
205200
  offset_in_block = allocation.state.offset_in_block;
205002
205201
 
@@ -205010,15 +205209,15 @@ void ColumnCheckpointState::FlushSegment(unique_ptr<ColumnSegment> segment, idx_
205010
205209
  auto new_handle = buffer_manager.Pin(pstate->first_segment->block);
205011
205210
  // memcpy the contents of the old block to the new block
205012
205211
  memcpy(new_handle.Ptr() + offset_in_block, old_handle.Ptr(), segment_size);
205013
- pstate->AddSegmentToTail(segment.get(), offset_in_block);
205212
+ pstate->AddSegmentToTail(&column_data, segment.get(), offset_in_block);
205014
205213
  } else {
205015
205214
  // Create a new block for future reuse.
205016
205215
  D_ASSERT(offset_in_block == 0);
205017
- allocation.partial_block =
205018
- make_unique<PartialBlockForCheckpoint>(segment.get(), *allocation.block_manager, allocation.state);
205216
+ allocation.partial_block = make_unique<PartialBlockForCheckpoint>(
205217
+ &column_data, segment.get(), *allocation.block_manager, allocation.state);
205019
205218
  }
205020
205219
  // Writer will decide whether to reuse this block.
205021
- writer.RegisterPartialBlock(move(allocation));
205220
+ partial_block_manager.RegisterPartialBlock(move(allocation));
205022
205221
  } else {
205023
205222
  // constant block: no need to write anything to disk besides the stats
205024
205223
  // set up the compression function to constant
@@ -205046,10 +205245,19 @@ void ColumnCheckpointState::FlushSegment(unique_ptr<ColumnSegment> segment, idx_
205046
205245
  data_pointers.push_back(move(data_pointer));
205047
205246
  }
205048
205247
 
205049
- void ColumnCheckpointState::WriteDataPointers() {
205248
+ void ColumnCheckpointState::WriteDataPointers(RowGroupWriter &writer) {
205050
205249
  writer.WriteColumnDataPointers(*this);
205051
205250
  }
205052
205251
 
205252
+ void ColumnCheckpointState::GetBlockIds(unordered_set<block_id_t> &result) {
205253
+ for (auto &pointer : data_pointers) {
205254
+ if (pointer.block_pointer.block_id == INVALID_BLOCK) {
205255
+ continue;
205256
+ }
205257
+ result.insert(pointer.block_pointer.block_id);
205258
+ }
205259
+ }
205260
+
205053
205261
  } // namespace duckdb
205054
205262
 
205055
205263
 
@@ -205119,8 +205327,9 @@ public:
205119
205327
 
205120
205328
  void CommitDropColumn() override;
205121
205329
 
205122
- unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, RowGroupWriter &writer) override;
205123
- unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, RowGroupWriter &writer,
205330
+ unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group,
205331
+ PartialBlockManager &partial_block_manager) override;
205332
+ unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, PartialBlockManager &partial_block_manager,
205124
205333
  ColumnCheckpointInfo &checkpoint_info) override;
205125
205334
 
205126
205335
  void DeserializeColumn(Deserializer &source) override;
@@ -205247,12 +205456,12 @@ namespace duckdb {
205247
205456
  ColumnData::ColumnData(BlockManager &block_manager, DataTableInfo &info, idx_t column_index, idx_t start_row,
205248
205457
  LogicalType type, ColumnData *parent)
205249
205458
  : block_manager(block_manager), info(info), column_index(column_index), start(start_row), type(move(type)),
205250
- parent(parent) {
205459
+ parent(parent), version(0) {
205251
205460
  }
205252
205461
 
205253
205462
  ColumnData::ColumnData(ColumnData &other, idx_t start, ColumnData *parent)
205254
205463
  : block_manager(other.block_manager), info(other.info), column_index(other.column_index), start(start),
205255
- type(move(other.type)), parent(parent), updates(move(other.updates)) {
205464
+ type(move(other.type)), parent(parent), updates(move(other.updates)), version(parent ? parent->version + 1 : 0) {
205256
205465
  idx_t offset = 0;
205257
205466
  for (auto segment = other.data.GetRootSegment(); segment; segment = segment->next.get()) {
205258
205467
  auto &other = (ColumnSegment &)*segment;
@@ -205279,6 +205488,10 @@ const LogicalType &ColumnData::RootType() const {
205279
205488
  return type;
205280
205489
  }
205281
205490
 
205491
+ void ColumnData::IncrementVersion() {
205492
+ version++;
205493
+ }
205494
+
205282
205495
  idx_t ColumnData::GetMaxEntry() {
205283
205496
  auto first_segment = data.GetRootSegment();
205284
205497
  auto last_segment = data.GetLastSegment();
@@ -205296,6 +205509,8 @@ void ColumnData::InitializeScan(ColumnScanState &state) {
205296
205509
  state.row_index = state.current ? state.current->start : 0;
205297
205510
  state.internal_index = state.row_index;
205298
205511
  state.initialized = false;
205512
+ state.version = version;
205513
+ state.scan_state.reset();
205299
205514
  }
205300
205515
 
205301
205516
  void ColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) {
@@ -205303,15 +205518,23 @@ void ColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx)
205303
205518
  state.row_index = row_idx;
205304
205519
  state.internal_index = state.current->start;
205305
205520
  state.initialized = false;
205521
+ state.version = version;
205522
+ state.scan_state.reset();
205306
205523
  }
205307
205524
 
205308
205525
  idx_t ColumnData::ScanVector(ColumnScanState &state, Vector &result, idx_t remaining) {
205309
- if (!state.initialized) {
205526
+ if (state.version != version) {
205527
+ InitializeScanWithOffset(state, state.row_index);
205528
+ state.current->InitializeScan(state);
205529
+ state.initialized = true;
205530
+ } else if (!state.initialized) {
205310
205531
  D_ASSERT(state.current);
205311
205532
  state.current->InitializeScan(state);
205312
205533
  state.internal_index = state.current->start;
205313
205534
  state.initialized = true;
205314
205535
  }
205536
+ D_ASSERT(data.HasSegment(state.current));
205537
+ D_ASSERT(state.version == version);
205315
205538
  D_ASSERT(state.internal_index <= state.row_index);
205316
205539
  if (state.internal_index < state.row_index) {
205317
205540
  state.current->Skip(state);
@@ -205563,8 +205786,9 @@ void ColumnData::CommitDropColumn() {
205563
205786
  }
205564
205787
  }
205565
205788
 
205566
- unique_ptr<ColumnCheckpointState> ColumnData::CreateCheckpointState(RowGroup &row_group, RowGroupWriter &writer) {
205567
- return make_unique<ColumnCheckpointState>(row_group, *this, writer);
205789
+ unique_ptr<ColumnCheckpointState> ColumnData::CreateCheckpointState(RowGroup &row_group,
205790
+ PartialBlockManager &partial_block_manager) {
205791
+ return make_unique<ColumnCheckpointState>(row_group, *this, partial_block_manager);
205568
205792
  }
205569
205793
 
205570
205794
  void ColumnData::CheckpointScan(ColumnSegment *segment, ColumnScanState &state, idx_t row_group_start, idx_t count,
@@ -205576,11 +205800,12 @@ void ColumnData::CheckpointScan(ColumnSegment *segment, ColumnScanState &state,
205576
205800
  }
205577
205801
  }
205578
205802
 
205579
- unique_ptr<ColumnCheckpointState> ColumnData::Checkpoint(RowGroup &row_group, RowGroupWriter &writer,
205803
+ unique_ptr<ColumnCheckpointState> ColumnData::Checkpoint(RowGroup &row_group,
205804
+ PartialBlockManager &partial_block_manager,
205580
205805
  ColumnCheckpointInfo &checkpoint_info) {
205581
205806
  // scan the segments of the column data
205582
205807
  // set up the checkpoint state
205583
- auto checkpoint_state = CreateCheckpointState(row_group, writer);
205808
+ auto checkpoint_state = CreateCheckpointState(row_group, partial_block_manager);
205584
205809
  checkpoint_state->global_stats = BaseStatistics::CreateEmpty(type, StatisticsType::LOCAL_STATS);
205585
205810
 
205586
205811
  if (!data.root_node) {
@@ -205594,6 +205819,7 @@ unique_ptr<ColumnCheckpointState> ColumnData::Checkpoint(RowGroup &row_group, Ro
205594
205819
 
205595
205820
  // replace the old tree with the new one
205596
205821
  data.Replace(checkpoint_state->new_tree);
205822
+ version++;
205597
205823
 
205598
205824
  return checkpoint_state;
205599
205825
  }
@@ -206166,6 +206392,7 @@ void ColumnSegment::ConvertToPersistent(BlockManager *block_manager, block_id_t
206166
206392
  block_id = block_id_p;
206167
206393
  offset = 0;
206168
206394
 
206395
+ D_ASSERT(stats.statistics);
206169
206396
  if (block_id == INVALID_BLOCK) {
206170
206397
  // constant block: reset the block buffer
206171
206398
  D_ASSERT(stats.statistics->IsConstant());
@@ -206797,8 +207024,8 @@ void ListColumnData::CommitDropColumn() {
206797
207024
  }
206798
207025
 
206799
207026
  struct ListColumnCheckpointState : public ColumnCheckpointState {
206800
- ListColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, RowGroupWriter &writer)
206801
- : ColumnCheckpointState(row_group, column_data, writer) {
207027
+ ListColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, PartialBlockManager &partial_block_manager)
207028
+ : ColumnCheckpointState(row_group, column_data, partial_block_manager) {
206802
207029
  global_stats = make_unique<ListStatistics>(column_data.type);
206803
207030
  }
206804
207031
 
@@ -206814,22 +207041,29 @@ public:
206814
207041
  return stats;
206815
207042
  }
206816
207043
 
206817
- void WriteDataPointers() override {
206818
- ColumnCheckpointState::WriteDataPointers();
206819
- validity_state->WriteDataPointers();
206820
- child_state->WriteDataPointers();
207044
+ void WriteDataPointers(RowGroupWriter &writer) override {
207045
+ ColumnCheckpointState::WriteDataPointers(writer);
207046
+ validity_state->WriteDataPointers(writer);
207047
+ child_state->WriteDataPointers(writer);
207048
+ }
207049
+ void GetBlockIds(unordered_set<block_id_t> &result) override {
207050
+ ColumnCheckpointState::GetBlockIds(result);
207051
+ validity_state->GetBlockIds(result);
207052
+ child_state->GetBlockIds(result);
206821
207053
  }
206822
207054
  };
206823
207055
 
206824
- unique_ptr<ColumnCheckpointState> ListColumnData::CreateCheckpointState(RowGroup &row_group, RowGroupWriter &writer) {
206825
- return make_unique<ListColumnCheckpointState>(row_group, *this, writer);
207056
+ unique_ptr<ColumnCheckpointState> ListColumnData::CreateCheckpointState(RowGroup &row_group,
207057
+ PartialBlockManager &partial_block_manager) {
207058
+ return make_unique<ListColumnCheckpointState>(row_group, *this, partial_block_manager);
206826
207059
  }
206827
207060
 
206828
- unique_ptr<ColumnCheckpointState> ListColumnData::Checkpoint(RowGroup &row_group, RowGroupWriter &writer,
207061
+ unique_ptr<ColumnCheckpointState> ListColumnData::Checkpoint(RowGroup &row_group,
207062
+ PartialBlockManager &partial_block_manager,
206829
207063
  ColumnCheckpointInfo &checkpoint_info) {
206830
- auto validity_state = validity.Checkpoint(row_group, writer, checkpoint_info);
206831
- auto base_state = ColumnData::Checkpoint(row_group, writer, checkpoint_info);
206832
- auto child_state = child_column->Checkpoint(row_group, writer, checkpoint_info);
207064
+ auto validity_state = validity.Checkpoint(row_group, partial_block_manager, checkpoint_info);
207065
+ auto base_state = ColumnData::Checkpoint(row_group, partial_block_manager, checkpoint_info);
207066
+ auto child_state = child_column->Checkpoint(row_group, partial_block_manager, checkpoint_info);
206833
207067
 
206834
207068
  auto &checkpoint_state = (ListColumnCheckpointState &)*base_state;
206835
207069
  checkpoint_state.validity_state = move(validity_state);
@@ -207545,10 +207779,11 @@ void RowGroup::MergeIntoStatistics(idx_t column_idx, BaseStatistics &other) {
207545
207779
  other.Merge(*stats[column_idx]->statistics);
207546
207780
  }
207547
207781
 
207548
- RowGroupPointer RowGroup::Checkpoint(RowGroupWriter &writer, vector<unique_ptr<BaseStatistics>> &global_stats) {
207549
- RowGroupPointer row_group_pointer;
207550
- vector<unique_ptr<ColumnCheckpointState>> states;
207551
- states.reserve(columns.size());
207782
+ RowGroupWriteData RowGroup::WriteToDisk(PartialBlockManager &manager,
207783
+ const vector<CompressionType> &compression_types) {
207784
+ RowGroupWriteData result;
207785
+ result.states.reserve(columns.size());
207786
+ result.statistics.reserve(columns.size());
207552
207787
 
207553
207788
  // Checkpoint the individual columns of the row group
207554
207789
  // Here we're iterating over columns. Each column can have multiple segments.
@@ -207560,23 +207795,39 @@ RowGroupPointer RowGroup::Checkpoint(RowGroupWriter &writer, vector<unique_ptr<B
207560
207795
  // pointers all end up densely packed, and thus more cache-friendly.
207561
207796
  for (idx_t column_idx = 0; column_idx < columns.size(); column_idx++) {
207562
207797
  auto &column = columns[column_idx];
207563
- ColumnCheckpointInfo checkpoint_info {writer.GetColumnCompressionType(column_idx)};
207564
- auto checkpoint_state = column->Checkpoint(*this, writer, checkpoint_info);
207798
+ ColumnCheckpointInfo checkpoint_info {compression_types[column_idx]};
207799
+ auto checkpoint_state = column->Checkpoint(*this, manager, checkpoint_info);
207565
207800
  D_ASSERT(checkpoint_state);
207566
207801
 
207567
207802
  auto stats = checkpoint_state->GetStatistics();
207568
207803
  D_ASSERT(stats);
207569
207804
 
207570
- global_stats[column_idx]->Merge(*stats);
207571
- row_group_pointer.statistics.push_back(move(stats));
207572
- states.push_back(move(checkpoint_state));
207805
+ result.statistics.push_back(move(stats));
207806
+ result.states.push_back(move(checkpoint_state));
207573
207807
  }
207808
+ D_ASSERT(result.states.size() == result.statistics.size());
207809
+ return result;
207810
+ }
207811
+
207812
+ RowGroupPointer RowGroup::Checkpoint(RowGroupWriter &writer, vector<unique_ptr<BaseStatistics>> &global_stats) {
207813
+ RowGroupPointer row_group_pointer;
207814
+
207815
+ vector<CompressionType> compression_types;
207816
+ compression_types.reserve(columns.size());
207817
+ for (idx_t column_idx = 0; column_idx < columns.size(); column_idx++) {
207818
+ compression_types.push_back(writer.GetColumnCompressionType(column_idx));
207819
+ }
207820
+ auto result = WriteToDisk(writer.GetPartialBlockManager(), compression_types);
207821
+ for (idx_t column_idx = 0; column_idx < columns.size(); column_idx++) {
207822
+ global_stats[column_idx]->Merge(*result.statistics[column_idx]);
207823
+ }
207824
+ row_group_pointer.statistics = move(result.statistics);
207574
207825
 
207575
207826
  // construct the row group pointer and write the column meta data to disk
207576
- D_ASSERT(states.size() == columns.size());
207827
+ D_ASSERT(result.states.size() == columns.size());
207577
207828
  row_group_pointer.row_start = start;
207578
207829
  row_group_pointer.tuple_count = count;
207579
- for (auto &state : states) {
207830
+ for (auto &state : result.states) {
207580
207831
  // get the current position of the table data writer
207581
207832
  auto &data_writer = writer.GetPayloadWriter();
207582
207833
  auto pointer = data_writer.GetBlockPointer();
@@ -207588,7 +207839,7 @@ RowGroupPointer RowGroup::Checkpoint(RowGroupWriter &writer, vector<unique_ptr<B
207588
207839
  //
207589
207840
  // Just as above, the state can refer to many other states, so this
207590
207841
  // can cascade recursively into more pointer writes.
207591
- state->WriteDataPointers();
207842
+ state->WriteDataPointers(writer);
207592
207843
  }
207593
207844
  row_group_pointer.versions = version_info;
207594
207845
  Verify();
@@ -207849,6 +208100,10 @@ void RowGroupCollection::AppendRowGroup(idx_t start_row) {
207849
208100
  row_groups->AppendSegment(move(new_row_group));
207850
208101
  }
207851
208102
 
208103
+ RowGroup *RowGroupCollection::GetRowGroup(int64_t index) {
208104
+ return (RowGroup *)row_groups->GetSegmentByIndex(index);
208105
+ }
208106
+
207852
208107
  void RowGroupCollection::Verify() {
207853
208108
  #ifdef DEBUG
207854
208109
  idx_t current_total_rows = 0;
@@ -207999,10 +208254,11 @@ void RowGroupCollection::InitializeAppend(TableAppendState &state) {
207999
208254
  InitializeAppend(tdata, state, 0);
208000
208255
  }
208001
208256
 
208002
- void RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state, TableStatistics &stats) {
208257
+ bool RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state, TableStatistics &stats) {
208003
208258
  D_ASSERT(chunk.ColumnCount() == types.size());
208004
208259
  chunk.Verify();
208005
208260
 
208261
+ bool new_row_group = false;
208006
208262
  idx_t append_count = chunk.size();
208007
208263
  idx_t remaining = chunk.size();
208008
208264
  state.total_append_count += append_count;
@@ -208036,6 +208292,7 @@ void RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state, Table
208036
208292
  chunk.Slice(sel, remaining);
208037
208293
  }
208038
208294
  // append a new row_group
208295
+ new_row_group = true;
208039
208296
  auto next_start = current_row_group->start + state.row_group_append_state.offset_in_row_group;
208040
208297
  AppendRowGroup(next_start);
208041
208298
  // set up the append state for this row_group
@@ -208059,6 +208316,7 @@ void RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state, Table
208059
208316
  }
208060
208317
  stats.GetStats(col_idx).stats->UpdateDistinctStatistics(chunk.data[col_idx], chunk.size());
208061
208318
  }
208319
+ return new_row_group;
208062
208320
  }
208063
208321
 
208064
208322
  void RowGroupCollection::FinalizeAppend(TransactionData transaction, TableAppendState &state) {
@@ -208099,12 +208357,7 @@ void RowGroupCollection::CommitAppend(transaction_t commit_id, idx_t row_start,
208099
208357
 
208100
208358
  void RowGroupCollection::RevertAppendInternal(idx_t start_row, idx_t count) {
208101
208359
  if (total_rows != start_row + count) {
208102
- // interleaved append: don't do anything
208103
- // in this case the rows will stay as "inserted by transaction X", but will never be committed
208104
- // they will never be used by any other transaction and will essentially leave a gap
208105
- // this situation is rare, and as such we don't care about optimizing it (yet?)
208106
- // it only happens if C1 appends a lot of data -> C2 appends a lot of data -> C1 rolls back
208107
- return;
208360
+ throw InternalException("Interleaved appends: this should no longer happen");
208108
208361
  }
208109
208362
  total_rows = start_row;
208110
208363
 
@@ -208559,6 +208812,21 @@ SegmentBase *SegmentTree::GetRootSegment() {
208559
208812
  return root_node.get();
208560
208813
  }
208561
208814
 
208815
+ SegmentBase *SegmentTree::GetSegmentByIndex(int64_t index) {
208816
+ if (index < 0) {
208817
+ index = nodes.size() + index;
208818
+ if (index < 0) {
208819
+ return nullptr;
208820
+ }
208821
+ return nodes[index].node;
208822
+ } else {
208823
+ if (idx_t(index) >= nodes.size()) {
208824
+ return nullptr;
208825
+ }
208826
+ return nodes[index].node;
208827
+ }
208828
+ }
208829
+
208562
208830
  SegmentBase *SegmentTree::GetLastSegment() {
208563
208831
  return nodes.empty() ? nullptr : nodes.back().node;
208564
208832
  }
@@ -208591,6 +208859,16 @@ idx_t SegmentTree::GetSegmentIndex(idx_t row_number) {
208591
208859
  throw InternalException("Could not find node in column segment tree!");
208592
208860
  }
208593
208861
 
208862
+ bool SegmentTree::HasSegment(SegmentBase *segment) {
208863
+ lock_guard<mutex> tree_lock(node_lock);
208864
+ for (auto &node : nodes) {
208865
+ if (node.node == segment) {
208866
+ return true;
208867
+ }
208868
+ }
208869
+ return false;
208870
+ }
208871
+
208594
208872
  void SegmentTree::AppendSegment(unique_ptr<SegmentBase> segment) {
208595
208873
  D_ASSERT(segment);
208596
208874
  // add the node to the list of nodes
@@ -208775,8 +209053,9 @@ void StandardColumnData::CommitDropColumn() {
208775
209053
  }
208776
209054
 
208777
209055
  struct StandardColumnCheckpointState : public ColumnCheckpointState {
208778
- StandardColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, RowGroupWriter &writer)
208779
- : ColumnCheckpointState(row_group, column_data, writer) {
209056
+ StandardColumnCheckpointState(RowGroup &row_group, ColumnData &column_data,
209057
+ PartialBlockManager &partial_block_manager)
209058
+ : ColumnCheckpointState(row_group, column_data, partial_block_manager) {
208780
209059
  }
208781
209060
 
208782
209061
  unique_ptr<ColumnCheckpointState> validity_state;
@@ -208788,21 +209067,27 @@ public:
208788
209067
  return move(global_stats);
208789
209068
  }
208790
209069
 
208791
- void WriteDataPointers() override {
208792
- ColumnCheckpointState::WriteDataPointers();
208793
- validity_state->WriteDataPointers();
209070
+ void WriteDataPointers(RowGroupWriter &writer) override {
209071
+ ColumnCheckpointState::WriteDataPointers(writer);
209072
+ validity_state->WriteDataPointers(writer);
209073
+ }
209074
+
209075
+ void GetBlockIds(unordered_set<block_id_t> &result) override {
209076
+ ColumnCheckpointState::GetBlockIds(result);
209077
+ validity_state->GetBlockIds(result);
208794
209078
  }
208795
209079
  };
208796
209080
 
208797
- unique_ptr<ColumnCheckpointState> StandardColumnData::CreateCheckpointState(RowGroup &row_group,
208798
- RowGroupWriter &writer) {
208799
- return make_unique<StandardColumnCheckpointState>(row_group, *this, writer);
209081
+ unique_ptr<ColumnCheckpointState>
209082
+ StandardColumnData::CreateCheckpointState(RowGroup &row_group, PartialBlockManager &partial_block_manager) {
209083
+ return make_unique<StandardColumnCheckpointState>(row_group, *this, partial_block_manager);
208800
209084
  }
208801
209085
 
208802
- unique_ptr<ColumnCheckpointState> StandardColumnData::Checkpoint(RowGroup &row_group, RowGroupWriter &writer,
209086
+ unique_ptr<ColumnCheckpointState> StandardColumnData::Checkpoint(RowGroup &row_group,
209087
+ PartialBlockManager &partial_block_manager,
208803
209088
  ColumnCheckpointInfo &checkpoint_info) {
208804
- auto validity_state = validity.Checkpoint(row_group, writer, checkpoint_info);
208805
- auto base_state = ColumnData::Checkpoint(row_group, writer, checkpoint_info);
209089
+ auto validity_state = validity.Checkpoint(row_group, partial_block_manager, checkpoint_info);
209090
+ auto base_state = ColumnData::Checkpoint(row_group, partial_block_manager, checkpoint_info);
208806
209091
  auto &checkpoint_state = (StandardColumnCheckpointState &)*base_state;
208807
209092
  checkpoint_state.validity_state = move(validity_state);
208808
209093
  return base_state;
@@ -209074,8 +209359,9 @@ void StructColumnData::CommitDropColumn() {
209074
209359
  }
209075
209360
 
209076
209361
  struct StructColumnCheckpointState : public ColumnCheckpointState {
209077
- StructColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, RowGroupWriter &writer)
209078
- : ColumnCheckpointState(row_group, column_data, writer) {
209362
+ StructColumnCheckpointState(RowGroup &row_group, ColumnData &column_data,
209363
+ PartialBlockManager &partial_block_manager)
209364
+ : ColumnCheckpointState(row_group, column_data, partial_block_manager) {
209079
209365
  global_stats = make_unique<StructStatistics>(column_data.type);
209080
209366
  }
209081
209367
 
@@ -209094,24 +209380,33 @@ public:
209094
209380
  return move(stats);
209095
209381
  }
209096
209382
 
209097
- void WriteDataPointers() override {
209098
- validity_state->WriteDataPointers();
209383
+ void WriteDataPointers(RowGroupWriter &writer) override {
209384
+ validity_state->WriteDataPointers(writer);
209385
+ for (auto &state : child_states) {
209386
+ state->WriteDataPointers(writer);
209387
+ }
209388
+ }
209389
+ void GetBlockIds(unordered_set<block_id_t> &result) override {
209390
+ validity_state->GetBlockIds(result);
209099
209391
  for (auto &state : child_states) {
209100
- state->WriteDataPointers();
209392
+ state->GetBlockIds(result);
209101
209393
  }
209102
209394
  }
209103
209395
  };
209104
209396
 
209105
- unique_ptr<ColumnCheckpointState> StructColumnData::CreateCheckpointState(RowGroup &row_group, RowGroupWriter &writer) {
209106
- return make_unique<StructColumnCheckpointState>(row_group, *this, writer);
209397
+ unique_ptr<ColumnCheckpointState> StructColumnData::CreateCheckpointState(RowGroup &row_group,
209398
+ PartialBlockManager &partial_block_manager) {
209399
+ return make_unique<StructColumnCheckpointState>(row_group, *this, partial_block_manager);
209107
209400
  }
209108
209401
 
209109
- unique_ptr<ColumnCheckpointState> StructColumnData::Checkpoint(RowGroup &row_group, RowGroupWriter &writer,
209402
+ unique_ptr<ColumnCheckpointState> StructColumnData::Checkpoint(RowGroup &row_group,
209403
+ PartialBlockManager &partial_block_manager,
209110
209404
  ColumnCheckpointInfo &checkpoint_info) {
209111
- auto checkpoint_state = make_unique<StructColumnCheckpointState>(row_group, *this, writer);
209112
- checkpoint_state->validity_state = validity.Checkpoint(row_group, writer, checkpoint_info);
209405
+ auto checkpoint_state = make_unique<StructColumnCheckpointState>(row_group, *this, partial_block_manager);
209406
+ checkpoint_state->validity_state = validity.Checkpoint(row_group, partial_block_manager, checkpoint_info);
209113
209407
  for (auto &sub_column : sub_columns) {
209114
- checkpoint_state->child_states.push_back(sub_column->Checkpoint(row_group, writer, checkpoint_info));
209408
+ checkpoint_state->child_states.push_back(
209409
+ sub_column->Checkpoint(row_group, partial_block_manager, checkpoint_info));
209115
209410
  }
209116
209411
  return move(checkpoint_state);
209117
209412
  }
@@ -212062,6 +212357,7 @@ void RollbackState::RollbackEntry(UndoFlags type, data_ptr_t data) {
212062
212357
 
212063
212358
 
212064
212359
 
212360
+
212065
212361
  #include <cstring>
212066
212362
 
212067
212363
  namespace duckdb {
@@ -212077,13 +212373,21 @@ Transaction::Transaction(weak_ptr<ClientContext> context_p, transaction_t start_
212077
212373
  timestamp_t start_timestamp, idx_t catalog_version)
212078
212374
  : context(move(context_p)), start_time(start_time), transaction_id(transaction_id), commit_id(0),
212079
212375
  highest_active_query(0), active_query(MAXIMUM_QUERY_ID), start_timestamp(start_timestamp),
212080
- catalog_version(catalog_version), storage(*this), is_invalidated(false), undo_buffer(context.lock()) {
212376
+ catalog_version(catalog_version), is_invalidated(false), undo_buffer(context.lock()),
212377
+ storage(make_unique<LocalStorage>(*this)) {
212378
+ }
212379
+
212380
+ Transaction::~Transaction() {
212081
212381
  }
212082
212382
 
212083
212383
  Transaction &Transaction::GetTransaction(ClientContext &context) {
212084
212384
  return context.ActiveTransaction();
212085
212385
  }
212086
212386
 
212387
+ LocalStorage &Transaction::GetLocalStorage() {
212388
+ return *storage;
212389
+ }
212390
+
212087
212391
  void Transaction::PushCatalogEntry(CatalogEntry *entry, data_ptr_t extra_data, idx_t extra_data_size) {
212088
212392
  idx_t alloc_size = sizeof(CatalogEntry *);
212089
212393
  if (extra_data_size > 0) {
@@ -212131,12 +212435,12 @@ UpdateInfo *Transaction::CreateUpdateInfo(idx_t type_size, idx_t entries) {
212131
212435
  }
212132
212436
 
212133
212437
  bool Transaction::ChangesMade() {
212134
- return undo_buffer.ChangesMade() || storage.ChangesMade();
212438
+ return undo_buffer.ChangesMade() || storage->ChangesMade();
212135
212439
  }
212136
212440
 
212137
212441
  bool Transaction::AutomaticCheckpoint(DatabaseInstance &db) {
212138
212442
  auto &storage_manager = StorageManager::GetStorageManager(db);
212139
- return storage_manager.AutomaticCheckpoint(storage.EstimatedSize() + undo_buffer.EstimatedSize());
212443
+ return storage_manager.AutomaticCheckpoint(storage->EstimatedSize() + undo_buffer.EstimatedSize());
212140
212444
  }
212141
212445
 
212142
212446
  string Transaction::Commit(DatabaseInstance &db, transaction_t commit_id, bool checkpoint) noexcept {
@@ -212152,7 +212456,7 @@ string Transaction::Commit(DatabaseInstance &db, transaction_t commit_id, bool c
212152
212456
  LocalStorage::CommitState commit_state;
212153
212457
  auto storage_commit_state = storage_manager.GenStorageCommitState(*this, checkpoint);
212154
212458
  try {
212155
- storage.Commit(commit_state, *this);
212459
+ storage->Commit(commit_state, *this);
212156
212460
  undo_buffer.Commit(iterator_state, log, commit_id);
212157
212461
  if (log) {
212158
212462
  // commit any sequences that were used to the WAL
@@ -212168,6 +212472,22 @@ string Transaction::Commit(DatabaseInstance &db, transaction_t commit_id, bool c
212168
212472
  }
212169
212473
  }
212170
212474
 
212475
+ void Transaction::Rollback() noexcept {
212476
+ storage->Rollback();
212477
+ undo_buffer.Rollback();
212478
+ }
212479
+
212480
+ void Transaction::Cleanup() {
212481
+ undo_buffer.Cleanup();
212482
+ }
212483
+
212484
+ void Transaction::Invalidate() {
212485
+ is_invalidated = true;
212486
+ }
212487
+ bool Transaction::IsInvalidated() {
212488
+ return is_invalidated;
212489
+ }
212490
+
212171
212491
  } // namespace duckdb
212172
212492
 
212173
212493