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 | |
11 | namespace duckdb { |
12 | |
13 | FileBuffer::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 | |
21 | void FileBuffer::Init() { |
22 | buffer = nullptr; |
23 | size = 0; |
24 | internal_buffer = nullptr; |
25 | internal_size = 0; |
26 | } |
27 | |
28 | FileBuffer::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 | |
38 | FileBuffer::~FileBuffer() { |
39 | if (!internal_buffer) { |
40 | return; |
41 | } |
42 | allocator.FreeData(pointer: internal_buffer, size: internal_size); |
43 | } |
44 | |
45 | void 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 | |
62 | FileBuffer::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 | |
76 | void 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 | |
86 | void 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 | |
91 | void 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 | |
96 | void FileBuffer::Clear() { |
97 | memset(s: internal_buffer, c: 0, n: internal_size); |
98 | } |
99 | |
100 | void 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 | |