duckdb 0.7.2-dev1684.0 → 0.7.2-dev1734.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 (24) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/extension/icu/icu-datefunc.cpp +20 -8
  3. package/src/duckdb/extension/icu/icu-strptime.cpp +117 -29
  4. package/src/duckdb/extension/icu/include/icu-datefunc.hpp +2 -0
  5. package/src/duckdb/src/common/local_file_system.cpp +13 -2
  6. package/src/duckdb/src/common/sort/partition_state.cpp +644 -0
  7. package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +77 -849
  8. package/src/duckdb/src/function/table/system/duckdb_extensions.cpp +2 -2
  9. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  10. package/src/duckdb/src/include/duckdb/common/sort/partition_state.hpp +247 -0
  11. package/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +1 -2
  12. package/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp +77 -0
  13. package/src/duckdb/src/include/duckdb/storage/buffer/temporary_file_information.hpp +12 -0
  14. package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +3 -59
  15. package/src/duckdb/src/main/extension/extension_install.cpp +11 -0
  16. package/src/duckdb/src/main/extension/extension_load.cpp +29 -3
  17. package/src/duckdb/src/storage/buffer/block_handle.cpp +128 -0
  18. package/src/duckdb/src/storage/buffer/block_manager.cpp +81 -0
  19. package/src/duckdb/src/storage/buffer/buffer_pool.cpp +132 -0
  20. package/src/duckdb/src/storage/buffer/buffer_pool_reservation.cpp +32 -0
  21. package/src/duckdb/src/storage/buffer_manager.cpp +0 -351
  22. package/src/duckdb/third_party/libpg_query/postgres_parser.cpp +3 -5
  23. package/src/duckdb/ub_src_common_sort.cpp +2 -0
  24. package/src/duckdb/ub_src_storage_buffer.cpp +8 -0
@@ -0,0 +1,81 @@
1
+ #include "duckdb/storage/block_manager.hpp"
2
+ #include "duckdb/storage/buffer_manager.hpp"
3
+
4
+ namespace duckdb {
5
+
6
+ shared_ptr<BlockHandle> BlockManager::RegisterBlock(block_id_t block_id, bool is_meta_block) {
7
+ lock_guard<mutex> lock(blocks_lock);
8
+ // check if the block already exists
9
+ auto entry = blocks.find(block_id);
10
+ if (entry != blocks.end()) {
11
+ // already exists: check if it hasn't expired yet
12
+ auto existing_ptr = entry->second.lock();
13
+ if (existing_ptr) {
14
+ //! it hasn't! return it
15
+ return existing_ptr;
16
+ }
17
+ }
18
+ // create a new block pointer for this block
19
+ auto result = make_shared<BlockHandle>(*this, block_id);
20
+ // for meta block, cache the handle in meta_blocks
21
+ if (is_meta_block) {
22
+ meta_blocks[block_id] = result;
23
+ }
24
+ // register the block pointer in the set of blocks as a weak pointer
25
+ blocks[block_id] = weak_ptr<BlockHandle>(result);
26
+ return result;
27
+ }
28
+
29
+ void BlockManager::ClearMetaBlockHandles() {
30
+ meta_blocks.clear();
31
+ }
32
+
33
+ shared_ptr<BlockHandle> BlockManager::ConvertToPersistent(block_id_t block_id, shared_ptr<BlockHandle> old_block) {
34
+
35
+ // pin the old block to ensure we have it loaded in memory
36
+ auto old_handle = buffer_manager.Pin(old_block);
37
+ D_ASSERT(old_block->state == BlockState::BLOCK_LOADED);
38
+ D_ASSERT(old_block->buffer);
39
+
40
+ // Temp buffers can be larger than the storage block size. But persistent buffers
41
+ // cannot.
42
+ D_ASSERT(old_block->buffer->AllocSize() <= Storage::BLOCK_ALLOC_SIZE);
43
+
44
+ // register a block with the new block id
45
+ auto new_block = RegisterBlock(block_id);
46
+ D_ASSERT(new_block->state == BlockState::BLOCK_UNLOADED);
47
+ D_ASSERT(new_block->readers == 0);
48
+
49
+ // move the data from the old block into data for the new block
50
+ new_block->state = BlockState::BLOCK_LOADED;
51
+ new_block->buffer = CreateBlock(block_id, old_block->buffer.get());
52
+ new_block->memory_usage = old_block->memory_usage;
53
+ new_block->memory_charge = std::move(old_block->memory_charge);
54
+
55
+ // clear the old buffer and unload it
56
+ old_block->buffer.reset();
57
+ old_block->state = BlockState::BLOCK_UNLOADED;
58
+ old_block->memory_usage = 0;
59
+ old_handle.Destroy();
60
+ old_block.reset();
61
+
62
+ // persist the new block to disk
63
+ Write(*new_block->buffer, block_id);
64
+
65
+ buffer_manager.buffer_pool.AddToEvictionQueue(new_block);
66
+
67
+ return new_block;
68
+ }
69
+
70
+ void BlockManager::UnregisterBlock(block_id_t block_id, bool can_destroy) {
71
+ if (block_id >= MAXIMUM_BLOCK) {
72
+ // in-memory buffer: buffer could have been offloaded to disk: remove the file
73
+ buffer_manager.DeleteTemporaryFile(block_id);
74
+ } else {
75
+ lock_guard<mutex> lock(blocks_lock);
76
+ // on-disk block: erase from list of blocks in manager
77
+ blocks.erase(block_id);
78
+ }
79
+ }
80
+
81
+ } // namespace duckdb
@@ -0,0 +1,132 @@
1
+ #include "duckdb/storage/buffer/buffer_pool.hpp"
2
+ #include "duckdb/parallel/concurrentqueue.hpp"
3
+ #include "duckdb/common/exception.hpp"
4
+
5
+ namespace duckdb {
6
+
7
+ typedef duckdb_moodycamel::ConcurrentQueue<BufferEvictionNode> eviction_queue_t;
8
+
9
+ struct EvictionQueue {
10
+ eviction_queue_t q;
11
+ };
12
+
13
+ bool BufferEvictionNode::CanUnload(BlockHandle &handle_p) {
14
+ if (timestamp != handle_p.eviction_timestamp) {
15
+ // handle was used in between
16
+ return false;
17
+ }
18
+ return handle_p.CanUnload();
19
+ }
20
+
21
+ shared_ptr<BlockHandle> BufferEvictionNode::TryGetBlockHandle() {
22
+ auto handle_p = handle.lock();
23
+ if (!handle_p) {
24
+ // BlockHandle has been destroyed
25
+ return nullptr;
26
+ }
27
+ if (!CanUnload(*handle_p)) {
28
+ // handle was used in between
29
+ return nullptr;
30
+ }
31
+ // this is the latest node in the queue with this handle
32
+ return handle_p;
33
+ }
34
+
35
+ BufferPool::BufferPool(idx_t maximum_memory)
36
+ : current_memory(0), maximum_memory(maximum_memory), queue(make_uniq<EvictionQueue>()), queue_insertions(0) {
37
+ }
38
+ BufferPool::~BufferPool() {
39
+ }
40
+
41
+ void BufferPool::AddToEvictionQueue(shared_ptr<BlockHandle> &handle) {
42
+ constexpr int INSERT_INTERVAL = 1024;
43
+
44
+ D_ASSERT(handle->readers == 0);
45
+ handle->eviction_timestamp++;
46
+ // After each 1024 insertions, run through the queue and purge.
47
+ if ((++queue_insertions % INSERT_INTERVAL) == 0) {
48
+ PurgeQueue();
49
+ }
50
+ queue->q.enqueue(BufferEvictionNode(weak_ptr<BlockHandle>(handle), handle->eviction_timestamp));
51
+ }
52
+
53
+ idx_t BufferPool::GetUsedMemory() {
54
+ return current_memory;
55
+ }
56
+ idx_t BufferPool::GetMaxMemory() {
57
+ return maximum_memory;
58
+ }
59
+
60
+ BufferPool::EvictionResult BufferPool::EvictBlocks(idx_t extra_memory, idx_t memory_limit,
61
+ unique_ptr<FileBuffer> *buffer) {
62
+ BufferEvictionNode node;
63
+ TempBufferPoolReservation r(current_memory, extra_memory);
64
+ while (current_memory > memory_limit) {
65
+ // get a block to unpin from the queue
66
+ if (!queue->q.try_dequeue(node)) {
67
+ // Failed to reserve. Adjust size of temp reservation to 0.
68
+ r.Resize(current_memory, 0);
69
+ return {false, std::move(r)};
70
+ }
71
+ // get a reference to the underlying block pointer
72
+ auto handle = node.TryGetBlockHandle();
73
+ if (!handle) {
74
+ continue;
75
+ }
76
+ // we might be able to free this block: grab the mutex and check if we can free it
77
+ lock_guard<mutex> lock(handle->lock);
78
+ if (!node.CanUnload(*handle)) {
79
+ // something changed in the mean-time, bail out
80
+ continue;
81
+ }
82
+ // hooray, we can unload the block
83
+ if (buffer && handle->buffer->AllocSize() == extra_memory) {
84
+ // we can actually re-use the memory directly!
85
+ *buffer = handle->UnloadAndTakeBlock();
86
+ return {true, std::move(r)};
87
+ } else {
88
+ // release the memory and mark the block as unloaded
89
+ handle->Unload();
90
+ }
91
+ }
92
+ return {true, std::move(r)};
93
+ }
94
+
95
+ void BufferPool::PurgeQueue() {
96
+ BufferEvictionNode node;
97
+ while (true) {
98
+ if (!queue->q.try_dequeue(node)) {
99
+ break;
100
+ }
101
+ auto handle = node.TryGetBlockHandle();
102
+ if (!handle) {
103
+ continue;
104
+ } else {
105
+ queue->q.enqueue(std::move(node));
106
+ break;
107
+ }
108
+ }
109
+ }
110
+
111
+ void BufferPool::SetLimit(idx_t limit, const char *exception_postscript) {
112
+ lock_guard<mutex> l_lock(limit_lock);
113
+ // try to evict until the limit is reached
114
+ if (!EvictBlocks(0, limit).success) {
115
+ throw OutOfMemoryException(
116
+ "Failed to change memory limit to %lld: could not free up enough memory for the new limit%s", limit,
117
+ exception_postscript);
118
+ }
119
+ idx_t old_limit = maximum_memory;
120
+ // set the global maximum memory to the new limit if successful
121
+ maximum_memory = limit;
122
+ // evict again
123
+ if (!EvictBlocks(0, limit).success) {
124
+ // failed: go back to old limit
125
+ maximum_memory = old_limit;
126
+ throw OutOfMemoryException(
127
+ "Failed to change memory limit to %lld: could not free up enough memory for the new limit%s", limit,
128
+ exception_postscript);
129
+ }
130
+ }
131
+
132
+ } // namespace duckdb
@@ -0,0 +1,32 @@
1
+ #include "duckdb/storage/buffer/block_handle.hpp"
2
+
3
+ namespace duckdb {
4
+
5
+ BufferPoolReservation::BufferPoolReservation(BufferPoolReservation &&src) noexcept {
6
+ size = src.size;
7
+ src.size = 0;
8
+ }
9
+
10
+ BufferPoolReservation &BufferPoolReservation::operator=(BufferPoolReservation &&src) noexcept {
11
+ size = src.size;
12
+ src.size = 0;
13
+ return *this;
14
+ }
15
+
16
+ BufferPoolReservation::~BufferPoolReservation() {
17
+ D_ASSERT(size == 0);
18
+ }
19
+
20
+ void BufferPoolReservation::Resize(atomic<idx_t> &counter, idx_t new_size) {
21
+ int64_t delta = (int64_t)new_size - size;
22
+ D_ASSERT(delta > 0 || (int64_t)counter >= -delta);
23
+ counter += delta;
24
+ size = new_size;
25
+ }
26
+
27
+ void BufferPoolReservation::Merge(BufferPoolReservation &&src) {
28
+ size += src.size;
29
+ src.size = 0;
30
+ }
31
+
32
+ } // namespace duckdb
@@ -3,7 +3,6 @@
3
3
  #include "duckdb/common/allocator.hpp"
4
4
  #include "duckdb/common/exception.hpp"
5
5
  #include "duckdb/common/set.hpp"
6
- #include "duckdb/parallel/concurrentqueue.hpp"
7
6
  #include "duckdb/storage/in_memory_block_manager.hpp"
8
7
  #include "duckdb/storage/storage_manager.hpp"
9
8
  #include "duckdb/main/attached_database.hpp"
@@ -11,33 +10,6 @@
11
10
 
12
11
  namespace duckdb {
13
12
 
14
- BufferPoolReservation::BufferPoolReservation(BufferPoolReservation &&src) noexcept {
15
- size = src.size;
16
- src.size = 0;
17
- }
18
-
19
- BufferPoolReservation &BufferPoolReservation::operator=(BufferPoolReservation &&src) noexcept {
20
- size = src.size;
21
- src.size = 0;
22
- return *this;
23
- }
24
-
25
- BufferPoolReservation::~BufferPoolReservation() {
26
- D_ASSERT(size == 0);
27
- }
28
-
29
- void BufferPoolReservation::Resize(atomic<idx_t> &counter, idx_t new_size) {
30
- int64_t delta = (int64_t)new_size - size;
31
- D_ASSERT(delta > 0 || (int64_t)counter >= -delta);
32
- counter += delta;
33
- size = new_size;
34
- }
35
-
36
- void BufferPoolReservation::Merge(BufferPoolReservation &&src) {
37
- size += src.size;
38
- src.size = 0;
39
- }
40
-
41
13
  struct BufferAllocatorData : PrivateAllocatorData {
42
14
  explicit BufferAllocatorData(BufferManager &manager) : manager(manager) {
43
15
  }
@@ -45,60 +17,6 @@ struct BufferAllocatorData : PrivateAllocatorData {
45
17
  BufferManager &manager;
46
18
  };
47
19
 
48
- BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p)
49
- : block_manager(block_manager), readers(0), block_id(block_id_p), buffer(nullptr), eviction_timestamp(0),
50
- can_destroy(false), unswizzled(nullptr) {
51
- eviction_timestamp = 0;
52
- state = BlockState::BLOCK_UNLOADED;
53
- memory_usage = Storage::BLOCK_ALLOC_SIZE;
54
- }
55
-
56
- BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, unique_ptr<FileBuffer> buffer_p,
57
- bool can_destroy_p, idx_t block_size, BufferPoolReservation &&reservation)
58
- : block_manager(block_manager), readers(0), block_id(block_id_p), eviction_timestamp(0), can_destroy(can_destroy_p),
59
- unswizzled(nullptr) {
60
- buffer = std::move(buffer_p);
61
- state = BlockState::BLOCK_LOADED;
62
- memory_usage = block_size;
63
- memory_charge = std::move(reservation);
64
- }
65
-
66
- BlockHandle::~BlockHandle() { // NOLINT: allow internal exceptions
67
- // being destroyed, so any unswizzled pointers are just binary junk now.
68
- unswizzled = nullptr;
69
- auto &buffer_manager = block_manager.buffer_manager;
70
- // no references remain to this block: erase
71
- if (buffer && state == BlockState::BLOCK_LOADED) {
72
- D_ASSERT(memory_charge.size > 0);
73
- // the block is still loaded in memory: erase it
74
- buffer.reset();
75
- memory_charge.Resize(buffer_manager.buffer_pool.current_memory, 0);
76
- } else {
77
- D_ASSERT(memory_charge.size == 0);
78
- }
79
- buffer_manager.buffer_pool.PurgeQueue();
80
- block_manager.UnregisterBlock(block_id, can_destroy);
81
- }
82
-
83
- unique_ptr<Block> AllocateBlock(BlockManager &block_manager, unique_ptr<FileBuffer> reusable_buffer,
84
- block_id_t block_id) {
85
- if (reusable_buffer) {
86
- // re-usable buffer: re-use it
87
- if (reusable_buffer->type == FileBufferType::BLOCK) {
88
- // we can reuse the buffer entirely
89
- auto &block = (Block &)*reusable_buffer;
90
- block.id = block_id;
91
- return unique_ptr_cast<FileBuffer, Block>(std::move(reusable_buffer));
92
- }
93
- auto block = block_manager.CreateBlock(block_id, reusable_buffer.get());
94
- reusable_buffer.reset();
95
- return block;
96
- } else {
97
- // no re-usable buffer: allocate a new block
98
- return block_manager.CreateBlock(block_id, nullptr);
99
- }
100
- }
101
-
102
20
  idx_t GetAllocSize(idx_t size) {
103
21
  return AlignValue<idx_t, Storage::SECTOR_SIZE>(size + Storage::BLOCK_HEADER_SIZE);
104
22
  }
@@ -115,110 +33,6 @@ unique_ptr<FileBuffer> BufferManager::ConstructManagedBuffer(idx_t size, unique_
115
33
  }
116
34
  }
117
35
 
118
- BufferHandle BlockHandle::Load(shared_ptr<BlockHandle> &handle, unique_ptr<FileBuffer> reusable_buffer) {
119
- if (handle->state == BlockState::BLOCK_LOADED) {
120
- // already loaded
121
- D_ASSERT(handle->buffer);
122
- return BufferHandle(handle, handle->buffer.get());
123
- }
124
-
125
- auto &block_manager = handle->block_manager;
126
- if (handle->block_id < MAXIMUM_BLOCK) {
127
- auto block = AllocateBlock(block_manager, std::move(reusable_buffer), handle->block_id);
128
- block_manager.Read(*block);
129
- handle->buffer = std::move(block);
130
- } else {
131
- if (handle->can_destroy) {
132
- return BufferHandle();
133
- } else {
134
- handle->buffer =
135
- block_manager.buffer_manager.ReadTemporaryBuffer(handle->block_id, std::move(reusable_buffer));
136
- }
137
- }
138
- handle->state = BlockState::BLOCK_LOADED;
139
- return BufferHandle(handle, handle->buffer.get());
140
- }
141
-
142
- unique_ptr<FileBuffer> BlockHandle::UnloadAndTakeBlock() {
143
- if (state == BlockState::BLOCK_UNLOADED) {
144
- // already unloaded: nothing to do
145
- return nullptr;
146
- }
147
- D_ASSERT(!unswizzled);
148
- D_ASSERT(CanUnload());
149
-
150
- if (block_id >= MAXIMUM_BLOCK && !can_destroy) {
151
- // temporary block that cannot be destroyed: write to temporary file
152
- block_manager.buffer_manager.WriteTemporaryBuffer(block_id, *buffer);
153
- }
154
- memory_charge.Resize(block_manager.buffer_manager.buffer_pool.current_memory, 0);
155
- state = BlockState::BLOCK_UNLOADED;
156
- return std::move(buffer);
157
- }
158
-
159
- void BlockHandle::Unload() {
160
- auto block = UnloadAndTakeBlock();
161
- block.reset();
162
- }
163
-
164
- bool BlockHandle::CanUnload() {
165
- if (state == BlockState::BLOCK_UNLOADED) {
166
- // already unloaded
167
- return false;
168
- }
169
- if (readers > 0) {
170
- // there are active readers
171
- return false;
172
- }
173
- if (block_id >= MAXIMUM_BLOCK && !can_destroy && block_manager.buffer_manager.temp_directory.empty()) {
174
- // in order to unload this block we need to write it to a temporary buffer
175
- // however, no temporary directory is specified!
176
- // hence we cannot unload the block
177
- return false;
178
- }
179
- return true;
180
- }
181
-
182
- struct BufferEvictionNode {
183
- BufferEvictionNode() {
184
- }
185
- BufferEvictionNode(weak_ptr<BlockHandle> handle_p, idx_t timestamp_p)
186
- : handle(std::move(handle_p)), timestamp(timestamp_p) {
187
- D_ASSERT(!handle.expired());
188
- }
189
-
190
- weak_ptr<BlockHandle> handle;
191
- idx_t timestamp;
192
-
193
- bool CanUnload(BlockHandle &handle_p) {
194
- if (timestamp != handle_p.eviction_timestamp) {
195
- // handle was used in between
196
- return false;
197
- }
198
- return handle_p.CanUnload();
199
- }
200
-
201
- shared_ptr<BlockHandle> TryGetBlockHandle() {
202
- auto handle_p = handle.lock();
203
- if (!handle_p) {
204
- // BlockHandle has been destroyed
205
- return nullptr;
206
- }
207
- if (!CanUnload(*handle_p)) {
208
- // handle was used in between
209
- return nullptr;
210
- }
211
- // this is the latest node in the queue with this handle
212
- return handle_p;
213
- }
214
- };
215
-
216
- typedef duckdb_moodycamel::ConcurrentQueue<BufferEvictionNode> eviction_queue_t;
217
-
218
- struct EvictionQueue {
219
- eviction_queue_t q;
220
- };
221
-
222
36
  class TemporaryFileManager;
223
37
 
224
38
  class TemporaryDirectoryHandle {
@@ -242,12 +56,6 @@ void BufferManager::SetTemporaryDirectory(string new_dir) {
242
56
  this->temp_directory = std::move(new_dir);
243
57
  }
244
58
 
245
- BufferPool::BufferPool(idx_t maximum_memory)
246
- : current_memory(0), maximum_memory(maximum_memory), queue(make_uniq<EvictionQueue>()), queue_insertions(0) {
247
- }
248
- BufferPool::~BufferPool() {
249
- }
250
-
251
59
  BufferManager::BufferManager(DatabaseInstance &db, string tmp)
252
60
  : db(db), buffer_pool(db.GetBufferPool()), temp_directory(std::move(tmp)), temporary_id(MAXIMUM_BLOCK),
253
61
  buffer_allocator(BufferAllocatorAllocate, BufferAllocatorFree, BufferAllocatorRealloc,
@@ -258,70 +66,6 @@ BufferManager::BufferManager(DatabaseInstance &db, string tmp)
258
66
  BufferManager::~BufferManager() {
259
67
  }
260
68
 
261
- shared_ptr<BlockHandle> BlockManager::RegisterBlock(block_id_t block_id, bool is_meta_block) {
262
- lock_guard<mutex> lock(blocks_lock);
263
- // check if the block already exists
264
- auto entry = blocks.find(block_id);
265
- if (entry != blocks.end()) {
266
- // already exists: check if it hasn't expired yet
267
- auto existing_ptr = entry->second.lock();
268
- if (existing_ptr) {
269
- //! it hasn't! return it
270
- return existing_ptr;
271
- }
272
- }
273
- // create a new block pointer for this block
274
- auto result = make_shared<BlockHandle>(*this, block_id);
275
- // for meta block, cache the handle in meta_blocks
276
- if (is_meta_block) {
277
- meta_blocks[block_id] = result;
278
- }
279
- // register the block pointer in the set of blocks as a weak pointer
280
- blocks[block_id] = weak_ptr<BlockHandle>(result);
281
- return result;
282
- }
283
-
284
- void BlockManager::ClearMetaBlockHandles() {
285
- meta_blocks.clear();
286
- }
287
-
288
- shared_ptr<BlockHandle> BlockManager::ConvertToPersistent(block_id_t block_id, shared_ptr<BlockHandle> old_block) {
289
-
290
- // pin the old block to ensure we have it loaded in memory
291
- auto old_handle = buffer_manager.Pin(old_block);
292
- D_ASSERT(old_block->state == BlockState::BLOCK_LOADED);
293
- D_ASSERT(old_block->buffer);
294
-
295
- // Temp buffers can be larger than the storage block size. But persistent buffers
296
- // cannot.
297
- D_ASSERT(old_block->buffer->AllocSize() <= Storage::BLOCK_ALLOC_SIZE);
298
-
299
- // register a block with the new block id
300
- auto new_block = RegisterBlock(block_id);
301
- D_ASSERT(new_block->state == BlockState::BLOCK_UNLOADED);
302
- D_ASSERT(new_block->readers == 0);
303
-
304
- // move the data from the old block into data for the new block
305
- new_block->state = BlockState::BLOCK_LOADED;
306
- new_block->buffer = CreateBlock(block_id, old_block->buffer.get());
307
- new_block->memory_usage = old_block->memory_usage;
308
- new_block->memory_charge = std::move(old_block->memory_charge);
309
-
310
- // clear the old buffer and unload it
311
- old_block->buffer.reset();
312
- old_block->state = BlockState::BLOCK_UNLOADED;
313
- old_block->memory_usage = 0;
314
- old_handle.Destroy();
315
- old_block.reset();
316
-
317
- // persist the new block to disk
318
- Write(*new_block->buffer, block_id);
319
-
320
- buffer_manager.buffer_pool.AddToEvictionQueue(new_block);
321
-
322
- return new_block;
323
- }
324
-
325
69
  template <typename... ARGS>
326
70
  TempBufferPoolReservation BufferManager::EvictBlocksOrThrow(idx_t memory_delta, unique_ptr<FileBuffer> *buffer,
327
71
  ARGS... args) {
@@ -438,18 +182,6 @@ BufferHandle BufferManager::Pin(shared_ptr<BlockHandle> &handle) {
438
182
  return buf;
439
183
  }
440
184
 
441
- void BufferPool::AddToEvictionQueue(shared_ptr<BlockHandle> &handle) {
442
- constexpr int INSERT_INTERVAL = 1024;
443
-
444
- D_ASSERT(handle->readers == 0);
445
- handle->eviction_timestamp++;
446
- // After each 1024 insertions, run through the queue and purge.
447
- if ((++queue_insertions % INSERT_INTERVAL) == 0) {
448
- PurgeQueue();
449
- }
450
- queue->q.enqueue(BufferEvictionNode(weak_ptr<BlockHandle>(handle), handle->eviction_timestamp));
451
- }
452
-
453
185
  void BufferManager::VerifyZeroReaders(shared_ptr<BlockHandle> &handle) {
454
186
  #ifdef DUCKDB_DEBUG_DESTROY_BLOCKS
455
187
  auto replacement_buffer = make_uniq<FileBuffer>(Allocator::Get(db), handle->buffer->type,
@@ -473,89 +205,6 @@ void BufferManager::Unpin(shared_ptr<BlockHandle> &handle) {
473
205
  }
474
206
  }
475
207
 
476
- BufferPool::EvictionResult BufferPool::EvictBlocks(idx_t extra_memory, idx_t memory_limit,
477
- unique_ptr<FileBuffer> *buffer) {
478
- BufferEvictionNode node;
479
- TempBufferPoolReservation r(current_memory, extra_memory);
480
- while (current_memory > memory_limit) {
481
- // get a block to unpin from the queue
482
- if (!queue->q.try_dequeue(node)) {
483
- // Failed to reserve. Adjust size of temp reservation to 0.
484
- r.Resize(current_memory, 0);
485
- return {false, std::move(r)};
486
- }
487
- // get a reference to the underlying block pointer
488
- auto handle = node.TryGetBlockHandle();
489
- if (!handle) {
490
- continue;
491
- }
492
- // we might be able to free this block: grab the mutex and check if we can free it
493
- lock_guard<mutex> lock(handle->lock);
494
- if (!node.CanUnload(*handle)) {
495
- // something changed in the mean-time, bail out
496
- continue;
497
- }
498
- // hooray, we can unload the block
499
- if (buffer && handle->buffer->AllocSize() == extra_memory) {
500
- // we can actually re-use the memory directly!
501
- *buffer = handle->UnloadAndTakeBlock();
502
- return {true, std::move(r)};
503
- } else {
504
- // release the memory and mark the block as unloaded
505
- handle->Unload();
506
- }
507
- }
508
- return {true, std::move(r)};
509
- }
510
-
511
- void BufferPool::PurgeQueue() {
512
- BufferEvictionNode node;
513
- while (true) {
514
- if (!queue->q.try_dequeue(node)) {
515
- break;
516
- }
517
- auto handle = node.TryGetBlockHandle();
518
- if (!handle) {
519
- continue;
520
- } else {
521
- queue->q.enqueue(std::move(node));
522
- break;
523
- }
524
- }
525
- }
526
-
527
- void BlockManager::UnregisterBlock(block_id_t block_id, bool can_destroy) {
528
- if (block_id >= MAXIMUM_BLOCK) {
529
- // in-memory buffer: buffer could have been offloaded to disk: remove the file
530
- buffer_manager.DeleteTemporaryFile(block_id);
531
- } else {
532
- lock_guard<mutex> lock(blocks_lock);
533
- // on-disk block: erase from list of blocks in manager
534
- blocks.erase(block_id);
535
- }
536
- }
537
-
538
- void BufferPool::SetLimit(idx_t limit, const char *exception_postscript) {
539
- lock_guard<mutex> l_lock(limit_lock);
540
- // try to evict until the limit is reached
541
- if (!EvictBlocks(0, limit).success) {
542
- throw OutOfMemoryException(
543
- "Failed to change memory limit to %lld: could not free up enough memory for the new limit%s", limit,
544
- exception_postscript);
545
- }
546
- idx_t old_limit = maximum_memory;
547
- // set the global maximum memory to the new limit if successful
548
- maximum_memory = limit;
549
- // evict again
550
- if (!EvictBlocks(0, limit).success) {
551
- // failed: go back to old limit
552
- maximum_memory = old_limit;
553
- throw OutOfMemoryException(
554
- "Failed to change memory limit to %lld: could not free up enough memory for the new limit%s", limit,
555
- exception_postscript);
556
- }
557
- }
558
-
559
208
  void BufferManager::IncreaseUsedMemory(idx_t size) {
560
209
  ReserveMemory(size);
561
210
  }
@@ -5,13 +5,11 @@
5
5
  #include "parser/scansup.hpp"
6
6
  #include "common/keywords.hpp"
7
7
 
8
- using namespace std;
9
-
10
8
  namespace duckdb {
11
9
 
12
10
  PostgresParser::PostgresParser() : success(false), parse_tree(nullptr), error_message(""), error_location(0) {}
13
11
 
14
- void PostgresParser::Parse(const string &query) {
12
+ void PostgresParser::Parse(const std::string &query) {
15
13
  duckdb_libpgquery::pg_parser_init();
16
14
  duckdb_libpgquery::parse_result res;
17
15
  pg_parser_parse(query.c_str(), &res);
@@ -20,7 +18,7 @@ void PostgresParser::Parse(const string &query) {
20
18
  if (success) {
21
19
  parse_tree = res.parse_tree;
22
20
  } else {
23
- error_message = string(res.error_message);
21
+ error_message = std::string(res.error_message);
24
22
  error_location = res.error_location;
25
23
  }
26
24
  }
@@ -42,7 +40,7 @@ bool PostgresParser::IsKeyword(const std::string &text) {
42
40
 
43
41
  vector<duckdb_libpgquery::PGKeyword> PostgresParser::KeywordList() {
44
42
  // FIXME: because of this, we might need to change the libpg_query library to use duckdb::vector
45
- return std::move(duckdb_libpgquery::keyword_list());
43
+ return std::forward<vector<duckdb_libpgquery::PGKeyword> >(duckdb_libpgquery::keyword_list());
46
44
  }
47
45
 
48
46
  void PostgresParser::SetPreserveIdentifierCase(bool preserve) {
@@ -2,6 +2,8 @@
2
2
 
3
3
  #include "src/common/sort/merge_sorter.cpp"
4
4
 
5
+ #include "src/common/sort/partition_state.cpp"
6
+
5
7
  #include "src/common/sort/radix_sort.cpp"
6
8
 
7
9
  #include "src/common/sort/sort_state.cpp"
@@ -1,2 +1,10 @@
1
1
  #include "src/storage/buffer/buffer_handle.cpp"
2
2
 
3
+ #include "src/storage/buffer/block_handle.cpp"
4
+
5
+ #include "src/storage/buffer/block_manager.cpp"
6
+
7
+ #include "src/storage/buffer/buffer_pool.cpp"
8
+
9
+ #include "src/storage/buffer/buffer_pool_reservation.cpp"
10
+