1#include "duckdb/storage/meta_block_reader.hpp"
2#include "duckdb/storage/buffer_manager.hpp"
3#include "duckdb/main/connection_manager.hpp"
4#include "duckdb/main/database.hpp"
5
6#include <cstring>
7
8namespace duckdb {
9
10MetaBlockReader::MetaBlockReader(BlockManager &block_manager, block_id_t block_id, bool free_blocks_on_read)
11 : block_manager(block_manager), offset(0), next_block(-1), free_blocks_on_read(free_blocks_on_read) {
12 ReadNewBlock(id: block_id);
13}
14
15MetaBlockReader::~MetaBlockReader() {
16}
17
18void MetaBlockReader::ReadData(data_ptr_t buffer, idx_t read_size) {
19 while (offset + read_size > handle.GetFileBuffer().size) {
20 // cannot read entire entry from block
21 // first read what we can from this block
22 idx_t to_read = handle.GetFileBuffer().size - offset;
23 if (to_read > 0) {
24 memcpy(dest: buffer, src: handle.Ptr() + offset, n: to_read);
25 read_size -= to_read;
26 buffer += to_read;
27 }
28 // then move to the next block
29 if (next_block == INVALID_BLOCK) {
30 throw IOException("Cannot read from INVALID_BLOCK.");
31 }
32 ReadNewBlock(id: next_block);
33 }
34 // we have enough left in this block to read from the buffer
35 memcpy(dest: buffer, src: handle.Ptr() + offset, n: read_size);
36 offset += read_size;
37}
38
39ClientContext &MetaBlockReader::GetContext() {
40 if (!context) {
41 throw InternalException("Meta Block Reader is missing context");
42 }
43 return *context;
44}
45
46optional_ptr<Catalog> MetaBlockReader::GetCatalog() {
47 return catalog;
48}
49
50void MetaBlockReader::ReadNewBlock(block_id_t id) {
51 auto &buffer_manager = block_manager.buffer_manager;
52
53 // Marking these blocks as modified will cause them to be moved to the free
54 // list upon the next successful checkpoint. Marking them modified here
55 // assumes MetaBlockReader is exclusively used for reading checkpoint data,
56 // and thus any blocks we're reading will be obviated by the next checkpoint.
57 if (free_blocks_on_read) {
58 block_manager.MarkBlockAsModified(block_id: id);
59 }
60 block = block_manager.RegisterBlock(block_id: id, is_meta_block: true);
61 handle = buffer_manager.Pin(handle&: block);
62
63 next_block = Load<block_id_t>(ptr: handle.Ptr());
64 D_ASSERT(next_block >= -1);
65 offset = sizeof(block_id_t);
66}
67
68void MetaBlockReader::SetCatalog(Catalog &catalog_p) {
69 D_ASSERT(!catalog);
70 catalog = &catalog_p;
71}
72
73void MetaBlockReader::SetContext(ClientContext &context_p) {
74 D_ASSERT(!context);
75 context = &context_p;
76}
77
78} // namespace duckdb
79