duckdb 0.8.2-dev4203.0 → 0.8.2-dev4314.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.
@@ -8,36 +8,61 @@
8
8
 
9
9
  #pragma once
10
10
 
11
+ #include "duckdb/storage/partial_block_manager.hpp"
11
12
  #include "duckdb/common/typedefs.hpp"
12
13
  #include "duckdb/storage/buffer/block_handle.hpp"
13
14
  #include "duckdb/storage/buffer/buffer_handle.hpp"
15
+ #include "duckdb/storage/block_manager.hpp"
14
16
 
15
17
  namespace duckdb {
16
18
 
17
19
  class FixedSizeAllocator;
18
20
  class MetadataWriter;
19
21
 
22
+ struct PartialBlockForIndex : public PartialBlock {
23
+ public:
24
+ PartialBlockForIndex(PartialBlockState state, BlockManager &block_manager,
25
+ const shared_ptr<BlockHandle> &block_handle);
26
+ ~PartialBlockForIndex() override {};
27
+
28
+ public:
29
+ void Flush(const idx_t free_space_left) override;
30
+ void Clear() override;
31
+ void Merge(PartialBlock &other, idx_t offset, idx_t other_size) override;
32
+ };
33
+
20
34
  //! A fixed-size buffer holds fixed-size segments of data. It lazily deserializes a buffer, if on-disk and not
21
35
  //! yet in memory, and it only serializes dirty and non-written buffers to disk during
22
36
  //! serialization.
23
37
  class FixedSizeBuffer {
38
+ public:
39
+ //! Constants for fast offset calculations in the bitmask
40
+ static constexpr idx_t BASE[] = {0x00000000FFFFFFFF, 0x0000FFFF, 0x00FF, 0x0F, 0x3, 0x1};
41
+ static constexpr uint8_t SHIFT[] = {32, 16, 8, 4, 2, 1};
42
+
24
43
  public:
25
44
  //! Constructor for a new in-memory buffer
26
45
  explicit FixedSizeBuffer(BlockManager &block_manager);
27
46
  //! Constructor for deserializing buffer metadata from disk
28
- FixedSizeBuffer(BlockManager &block_manager, const idx_t segment_count, const block_id_t &block_id);
47
+ FixedSizeBuffer(BlockManager &block_manager, const idx_t segment_count, const idx_t allocation_size,
48
+ const BlockPointer &block_pointer);
29
49
 
30
50
  //! Block manager of the database instance
31
51
  BlockManager &block_manager;
32
52
 
33
53
  //! The number of allocated segments
34
54
  idx_t segment_count;
55
+ //! The size of allocated memory in this buffer (necessary for copying while pinning)
56
+ idx_t allocation_size;
35
57
 
36
58
  //! True: the in-memory buffer is no longer consistent with a (possibly existing) copy on disk
37
59
  bool dirty;
38
60
  //! True: can be vacuumed after the vacuum operation
39
61
  bool vacuum;
40
62
 
63
+ //! Partial block id and offset
64
+ BlockPointer block_pointer;
65
+
41
66
  public:
42
67
  //! Returns true, if the buffer is in-memory
43
68
  inline bool InMemory() const {
@@ -45,12 +70,7 @@ public:
45
70
  }
46
71
  //! Returns true, if the block is on-disk
47
72
  inline bool OnDisk() const {
48
- return (block_handle != nullptr) && (block_handle->BlockId() < MAXIMUM_BLOCK);
49
- }
50
- //! Returns the block ID
51
- inline block_id_t BlockId() const {
52
- D_ASSERT(OnDisk());
53
- return block_handle->BlockId();
73
+ return block_pointer.IsValid();
54
74
  }
55
75
  //! Returns a pointer to the buffer in memory, and calls Deserialize, if the buffer is not in memory
56
76
  inline data_ptr_t Get(const bool dirty_p = true) {
@@ -65,15 +85,25 @@ public:
65
85
  //! Destroys the in-memory buffer and the on-disk block
66
86
  void Destroy();
67
87
  //! Serializes a buffer (if dirty or not on disk)
68
- void Serialize();
88
+ void Serialize(PartialBlockManager &partial_block_manager, const idx_t available_segments, const idx_t segment_size,
89
+ const idx_t bitmask_offset);
69
90
  //! Pin a buffer (if not in-memory)
70
91
  void Pin();
92
+ //! Returns the first free offset in a bitmask
93
+ uint32_t GetOffset(const idx_t bitmask_count);
71
94
 
72
95
  private:
73
96
  //! The buffer handle of the in-memory buffer
74
97
  BufferHandle buffer_handle;
75
98
  //! The block handle of the on-disk buffer
76
99
  shared_ptr<BlockHandle> block_handle;
100
+
101
+ private:
102
+ //! Returns the maximum non-free offset in a bitmask
103
+ uint32_t GetMaxOffset(const idx_t available_segments_per_buffer);
104
+ //! Sets all uninitialized regions of a buffer in the respective partial block allocation
105
+ void SetUninitializedRegions(PartialBlockForIndex &p_block_for_index, const idx_t segment_size, const idx_t offset,
106
+ const idx_t bitmask_offset);
77
107
  };
78
108
 
79
109
  } // namespace duckdb
@@ -19,8 +19,11 @@
19
19
  #include "duckdb/main/client_context.hpp"
20
20
  #include "duckdb/main/external_dependencies.hpp"
21
21
  #include "duckdb/parser/statement/explain_statement.hpp"
22
-
23
- #include <memory>
22
+ #include "duckdb/parser/parsed_expression.hpp"
23
+ #include "duckdb/parser/result_modifier.hpp"
24
+ #include "duckdb/common/unique_ptr.hpp"
25
+ #include "duckdb/common/vector.hpp"
26
+ #include "duckdb/common/helper.hpp"
24
27
 
25
28
  namespace duckdb {
26
29
  struct BoundStatement;
@@ -81,9 +84,12 @@ public:
81
84
  DUCKDB_API shared_ptr<Relation> Project(const string &select_list, const vector<string> &aliases);
82
85
  DUCKDB_API shared_ptr<Relation> Project(const vector<string> &expressions);
83
86
  DUCKDB_API shared_ptr<Relation> Project(const vector<string> &expressions, const vector<string> &aliases);
87
+ DUCKDB_API shared_ptr<Relation> Project(vector<unique_ptr<ParsedExpression>> expressions,
88
+ const vector<string> &aliases);
84
89
 
85
90
  // FILTER
86
91
  DUCKDB_API shared_ptr<Relation> Filter(const string &expression);
92
+ DUCKDB_API shared_ptr<Relation> Filter(unique_ptr<ParsedExpression> expression);
87
93
  DUCKDB_API shared_ptr<Relation> Filter(const vector<string> &expressions);
88
94
 
89
95
  // LIMIT
@@ -92,6 +98,7 @@ public:
92
98
  // ORDER
93
99
  DUCKDB_API shared_ptr<Relation> Order(const string &expression);
94
100
  DUCKDB_API shared_ptr<Relation> Order(const vector<string> &expressions);
101
+ DUCKDB_API shared_ptr<Relation> Order(vector<OrderByNode> expressions);
95
102
 
96
103
  // JOIN operation
97
104
  DUCKDB_API shared_ptr<Relation> Join(const shared_ptr<Relation> &other, const string &condition,
@@ -25,30 +25,46 @@ class TableCatalogEntry;
25
25
  class ViewCatalogEntry;
26
26
  class TypeCatalogEntry;
27
27
 
28
+ //! Regions that require zero-initialization to avoid leaking memory
29
+ struct UninitializedRegion {
30
+ idx_t start;
31
+ idx_t end;
32
+ };
33
+
34
+ //! The current state of a partial block
28
35
  struct PartialBlockState {
36
+ //! The block id of the partial block
29
37
  block_id_t block_id;
30
- //! How big is the block we're writing to. (Total bytes to assign).
38
+ //! The total bytes that we can assign to this block
31
39
  uint32_t block_size;
32
- //! How many bytes of the allocation are used. (offset_in_block of next allocation)
33
- uint32_t offset_in_block;
34
- //! How many times has the block been used?
40
+ //! Next allocation offset, and also the current allocation size
41
+ uint32_t offset;
42
+ //! The number of times that this block has been used for partial allocations
35
43
  uint32_t block_use_count;
36
44
  };
37
45
 
38
46
  struct PartialBlock {
39
- explicit PartialBlock(PartialBlockState state) : state(std::move(state)) {
40
- }
47
+ PartialBlock(PartialBlockState state, BlockManager &block_manager, const shared_ptr<BlockHandle> &block_handle);
41
48
  virtual ~PartialBlock() {
42
49
  }
43
50
 
51
+ //! The current state of a partial block
44
52
  PartialBlockState state;
53
+ //! All uninitialized regions on this block, we need to zero-initialize them when flushing
54
+ vector<UninitializedRegion> uninitialized_regions;
55
+ //! The block manager of the partial block manager
56
+ BlockManager &block_manager;
57
+ //! The block handle of the underlying block that this partial block writes to
58
+ shared_ptr<BlockHandle> block_handle;
45
59
 
46
60
  public:
47
- virtual void AddUninitializedRegion(idx_t start, idx_t end) = 0;
48
- virtual void Flush(idx_t free_space_left) = 0;
49
- virtual void Clear() {
50
- }
51
- virtual void Merge(PartialBlock &other, idx_t offset, idx_t other_size);
61
+ //! Add regions that need zero-initialization to avoid leaking memory
62
+ void AddUninitializedRegion(const idx_t start, const idx_t end);
63
+ //! Flush the block to disk and zero-initialize any free space and uninitialized regions
64
+ virtual void Flush(const idx_t free_space_left) = 0;
65
+ void FlushInternal(const idx_t free_space_left);
66
+ virtual void Merge(PartialBlock &other, idx_t offset, idx_t other_size) = 0;
67
+ virtual void Clear() = 0;
52
68
 
53
69
  public:
54
70
  template <class TARGET>
@@ -59,13 +75,13 @@ public:
59
75
  };
60
76
 
61
77
  struct PartialBlockAllocation {
62
- // BlockManager owning the block_id
78
+ //! The BlockManager owning the block_id
63
79
  BlockManager *block_manager {nullptr};
64
- //! How many bytes assigned to the caller?
80
+ //! The number of assigned bytes to the caller
65
81
  uint32_t allocation_size;
66
- //! State of assigned block.
82
+ //! The current state of the partial block
67
83
  PartialBlockState state;
68
- //! Arbitrary state related to partial block storage.
84
+ //! Arbitrary state related to the partial block storage
69
85
  unique_ptr<PartialBlock> partial_block;
70
86
  };
71
87
 
@@ -76,12 +92,12 @@ enum class CheckpointType { FULL_CHECKPOINT, APPEND_TO_TABLE };
76
92
  //! In any case, they must share a block manager.
77
93
  class PartialBlockManager {
78
94
  public:
79
- // 20% free / 80% utilization
95
+ //! 20% free / 80% utilization
80
96
  static constexpr const idx_t DEFAULT_MAX_PARTIAL_BLOCK_SIZE = Storage::BLOCK_SIZE / 5 * 4;
81
- // Max number of shared references to a block. No effective limit by default.
97
+ //! Max number of shared references to a block. No effective limit by default.
82
98
  static constexpr const idx_t DEFAULT_MAX_USE_COUNT = 1u << 20;
83
- // No point letting map size grow unbounded. We'll drop blocks with the
84
- // least free space first.
99
+ //! No point letting map size grow unbounded. We'll drop blocks with the
100
+ //! least free space first.
85
101
  static constexpr const idx_t MAX_BLOCK_MAP_SIZE = 1u << 31;
86
102
 
87
103
  public:
@@ -68,37 +68,22 @@ struct PartialBlockForCheckpoint : public PartialBlock {
68
68
  };
69
69
 
70
70
  public:
71
- PartialBlockForCheckpoint(ColumnData &data, ColumnSegment &segment, BlockManager &block_manager,
72
- PartialBlockState state);
71
+ PartialBlockForCheckpoint(ColumnData &data, ColumnSegment &segment, PartialBlockState state,
72
+ BlockManager &block_manager);
73
73
  ~PartialBlockForCheckpoint() override;
74
74
 
75
75
  // We will copy all segment data into the memory of the shared block.
76
76
  // Once the block is full (or checkpoint is complete) we'll invoke Flush().
77
77
  // This will cause the block to get written to storage (via BlockManger::ConvertToPersistent),
78
78
  // and all segments to have their references updated (via ColumnSegment::ConvertToPersistent)
79
- BlockManager &block_manager;
80
- shared_ptr<BlockHandle> block;
81
79
  vector<PartialColumnSegment> segments;
82
80
 
83
- private:
84
- struct UninitializedRegion {
85
- idx_t start;
86
- idx_t end;
87
- };
88
- vector<UninitializedRegion> uninitialized_regions;
89
-
90
81
  public:
91
82
  bool IsFlushed();
92
-
93
- void AddUninitializedRegion(idx_t start, idx_t end) override;
94
-
95
- void Flush(idx_t free_space_left) override;
96
-
97
- void Clear() override;
98
-
83
+ void Flush(const idx_t free_space_left) override;
99
84
  void Merge(PartialBlock &other, idx_t offset, idx_t other_size) override;
100
-
101
85
  void AddSegmentToTail(ColumnData &data, ColumnSegment &segment, uint32_t offset_in_block);
86
+ void Clear() override;
102
87
  };
103
88
 
104
89
  } // namespace duckdb
@@ -47,6 +47,11 @@ shared_ptr<Relation> Relation::Project(const vector<string> &expressions) {
47
47
  return Project(expressions, aliases);
48
48
  }
49
49
 
50
+ shared_ptr<Relation> Relation::Project(vector<unique_ptr<ParsedExpression>> expressions,
51
+ const vector<string> &aliases) {
52
+ return make_shared<ProjectionRelation>(shared_from_this(), std::move(expressions), aliases);
53
+ }
54
+
50
55
  static vector<unique_ptr<ParsedExpression>> StringListToExpressionList(ClientContext &context,
51
56
  const vector<string> &expressions) {
52
57
  if (expressions.empty()) {
@@ -73,7 +78,11 @@ shared_ptr<Relation> Relation::Filter(const string &expression) {
73
78
  if (expression_list.size() != 1) {
74
79
  throw ParserException("Expected a single expression as filter condition");
75
80
  }
76
- return make_shared<FilterRelation>(shared_from_this(), std::move(expression_list[0]));
81
+ return Filter(std::move(expression_list[0]));
82
+ }
83
+
84
+ shared_ptr<Relation> Relation::Filter(unique_ptr<ParsedExpression> expression) {
85
+ return make_shared<FilterRelation>(shared_from_this(), std::move(expression));
77
86
  }
78
87
 
79
88
  shared_ptr<Relation> Relation::Filter(const vector<string> &expressions) {
@@ -95,6 +104,10 @@ shared_ptr<Relation> Relation::Limit(int64_t limit, int64_t offset) {
95
104
 
96
105
  shared_ptr<Relation> Relation::Order(const string &expression) {
97
106
  auto order_list = Parser::ParseOrderList(expression, context.GetContext()->GetParserOptions());
107
+ return Order(std::move(order_list));
108
+ }
109
+
110
+ shared_ptr<Relation> Relation::Order(vector<OrderByNode> order_list) {
98
111
  return make_shared<OrderRelation>(shared_from_this(), std::move(order_list));
99
112
  }
100
113
 
@@ -110,7 +123,7 @@ shared_ptr<Relation> Relation::Order(const vector<string> &expressions) {
110
123
  }
111
124
  order_list.push_back(std::move(inner_list[0]));
112
125
  }
113
- return make_shared<OrderRelation>(shared_from_this(), std::move(order_list));
126
+ return Order(std::move(order_list));
114
127
  }
115
128
 
116
129
  shared_ptr<Relation> Relation::Join(const shared_ptr<Relation> &other, const string &condition, JoinType type,
@@ -2,6 +2,38 @@
2
2
 
3
3
  namespace duckdb {
4
4
 
5
+ //===--------------------------------------------------------------------===//
6
+ // PartialBlock
7
+ //===--------------------------------------------------------------------===//
8
+
9
+ PartialBlock::PartialBlock(PartialBlockState state, BlockManager &block_manager,
10
+ const shared_ptr<BlockHandle> &block_handle)
11
+ : state(state), block_manager(block_manager), block_handle(block_handle) {
12
+ }
13
+
14
+ void PartialBlock::AddUninitializedRegion(idx_t start, idx_t end) {
15
+ uninitialized_regions.push_back({start, end});
16
+ }
17
+
18
+ void PartialBlock::FlushInternal(const idx_t free_space_left) {
19
+
20
+ // ensure that we do not leak any data
21
+ if (free_space_left > 0 || !uninitialized_regions.empty()) {
22
+ auto buffer_handle = block_manager.buffer_manager.Pin(block_handle);
23
+
24
+ // memset any uninitialized regions
25
+ for (auto &uninitialized : uninitialized_regions) {
26
+ memset(buffer_handle.Ptr() + uninitialized.start, 0, uninitialized.end - uninitialized.start);
27
+ }
28
+ // memset any free space at the end of the block to 0 prior to writing to disk
29
+ memset(buffer_handle.Ptr() + Storage::BLOCK_SIZE - free_space_left, 0, free_space_left);
30
+ }
31
+ }
32
+
33
+ //===--------------------------------------------------------------------===//
34
+ // PartialBlockManager
35
+ //===--------------------------------------------------------------------===//
36
+
5
37
  PartialBlockManager::PartialBlockManager(BlockManager &block_manager, CheckpointType checkpoint_type,
6
38
  uint32_t max_partial_block_size, uint32_t max_use_count)
7
39
  : block_manager(block_manager), checkpoint_type(checkpoint_type), max_partial_block_size(max_partial_block_size),
@@ -9,9 +41,7 @@ PartialBlockManager::PartialBlockManager(BlockManager &block_manager, Checkpoint
9
41
  }
10
42
  PartialBlockManager::~PartialBlockManager() {
11
43
  }
12
- //===--------------------------------------------------------------------===//
13
- // Partial Blocks
14
- //===--------------------------------------------------------------------===//
44
+
15
45
  PartialBlockAllocation PartialBlockManager::GetBlockAllocation(uint32_t segment_size) {
16
46
  PartialBlockAllocation allocation;
17
47
  allocation.block_manager = &block_manager;
@@ -47,7 +77,7 @@ void PartialBlockManager::AllocateBlock(PartialBlockState &state, uint32_t segme
47
77
  state.block_id = INVALID_BLOCK;
48
78
  }
49
79
  state.block_size = Storage::BLOCK_SIZE;
50
- state.offset_in_block = 0;
80
+ state.offset = 0;
51
81
  state.block_use_count = 1;
52
82
  }
53
83
 
@@ -60,21 +90,22 @@ bool PartialBlockManager::GetPartialBlock(idx_t segment_size, unique_ptr<Partial
60
90
  partial_block = std::move(entry->second);
61
91
  partially_filled_blocks.erase(entry);
62
92
 
63
- D_ASSERT(partial_block->state.offset_in_block > 0);
64
- D_ASSERT(ValueIsAligned(partial_block->state.offset_in_block));
93
+ D_ASSERT(partial_block->state.offset > 0);
94
+ D_ASSERT(ValueIsAligned(partial_block->state.offset));
65
95
  return true;
66
96
  }
67
97
 
68
98
  void PartialBlockManager::RegisterPartialBlock(PartialBlockAllocation &&allocation) {
69
99
  auto &state = allocation.partial_block->state;
100
+ D_ASSERT(checkpoint_type != CheckpointType::FULL_CHECKPOINT || state.block_id >= 0);
70
101
  if (state.block_use_count < max_use_count) {
71
- auto unaligned_size = allocation.allocation_size + state.offset_in_block;
102
+ auto unaligned_size = allocation.allocation_size + state.offset;
72
103
  auto new_size = AlignValue(unaligned_size);
73
104
  if (new_size != unaligned_size) {
74
105
  // register the uninitialized region so we can correctly initialize it before writing to disk
75
106
  allocation.partial_block->AddUninitializedRegion(unaligned_size, new_size);
76
107
  }
77
- state.offset_in_block = new_size;
108
+ state.offset = new_size;
78
109
  auto new_space_left = state.block_size - new_size;
79
110
  // check if the block is STILL partially filled after adding the segment_size
80
111
  if (new_space_left >= Storage::BLOCK_SIZE - max_partial_block_size) {
@@ -82,7 +113,7 @@ void PartialBlockManager::RegisterPartialBlock(PartialBlockAllocation &&allocati
82
113
  partially_filled_blocks.insert(make_pair(new_space_left, std::move(allocation.partial_block)));
83
114
  }
84
115
  }
85
- idx_t free_space = state.block_size - state.offset_in_block;
116
+ idx_t free_space = state.block_size - state.offset;
86
117
  auto block_to_free = std::move(allocation.partial_block);
87
118
  if (!block_to_free && partially_filled_blocks.size() > MAX_BLOCK_MAP_SIZE) {
88
119
  // Free the page with the least space free.
@@ -98,10 +129,6 @@ void PartialBlockManager::RegisterPartialBlock(PartialBlockAllocation &&allocati
98
129
  }
99
130
  }
100
131
 
101
- void PartialBlock::Merge(PartialBlock &other, idx_t offset, idx_t other_size) {
102
- throw InternalException("PartialBlock::Merge not implemented for this block type");
103
- }
104
-
105
132
  void PartialBlockManager::Merge(PartialBlockManager &other) {
106
133
  if (&other == this) {
107
134
  throw InternalException("Cannot merge into itself");
@@ -117,10 +144,10 @@ void PartialBlockManager::Merge(PartialBlockManager &other) {
117
144
  // we can merge this block into an existing block - merge them
118
145
  // merge blocks
119
146
  auto allocation = GetBlockAllocation(used_space);
120
- allocation.partial_block->Merge(*e.second, allocation.state.offset_in_block, used_space);
147
+ allocation.partial_block->Merge(*e.second, allocation.state.offset, used_space);
121
148
 
122
149
  // re-register the partial block
123
- allocation.state.offset_in_block += used_space;
150
+ allocation.state.offset += used_space;
124
151
  RegisterPartialBlock(std::move(allocation));
125
152
  } else {
126
153
  // we cannot merge this block - append it directly to the current block manager
@@ -22,9 +22,9 @@ unique_ptr<BaseStatistics> ColumnCheckpointState::GetStatistics() {
22
22
  return std::move(global_stats);
23
23
  }
24
24
 
25
- PartialBlockForCheckpoint::PartialBlockForCheckpoint(ColumnData &data, ColumnSegment &segment,
26
- BlockManager &block_manager, PartialBlockState state)
27
- : PartialBlock(state), block_manager(block_manager), block(segment.block) {
25
+ PartialBlockForCheckpoint::PartialBlockForCheckpoint(ColumnData &data, ColumnSegment &segment, PartialBlockState state,
26
+ BlockManager &block_manager)
27
+ : PartialBlock(state, block_manager, segment.block) {
28
28
  AddSegmentToTail(data, segment, 0);
29
29
  }
30
30
 
@@ -37,24 +37,15 @@ bool PartialBlockForCheckpoint::IsFlushed() {
37
37
  return segments.empty();
38
38
  }
39
39
 
40
- void PartialBlockForCheckpoint::AddUninitializedRegion(idx_t start, idx_t end) {
41
- uninitialized_regions.push_back({start, end});
42
- }
40
+ void PartialBlockForCheckpoint::Flush(const idx_t free_space_left) {
43
41
 
44
- void PartialBlockForCheckpoint::Flush(idx_t free_space_left) {
45
42
  if (IsFlushed()) {
46
43
  throw InternalException("Flush called on partial block that was already flushed");
47
44
  }
48
- // if we have any free space or uninitialized regions we need to zero-initialize them
49
- if (free_space_left > 0 || !uninitialized_regions.empty()) {
50
- auto handle = block_manager.buffer_manager.Pin(block);
51
- // memset any uninitialized regions
52
- for (auto &uninitialized : uninitialized_regions) {
53
- memset(handle.Ptr() + uninitialized.start, 0, uninitialized.end - uninitialized.start);
54
- }
55
- // memset any free space at the end of the block to 0 prior to writing to disk
56
- memset(handle.Ptr() + Storage::BLOCK_SIZE - free_space_left, 0, free_space_left);
57
- }
45
+
46
+ // zero-initialize unused memory
47
+ FlushInternal(free_space_left);
48
+
58
49
  // At this point, we've already copied all data from tail_segments
59
50
  // into the page owned by first_segment. We flush all segment data to
60
51
  // disk with the following call.
@@ -63,6 +54,7 @@ void PartialBlockForCheckpoint::Flush(idx_t free_space_left) {
63
54
  if (fetch_new_block) {
64
55
  state.block_id = block_manager.GetFreeBlockId();
65
56
  }
57
+
66
58
  for (idx_t i = 0; i < segments.size(); i++) {
67
59
  auto &segment = segments[i];
68
60
  segment.data.IncrementVersion();
@@ -71,23 +63,18 @@ void PartialBlockForCheckpoint::Flush(idx_t free_space_left) {
71
63
  D_ASSERT(segment.offset_in_block == 0);
72
64
  segment.segment.ConvertToPersistent(&block_manager, state.block_id);
73
65
  // update the block after it has been converted to a persistent segment
74
- block = segment.segment.block;
66
+ block_handle = segment.segment.block;
75
67
  } else {
76
68
  // subsequent segments are MARKED as persistent - they don't need to be rewritten
77
- segment.segment.MarkAsPersistent(block, segment.offset_in_block);
69
+ segment.segment.MarkAsPersistent(block_handle, segment.offset_in_block);
78
70
  if (fetch_new_block) {
79
71
  // if we fetched a new block we need to increase the reference count to the block
80
72
  block_manager.IncreaseBlockReferenceCount(state.block_id);
81
73
  }
82
74
  }
83
75
  }
84
- Clear();
85
- }
86
76
 
87
- void PartialBlockForCheckpoint::Clear() {
88
- uninitialized_regions.clear();
89
- block.reset();
90
- segments.clear();
77
+ Clear();
91
78
  }
92
79
 
93
80
  void PartialBlockForCheckpoint::Merge(PartialBlock &other_p, idx_t offset, idx_t other_size) {
@@ -95,13 +82,13 @@ void PartialBlockForCheckpoint::Merge(PartialBlock &other_p, idx_t offset, idx_t
95
82
 
96
83
  auto &buffer_manager = block_manager.buffer_manager;
97
84
  // pin the source block
98
- auto old_handle = buffer_manager.Pin(other.block);
85
+ auto old_handle = buffer_manager.Pin(other.block_handle);
99
86
  // pin the target block
100
- auto new_handle = buffer_manager.Pin(block);
87
+ auto new_handle = buffer_manager.Pin(block_handle);
101
88
  // memcpy the contents of the old block to the new block
102
89
  memcpy(new_handle.Ptr() + offset, old_handle.Ptr(), other_size);
103
90
 
104
- // now copy over all of the segments to the new block
91
+ // now copy over all segments to the new block
105
92
  // move over the uninitialized regions
106
93
  for (auto &region : other.uninitialized_regions) {
107
94
  region.start += offset;
@@ -113,6 +100,7 @@ void PartialBlockForCheckpoint::Merge(PartialBlock &other_p, idx_t offset, idx_t
113
100
  for (auto &segment : other.segments) {
114
101
  AddSegmentToTail(segment.data, segment.segment, segment.offset_in_block + offset);
115
102
  }
103
+
116
104
  other.Clear();
117
105
  }
118
106
 
@@ -120,6 +108,12 @@ void PartialBlockForCheckpoint::AddSegmentToTail(ColumnData &data, ColumnSegment
120
108
  segments.emplace_back(data, segment, offset_in_block);
121
109
  }
122
110
 
111
+ void PartialBlockForCheckpoint::Clear() {
112
+ uninitialized_regions.clear();
113
+ block_handle.reset();
114
+ segments.clear();
115
+ }
116
+
123
117
  void ColumnCheckpointState::FlushSegment(unique_ptr<ColumnSegment> segment, idx_t segment_size) {
124
118
  D_ASSERT(segment_size <= Storage::BLOCK_SIZE);
125
119
  auto tuple_count = segment->count.load();
@@ -140,7 +134,7 @@ void ColumnCheckpointState::FlushSegment(unique_ptr<ColumnSegment> segment, idx_
140
134
  // non-constant block
141
135
  PartialBlockAllocation allocation = partial_block_manager.GetBlockAllocation(segment_size);
142
136
  block_id = allocation.state.block_id;
143
- offset_in_block = allocation.state.offset_in_block;
137
+ offset_in_block = allocation.state.offset;
144
138
 
145
139
  if (allocation.partial_block) {
146
140
  // Use an existing block.
@@ -149,7 +143,7 @@ void ColumnCheckpointState::FlushSegment(unique_ptr<ColumnSegment> segment, idx_
149
143
  // pin the source block
150
144
  auto old_handle = buffer_manager.Pin(segment->block);
151
145
  // pin the target block
152
- auto new_handle = buffer_manager.Pin(pstate.block);
146
+ auto new_handle = buffer_manager.Pin(pstate.block_handle);
153
147
  // memcpy the contents of the old block to the new block
154
148
  memcpy(new_handle.Ptr() + offset_in_block, old_handle.Ptr(), segment_size);
155
149
  pstate.AddSegmentToTail(column_data, *segment, offset_in_block);
@@ -162,8 +156,8 @@ void ColumnCheckpointState::FlushSegment(unique_ptr<ColumnSegment> segment, idx_
162
156
  segment->Resize(Storage::BLOCK_SIZE);
163
157
  }
164
158
  D_ASSERT(offset_in_block == 0);
165
- allocation.partial_block = make_uniq<PartialBlockForCheckpoint>(
166
- column_data, *segment, *allocation.block_manager, allocation.state);
159
+ allocation.partial_block = make_uniq<PartialBlockForCheckpoint>(column_data, *segment, allocation.state,
160
+ *allocation.block_manager);
167
161
  }
168
162
  // Writer will decide whether to reuse this block.
169
163
  partial_block_manager.RegisterPartialBlock(std::move(allocation));