duckdb 0.7.2-dev1803.0 → 0.7.2-dev1898.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/src/catalog/catalog.cpp +27 -27
  3. package/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp +6 -6
  4. package/src/duckdb/src/catalog/catalog_set.cpp +27 -25
  5. package/src/duckdb/src/catalog/default/default_functions.cpp +6 -6
  6. package/src/duckdb/src/catalog/default/default_types.cpp +4 -4
  7. package/src/duckdb/src/catalog/default/default_views.cpp +4 -4
  8. package/src/duckdb/src/catalog/dependency_list.cpp +7 -6
  9. package/src/duckdb/src/catalog/dependency_manager.cpp +44 -38
  10. package/src/duckdb/src/common/serializer/buffered_file_reader.cpp +11 -6
  11. package/src/duckdb/src/common/sort/sorted_block.cpp +9 -4
  12. package/src/duckdb/src/common/types/batched_data_collection.cpp +2 -1
  13. package/src/duckdb/src/common/types/column_data_allocator.cpp +1 -0
  14. package/src/duckdb/src/common/types/vector.cpp +2 -2
  15. package/src/duckdb/src/common/vector_operations/vector_copy.cpp +14 -11
  16. package/src/duckdb/src/execution/operator/aggregate/distinct_aggregate_data.cpp +1 -1
  17. package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +51 -50
  18. package/src/duckdb/src/execution/operator/join/physical_iejoin.cpp +4 -0
  19. package/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp +14 -13
  20. package/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +20 -20
  21. package/src/duckdb/src/execution/operator/schema/physical_create_table.cpp +2 -2
  22. package/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +1 -1
  23. package/src/duckdb/src/execution/physical_plan/plan_create_table.cpp +3 -3
  24. package/src/duckdb/src/execution/physical_plan/plan_delete.cpp +1 -1
  25. package/src/duckdb/src/execution/physical_plan/plan_insert.cpp +1 -1
  26. package/src/duckdb/src/execution/physical_plan/plan_update.cpp +1 -1
  27. package/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +172 -63
  28. package/src/duckdb/src/function/cast/cast_function_set.cpp +2 -1
  29. package/src/duckdb/src/function/scalar/operators/arithmetic.cpp +15 -9
  30. package/src/duckdb/src/function/scalar/sequence/nextval.cpp +29 -29
  31. package/src/duckdb/src/function/scalar/string/damerau_levenshtein.cpp +106 -0
  32. package/src/duckdb/src/function/scalar/string/regexp.cpp +145 -28
  33. package/src/duckdb/src/function/scalar/string_functions.cpp +1 -0
  34. package/src/duckdb/src/function/table/checkpoint.cpp +4 -4
  35. package/src/duckdb/src/function/table/system/duckdb_columns.cpp +24 -24
  36. package/src/duckdb/src/function/table/system/duckdb_constraints.cpp +7 -6
  37. package/src/duckdb/src/function/table/system/duckdb_databases.cpp +1 -1
  38. package/src/duckdb/src/function/table/system/duckdb_dependencies.cpp +11 -11
  39. package/src/duckdb/src/function/table/system/pragma_database_size.cpp +1 -1
  40. package/src/duckdb/src/function/table/system/pragma_table_info.cpp +17 -18
  41. package/src/duckdb/src/function/table/table_scan.cpp +8 -11
  42. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  43. package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +9 -9
  44. package/src/duckdb/src/include/duckdb/catalog/catalog_entry_map.hpp +38 -0
  45. package/src/duckdb/src/include/duckdb/catalog/catalog_transaction.hpp +4 -3
  46. package/src/duckdb/src/include/duckdb/catalog/default/default_functions.hpp +2 -2
  47. package/src/duckdb/src/include/duckdb/catalog/default/default_types.hpp +2 -2
  48. package/src/duckdb/src/include/duckdb/catalog/default/default_views.hpp +2 -2
  49. package/src/duckdb/src/include/duckdb/catalog/dependency.hpp +4 -5
  50. package/src/duckdb/src/include/duckdb/catalog/dependency_list.hpp +4 -5
  51. package/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp +10 -9
  52. package/src/duckdb/src/include/duckdb/common/allocator.hpp +2 -1
  53. package/src/duckdb/src/include/duckdb/common/field_writer.hpp +1 -1
  54. package/src/duckdb/src/include/duckdb/common/helper.hpp +9 -0
  55. package/src/duckdb/src/include/duckdb/common/optional_ptr.hpp +29 -6
  56. package/src/duckdb/src/include/duckdb/common/serializer/buffered_file_reader.hpp +6 -5
  57. package/src/duckdb/src/include/duckdb/common/serializer.hpp +1 -1
  58. package/src/duckdb/src/include/duckdb/common/types/row_data_collection.hpp +1 -0
  59. package/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp +2 -2
  60. package/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_insert.hpp +5 -5
  61. package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_table.hpp +2 -2
  62. package/src/duckdb/src/include/duckdb/function/cast/default_casts.hpp +3 -2
  63. package/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp +4 -0
  64. package/src/duckdb/src/include/duckdb/main/client_config.hpp +5 -0
  65. package/src/duckdb/src/include/duckdb/main/database_manager.hpp +4 -3
  66. package/src/duckdb/src/include/duckdb/main/query_result.hpp +3 -2
  67. package/src/duckdb/src/include/duckdb/main/settings.hpp +19 -0
  68. package/src/duckdb/src/include/duckdb/optimizer/filter_combiner.hpp +7 -7
  69. package/src/duckdb/src/include/duckdb/optimizer/matcher/expression_matcher.hpp +11 -11
  70. package/src/duckdb/src/include/duckdb/optimizer/matcher/set_matcher.hpp +8 -8
  71. package/src/duckdb/src/include/duckdb/optimizer/rule/arithmetic_simplification.hpp +1 -1
  72. package/src/duckdb/src/include/duckdb/optimizer/rule/case_simplification.hpp +1 -1
  73. package/src/duckdb/src/include/duckdb/optimizer/rule/comparison_simplification.hpp +1 -1
  74. package/src/duckdb/src/include/duckdb/optimizer/rule/conjunction_simplification.hpp +2 -2
  75. package/src/duckdb/src/include/duckdb/optimizer/rule/constant_folding.hpp +1 -1
  76. package/src/duckdb/src/include/duckdb/optimizer/rule/date_part_simplification.hpp +1 -1
  77. package/src/duckdb/src/include/duckdb/optimizer/rule/distributivity.hpp +1 -1
  78. package/src/duckdb/src/include/duckdb/optimizer/rule/empty_needle_removal.hpp +1 -1
  79. package/src/duckdb/src/include/duckdb/optimizer/rule/enum_comparison.hpp +1 -1
  80. package/src/duckdb/src/include/duckdb/optimizer/rule/equal_or_null_simplification.hpp +1 -1
  81. package/src/duckdb/src/include/duckdb/optimizer/rule/in_clause_simplification.hpp +1 -1
  82. package/src/duckdb/src/include/duckdb/optimizer/rule/like_optimizations.hpp +1 -1
  83. package/src/duckdb/src/include/duckdb/optimizer/rule/move_constants.hpp +1 -1
  84. package/src/duckdb/src/include/duckdb/optimizer/rule/ordered_aggregate_optimizer.hpp +1 -1
  85. package/src/duckdb/src/include/duckdb/optimizer/rule/regex_optimizations.hpp +1 -1
  86. package/src/duckdb/src/include/duckdb/optimizer/rule.hpp +2 -2
  87. package/src/duckdb/src/include/duckdb/parser/base_expression.hpp +1 -1
  88. package/src/duckdb/src/include/duckdb/parser/expression_map.hpp +19 -6
  89. package/src/duckdb/src/include/duckdb/parser/expression_util.hpp +1 -1
  90. package/src/duckdb/src/include/duckdb/parser/parser.hpp +1 -7
  91. package/src/duckdb/src/include/duckdb/parser/parser_options.hpp +23 -0
  92. package/src/duckdb/src/include/duckdb/parser/transformer.hpp +5 -3
  93. package/src/duckdb/src/include/duckdb/planner/expression.hpp +5 -2
  94. package/src/duckdb/src/include/duckdb/planner/expression_binder/base_select_binder.hpp +1 -1
  95. package/src/duckdb/src/include/duckdb/planner/expression_binder/order_binder.hpp +3 -3
  96. package/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +10 -2
  97. package/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp +1 -0
  98. package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +49 -126
  99. package/src/duckdb/src/include/duckdb/storage/meta_block_reader.hpp +5 -5
  100. package/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp +159 -0
  101. package/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp +1 -0
  102. package/src/duckdb/src/include/duckdb/transaction/meta_transaction.hpp +6 -5
  103. package/src/duckdb/src/main/client_context.cpp +5 -3
  104. package/src/duckdb/src/main/config.cpp +2 -0
  105. package/src/duckdb/src/main/database.cpp +2 -1
  106. package/src/duckdb/src/main/database_manager.cpp +4 -4
  107. package/src/duckdb/src/main/settings/settings.cpp +36 -0
  108. package/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp +2 -2
  109. package/src/duckdb/src/optimizer/cse_optimizer.cpp +4 -4
  110. package/src/duckdb/src/optimizer/deliminator.cpp +13 -11
  111. package/src/duckdb/src/optimizer/expression_rewriter.cpp +2 -2
  112. package/src/duckdb/src/optimizer/filter_combiner.cpp +67 -65
  113. package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +1 -0
  114. package/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +26 -25
  115. package/src/duckdb/src/optimizer/matcher/expression_matcher.cpp +23 -21
  116. package/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp +7 -6
  117. package/src/duckdb/src/optimizer/rule/case_simplification.cpp +2 -2
  118. package/src/duckdb/src/optimizer/rule/comparison_simplification.cpp +6 -7
  119. package/src/duckdb/src/optimizer/rule/conjunction_simplification.cpp +9 -8
  120. package/src/duckdb/src/optimizer/rule/constant_folding.cpp +7 -7
  121. package/src/duckdb/src/optimizer/rule/date_part_simplification.cpp +3 -3
  122. package/src/duckdb/src/optimizer/rule/distributivity.cpp +5 -5
  123. package/src/duckdb/src/optimizer/rule/empty_needle_removal.cpp +6 -6
  124. package/src/duckdb/src/optimizer/rule/enum_comparison.cpp +4 -4
  125. package/src/duckdb/src/optimizer/rule/equal_or_null_simplification.cpp +23 -26
  126. package/src/duckdb/src/optimizer/rule/in_clause_simplification_rule.cpp +2 -3
  127. package/src/duckdb/src/optimizer/rule/like_optimizations.cpp +3 -3
  128. package/src/duckdb/src/optimizer/rule/move_constants.cpp +6 -6
  129. package/src/duckdb/src/optimizer/rule/ordered_aggregate_optimizer.cpp +2 -2
  130. package/src/duckdb/src/optimizer/rule/regex_optimizations.cpp +3 -3
  131. package/src/duckdb/src/parser/expression_util.cpp +6 -6
  132. package/src/duckdb/src/parser/parser.cpp +1 -1
  133. package/src/duckdb/src/parser/transform/expression/transform_operator.cpp +7 -3
  134. package/src/duckdb/src/parser/transform/helpers/transform_groupby.cpp +3 -3
  135. package/src/duckdb/src/parser/transformer.cpp +6 -5
  136. package/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +2 -2
  137. package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +3 -3
  138. package/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp +5 -5
  139. package/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +2 -2
  140. package/src/duckdb/src/planner/expression_binder/base_select_binder.cpp +4 -4
  141. package/src/duckdb/src/planner/expression_binder/order_binder.cpp +3 -3
  142. package/src/duckdb/src/storage/buffer/block_handle.cpp +3 -2
  143. package/src/duckdb/src/storage/buffer/block_manager.cpp +3 -1
  144. package/src/duckdb/src/storage/buffer/buffer_handle.cpp +1 -0
  145. package/src/duckdb/src/storage/buffer/buffer_pool_reservation.cpp +3 -0
  146. package/src/duckdb/src/storage/buffer_manager.cpp +35 -726
  147. package/src/duckdb/src/storage/checkpoint_manager.cpp +2 -2
  148. package/src/duckdb/src/storage/meta_block_reader.cpp +6 -5
  149. package/src/duckdb/src/storage/standard_buffer_manager.cpp +801 -0
  150. package/src/duckdb/src/storage/wal_replay.cpp +2 -2
  151. package/src/duckdb/src/transaction/meta_transaction.cpp +13 -13
  152. package/src/duckdb/src/transaction/transaction.cpp +1 -1
  153. package/src/duckdb/src/transaction/transaction_context.cpp +1 -1
  154. package/src/duckdb/third_party/libpg_query/include/parser/gram.hpp +949 -947
  155. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +16431 -16385
  156. package/src/duckdb/third_party/libpg_query/src_backend_parser_scan.cpp +503 -493
  157. package/src/duckdb/ub_src_function_scalar_string.cpp +2 -0
  158. package/src/duckdb/ub_src_storage.cpp +2 -0
@@ -0,0 +1,801 @@
1
+ #include "duckdb/storage/standard_buffer_manager.hpp"
2
+
3
+ #include "duckdb/common/allocator.hpp"
4
+ #include "duckdb/common/exception.hpp"
5
+ #include "duckdb/common/set.hpp"
6
+ #include "duckdb/storage/in_memory_block_manager.hpp"
7
+ #include "duckdb/storage/storage_manager.hpp"
8
+ #include "duckdb/main/attached_database.hpp"
9
+ #include "duckdb/main/database.hpp"
10
+ #include "duckdb/storage/buffer/buffer_pool.hpp"
11
+
12
+ namespace duckdb {
13
+
14
+ struct BufferAllocatorData : PrivateAllocatorData {
15
+ explicit BufferAllocatorData(StandardBufferManager &manager) : manager(manager) {
16
+ }
17
+
18
+ StandardBufferManager &manager;
19
+ };
20
+
21
+ unique_ptr<FileBuffer> StandardBufferManager::ConstructManagedBuffer(idx_t size, unique_ptr<FileBuffer> &&source,
22
+ FileBufferType type) {
23
+ if (source) {
24
+ auto tmp = std::move(source);
25
+ D_ASSERT(tmp->AllocSize() == BufferManager::GetAllocSize(size));
26
+ return make_uniq<FileBuffer>(*tmp, type);
27
+ } else {
28
+ // no re-usable buffer: allocate a new buffer
29
+ return make_uniq<FileBuffer>(Allocator::Get(db), type, size);
30
+ }
31
+ }
32
+
33
+ class TemporaryFileManager;
34
+
35
+ class TemporaryDirectoryHandle {
36
+ public:
37
+ TemporaryDirectoryHandle(DatabaseInstance &db, string path_p);
38
+ ~TemporaryDirectoryHandle();
39
+
40
+ TemporaryFileManager &GetTempFile();
41
+
42
+ private:
43
+ DatabaseInstance &db;
44
+ string temp_directory;
45
+ bool created_directory = false;
46
+ unique_ptr<TemporaryFileManager> temp_file;
47
+ };
48
+
49
+ void StandardBufferManager::SetTemporaryDirectory(const string &new_dir) {
50
+ if (temp_directory_handle) {
51
+ throw NotImplementedException("Cannot switch temporary directory after the current one has been used");
52
+ }
53
+ this->temp_directory = new_dir;
54
+ }
55
+
56
+ StandardBufferManager::StandardBufferManager(DatabaseInstance &db, string tmp)
57
+ : BufferManager(), db(db), buffer_pool(db.GetBufferPool()), temp_directory(std::move(tmp)),
58
+ temporary_id(MAXIMUM_BLOCK), buffer_allocator(BufferAllocatorAllocate, BufferAllocatorFree,
59
+ BufferAllocatorRealloc, make_uniq<BufferAllocatorData>(*this)) {
60
+ temp_block_manager = make_uniq<InMemoryBlockManager>(*this);
61
+ }
62
+
63
+ StandardBufferManager::~StandardBufferManager() {
64
+ }
65
+
66
+ BufferPool &StandardBufferManager::GetBufferPool() {
67
+ return buffer_pool;
68
+ }
69
+
70
+ idx_t StandardBufferManager::GetUsedMemory() const {
71
+ return buffer_pool.GetUsedMemory();
72
+ }
73
+ idx_t StandardBufferManager::GetMaxMemory() const {
74
+ return buffer_pool.GetMaxMemory();
75
+ }
76
+
77
+ // POTENTIALLY PROBLEMATIC
78
+ // void StandardBufferManager::IncreaseUsedMemory(idx_t size, bool unsafe) {
79
+ // if (!unsafe && buffer_pool.GetUsedMemory() + size > buffer_pool.GetMaxMemory()) {
80
+ // throw OutOfMemoryException("Failed to allocate data of size %lld%s", size, InMemoryWarning());
81
+ // }
82
+ // buffer_pool.IncreaseUsedMemory(size);
83
+ //}
84
+
85
+ template <typename... ARGS>
86
+ TempBufferPoolReservation StandardBufferManager::EvictBlocksOrThrow(idx_t memory_delta, unique_ptr<FileBuffer> *buffer,
87
+ ARGS... args) {
88
+ auto r = buffer_pool.EvictBlocks(memory_delta, buffer_pool.maximum_memory, buffer);
89
+ if (!r.success) {
90
+ throw OutOfMemoryException(args..., InMemoryWarning());
91
+ }
92
+ return std::move(r.reservation);
93
+ }
94
+
95
+ shared_ptr<BlockHandle> StandardBufferManager::RegisterSmallMemory(idx_t block_size) {
96
+ D_ASSERT(block_size < Storage::BLOCK_SIZE);
97
+ auto res = EvictBlocksOrThrow(block_size, nullptr, "could not allocate block of %lld bytes (%lld/%lld used) %s",
98
+ block_size, GetUsedMemory(), GetMaxMemory());
99
+
100
+ auto buffer = ConstructManagedBuffer(block_size, nullptr, FileBufferType::TINY_BUFFER);
101
+
102
+ // create a new block pointer for this block
103
+ return make_shared<BlockHandle>(*temp_block_manager, ++temporary_id, std::move(buffer), false, block_size,
104
+ std::move(res));
105
+ }
106
+
107
+ shared_ptr<BlockHandle> StandardBufferManager::RegisterMemory(idx_t block_size, bool can_destroy) {
108
+ D_ASSERT(block_size >= Storage::BLOCK_SIZE);
109
+ auto alloc_size = GetAllocSize(block_size);
110
+ // first evict blocks until we have enough memory to store this buffer
111
+ unique_ptr<FileBuffer> reusable_buffer;
112
+ auto res =
113
+ EvictBlocksOrThrow(alloc_size, &reusable_buffer, "could not allocate block of %lld bytes (%lld/%lld used) %s",
114
+ alloc_size, GetUsedMemory(), GetMaxMemory());
115
+
116
+ auto buffer = ConstructManagedBuffer(block_size, std::move(reusable_buffer));
117
+
118
+ // create a new block pointer for this block
119
+ return make_shared<BlockHandle>(*temp_block_manager, ++temporary_id, std::move(buffer), can_destroy, alloc_size,
120
+ std::move(res));
121
+ }
122
+
123
+ BufferHandle StandardBufferManager::Allocate(idx_t block_size, bool can_destroy, shared_ptr<BlockHandle> *block) {
124
+ shared_ptr<BlockHandle> local_block;
125
+ auto block_ptr = block ? block : &local_block;
126
+ *block_ptr = RegisterMemory(block_size, can_destroy);
127
+ return Pin(*block_ptr);
128
+ }
129
+
130
+ void StandardBufferManager::ReAllocate(shared_ptr<BlockHandle> &handle, idx_t block_size) {
131
+ D_ASSERT(block_size >= Storage::BLOCK_SIZE);
132
+ lock_guard<mutex> lock(handle->lock);
133
+ D_ASSERT(handle->state == BlockState::BLOCK_LOADED);
134
+ D_ASSERT(handle->memory_usage == handle->buffer->AllocSize());
135
+ D_ASSERT(handle->memory_usage == handle->memory_charge.size);
136
+
137
+ auto req = handle->buffer->CalculateMemory(block_size);
138
+ int64_t memory_delta = (int64_t)req.alloc_size - handle->memory_usage;
139
+
140
+ if (memory_delta == 0) {
141
+ return;
142
+ } else if (memory_delta > 0) {
143
+ // evict blocks until we have space to resize this block
144
+ auto reservation = EvictBlocksOrThrow(memory_delta, nullptr, "failed to resize block from %lld to %lld%s",
145
+ handle->memory_usage, req.alloc_size);
146
+ // EvictBlocks decrements 'current_memory' for us.
147
+ handle->memory_charge.Merge(std::move(reservation));
148
+ } else {
149
+ // no need to evict blocks, but we do need to decrement 'current_memory'.
150
+ handle->memory_charge.Resize(req.alloc_size);
151
+ }
152
+
153
+ handle->ResizeBuffer(block_size, memory_delta);
154
+ }
155
+
156
+ BufferHandle StandardBufferManager::Pin(shared_ptr<BlockHandle> &handle) {
157
+ idx_t required_memory;
158
+ {
159
+ // lock the block
160
+ lock_guard<mutex> lock(handle->lock);
161
+ // check if the block is already loaded
162
+ if (handle->state == BlockState::BLOCK_LOADED) {
163
+ // the block is loaded, increment the reader count and return a pointer to the handle
164
+ handle->readers++;
165
+ return handle->Load(handle);
166
+ }
167
+ required_memory = handle->memory_usage;
168
+ }
169
+ // evict blocks until we have space for the current block
170
+ unique_ptr<FileBuffer> reusable_buffer;
171
+ auto reservation =
172
+ EvictBlocksOrThrow(required_memory, &reusable_buffer, "failed to pin block of size %lld%s", required_memory);
173
+ // lock the handle again and repeat the check (in case anybody loaded in the mean time)
174
+ lock_guard<mutex> lock(handle->lock);
175
+ // check if the block is already loaded
176
+ if (handle->state == BlockState::BLOCK_LOADED) {
177
+ // the block is loaded, increment the reader count and return a pointer to the handle
178
+ handle->readers++;
179
+ reservation.Resize(0);
180
+ return handle->Load(handle);
181
+ }
182
+ // now we can actually load the current block
183
+ D_ASSERT(handle->readers == 0);
184
+ handle->readers = 1;
185
+ auto buf = handle->Load(handle, std::move(reusable_buffer));
186
+ handle->memory_charge = std::move(reservation);
187
+ // In the case of a variable sized block, the buffer may be smaller than a full block.
188
+ int64_t delta = handle->buffer->AllocSize() - handle->memory_usage;
189
+ if (delta) {
190
+ D_ASSERT(delta < 0);
191
+ handle->memory_usage += delta;
192
+ handle->memory_charge.Resize(handle->memory_usage);
193
+ }
194
+ D_ASSERT(handle->memory_usage == handle->buffer->AllocSize());
195
+ return buf;
196
+ }
197
+
198
+ void StandardBufferManager::PurgeQueue() {
199
+ buffer_pool.PurgeQueue();
200
+ }
201
+
202
+ void StandardBufferManager::AddToEvictionQueue(shared_ptr<BlockHandle> &handle) {
203
+ buffer_pool.AddToEvictionQueue(handle);
204
+ }
205
+
206
+ void StandardBufferManager::VerifyZeroReaders(shared_ptr<BlockHandle> &handle) {
207
+ #ifdef DUCKDB_DEBUG_DESTROY_BLOCKS
208
+ auto replacement_buffer = make_uniq<FileBuffer>(Allocator::Get(db), handle->buffer->type,
209
+ handle->memory_usage - Storage::BLOCK_HEADER_SIZE);
210
+ memcpy(replacement_buffer->buffer, handle->buffer->buffer, handle->buffer->size);
211
+ memset(handle->buffer->buffer, 165, handle->buffer->size); // 165 is default memory in debug mode
212
+ handle->buffer = std::move(replacement_buffer);
213
+ #endif
214
+ }
215
+
216
+ void StandardBufferManager::Unpin(shared_ptr<BlockHandle> &handle) {
217
+ lock_guard<mutex> lock(handle->lock);
218
+ if (!handle->buffer || handle->buffer->type == FileBufferType::TINY_BUFFER) {
219
+ return;
220
+ }
221
+ D_ASSERT(handle->readers > 0);
222
+ handle->readers--;
223
+ if (handle->readers == 0) {
224
+ VerifyZeroReaders(handle);
225
+ buffer_pool.AddToEvictionQueue(handle);
226
+ }
227
+ }
228
+
229
+ // POTENTIALLY PROBLEMATIC
230
+ void StandardBufferManager::IncreaseUsedMemory(idx_t size, bool unsafe) {
231
+ ReserveMemory(size);
232
+ }
233
+
234
+ void StandardBufferManager::DecreaseUsedMemory(idx_t size) {
235
+ FreeReservedMemory(size);
236
+ }
237
+
238
+ void StandardBufferManager::SetLimit(idx_t limit) {
239
+ buffer_pool.SetLimit(limit, InMemoryWarning());
240
+ }
241
+
242
+ //===--------------------------------------------------------------------===//
243
+ // Temporary File Management
244
+ //===--------------------------------------------------------------------===//
245
+ unique_ptr<FileBuffer> ReadTemporaryBufferInternal(BufferManager &buffer_manager, FileHandle &handle, idx_t position,
246
+ idx_t size, block_id_t id, unique_ptr<FileBuffer> reusable_buffer) {
247
+ auto buffer = buffer_manager.ConstructManagedBuffer(size, std::move(reusable_buffer));
248
+ buffer->Read(handle, position);
249
+ return buffer;
250
+ }
251
+
252
+ struct TemporaryFileIndex {
253
+ explicit TemporaryFileIndex(idx_t file_index = DConstants::INVALID_INDEX,
254
+ idx_t block_index = DConstants::INVALID_INDEX)
255
+ : file_index(file_index), block_index(block_index) {
256
+ }
257
+
258
+ idx_t file_index;
259
+ idx_t block_index;
260
+
261
+ public:
262
+ bool IsValid() {
263
+ return block_index != DConstants::INVALID_INDEX;
264
+ }
265
+ };
266
+
267
+ struct BlockIndexManager {
268
+ BlockIndexManager() : max_index(0) {
269
+ }
270
+
271
+ public:
272
+ //! Obtains a new block index from the index manager
273
+ idx_t GetNewBlockIndex() {
274
+ auto index = GetNewBlockIndexInternal();
275
+ indexes_in_use.insert(index);
276
+ return index;
277
+ }
278
+
279
+ //! Removes an index from the block manager
280
+ //! Returns true if the max_index has been altered
281
+ bool RemoveIndex(idx_t index) {
282
+ // remove this block from the set of blocks
283
+ auto entry = indexes_in_use.find(index);
284
+ if (entry == indexes_in_use.end()) {
285
+ throw InternalException("RemoveIndex - index %llu not found in indexes_in_use", index);
286
+ }
287
+ indexes_in_use.erase(entry);
288
+ free_indexes.insert(index);
289
+ // check if we can truncate the file
290
+
291
+ // get the max_index in use right now
292
+ auto max_index_in_use = indexes_in_use.empty() ? 0 : *indexes_in_use.rbegin();
293
+ if (max_index_in_use < max_index) {
294
+ // max index in use is lower than the max_index
295
+ // reduce the max_index
296
+ max_index = indexes_in_use.empty() ? 0 : max_index_in_use + 1;
297
+ // we can remove any free_indexes that are larger than the current max_index
298
+ while (!free_indexes.empty()) {
299
+ auto max_entry = *free_indexes.rbegin();
300
+ if (max_entry < max_index) {
301
+ break;
302
+ }
303
+ free_indexes.erase(max_entry);
304
+ }
305
+ return true;
306
+ }
307
+ return false;
308
+ }
309
+
310
+ idx_t GetMaxIndex() {
311
+ return max_index;
312
+ }
313
+
314
+ bool HasFreeBlocks() {
315
+ return !free_indexes.empty();
316
+ }
317
+
318
+ private:
319
+ idx_t GetNewBlockIndexInternal() {
320
+ if (free_indexes.empty()) {
321
+ return max_index++;
322
+ }
323
+ auto entry = free_indexes.begin();
324
+ auto index = *entry;
325
+ free_indexes.erase(entry);
326
+ return index;
327
+ }
328
+
329
+ idx_t max_index;
330
+ set<idx_t> free_indexes;
331
+ set<idx_t> indexes_in_use;
332
+ };
333
+
334
+ class TemporaryFileHandle {
335
+ constexpr static idx_t MAX_ALLOWED_INDEX = 4000;
336
+
337
+ public:
338
+ TemporaryFileHandle(DatabaseInstance &db, const string &temp_directory, idx_t index)
339
+ : db(db), file_index(index), path(FileSystem::GetFileSystem(db).JoinPath(
340
+ temp_directory, "duckdb_temp_storage-" + to_string(index) + ".tmp")) {
341
+ }
342
+
343
+ public:
344
+ struct TemporaryFileLock {
345
+ explicit TemporaryFileLock(mutex &mutex) : lock(mutex) {
346
+ }
347
+
348
+ lock_guard<mutex> lock;
349
+ };
350
+
351
+ public:
352
+ TemporaryFileIndex TryGetBlockIndex() {
353
+ TemporaryFileLock lock(file_lock);
354
+ if (index_manager.GetMaxIndex() >= MAX_ALLOWED_INDEX && index_manager.HasFreeBlocks()) {
355
+ // file is at capacity
356
+ return TemporaryFileIndex();
357
+ }
358
+ // open the file handle if it does not yet exist
359
+ CreateFileIfNotExists(lock);
360
+ // fetch a new block index to write to
361
+ auto block_index = index_manager.GetNewBlockIndex();
362
+ return TemporaryFileIndex(file_index, block_index);
363
+ }
364
+
365
+ void WriteTemporaryFile(FileBuffer &buffer, TemporaryFileIndex index) {
366
+ D_ASSERT(buffer.size == Storage::BLOCK_SIZE);
367
+ buffer.Write(*handle, GetPositionInFile(index.block_index));
368
+ }
369
+
370
+ unique_ptr<FileBuffer> ReadTemporaryBuffer(block_id_t id, idx_t block_index,
371
+ unique_ptr<FileBuffer> reusable_buffer) {
372
+ return ReadTemporaryBufferInternal(BufferManager::GetBufferManager(db), *handle, GetPositionInFile(block_index),
373
+ Storage::BLOCK_SIZE, id, std::move(reusable_buffer));
374
+ }
375
+
376
+ void EraseBlockIndex(block_id_t block_index) {
377
+ // remove the block (and potentially truncate the temp file)
378
+ TemporaryFileLock lock(file_lock);
379
+ D_ASSERT(handle);
380
+ RemoveTempBlockIndex(lock, block_index);
381
+ }
382
+
383
+ bool DeleteIfEmpty() {
384
+ TemporaryFileLock lock(file_lock);
385
+ if (index_manager.GetMaxIndex() > 0) {
386
+ // there are still blocks in this file
387
+ return false;
388
+ }
389
+ // the file is empty: delete it
390
+ handle.reset();
391
+ auto &fs = FileSystem::GetFileSystem(db);
392
+ fs.RemoveFile(path);
393
+ return true;
394
+ }
395
+
396
+ TemporaryFileInformation GetTemporaryFile() {
397
+ TemporaryFileLock lock(file_lock);
398
+ TemporaryFileInformation info;
399
+ info.path = path;
400
+ info.size = GetPositionInFile(index_manager.GetMaxIndex());
401
+ return info;
402
+ }
403
+
404
+ private:
405
+ void CreateFileIfNotExists(TemporaryFileLock &) {
406
+ if (handle) {
407
+ return;
408
+ }
409
+ auto &fs = FileSystem::GetFileSystem(db);
410
+ handle = fs.OpenFile(path, FileFlags::FILE_FLAGS_READ | FileFlags::FILE_FLAGS_WRITE |
411
+ FileFlags::FILE_FLAGS_FILE_CREATE);
412
+ }
413
+
414
+ void RemoveTempBlockIndex(TemporaryFileLock &, idx_t index) {
415
+ // remove the block index from the index manager
416
+ if (index_manager.RemoveIndex(index)) {
417
+ // the max_index that is currently in use has decreased
418
+ // as a result we can truncate the file
419
+ #ifndef WIN32 // this ended up causing issues when sorting
420
+ auto max_index = index_manager.GetMaxIndex();
421
+ auto &fs = FileSystem::GetFileSystem(db);
422
+ fs.Truncate(*handle, GetPositionInFile(max_index + 1));
423
+ #endif
424
+ }
425
+ }
426
+
427
+ idx_t GetPositionInFile(idx_t index) {
428
+ return index * Storage::BLOCK_ALLOC_SIZE;
429
+ }
430
+
431
+ private:
432
+ DatabaseInstance &db;
433
+ unique_ptr<FileHandle> handle;
434
+ idx_t file_index;
435
+ string path;
436
+ mutex file_lock;
437
+ BlockIndexManager index_manager;
438
+ };
439
+
440
+ class TemporaryFileManager {
441
+ public:
442
+ TemporaryFileManager(DatabaseInstance &db, const string &temp_directory_p)
443
+ : db(db), temp_directory(temp_directory_p) {
444
+ }
445
+
446
+ public:
447
+ struct TemporaryManagerLock {
448
+ explicit TemporaryManagerLock(mutex &mutex) : lock(mutex) {
449
+ }
450
+
451
+ lock_guard<mutex> lock;
452
+ };
453
+
454
+ void WriteTemporaryBuffer(block_id_t block_id, FileBuffer &buffer) {
455
+ D_ASSERT(buffer.size == Storage::BLOCK_SIZE);
456
+ TemporaryFileIndex index;
457
+ TemporaryFileHandle *handle = nullptr;
458
+
459
+ {
460
+ TemporaryManagerLock lock(manager_lock);
461
+ // first check if we can write to an open existing file
462
+ for (auto &entry : files) {
463
+ auto &temp_file = entry.second;
464
+ index = temp_file->TryGetBlockIndex();
465
+ if (index.IsValid()) {
466
+ handle = entry.second.get();
467
+ break;
468
+ }
469
+ }
470
+ if (!handle) {
471
+ // no existing handle to write to; we need to create & open a new file
472
+ auto new_file_index = index_manager.GetNewBlockIndex();
473
+ auto new_file = make_uniq<TemporaryFileHandle>(db, temp_directory, new_file_index);
474
+ handle = new_file.get();
475
+ files[new_file_index] = std::move(new_file);
476
+
477
+ index = handle->TryGetBlockIndex();
478
+ }
479
+ D_ASSERT(used_blocks.find(block_id) == used_blocks.end());
480
+ used_blocks[block_id] = index;
481
+ }
482
+ D_ASSERT(handle);
483
+ D_ASSERT(index.IsValid());
484
+ handle->WriteTemporaryFile(buffer, index);
485
+ }
486
+
487
+ bool HasTemporaryBuffer(block_id_t block_id) {
488
+ lock_guard<mutex> lock(manager_lock);
489
+ return used_blocks.find(block_id) != used_blocks.end();
490
+ }
491
+
492
+ unique_ptr<FileBuffer> ReadTemporaryBuffer(block_id_t id, unique_ptr<FileBuffer> reusable_buffer) {
493
+ TemporaryFileIndex index;
494
+ TemporaryFileHandle *handle;
495
+ {
496
+ TemporaryManagerLock lock(manager_lock);
497
+ index = GetTempBlockIndex(lock, id);
498
+ handle = GetFileHandle(lock, index.file_index);
499
+ }
500
+ auto buffer = handle->ReadTemporaryBuffer(id, index.block_index, std::move(reusable_buffer));
501
+ {
502
+ // remove the block (and potentially erase the temp file)
503
+ TemporaryManagerLock lock(manager_lock);
504
+ EraseUsedBlock(lock, id, handle, index);
505
+ }
506
+ return buffer;
507
+ }
508
+
509
+ void DeleteTemporaryBuffer(block_id_t id) {
510
+ TemporaryManagerLock lock(manager_lock);
511
+ auto index = GetTempBlockIndex(lock, id);
512
+ auto handle = GetFileHandle(lock, index.file_index);
513
+ EraseUsedBlock(lock, id, handle, index);
514
+ }
515
+
516
+ vector<TemporaryFileInformation> GetTemporaryFiles() {
517
+ lock_guard<mutex> lock(manager_lock);
518
+ vector<TemporaryFileInformation> result;
519
+ for (auto &file : files) {
520
+ result.push_back(file.second->GetTemporaryFile());
521
+ }
522
+ return result;
523
+ }
524
+
525
+ private:
526
+ void EraseUsedBlock(TemporaryManagerLock &lock, block_id_t id, TemporaryFileHandle *handle,
527
+ TemporaryFileIndex index) {
528
+ auto entry = used_blocks.find(id);
529
+ if (entry == used_blocks.end()) {
530
+ throw InternalException("EraseUsedBlock - Block %llu not found in used blocks", id);
531
+ }
532
+ used_blocks.erase(entry);
533
+ handle->EraseBlockIndex(index.block_index);
534
+ if (handle->DeleteIfEmpty()) {
535
+ EraseFileHandle(lock, index.file_index);
536
+ }
537
+ }
538
+
539
+ TemporaryFileHandle *GetFileHandle(TemporaryManagerLock &, idx_t index) {
540
+ return files[index].get();
541
+ }
542
+
543
+ TemporaryFileIndex GetTempBlockIndex(TemporaryManagerLock &, block_id_t id) {
544
+ D_ASSERT(used_blocks.find(id) != used_blocks.end());
545
+ return used_blocks[id];
546
+ }
547
+
548
+ void EraseFileHandle(TemporaryManagerLock &, idx_t file_index) {
549
+ files.erase(file_index);
550
+ index_manager.RemoveIndex(file_index);
551
+ }
552
+
553
+ private:
554
+ DatabaseInstance &db;
555
+ mutex manager_lock;
556
+ //! The temporary directory
557
+ string temp_directory;
558
+ //! The set of active temporary file handles
559
+ unordered_map<idx_t, unique_ptr<TemporaryFileHandle>> files;
560
+ //! map of block_id -> temporary file position
561
+ unordered_map<block_id_t, TemporaryFileIndex> used_blocks;
562
+ //! Manager of in-use temporary file indexes
563
+ BlockIndexManager index_manager;
564
+ };
565
+
566
+ TemporaryDirectoryHandle::TemporaryDirectoryHandle(DatabaseInstance &db, string path_p)
567
+ : db(db), temp_directory(std::move(path_p)), temp_file(make_uniq<TemporaryFileManager>(db, temp_directory)) {
568
+ auto &fs = FileSystem::GetFileSystem(db);
569
+ if (!temp_directory.empty()) {
570
+ if (!fs.DirectoryExists(temp_directory)) {
571
+ fs.CreateDirectory(temp_directory);
572
+ created_directory = true;
573
+ }
574
+ }
575
+ }
576
+ TemporaryDirectoryHandle::~TemporaryDirectoryHandle() {
577
+ // first release any temporary files
578
+ temp_file.reset();
579
+ // then delete the temporary file directory
580
+ auto &fs = FileSystem::GetFileSystem(db);
581
+ if (!temp_directory.empty()) {
582
+ bool delete_directory = created_directory;
583
+ vector<string> files_to_delete;
584
+ if (!created_directory) {
585
+ bool deleted_everything = true;
586
+ fs.ListFiles(temp_directory, [&](const string &path, bool isdir) {
587
+ if (isdir) {
588
+ deleted_everything = false;
589
+ return;
590
+ }
591
+ if (!StringUtil::StartsWith(path, "duckdb_temp_")) {
592
+ deleted_everything = false;
593
+ return;
594
+ }
595
+ files_to_delete.push_back(path);
596
+ });
597
+ }
598
+ if (delete_directory) {
599
+ // we want to remove all files in the directory
600
+ fs.RemoveDirectory(temp_directory);
601
+ } else {
602
+ for (auto &file : files_to_delete) {
603
+ fs.RemoveFile(fs.JoinPath(temp_directory, file));
604
+ }
605
+ }
606
+ }
607
+ }
608
+
609
+ TemporaryFileManager &TemporaryDirectoryHandle::GetTempFile() {
610
+ return *temp_file;
611
+ }
612
+
613
+ string StandardBufferManager::GetTemporaryPath(block_id_t id) {
614
+ auto &fs = FileSystem::GetFileSystem(db);
615
+ return fs.JoinPath(temp_directory, "duckdb_temp_block-" + to_string(id) + ".block");
616
+ }
617
+
618
+ void StandardBufferManager::RequireTemporaryDirectory() {
619
+ if (temp_directory.empty()) {
620
+ throw Exception(
621
+ "Out-of-memory: cannot write buffer because no temporary directory is specified!\nTo enable "
622
+ "temporary buffer eviction set a temporary directory using PRAGMA temp_directory='/path/to/tmp.tmp'");
623
+ }
624
+ lock_guard<mutex> temp_handle_guard(temp_handle_lock);
625
+ if (!temp_directory_handle) {
626
+ // temp directory has not been created yet: initialize it
627
+ temp_directory_handle = make_uniq<TemporaryDirectoryHandle>(db, temp_directory);
628
+ }
629
+ }
630
+
631
+ void StandardBufferManager::WriteTemporaryBuffer(block_id_t block_id, FileBuffer &buffer) {
632
+ RequireTemporaryDirectory();
633
+ if (buffer.size == Storage::BLOCK_SIZE) {
634
+ temp_directory_handle->GetTempFile().WriteTemporaryBuffer(block_id, buffer);
635
+ return;
636
+ }
637
+ // get the path to write to
638
+ auto path = GetTemporaryPath(block_id);
639
+ D_ASSERT(buffer.size > Storage::BLOCK_SIZE);
640
+ // create the file and write the size followed by the buffer contents
641
+ auto &fs = FileSystem::GetFileSystem(db);
642
+ auto handle = fs.OpenFile(path, FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_FILE_CREATE);
643
+ handle->Write(&buffer.size, sizeof(idx_t), 0);
644
+ buffer.Write(*handle, sizeof(idx_t));
645
+ }
646
+
647
+ unique_ptr<FileBuffer> StandardBufferManager::ReadTemporaryBuffer(block_id_t id,
648
+ unique_ptr<FileBuffer> reusable_buffer) {
649
+ D_ASSERT(!temp_directory.empty());
650
+ D_ASSERT(temp_directory_handle.get());
651
+ if (temp_directory_handle->GetTempFile().HasTemporaryBuffer(id)) {
652
+ return temp_directory_handle->GetTempFile().ReadTemporaryBuffer(id, std::move(reusable_buffer));
653
+ }
654
+ idx_t block_size;
655
+ // open the temporary file and read the size
656
+ auto path = GetTemporaryPath(id);
657
+ auto &fs = FileSystem::GetFileSystem(db);
658
+ auto handle = fs.OpenFile(path, FileFlags::FILE_FLAGS_READ);
659
+ handle->Read(&block_size, sizeof(idx_t), 0);
660
+
661
+ // now allocate a buffer of this size and read the data into that buffer
662
+ auto buffer =
663
+ ReadTemporaryBufferInternal(*this, *handle, sizeof(idx_t), block_size, id, std::move(reusable_buffer));
664
+
665
+ handle.reset();
666
+ DeleteTemporaryFile(id);
667
+ return buffer;
668
+ }
669
+
670
+ void StandardBufferManager::DeleteTemporaryFile(block_id_t id) {
671
+ if (temp_directory.empty()) {
672
+ // no temporary directory specified: nothing to delete
673
+ return;
674
+ }
675
+ {
676
+ lock_guard<mutex> temp_handle_guard(temp_handle_lock);
677
+ if (!temp_directory_handle) {
678
+ // temporary directory was not initialized yet: nothing to delete
679
+ return;
680
+ }
681
+ }
682
+ // check if we should delete the file from the shared pool of files, or from the general file system
683
+ if (temp_directory_handle->GetTempFile().HasTemporaryBuffer(id)) {
684
+ temp_directory_handle->GetTempFile().DeleteTemporaryBuffer(id);
685
+ return;
686
+ }
687
+ auto &fs = FileSystem::GetFileSystem(db);
688
+ auto path = GetTemporaryPath(id);
689
+ if (fs.FileExists(path)) {
690
+ fs.RemoveFile(path);
691
+ }
692
+ }
693
+
694
+ bool StandardBufferManager::HasTemporaryDirectory() const {
695
+ return !temp_directory.empty();
696
+ }
697
+
698
+ vector<TemporaryFileInformation> StandardBufferManager::GetTemporaryFiles() {
699
+ vector<TemporaryFileInformation> result;
700
+ if (temp_directory.empty()) {
701
+ return result;
702
+ }
703
+ {
704
+ lock_guard<mutex> temp_handle_guard(temp_handle_lock);
705
+ if (temp_directory_handle) {
706
+ result = temp_directory_handle->GetTempFile().GetTemporaryFiles();
707
+ }
708
+ }
709
+ auto &fs = FileSystem::GetFileSystem(db);
710
+ fs.ListFiles(temp_directory, [&](const string &name, bool is_dir) {
711
+ if (is_dir) {
712
+ return;
713
+ }
714
+ if (!StringUtil::EndsWith(name, ".block")) {
715
+ return;
716
+ }
717
+ TemporaryFileInformation info;
718
+ info.path = name;
719
+ auto handle = fs.OpenFile(name, FileFlags::FILE_FLAGS_READ);
720
+ info.size = fs.GetFileSize(*handle);
721
+ handle.reset();
722
+ result.push_back(info);
723
+ });
724
+ return result;
725
+ }
726
+
727
+ const char *StandardBufferManager::InMemoryWarning() {
728
+ if (!temp_directory.empty()) {
729
+ return "";
730
+ }
731
+ return "\nDatabase is launched in in-memory mode and no temporary directory is specified."
732
+ "\nUnused blocks cannot be offloaded to disk."
733
+ "\n\nLaunch the database with a persistent storage back-end"
734
+ "\nOr set PRAGMA temp_directory='/path/to/tmp.tmp'";
735
+ }
736
+
737
+ void StandardBufferManager::ReserveMemory(idx_t size) {
738
+ if (size == 0) {
739
+ return;
740
+ }
741
+ auto reservation = EvictBlocksOrThrow(size, nullptr, "failed to reserve memory data of size %lld%s", size);
742
+ reservation.size = 0;
743
+ }
744
+
745
+ void StandardBufferManager::FreeReservedMemory(idx_t size) {
746
+ if (size == 0) {
747
+ return;
748
+ }
749
+ buffer_pool.current_memory -= size;
750
+ }
751
+
752
+ //===--------------------------------------------------------------------===//
753
+ // Buffer Allocator
754
+ //===--------------------------------------------------------------------===//
755
+ data_ptr_t StandardBufferManager::BufferAllocatorAllocate(PrivateAllocatorData *private_data, idx_t size) {
756
+ auto &data = (BufferAllocatorData &)*private_data;
757
+ auto reservation = data.manager.EvictBlocksOrThrow(size, nullptr, "failed to allocate data of size %lld%s", size);
758
+ // We rely on manual tracking of this one. :(
759
+ reservation.size = 0;
760
+ return Allocator::Get(data.manager.db).AllocateData(size);
761
+ }
762
+
763
+ void StandardBufferManager::BufferAllocatorFree(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t size) {
764
+ auto &data = (BufferAllocatorData &)*private_data;
765
+ BufferPoolReservation r(data.manager.GetBufferPool());
766
+ r.size = size;
767
+ r.Resize(0);
768
+ return Allocator::Get(data.manager.db).FreeData(pointer, size);
769
+ }
770
+
771
+ data_ptr_t StandardBufferManager::BufferAllocatorRealloc(PrivateAllocatorData *private_data, data_ptr_t pointer,
772
+ idx_t old_size, idx_t size) {
773
+ if (old_size == size) {
774
+ return pointer;
775
+ }
776
+ auto &data = (BufferAllocatorData &)*private_data;
777
+ BufferPoolReservation r(data.manager.GetBufferPool());
778
+ r.size = old_size;
779
+ r.Resize(size);
780
+ r.size = 0;
781
+ return Allocator::Get(data.manager.db).ReallocateData(pointer, old_size, size);
782
+ }
783
+
784
+ Allocator &BufferAllocator::Get(ClientContext &context) {
785
+ auto &manager = StandardBufferManager::GetBufferManager(context);
786
+ return manager.GetBufferAllocator();
787
+ }
788
+
789
+ Allocator &BufferAllocator::Get(DatabaseInstance &db) {
790
+ return StandardBufferManager::GetBufferManager(db).GetBufferAllocator();
791
+ }
792
+
793
+ Allocator &BufferAllocator::Get(AttachedDatabase &db) {
794
+ return BufferAllocator::Get(db.GetDatabase());
795
+ }
796
+
797
+ Allocator &StandardBufferManager::GetBufferAllocator() {
798
+ return buffer_allocator;
799
+ }
800
+
801
+ } // namespace duckdb