1#include "duckdb/common/file_buffer.hpp"
2
3#include "duckdb/common/allocator.hpp"
4#include "duckdb/common/checksum.hpp"
5#include "duckdb/common/exception.hpp"
6#include "duckdb/common/file_system.hpp"
7#include "duckdb/common/helper.hpp"
8
9#include <cstring>
10
11namespace duckdb {
12
13FileBuffer::FileBuffer(Allocator &allocator, FileBufferType type, uint64_t user_size)
14 : allocator(allocator), type(type) {
15 Init();
16 if (user_size) {
17 Resize(user_size);
18 }
19}
20
21void FileBuffer::Init() {
22 buffer = nullptr;
23 size = 0;
24 internal_buffer = nullptr;
25 internal_size = 0;
26}
27
28FileBuffer::FileBuffer(FileBuffer &source, FileBufferType type_p) : allocator(source.allocator), type(type_p) {
29 // take over the structures of the source buffer
30 buffer = source.buffer;
31 size = source.size;
32 internal_buffer = source.internal_buffer;
33 internal_size = source.internal_size;
34
35 source.Init();
36}
37
38FileBuffer::~FileBuffer() {
39 if (!internal_buffer) {
40 return;
41 }
42 allocator.FreeData(pointer: internal_buffer, size: internal_size);
43}
44
45void FileBuffer::ReallocBuffer(size_t new_size) {
46 data_ptr_t new_buffer;
47 if (internal_buffer) {
48 new_buffer = allocator.ReallocateData(pointer: internal_buffer, old_size: internal_size, size: new_size);
49 } else {
50 new_buffer = allocator.AllocateData(size: new_size);
51 }
52 if (!new_buffer) {
53 throw std::bad_alloc();
54 }
55 internal_buffer = new_buffer;
56 internal_size = new_size;
57 // Caller must update these.
58 buffer = nullptr;
59 size = 0;
60}
61
62FileBuffer::MemoryRequirement FileBuffer::CalculateMemory(uint64_t user_size) {
63 FileBuffer::MemoryRequirement result;
64
65 if (type == FileBufferType::TINY_BUFFER) {
66 // We never do IO on tiny buffers, so there's no need to add a header or sector-align.
67 result.header_size = 0;
68 result.alloc_size = user_size;
69 } else {
70 result.header_size = Storage::BLOCK_HEADER_SIZE;
71 result.alloc_size = AlignValue<uint32_t, Storage::SECTOR_SIZE>(n: result.header_size + user_size);
72 }
73 return result;
74}
75
76void FileBuffer::Resize(uint64_t new_size) {
77 auto req = CalculateMemory(user_size: new_size);
78 ReallocBuffer(new_size: req.alloc_size);
79
80 if (new_size > 0) {
81 buffer = internal_buffer + req.header_size;
82 size = internal_size - req.header_size;
83 }
84}
85
86void FileBuffer::Read(FileHandle &handle, uint64_t location) {
87 D_ASSERT(type != FileBufferType::TINY_BUFFER);
88 handle.Read(buffer: internal_buffer, nr_bytes: internal_size, location);
89}
90
91void FileBuffer::Write(FileHandle &handle, uint64_t location) {
92 D_ASSERT(type != FileBufferType::TINY_BUFFER);
93 handle.Write(buffer: internal_buffer, nr_bytes: internal_size, location);
94}
95
96void FileBuffer::Clear() {
97 memset(s: internal_buffer, c: 0, n: internal_size);
98}
99
100void FileBuffer::Initialize(DebugInitialize initialize) {
101 if (initialize == DebugInitialize::NO_INITIALIZE) {
102 return;
103 }
104 uint8_t value = initialize == DebugInitialize::DEBUG_ZERO_INITIALIZE ? 0 : 0xFF;
105 memset(s: internal_buffer, c: value, n: internal_size);
106}
107
108} // namespace duckdb
109