Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/include/duckdb/storage/block_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "duckdb/common/optional_idx.hpp"
#include "duckdb/common/unordered_map.hpp"
#include "duckdb/storage/block.hpp"
#include "duckdb/storage/buffer/buffer_handle.hpp"
#include "duckdb/storage/storage_info.hpp"

namespace duckdb {
Expand Down Expand Up @@ -182,6 +183,12 @@ class BlockManager {
return reinterpret_cast<const TARGET &>(*this);
}

public:
//! Begin deferring eviction queue additions (call before checkpoint writes)
void BeginDeferEviction();
//! End deferring and release all retained blocks to the eviction queue
void EndDeferEviction();

protected:
//! A flag to be flipped in the destructor of the subclass, which is called first.
//! Relevant for some Windows edge cases.
Expand All @@ -192,6 +199,10 @@ class BlockManager {
mutex blocks_lock;
//! A mapping of block id -> BlockHandle
unordered_map<block_id_t, weak_ptr<BlockHandle>> blocks;
//! When true, ConvertToPersistent pins blocks instead of adding to eviction queue
bool defer_eviction = false;
//! Blocks pinned during deferred eviction (kept alive until EndDeferEviction)
vector<BufferHandle> deferred_pins;
//! The metadata manager
unique_ptr<MetadataManager> metadata_manager;
//! The allocation size of blocks managed by this block manager. Defaults to DEFAULT_BLOCK_ALLOC_SIZE
Expand Down
24 changes: 20 additions & 4 deletions src/storage/buffer/block_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,13 @@ shared_ptr<BlockHandle> BlockManager::ConvertToPersistent(QueryContext context,
old_handle.Destroy();
old_block.reset();

// potentially purge the queue
auto purge_queue = buffer_manager.GetBufferPool().AddToEvictionQueue(new_block);
if (purge_queue) {
buffer_manager.GetBufferPool().PurgeQueue(*new_block);
if (defer_eviction) {
deferred_pins.push_back(buffer_manager.Pin(new_block));
} else {
auto purge_queue = buffer_manager.GetBufferPool().AddToEvictionQueue(new_block);
if (purge_queue) {
buffer_manager.GetBufferPool().PurgeQueue(*new_block);
}
}
return new_block;
}
Expand Down Expand Up @@ -148,4 +151,17 @@ void BlockManager::Write(QueryContext context, FileBuffer &block, block_id_t blo
void BlockManager::Truncate() {
}

void BlockManager::BeginDeferEviction() {
defer_eviction = true;
}

void BlockManager::EndDeferEviction() {
defer_eviction = false;
// Release all pins — blocks become eligible for eviction
for (auto &pin : deferred_pins) {
pin.Destroy();
}
deferred_pins.clear();
}

} // namespace duckdb
3 changes: 3 additions & 0 deletions src/storage/checkpoint_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ void SingleFileCheckpointWriter::CreateCheckpoint() {
dependency_manager.ReorderEntries(catalog_entries);

// write the actual data into the database
block_manager.BeginDeferEviction();

// Create a serializer to write the checkpoint data
// The serialized format is roughly:
Expand Down Expand Up @@ -277,6 +278,8 @@ void SingleFileCheckpointWriter::CreateCheckpoint() {
metadata_writer->Flush();
table_metadata_writer->Flush();

block_manager.EndDeferEviction();

auto debug_checkpoint_abort = Settings::Get<DebugCheckpointAbortSetting>(db.GetDatabase());
if (debug_checkpoint_abort == CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER) {
throw FatalException("Checkpoint aborted before header write because of PRAGMA checkpoint_abort flag");
Expand Down
Loading