1//===----------------------------------------------------------------------===//
2// DuckDB
3//
4// duckdb/storage/block_manager.hpp
5//
6//
7//===----------------------------------------------------------------------===//
8
9#pragma once
10
11#include "duckdb/common/common.hpp"
12#include "duckdb/common/mutex.hpp"
13#include "duckdb/storage/block.hpp"
14#include "duckdb/storage/storage_info.hpp"
15#include "duckdb/common/unordered_map.hpp"
16
17namespace duckdb {
18class BlockHandle;
19class BufferManager;
20class ClientContext;
21class DatabaseInstance;
22
23//! BlockManager is an abstract representation to manage blocks on DuckDB. When writing or reading blocks, the
24//! BlockManager creates and accesses blocks. The concrete types implements how blocks are stored.
25class BlockManager {
26public:
27 explicit BlockManager(BufferManager &buffer_manager) : buffer_manager(buffer_manager) {
28 }
29 virtual ~BlockManager() = default;
30
31 //! The buffer manager
32 BufferManager &buffer_manager;
33
34public:
35 //! Creates a new block inside the block manager
36 virtual unique_ptr<Block> ConvertBlock(block_id_t block_id, FileBuffer &source_buffer) = 0;
37 virtual unique_ptr<Block> CreateBlock(block_id_t block_id, FileBuffer *source_buffer) = 0;
38 //! Return the next free block id
39 virtual block_id_t GetFreeBlockId() = 0;
40 //! Returns whether or not a specified block is the root block
41 virtual bool IsRootBlock(block_id_t root) = 0;
42 //! Mark a block as "free"; free blocks are immediately added to the free list and can be immediately overwritten
43 virtual void MarkBlockAsFree(block_id_t block_id) = 0;
44 //! Mark a block as "modified"; modified blocks are added to the free list after a checkpoint (i.e. their data is
45 //! assumed to be rewritten)
46 virtual void MarkBlockAsModified(block_id_t block_id) = 0;
47 //! Increase the reference count of a block. The block should hold at least one reference before this method is
48 //! called.
49 virtual void IncreaseBlockReferenceCount(block_id_t block_id) = 0;
50 //! Get the first meta block id
51 virtual block_id_t GetMetaBlock() = 0;
52 //! Read the content of the block from disk
53 virtual void Read(Block &block) = 0;
54 //! Writes the block to disk
55 virtual void Write(FileBuffer &block, block_id_t block_id) = 0;
56 //! Writes the block to disk
57 void Write(Block &block) {
58 Write(block, block_id: block.id);
59 }
60 //! Write the header; should be the final step of a checkpoint
61 virtual void WriteHeader(DatabaseHeader header) = 0;
62
63 //! Returns the number of total blocks
64 virtual idx_t TotalBlocks() = 0;
65 //! Returns the number of free blocks
66 virtual idx_t FreeBlocks() = 0;
67
68 //! Register a block with the given block id in the base file
69 shared_ptr<BlockHandle> RegisterBlock(block_id_t block_id, bool is_meta_block = false);
70 //! Clear cached handles for meta blocks
71 void ClearMetaBlockHandles();
72 //! Convert an existing in-memory buffer into a persistent disk-backed block
73 shared_ptr<BlockHandle> ConvertToPersistent(block_id_t block_id, shared_ptr<BlockHandle> old_block);
74
75 void UnregisterBlock(block_id_t block_id, bool can_destroy);
76
77 static BlockManager &GetBlockManager(ClientContext &context);
78 static BlockManager &GetBlockManager(DatabaseInstance &db);
79
80private:
81 //! The lock for the set of blocks
82 mutex blocks_lock;
83 //! A mapping of block id -> BlockHandle
84 unordered_map<block_id_t, weak_ptr<BlockHandle>> blocks;
85 //! A map to cache the BlockHandles of meta blocks
86 unordered_map<block_id_t, shared_ptr<BlockHandle>> meta_blocks;
87};
88} // namespace duckdb
89