1//===----------------------------------------------------------------------===//
2// DuckDB
3//
4// duckdb/storage/buffer/block_handle.hpp
5//
6//
7//===----------------------------------------------------------------------===//
8
9#pragma once
10
11#include "duckdb/common/atomic.hpp"
12#include "duckdb/common/common.hpp"
13#include "duckdb/common/mutex.hpp"
14#include "duckdb/storage/storage_info.hpp"
15#include "duckdb/common/file_buffer.hpp"
16
17namespace duckdb {
18class BlockManager;
19class BufferHandle;
20class BufferPool;
21class DatabaseInstance;
22
23enum class BlockState : uint8_t { BLOCK_UNLOADED = 0, BLOCK_LOADED = 1 };
24
25struct BufferPoolReservation {
26 idx_t size {0};
27 BufferPool &pool;
28
29 BufferPoolReservation(BufferPool &pool);
30 BufferPoolReservation(const BufferPoolReservation &) = delete;
31 BufferPoolReservation &operator=(const BufferPoolReservation &) = delete;
32
33 BufferPoolReservation(BufferPoolReservation &&) noexcept;
34 BufferPoolReservation &operator=(BufferPoolReservation &&) noexcept;
35
36 ~BufferPoolReservation();
37
38 void Resize(idx_t new_size);
39 void Merge(BufferPoolReservation &&src);
40};
41
42struct TempBufferPoolReservation : BufferPoolReservation {
43 TempBufferPoolReservation(BufferPool &pool, idx_t size) : BufferPoolReservation(pool) {
44 Resize(new_size: size);
45 }
46 TempBufferPoolReservation(TempBufferPoolReservation &&) = default;
47 ~TempBufferPoolReservation() {
48 Resize(new_size: 0);
49 }
50};
51
52class BlockHandle {
53 friend class BlockManager;
54 friend struct BufferEvictionNode;
55 friend class BufferHandle;
56 friend class BufferManager;
57 friend class StandardBufferManager;
58 friend class BufferPool;
59
60public:
61 BlockHandle(BlockManager &block_manager, block_id_t block_id);
62 BlockHandle(BlockManager &block_manager, block_id_t block_id, unique_ptr<FileBuffer> buffer, bool can_destroy,
63 idx_t block_size, BufferPoolReservation &&reservation);
64 ~BlockHandle();
65
66 BlockManager &block_manager;
67
68public:
69 block_id_t BlockId() {
70 return block_id;
71 }
72
73 void ResizeBuffer(idx_t block_size, int64_t memory_delta) {
74 D_ASSERT(buffer);
75 // resize and adjust current memory
76 buffer->Resize(user_size: block_size);
77 memory_usage += memory_delta;
78 D_ASSERT(memory_usage == buffer->AllocSize());
79 }
80
81 int32_t Readers() const {
82 return readers;
83 }
84
85 inline bool IsSwizzled() const {
86 return !unswizzled;
87 }
88
89 inline void SetSwizzling(const char *unswizzler) {
90 unswizzled = unswizzler;
91 }
92
93 inline void SetCanDestroy(bool can_destroy_p) {
94 can_destroy = can_destroy_p;
95 }
96
97 inline const idx_t &GetMemoryUsage() const {
98 return memory_usage;
99 }
100
101private:
102 static BufferHandle Load(shared_ptr<BlockHandle> &handle, unique_ptr<FileBuffer> buffer = nullptr);
103 unique_ptr<FileBuffer> UnloadAndTakeBlock();
104 void Unload();
105 bool CanUnload();
106
107 //! The block-level lock
108 mutex lock;
109 //! Whether or not the block is loaded/unloaded
110 atomic<BlockState> state;
111 //! Amount of concurrent readers
112 atomic<int32_t> readers;
113 //! The block id of the block
114 const block_id_t block_id;
115 //! Pointer to loaded data (if any)
116 unique_ptr<FileBuffer> buffer;
117 //! Internal eviction timestamp
118 atomic<idx_t> eviction_timestamp;
119 //! Whether or not the buffer can be destroyed (only used for temporary buffers)
120 bool can_destroy;
121 //! The memory usage of the block (when loaded). If we are pinning/loading
122 //! an unloaded block, this tells us how much memory to reserve.
123 idx_t memory_usage;
124 //! Current memory reservation / usage
125 BufferPoolReservation memory_charge;
126 //! Does the block contain any memory pointers?
127 const char *unswizzled;
128};
129
130} // namespace duckdb
131