duckdb 0.5.2-dev1809.0 → 0.5.2-dev1819.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/duckdb.cpp +133 -73
- package/src/duckdb.hpp +57 -6
- package/src/parquet-amalgamation.cpp +37562 -37562
package/package.json
CHANGED
package/src/duckdb.cpp
CHANGED
|
@@ -17105,32 +17105,32 @@ void FileBuffer::ReallocBuffer(size_t new_size) {
|
|
|
17105
17105
|
size = 0;
|
|
17106
17106
|
}
|
|
17107
17107
|
|
|
17108
|
-
|
|
17109
|
-
|
|
17110
|
-
|
|
17111
|
-
|
|
17112
|
-
//
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
if (type == FileBufferType::MANAGED_BUFFER) {
|
|
17119
|
-
new_size += Storage::BLOCK_HEADER_SIZE;
|
|
17120
|
-
}
|
|
17121
|
-
if (type != FileBufferType::TINY_BUFFER) {
|
|
17122
|
-
new_size = AlignValue<uint32_t, Storage::SECTOR_SIZE>(new_size);
|
|
17123
|
-
}
|
|
17124
|
-
ReallocBuffer(new_size);
|
|
17108
|
+
FileBuffer::MemoryRequirement FileBuffer::CalculateMemory(uint64_t user_size) {
|
|
17109
|
+
FileBuffer::MemoryRequirement result;
|
|
17110
|
+
|
|
17111
|
+
if (type == FileBufferType::TINY_BUFFER) {
|
|
17112
|
+
// We never do IO on tiny buffers, so there's no need to add a header or sector-align.
|
|
17113
|
+
result.header_size = 0;
|
|
17114
|
+
result.alloc_size = user_size;
|
|
17115
|
+
} else {
|
|
17116
|
+
result.header_size = Storage::BLOCK_HEADER_SIZE;
|
|
17117
|
+
result.alloc_size = AlignValue<uint32_t, Storage::SECTOR_SIZE>(result.header_size + user_size);
|
|
17125
17118
|
}
|
|
17119
|
+
return result;
|
|
17120
|
+
}
|
|
17121
|
+
|
|
17122
|
+
void FileBuffer::Resize(uint64_t new_size) {
|
|
17123
|
+
auto req = CalculateMemory(new_size);
|
|
17124
|
+
ReallocBuffer(req.alloc_size);
|
|
17126
17125
|
|
|
17127
17126
|
if (new_size > 0) {
|
|
17128
|
-
buffer = internal_buffer + header_size;
|
|
17129
|
-
size = internal_size - header_size;
|
|
17127
|
+
buffer = internal_buffer + req.header_size;
|
|
17128
|
+
size = internal_size - req.header_size;
|
|
17130
17129
|
}
|
|
17131
17130
|
}
|
|
17132
17131
|
|
|
17133
17132
|
void FileBuffer::Read(FileHandle &handle, uint64_t location) {
|
|
17133
|
+
D_ASSERT(type != FileBufferType::TINY_BUFFER);
|
|
17134
17134
|
handle.Read(internal_buffer, internal_size, location);
|
|
17135
17135
|
}
|
|
17136
17136
|
|
|
@@ -17148,6 +17148,7 @@ void FileBuffer::ReadAndChecksum(FileHandle &handle, uint64_t location) {
|
|
|
17148
17148
|
}
|
|
17149
17149
|
|
|
17150
17150
|
void FileBuffer::Write(FileHandle &handle, uint64_t location) {
|
|
17151
|
+
D_ASSERT(type != FileBufferType::TINY_BUFFER);
|
|
17151
17152
|
handle.Write(internal_buffer, internal_size, location);
|
|
17152
17153
|
}
|
|
17153
17154
|
|
|
@@ -199118,6 +199119,33 @@ public:
|
|
|
199118
199119
|
|
|
199119
199120
|
namespace duckdb {
|
|
199120
199121
|
|
|
199122
|
+
BufferPoolReservation::BufferPoolReservation(BufferPoolReservation &&src) noexcept {
|
|
199123
|
+
size = src.size;
|
|
199124
|
+
src.size = 0;
|
|
199125
|
+
}
|
|
199126
|
+
|
|
199127
|
+
BufferPoolReservation &BufferPoolReservation::operator=(BufferPoolReservation &&src) noexcept {
|
|
199128
|
+
size = src.size;
|
|
199129
|
+
src.size = 0;
|
|
199130
|
+
return *this;
|
|
199131
|
+
}
|
|
199132
|
+
|
|
199133
|
+
BufferPoolReservation::~BufferPoolReservation() {
|
|
199134
|
+
D_ASSERT(size == 0);
|
|
199135
|
+
}
|
|
199136
|
+
|
|
199137
|
+
void BufferPoolReservation::Resize(atomic<idx_t> &counter, idx_t new_size) {
|
|
199138
|
+
int64_t delta = (int64_t)new_size - size;
|
|
199139
|
+
D_ASSERT(delta > 0 || (int64_t)counter >= -delta);
|
|
199140
|
+
counter += delta;
|
|
199141
|
+
size = new_size;
|
|
199142
|
+
}
|
|
199143
|
+
|
|
199144
|
+
void BufferPoolReservation::Merge(BufferPoolReservation &&src) {
|
|
199145
|
+
size += src.size;
|
|
199146
|
+
src.size = 0;
|
|
199147
|
+
}
|
|
199148
|
+
|
|
199121
199149
|
struct BufferAllocatorData : PrivateAllocatorData {
|
|
199122
199150
|
explicit BufferAllocatorData(BufferManager &manager) : manager(manager) {
|
|
199123
199151
|
}
|
|
@@ -199134,12 +199162,13 @@ BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p)
|
|
|
199134
199162
|
}
|
|
199135
199163
|
|
|
199136
199164
|
BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, unique_ptr<FileBuffer> buffer_p,
|
|
199137
|
-
bool can_destroy_p, idx_t block_size)
|
|
199165
|
+
bool can_destroy_p, idx_t block_size, BufferPoolReservation &&reservation)
|
|
199138
199166
|
: block_manager(block_manager), readers(0), block_id(block_id_p), eviction_timestamp(0), can_destroy(can_destroy_p),
|
|
199139
199167
|
unswizzled(nullptr) {
|
|
199140
199168
|
buffer = move(buffer_p);
|
|
199141
199169
|
state = BlockState::BLOCK_LOADED;
|
|
199142
|
-
memory_usage = buffer->
|
|
199170
|
+
memory_usage = buffer->AllocSize();
|
|
199171
|
+
memory_charge = move(reservation);
|
|
199143
199172
|
}
|
|
199144
199173
|
|
|
199145
199174
|
BlockHandle::~BlockHandle() {
|
|
@@ -199148,10 +199177,12 @@ BlockHandle::~BlockHandle() {
|
|
|
199148
199177
|
auto &buffer_manager = block_manager.buffer_manager;
|
|
199149
199178
|
// no references remain to this block: erase
|
|
199150
199179
|
if (buffer && state == BlockState::BLOCK_LOADED) {
|
|
199180
|
+
D_ASSERT(memory_charge.size > 0);
|
|
199151
199181
|
// the block is still loaded in memory: erase it
|
|
199152
199182
|
buffer.reset();
|
|
199153
|
-
|
|
199154
|
-
|
|
199183
|
+
memory_charge.Resize(buffer_manager.current_memory, 0);
|
|
199184
|
+
} else {
|
|
199185
|
+
D_ASSERT(memory_charge.size == 0);
|
|
199155
199186
|
}
|
|
199156
199187
|
block_manager.UnregisterBlock(block_id, can_destroy);
|
|
199157
199188
|
}
|
|
@@ -199220,10 +199251,9 @@ unique_ptr<FileBuffer> BlockHandle::UnloadAndTakeBlock() {
|
|
|
199220
199251
|
|
|
199221
199252
|
if (block_id >= MAXIMUM_BLOCK && !can_destroy) {
|
|
199222
199253
|
// temporary block that cannot be destroyed: write to temporary file
|
|
199223
|
-
D_ASSERT(memory_usage >= Storage::BLOCK_ALLOC_SIZE);
|
|
199224
199254
|
block_manager.buffer_manager.WriteTemporaryBuffer(block_id, *buffer);
|
|
199225
199255
|
}
|
|
199226
|
-
block_manager.buffer_manager.current_memory
|
|
199256
|
+
memory_charge.Resize(block_manager.buffer_manager.current_memory, 0);
|
|
199227
199257
|
state = BlockState::BLOCK_UNLOADED;
|
|
199228
199258
|
return move(buffer);
|
|
199229
199259
|
}
|
|
@@ -199362,6 +199392,8 @@ shared_ptr<BlockHandle> BlockManager::ConvertToPersistent(block_id_t block_id, s
|
|
|
199362
199392
|
// move the data from the old block into data for the new block
|
|
199363
199393
|
new_block->state = BlockState::BLOCK_LOADED;
|
|
199364
199394
|
new_block->buffer = CreateBlock(block_id, old_block->buffer.get());
|
|
199395
|
+
new_block->memory_usage = old_block->memory_usage;
|
|
199396
|
+
new_block->memory_charge = move(old_block->memory_charge);
|
|
199365
199397
|
|
|
199366
199398
|
// clear the old buffer and unload it
|
|
199367
199399
|
old_block->buffer.reset();
|
|
@@ -199378,15 +199410,25 @@ shared_ptr<BlockHandle> BlockManager::ConvertToPersistent(block_id_t block_id, s
|
|
|
199378
199410
|
return new_block;
|
|
199379
199411
|
}
|
|
199380
199412
|
|
|
199381
|
-
|
|
199382
|
-
|
|
199383
|
-
|
|
199384
|
-
|
|
199413
|
+
template <typename... ARGS>
|
|
199414
|
+
TempBufferPoolReservation BufferManager::EvictBlocksOrThrow(idx_t memory_delta, idx_t limit,
|
|
199415
|
+
unique_ptr<FileBuffer> *buffer, ARGS... args) {
|
|
199416
|
+
auto r = EvictBlocks(memory_delta, limit, buffer);
|
|
199417
|
+
if (!r.success) {
|
|
199418
|
+
throw OutOfMemoryException(args..., InMemoryWarning());
|
|
199385
199419
|
}
|
|
199420
|
+
return move(r.reservation);
|
|
199421
|
+
}
|
|
199422
|
+
|
|
199423
|
+
shared_ptr<BlockHandle> BufferManager::RegisterSmallMemory(idx_t block_size) {
|
|
199424
|
+
auto res = EvictBlocksOrThrow(block_size, maximum_memory, nullptr,
|
|
199425
|
+
"could not allocate block of %lld bytes (%lld/%lld used) %s", block_size,
|
|
199426
|
+
GetUsedMemory(), GetMaxMemory());
|
|
199427
|
+
|
|
199386
199428
|
auto buffer = ConstructManagedBuffer(block_size, nullptr, FileBufferType::TINY_BUFFER);
|
|
199387
199429
|
|
|
199388
199430
|
// create a new block pointer for this block
|
|
199389
|
-
return make_shared<BlockHandle>(*temp_block_manager, ++temporary_id, move(buffer), false, block_size);
|
|
199431
|
+
return make_shared<BlockHandle>(*temp_block_manager, ++temporary_id, move(buffer), false, block_size, move(res));
|
|
199390
199432
|
}
|
|
199391
199433
|
|
|
199392
199434
|
shared_ptr<BlockHandle> BufferManager::RegisterMemory(idx_t block_size, bool can_destroy) {
|
|
@@ -199394,15 +199436,15 @@ shared_ptr<BlockHandle> BufferManager::RegisterMemory(idx_t block_size, bool can
|
|
|
199394
199436
|
auto alloc_size = AlignValue<idx_t, Storage::SECTOR_SIZE>(block_size + Storage::BLOCK_HEADER_SIZE);
|
|
199395
199437
|
// first evict blocks until we have enough memory to store this buffer
|
|
199396
199438
|
unique_ptr<FileBuffer> reusable_buffer;
|
|
199397
|
-
|
|
199398
|
-
|
|
199399
|
-
|
|
199400
|
-
}
|
|
199439
|
+
auto res = EvictBlocksOrThrow(alloc_size, maximum_memory, &reusable_buffer,
|
|
199440
|
+
"could not allocate block of %lld bytes (%lld/%lld used) %s", alloc_size,
|
|
199441
|
+
GetUsedMemory(), GetMaxMemory());
|
|
199401
199442
|
|
|
199402
199443
|
auto buffer = ConstructManagedBuffer(block_size, move(reusable_buffer));
|
|
199403
199444
|
|
|
199404
199445
|
// create a new block pointer for this block
|
|
199405
|
-
return make_shared<BlockHandle>(*temp_block_manager, ++temporary_id, move(buffer), can_destroy, block_size
|
|
199446
|
+
return make_shared<BlockHandle>(*temp_block_manager, ++temporary_id, move(buffer), can_destroy, block_size,
|
|
199447
|
+
move(res));
|
|
199406
199448
|
}
|
|
199407
199449
|
|
|
199408
199450
|
BufferHandle BufferManager::Allocate(idx_t block_size) {
|
|
@@ -199414,25 +199456,29 @@ void BufferManager::ReAllocate(shared_ptr<BlockHandle> &handle, idx_t block_size
|
|
|
199414
199456
|
D_ASSERT(block_size >= Storage::BLOCK_SIZE);
|
|
199415
199457
|
lock_guard<mutex> lock(handle->lock);
|
|
199416
199458
|
D_ASSERT(handle->state == BlockState::BLOCK_LOADED);
|
|
199417
|
-
|
|
199418
|
-
|
|
199419
|
-
|
|
199459
|
+
D_ASSERT(handle->memory_usage == handle->buffer->AllocSize());
|
|
199460
|
+
D_ASSERT(handle->memory_usage == handle->memory_charge.size);
|
|
199461
|
+
|
|
199462
|
+
auto req = handle->buffer->CalculateMemory(block_size);
|
|
199463
|
+
int64_t memory_delta = (int64_t)req.alloc_size - handle->memory_usage;
|
|
199464
|
+
|
|
199465
|
+
if (memory_delta == 0) {
|
|
199420
199466
|
return;
|
|
199421
|
-
} else if (
|
|
199467
|
+
} else if (memory_delta > 0) {
|
|
199422
199468
|
// evict blocks until we have space to resize this block
|
|
199423
|
-
|
|
199424
|
-
|
|
199425
|
-
|
|
199426
|
-
|
|
199469
|
+
auto reservation =
|
|
199470
|
+
EvictBlocksOrThrow(memory_delta, maximum_memory, nullptr, "failed to resize block from %lld to %lld%s",
|
|
199471
|
+
handle->memory_usage, req.alloc_size);
|
|
199472
|
+
// EvictBlocks decrements 'current_memory' for us.
|
|
199473
|
+
handle->memory_charge.Merge(move(reservation));
|
|
199427
199474
|
} else {
|
|
199428
|
-
// no need to evict blocks
|
|
199429
|
-
|
|
199430
|
-
current_memory -= idx_t(-required_memory);
|
|
199475
|
+
// no need to evict blocks, but we do need to decrement 'current_memory'.
|
|
199476
|
+
handle->memory_charge.Resize(current_memory, req.alloc_size);
|
|
199431
199477
|
}
|
|
199432
199478
|
|
|
199433
199479
|
// resize and adjust current memory
|
|
199434
199480
|
handle->buffer->Resize(block_size);
|
|
199435
|
-
handle->memory_usage
|
|
199481
|
+
handle->memory_usage += memory_delta;
|
|
199436
199482
|
}
|
|
199437
199483
|
|
|
199438
199484
|
BufferHandle BufferManager::Pin(shared_ptr<BlockHandle> &handle) {
|
|
@@ -199448,32 +199494,43 @@ BufferHandle BufferManager::Pin(shared_ptr<BlockHandle> &handle) {
|
|
|
199448
199494
|
}
|
|
199449
199495
|
required_memory = handle->memory_usage;
|
|
199450
199496
|
}
|
|
199451
|
-
D_ASSERT(required_memory >= Storage::BLOCK_SIZE);
|
|
199452
199497
|
// evict blocks until we have space for the current block
|
|
199453
199498
|
unique_ptr<FileBuffer> reusable_buffer;
|
|
199454
|
-
|
|
199455
|
-
|
|
199456
|
-
}
|
|
199499
|
+
auto reservation = EvictBlocksOrThrow(required_memory, maximum_memory, &reusable_buffer,
|
|
199500
|
+
"failed to pin block of size %lld%s", required_memory);
|
|
199457
199501
|
// lock the handle again and repeat the check (in case anybody loaded in the mean time)
|
|
199458
199502
|
lock_guard<mutex> lock(handle->lock);
|
|
199459
199503
|
// check if the block is already loaded
|
|
199460
199504
|
if (handle->state == BlockState::BLOCK_LOADED) {
|
|
199461
199505
|
// the block is loaded, increment the reader count and return a pointer to the handle
|
|
199462
199506
|
handle->readers++;
|
|
199463
|
-
|
|
199464
|
-
current_memory -= required_memory;
|
|
199507
|
+
reservation.Resize(current_memory, 0);
|
|
199465
199508
|
return handle->Load(handle);
|
|
199466
199509
|
}
|
|
199467
199510
|
// now we can actually load the current block
|
|
199468
199511
|
D_ASSERT(handle->readers == 0);
|
|
199469
199512
|
handle->readers = 1;
|
|
199470
|
-
|
|
199513
|
+
auto buf = handle->Load(handle, move(reusable_buffer));
|
|
199514
|
+
handle->memory_charge = move(reservation);
|
|
199515
|
+
// In the case of a variable sized block, the buffer may be smaller than a full block.
|
|
199516
|
+
int64_t delta = handle->buffer->AllocSize() - handle->memory_usage;
|
|
199517
|
+
if (delta) {
|
|
199518
|
+
D_ASSERT(delta < 0);
|
|
199519
|
+
handle->memory_usage += delta;
|
|
199520
|
+
handle->memory_charge.Resize(current_memory, handle->memory_usage);
|
|
199521
|
+
}
|
|
199522
|
+
return buf;
|
|
199471
199523
|
}
|
|
199472
199524
|
|
|
199473
199525
|
void BufferManager::AddToEvictionQueue(shared_ptr<BlockHandle> &handle) {
|
|
199526
|
+
constexpr int INSERT_INTERVAL = 1024;
|
|
199527
|
+
|
|
199474
199528
|
D_ASSERT(handle->readers == 0);
|
|
199475
199529
|
handle->eviction_timestamp++;
|
|
199476
|
-
|
|
199530
|
+
// After each 1024 insertions, run through the queue and purge.
|
|
199531
|
+
if ((++queue_insertions % INSERT_INTERVAL) == 0) {
|
|
199532
|
+
PurgeQueue();
|
|
199533
|
+
}
|
|
199477
199534
|
queue->q.enqueue(BufferEvictionNode(weak_ptr<BlockHandle>(handle), handle->eviction_timestamp));
|
|
199478
199535
|
}
|
|
199479
199536
|
|
|
@@ -199489,17 +199546,16 @@ void BufferManager::Unpin(shared_ptr<BlockHandle> &handle) {
|
|
|
199489
199546
|
}
|
|
199490
199547
|
}
|
|
199491
199548
|
|
|
199492
|
-
|
|
199493
|
-
|
|
199494
|
-
|
|
199549
|
+
BufferManager::EvictionResult BufferManager::EvictBlocks(idx_t extra_memory, idx_t memory_limit,
|
|
199550
|
+
unique_ptr<FileBuffer> *buffer) {
|
|
199495
199551
|
BufferEvictionNode node;
|
|
199496
|
-
current_memory
|
|
199552
|
+
TempBufferPoolReservation r(current_memory, extra_memory);
|
|
199497
199553
|
while (current_memory > memory_limit) {
|
|
199498
199554
|
// get a block to unpin from the queue
|
|
199499
199555
|
if (!queue->q.try_dequeue(node)) {
|
|
199500
|
-
|
|
199501
|
-
current_memory
|
|
199502
|
-
return false;
|
|
199556
|
+
// Failed to reserve. Adjust size of temp reservation to 0.
|
|
199557
|
+
r.Resize(current_memory, 0);
|
|
199558
|
+
return {false, move(r)};
|
|
199503
199559
|
}
|
|
199504
199560
|
// get a reference to the underlying block pointer
|
|
199505
199561
|
auto handle = node.TryGetBlockHandle();
|
|
@@ -199516,13 +199572,13 @@ bool BufferManager::EvictBlocks(idx_t extra_memory, idx_t memory_limit, unique_p
|
|
|
199516
199572
|
if (buffer && handle->buffer->AllocSize() == extra_memory) {
|
|
199517
199573
|
// we can actually re-use the memory directly!
|
|
199518
199574
|
*buffer = handle->UnloadAndTakeBlock();
|
|
199519
|
-
return true;
|
|
199575
|
+
return {true, move(r)};
|
|
199520
199576
|
} else {
|
|
199521
199577
|
// release the memory and mark the block as unloaded
|
|
199522
199578
|
handle->Unload();
|
|
199523
199579
|
}
|
|
199524
199580
|
}
|
|
199525
|
-
return true;
|
|
199581
|
+
return {true, move(r)};
|
|
199526
199582
|
}
|
|
199527
199583
|
|
|
199528
199584
|
void BufferManager::PurgeQueue() {
|
|
@@ -199558,7 +199614,7 @@ void BlockManager::UnregisterBlock(block_id_t block_id, bool can_destroy) {
|
|
|
199558
199614
|
void BufferManager::SetLimit(idx_t limit) {
|
|
199559
199615
|
lock_guard<mutex> l_lock(limit_lock);
|
|
199560
199616
|
// try to evict until the limit is reached
|
|
199561
|
-
if (!EvictBlocks(0, limit)) {
|
|
199617
|
+
if (!EvictBlocks(0, limit).success) {
|
|
199562
199618
|
throw OutOfMemoryException(
|
|
199563
199619
|
"Failed to change memory limit to %lld: could not free up enough memory for the new limit%s", limit,
|
|
199564
199620
|
InMemoryWarning());
|
|
@@ -199567,7 +199623,7 @@ void BufferManager::SetLimit(idx_t limit) {
|
|
|
199567
199623
|
// set the global maximum memory to the new limit if successful
|
|
199568
199624
|
maximum_memory = limit;
|
|
199569
199625
|
// evict again
|
|
199570
|
-
if (!EvictBlocks(0, limit)) {
|
|
199626
|
+
if (!EvictBlocks(0, limit).success) {
|
|
199571
199627
|
// failed: go back to old limit
|
|
199572
199628
|
maximum_memory = old_limit;
|
|
199573
199629
|
throw OutOfMemoryException(
|
|
@@ -199987,24 +200043,28 @@ string BufferManager::InMemoryWarning() {
|
|
|
199987
200043
|
//===--------------------------------------------------------------------===//
|
|
199988
200044
|
data_ptr_t BufferManager::BufferAllocatorAllocate(PrivateAllocatorData *private_data, idx_t size) {
|
|
199989
200045
|
auto &data = (BufferAllocatorData &)*private_data;
|
|
199990
|
-
|
|
199991
|
-
|
|
199992
|
-
|
|
200046
|
+
auto reservation = data.manager.EvictBlocksOrThrow(size, data.manager.maximum_memory, nullptr,
|
|
200047
|
+
"failed to allocate data of size %lld%s", size);
|
|
200048
|
+
// We rely on manual tracking of this one. :(
|
|
200049
|
+
reservation.size = 0;
|
|
199993
200050
|
return Allocator::Get(data.manager.db).AllocateData(size);
|
|
199994
200051
|
}
|
|
199995
200052
|
|
|
199996
200053
|
void BufferManager::BufferAllocatorFree(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t size) {
|
|
199997
200054
|
auto &data = (BufferAllocatorData &)*private_data;
|
|
199998
|
-
|
|
199999
|
-
|
|
200055
|
+
BufferPoolReservation r;
|
|
200056
|
+
r.size = size;
|
|
200057
|
+
r.Resize(data.manager.current_memory, 0);
|
|
200000
200058
|
return Allocator::Get(data.manager.db).FreeData(pointer, size);
|
|
200001
200059
|
}
|
|
200002
200060
|
|
|
200003
200061
|
data_ptr_t BufferManager::BufferAllocatorRealloc(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t old_size,
|
|
200004
200062
|
idx_t size) {
|
|
200005
200063
|
auto &data = (BufferAllocatorData &)*private_data;
|
|
200006
|
-
|
|
200007
|
-
|
|
200064
|
+
BufferPoolReservation r;
|
|
200065
|
+
r.size = old_size;
|
|
200066
|
+
r.Resize(data.manager.current_memory, size);
|
|
200067
|
+
r.size = 0;
|
|
200008
200068
|
return Allocator::Get(data.manager.db).ReallocateData(pointer, old_size, size);
|
|
200009
200069
|
}
|
|
200010
200070
|
|
package/src/duckdb.hpp
CHANGED
|
@@ -11,8 +11,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
11
11
|
#pragma once
|
|
12
12
|
#define DUCKDB_AMALGAMATION 1
|
|
13
13
|
#define DUCKDB_AMALGAMATION_EXTENDED 1
|
|
14
|
-
#define DUCKDB_SOURCE_ID "
|
|
15
|
-
#define DUCKDB_VERSION "v0.5.2-
|
|
14
|
+
#define DUCKDB_SOURCE_ID "bf5b49fcee"
|
|
15
|
+
#define DUCKDB_VERSION "v0.5.2-dev1819"
|
|
16
16
|
//===----------------------------------------------------------------------===//
|
|
17
17
|
// DuckDB
|
|
18
18
|
//
|
|
@@ -1980,12 +1980,19 @@ public:
|
|
|
1980
1980
|
|
|
1981
1981
|
// Same rules as the constructor. We will add room for a header, in additio to
|
|
1982
1982
|
// the requested user bytes. We will then sector-align the result.
|
|
1983
|
-
|
|
1983
|
+
void Resize(uint64_t user_size);
|
|
1984
1984
|
|
|
1985
1985
|
uint64_t AllocSize() const {
|
|
1986
1986
|
return internal_size;
|
|
1987
1987
|
}
|
|
1988
1988
|
|
|
1989
|
+
struct MemoryRequirement {
|
|
1990
|
+
idx_t alloc_size;
|
|
1991
|
+
idx_t header_size;
|
|
1992
|
+
};
|
|
1993
|
+
|
|
1994
|
+
MemoryRequirement CalculateMemory(uint64_t user_size);
|
|
1995
|
+
|
|
1989
1996
|
protected:
|
|
1990
1997
|
//! The pointer to the internal buffer that will be read or written, including the buffer header
|
|
1991
1998
|
data_ptr_t internal_buffer;
|
|
@@ -25280,6 +25287,34 @@ class FileBuffer;
|
|
|
25280
25287
|
|
|
25281
25288
|
enum class BlockState : uint8_t { BLOCK_UNLOADED = 0, BLOCK_LOADED = 1 };
|
|
25282
25289
|
|
|
25290
|
+
struct BufferPoolReservation {
|
|
25291
|
+
idx_t size {0};
|
|
25292
|
+
|
|
25293
|
+
BufferPoolReservation() {
|
|
25294
|
+
}
|
|
25295
|
+
BufferPoolReservation(const BufferPoolReservation &) = delete;
|
|
25296
|
+
BufferPoolReservation &operator=(const BufferPoolReservation &) = delete;
|
|
25297
|
+
|
|
25298
|
+
BufferPoolReservation(BufferPoolReservation &&) noexcept;
|
|
25299
|
+
BufferPoolReservation &operator=(BufferPoolReservation &&) noexcept;
|
|
25300
|
+
|
|
25301
|
+
~BufferPoolReservation();
|
|
25302
|
+
|
|
25303
|
+
void Resize(atomic<idx_t> &counter, idx_t new_size);
|
|
25304
|
+
void Merge(BufferPoolReservation &&src);
|
|
25305
|
+
};
|
|
25306
|
+
|
|
25307
|
+
struct TempBufferPoolReservation : BufferPoolReservation {
|
|
25308
|
+
atomic<idx_t> &counter;
|
|
25309
|
+
TempBufferPoolReservation(atomic<idx_t> &counter, idx_t size) : counter(counter) {
|
|
25310
|
+
Resize(counter, size);
|
|
25311
|
+
}
|
|
25312
|
+
TempBufferPoolReservation(TempBufferPoolReservation &&) = default;
|
|
25313
|
+
~TempBufferPoolReservation() {
|
|
25314
|
+
Resize(counter, 0);
|
|
25315
|
+
}
|
|
25316
|
+
};
|
|
25317
|
+
|
|
25283
25318
|
class BlockHandle {
|
|
25284
25319
|
friend class BlockManager;
|
|
25285
25320
|
friend struct BufferEvictionNode;
|
|
@@ -25289,7 +25324,7 @@ class BlockHandle {
|
|
|
25289
25324
|
public:
|
|
25290
25325
|
BlockHandle(BlockManager &block_manager, block_id_t block_id);
|
|
25291
25326
|
BlockHandle(BlockManager &block_manager, block_id_t block_id, unique_ptr<FileBuffer> buffer, bool can_destroy,
|
|
25292
|
-
idx_t block_size);
|
|
25327
|
+
idx_t block_size, BufferPoolReservation &&reservation);
|
|
25293
25328
|
~BlockHandle();
|
|
25294
25329
|
|
|
25295
25330
|
BlockManager &block_manager;
|
|
@@ -25331,8 +25366,11 @@ private:
|
|
|
25331
25366
|
atomic<idx_t> eviction_timestamp;
|
|
25332
25367
|
//! Whether or not the buffer can be destroyed (only used for temporary buffers)
|
|
25333
25368
|
const bool can_destroy;
|
|
25334
|
-
//! The memory usage of the block
|
|
25369
|
+
//! The memory usage of the block (when loaded). If we are pinning/loading
|
|
25370
|
+
//! an unloaded block, this tells us how much memory to reserve.
|
|
25335
25371
|
idx_t memory_usage;
|
|
25372
|
+
//! Current memory reservation / usage
|
|
25373
|
+
BufferPoolReservation memory_charge;
|
|
25336
25374
|
//! Does the block contain any memory pointers?
|
|
25337
25375
|
const char *unswizzled;
|
|
25338
25376
|
};
|
|
@@ -25418,7 +25456,18 @@ private:
|
|
|
25418
25456
|
//! (i.e. not enough blocks could be evicted)
|
|
25419
25457
|
//! If the "buffer" argument is specified AND the system can find a buffer to re-use for the given allocation size
|
|
25420
25458
|
//! "buffer" will be made to point to the re-usable memory. Note that this is not guaranteed.
|
|
25421
|
-
|
|
25459
|
+
//! Returns a pair. result.first indicates if eviction was successful. result.second contains the
|
|
25460
|
+
//! reservation handle, which can be moved to the BlockHandle that will own the reservation.
|
|
25461
|
+
struct EvictionResult {
|
|
25462
|
+
bool success;
|
|
25463
|
+
TempBufferPoolReservation reservation;
|
|
25464
|
+
};
|
|
25465
|
+
EvictionResult EvictBlocks(idx_t extra_memory, idx_t memory_limit, unique_ptr<FileBuffer> *buffer = nullptr);
|
|
25466
|
+
|
|
25467
|
+
//! Helper
|
|
25468
|
+
template <typename... ARGS>
|
|
25469
|
+
TempBufferPoolReservation EvictBlocksOrThrow(idx_t extra_memory, idx_t limit, unique_ptr<FileBuffer> *buffer,
|
|
25470
|
+
ARGS...);
|
|
25422
25471
|
|
|
25423
25472
|
//! Garbage collect eviction queue
|
|
25424
25473
|
void PurgeQueue();
|
|
@@ -25462,6 +25511,8 @@ private:
|
|
|
25462
25511
|
unique_ptr<EvictionQueue> queue;
|
|
25463
25512
|
//! The temporary id used for managed buffers
|
|
25464
25513
|
atomic<block_id_t> temporary_id;
|
|
25514
|
+
//! Total number of insertions into the eviction queue. This guides the schedule for calling PurgeQueue.
|
|
25515
|
+
atomic<uint32_t> queue_insertions;
|
|
25465
25516
|
//! Allocator associated with the buffer manager, that passes all allocations through this buffer manager
|
|
25466
25517
|
Allocator buffer_allocator;
|
|
25467
25518
|
//! Block manager for temp data
|