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 | |
17 | namespace duckdb { |
18 | class BlockHandle; |
19 | class BufferManager; |
20 | class ClientContext; |
21 | class 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. |
25 | class BlockManager { |
26 | public: |
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 | |
34 | public: |
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 (DatabaseHeader ) = 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 | |
80 | private: |
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 | |